diff --git a/assets/icons/1gang.svg b/assets/icons/1gang.svg new file mode 100644 index 0000000..23dee22 --- /dev/null +++ b/assets/icons/1gang.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart b/lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart new file mode 100644 index 0000000..b92717d --- /dev/null +++ b/lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart @@ -0,0 +1,179 @@ +import 'dart:async'; +import 'package:firebase_database/firebase_database.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_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/one_gang_model.dart'; +import 'package:syncrow_app/features/devices/model/status_model.dart'; +import 'package:syncrow_app/services/api/devices_api.dart'; +import 'one_gang_event.dart'; + +class OneGangBloc extends Bloc { + final String oneGangId; + OneGangModel deviceStatus = OneGangModel( + firstSwitch: false, + firstCountDown: 0, + ); + Timer? _timer; + + bool oneGangGroup = false; + List devicesList = []; + bool allSwitchesOn = true; + + OneGangBloc({required this.oneGangId}) : super(InitialState()) { + on(_fetchTwoGangStatus); + on(_oneGangUpdated); + on(_changeFirstSwitch); + on(_changeSliding); + on(_setCounterValue); + on(_getCounterValue); + on(_onTickTimer); + on(_onClose); + } + + void _fetchTwoGangStatus(InitialEvent event, Emitter emit) async { + emit(LoadingInitialState()); + try { + var response = await DevicesAPI.getDeviceStatus(oneGangId); + List statusModelList = []; + for (var status in response['status']) { + statusModelList.add(StatusModel.fromJson(status)); + } + deviceStatus = OneGangModel.fromJson(statusModelList); + emit(UpdateState(oneGangModel: deviceStatus)); + _listenToChanges(); + } catch (e) { + emit(FailedState(error: e.toString())); + return; + } + } + + _listenToChanges() { + try { + DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$oneGangId'); + Stream stream = ref.onValue; + + stream.listen((DatabaseEvent event) async { + if (_timer != null) { + await Future.delayed(const Duration(seconds: 2)); + } + Map usersMap = event.snapshot.value as Map; + List statusList = []; + + usersMap['status'].forEach((element) { + statusList.add(StatusModel(code: element['code'], value: element['value'])); + }); + + deviceStatus = OneGangModel.fromJson(statusList); + if (!isClosed) { + add(OneGangUpdated()); + } + }); + } catch (_) {} + } + + _oneGangUpdated(OneGangUpdated event, Emitter emit) { + emit(UpdateState(oneGangModel: deviceStatus)); + } + + void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter emit) async { + emit(LoadingNewSate(oneGangModel: deviceStatus)); + try { + deviceStatus.firstSwitch = !event.value; + emit(UpdateState(oneGangModel: deviceStatus)); + if (_timer != null) { + _timer!.cancel(); + } + _timer = Timer(const Duration(milliseconds: 500), () async { + final response = await DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: oneGangGroup ? event.deviceId : oneGangId, + code: 'switch_1', + value: !event.value), + oneGangGroup ? event.deviceId : oneGangId); + + if (!response['success']) { + add(InitialEvent(groupScreen: oneGangGroup)); + } + }); + } catch (_) { + add(InitialEvent(groupScreen: oneGangGroup)); + } + } + + + void _changeSliding(ChangeSlidingSegment event, Emitter emit) async { + emit(ChangeSlidingSegmentState(value: event.value)); + } + + void _setCounterValue(SetCounterValue event, Emitter emit) async { + emit(LoadingNewSate(oneGangModel: deviceStatus)); + int seconds = 0; + try { + seconds = event.duration.inSeconds; + final response = await DevicesAPI.controlDevice( + DeviceControlModel(deviceId: oneGangId, code: event.deviceCode, value: seconds), + oneGangId); + + if (response['success'] ?? false) { + if (event.deviceCode == 'countdown_1') { + deviceStatus.firstCountDown = 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 emit) async { + emit(LoadingInitialState()); + try { + var response = await DevicesAPI.getDeviceStatus(oneGangId); + List statusModelList = []; + for (var status in response['status']) { + statusModelList.add(StatusModel.fromJson(status)); + } + deviceStatus = OneGangModel.fromJson(statusModelList); + + if (event.deviceCode == 'countdown_1') { + deviceStatus.firstCountDown > 0 + ? _onStartTimer(deviceStatus.firstCountDown) + : emit(UpdateTimerState(seconds: deviceStatus.firstCountDown)); + } + } catch (e) { + emit(FailedState(error: e.toString())); + return; + } + } + + void _onClose(OnClose event, Emitter 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 emit) { + if (event.remainingTime > 0) { + emit(TimerRunInProgress(event.remainingTime)); + } else { + _timer?.cancel(); + emit(TimerRunComplete()); + } + } +} diff --git a/lib/features/devices/bloc/one_gang_bloc/one_gang_event.dart b/lib/features/devices/bloc/one_gang_bloc/one_gang_event.dart new file mode 100644 index 0000000..e245b39 --- /dev/null +++ b/lib/features/devices/bloc/one_gang_bloc/one_gang_event.dart @@ -0,0 +1,88 @@ +import 'package:equatable/equatable.dart'; + +abstract class OneGangEvent extends Equatable { + const OneGangEvent(); + + @override + List get props => []; +} + +class LoadingEvent extends OneGangEvent {} + +class OneGangUpdated extends OneGangEvent {} + +class InitialEvent extends OneGangEvent { + final bool groupScreen; + const InitialEvent({required this.groupScreen}); + @override + List get props => [groupScreen]; +} + +class ChangeFirstSwitchStatusEvent extends OneGangEvent { + final bool value; + final String deviceId; + const ChangeFirstSwitchStatusEvent({required this.value, this.deviceId = ''}); + @override + List get props => [value, deviceId]; +} + +class ChangeSecondSwitchStatusEvent extends OneGangEvent { + final bool value; + final String deviceId; + const ChangeSecondSwitchStatusEvent({required this.value, this.deviceId = ''}); + @override + List get props => [value, deviceId]; +} + + +class AllOffEvent extends OneGangEvent {} + +class AllOnEvent extends OneGangEvent {} + +class GroupAllOnEvent extends OneGangEvent {} + +class GroupAllOffEvent extends OneGangEvent {} + +class ChangeSlidingSegment extends OneGangEvent { + final int value; + const ChangeSlidingSegment({required this.value}); + @override + List get props => [value]; +} + +class GetCounterEvent extends OneGangEvent { + final String deviceCode; + const GetCounterEvent({required this.deviceCode}); + @override + List get props => [deviceCode]; +} + +class SetCounterValue extends OneGangEvent { + final Duration duration; + final String deviceCode; + const SetCounterValue({required this.duration, required this.deviceCode}); + @override + List get props => [duration, deviceCode]; +} + +class StartTimer extends OneGangEvent { + final int duration; + + const StartTimer(this.duration); + + @override + List get props => [duration]; +} + +class TickTimer extends OneGangEvent { + final int remainingTime; + + const TickTimer(this.remainingTime); + + @override + List get props => [remainingTime]; +} + +class StopTimer extends OneGangEvent {} + +class OnClose extends OneGangEvent {} diff --git a/lib/features/devices/bloc/one_gang_bloc/one_gang_state.dart b/lib/features/devices/bloc/one_gang_bloc/one_gang_state.dart new file mode 100644 index 0000000..54ab9e7 --- /dev/null +++ b/lib/features/devices/bloc/one_gang_bloc/one_gang_state.dart @@ -0,0 +1,79 @@ +import 'package:equatable/equatable.dart'; +import 'package:syncrow_app/features/devices/model/groupTwoGangModel.dart'; +import 'package:syncrow_app/features/devices/model/one_gang_model.dart'; +import 'package:syncrow_app/features/devices/model/two_gang_model.dart'; + + +class OneGangState extends Equatable { + const OneGangState(); + + @override + List get props => []; +} + +class InitialState extends OneGangState {} + +class LoadingInitialState extends OneGangState {} + +class UpdateState extends OneGangState { + final OneGangModel oneGangModel; + const UpdateState({required this.oneGangModel}); + + @override + List get props => [TwoGangModel]; +} + +class LoadingNewSate extends OneGangState { + final OneGangModel oneGangModel; + const LoadingNewSate({required this.oneGangModel}); + + @override + List get props => [OneGangModel]; +} + +class UpdateGroupState extends OneGangState { + final List twoGangList; + final bool allSwitches; + + const UpdateGroupState({required this.twoGangList, required this.allSwitches}); + + @override + List get props => [twoGangList, allSwitches]; +} + +class FailedState extends OneGangState { + final String error; + + const FailedState({required this.error}); + + @override + List get props => [error]; +} + +class ChangeSlidingSegmentState extends OneGangState { + final int value; + + const ChangeSlidingSegmentState({required this.value}); + + @override + List get props => [value]; +} + +class UpdateTimerState extends OneGangState { + final int seconds; + const UpdateTimerState({required this.seconds}); + + @override + List get props => [seconds]; +} + +class TimerRunInProgress extends OneGangState { + final int remainingTime; + + const TimerRunInProgress(this.remainingTime); + + @override + List get props => [remainingTime]; +} + +class TimerRunComplete extends OneGangState {} diff --git a/lib/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart b/lib/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart index 53bb034..c796892 100644 --- a/lib/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart +++ b/lib/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart @@ -190,7 +190,6 @@ class ThreeGangBloc extends Bloc { if (_timer != null) { _timer!.cancel(); } - _timer = Timer(const Duration(milliseconds: 500), () async { final response = await DevicesAPI.controlDevice( DeviceControlModel( diff --git a/lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart b/lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart new file mode 100644 index 0000000..8e32ef7 --- /dev/null +++ b/lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart @@ -0,0 +1,419 @@ +import 'dart:async'; +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_gang_bloc/two_gang_event.dart'; +import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_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/groupTwoGangModel.dart'; +import 'package:syncrow_app/features/devices/model/status_model.dart'; +import 'package:syncrow_app/features/devices/model/two_gang_model.dart'; +import 'package:syncrow_app/services/api/devices_api.dart'; + +class TwoGangBloc extends Bloc { + final String twoGangId; + TwoGangModel deviceStatus = TwoGangModel( + firstSwitch: false, + secondSwitch: false, + firstCountDown: 0, + secondCountDown: 0, + ); + Timer? _timer; + // Timer? _firstSwitchTimer; + // Timer? _secondSwitchTimer; + // Timer? _thirdSwitchTimer; + + bool twoGangGroup = false; + List devicesList = []; + List groupTwoGangList = []; + bool allSwitchesOn = true; + + TwoGangBloc({required this.twoGangId}) : super(InitialState()) { + on(_fetchTwoGangStatus); + on(_twoGangUpdated); + on(_changeFirstSwitch); + on(_changeSecondSwitch); + on(_allOff); + on(_allOn); + on(_changeSliding); + on(_setCounterValue); + on(_getCounterValue); + on(_onTickTimer); + on(_onClose); + on(_groupAllOn); + on(_groupAllOff); + } + + void _fetchTwoGangStatus(InitialEvent event, Emitter emit) async { + emit(LoadingInitialState()); + try { + twoGangGroup = event.groupScreen; + if (twoGangGroup) { + devicesList = []; + groupTwoGangList = []; + allSwitchesOn = true; + devicesList = await DevicesAPI.getDeviceByGroupName( + HomeCubit.getInstance().selectedSpace?.id ?? '', '2G'); + + for (int i = 0; i < devicesList.length; i++) { + var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); + List statusModelList = []; + for (var status in response['status']) { + statusModelList.add(StatusModel.fromJson(status)); + } + deviceStatus = TwoGangModel.fromJson(statusModelList); + + groupTwoGangList.add(GroupTwoGangModel( + deviceId: devicesList[i].uuid ?? '', + deviceName: devicesList[i].name ?? '', + firstSwitch: deviceStatus.firstSwitch, + secondSwitch: deviceStatus.secondSwitch, + )); + } + + if (groupTwoGangList.isNotEmpty) { + groupTwoGangList.firstWhere((element) { + if (!element.firstSwitch || !element.secondSwitch ) { + allSwitchesOn = false; + } + return true; + }); + } + emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesOn)); + } else { + var response = await DevicesAPI.getDeviceStatus(twoGangId); + List statusModelList = []; + for (var status in response['status']) { + statusModelList.add(StatusModel.fromJson(status)); + } + deviceStatus = TwoGangModel.fromJson(statusModelList); + emit(UpdateState(twoGangModel: deviceStatus)); + _listenToChanges(); + } + } catch (e) { + emit(FailedState(error: e.toString())); + return; + } + } + + _listenToChanges() { + try { + DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$twoGangId'); + Stream stream = ref.onValue; + + stream.listen((DatabaseEvent event) async { + if (_timer != null) { + await Future.delayed(const Duration(seconds: 2)); + } + Map usersMap = event.snapshot.value as Map; + List statusList = []; + + usersMap['status'].forEach((element) { + statusList.add(StatusModel(code: element['code'], value: element['value'])); + }); + + deviceStatus = TwoGangModel.fromJson(statusList); + if (!isClosed) { + add(TwoGangUpdated()); + } + }); + } catch (_) {} + } + + _twoGangUpdated(TwoGangUpdated event, Emitter emit) { + emit(UpdateState(twoGangModel: deviceStatus)); + } + + void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter emit) async { + emit(LoadingNewSate(twoGangModel: deviceStatus)); + try { + if (twoGangGroup) { + bool allSwitchesValue = true; + groupTwoGangList.forEach((element) { + if (element.deviceId == event.deviceId) { + element.firstSwitch = !event.value; + } + if (!element.firstSwitch || !element.secondSwitch ) { + allSwitchesValue = false; + } + }); + emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesValue)); + } else { + deviceStatus.firstSwitch = !event.value; + emit(UpdateState(twoGangModel: deviceStatus)); + } + + if (_timer != null) { + _timer!.cancel(); + } + + _timer = Timer(const Duration(milliseconds: 500), () async { + final response = await DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: twoGangGroup ? event.deviceId : twoGangId, + code: 'switch_1', + value: !event.value), + twoGangGroup ? event.deviceId : twoGangId); + + if (!response['success']) { + add(InitialEvent(groupScreen: twoGangGroup)); + } + }); + } catch (_) { + add(InitialEvent(groupScreen: twoGangGroup)); + } + } + + void _changeSecondSwitch( + ChangeSecondSwitchStatusEvent event, Emitter emit) async { + emit(LoadingNewSate(twoGangModel: deviceStatus)); + try { + if (twoGangGroup) { + bool allSwitchesValue = true; + groupTwoGangList.forEach((element) { + if (element.deviceId == event.deviceId) { + element.secondSwitch = !event.value; + } + if (!element.firstSwitch || !element.secondSwitch ) { + allSwitchesValue = false; + } + }); + emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesValue)); + } else { + deviceStatus.secondSwitch = !event.value; + emit(UpdateState(twoGangModel: deviceStatus)); + } + + if (_timer != null) { + _timer!.cancel(); + } + _timer = Timer(const Duration(milliseconds: 500), () async { + final response = await DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: twoGangGroup ? event.deviceId : twoGangId, + code: 'switch_2', + value: !event.value), + twoGangGroup ? event.deviceId : twoGangId); + + if (!response['success']) { + add(InitialEvent(groupScreen: twoGangGroup)); + } + }); + } catch (_) { + add(InitialEvent(groupScreen: twoGangGroup)); + } + } + + + void _allOff(AllOffEvent event, Emitter emit) async { + emit(LoadingNewSate(twoGangModel: deviceStatus)); + + try { + deviceStatus.firstSwitch = false; + deviceStatus.secondSwitch = false; + emit(UpdateState(twoGangModel: deviceStatus)); + + final response = await Future.wait([ + DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: twoGangId, code: 'switch_1', value: deviceStatus.firstSwitch), + twoGangId), + DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: twoGangId, code: 'switch_2', value: deviceStatus.secondSwitch), + twoGangId), + + ]); + + 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 emit) async { + emit(LoadingNewSate(twoGangModel: deviceStatus)); + + try { + deviceStatus.firstSwitch = true; + deviceStatus.secondSwitch = true; + emit(UpdateState(twoGangModel: deviceStatus)); + + final response = await Future.wait([ + DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: twoGangId, code: 'switch_1', value: deviceStatus.firstSwitch), + twoGangId), + DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: twoGangId, code: 'switch_2', value: deviceStatus.secondSwitch), + twoGangId), + + ]); + + 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 emit) async { + emit(LoadingNewSate(twoGangModel: deviceStatus)); + try { + for (int i = 0; i < groupTwoGangList.length; i++) { + groupTwoGangList[i].firstSwitch = true; + groupTwoGangList[i].secondSwitch = true; + + } + emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: true)); + + for (int i = 0; i < groupTwoGangList.length; i++) { + final response = await Future.wait([ + DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: groupTwoGangList[i].deviceId, code: 'switch_1', value: true), + groupTwoGangList[i].deviceId), + DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: groupTwoGangList[i].deviceId, code: 'switch_2', value: true), + groupTwoGangList[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 emit) async { + emit(LoadingNewSate(twoGangModel: deviceStatus)); + try { + for (int i = 0; i < groupTwoGangList.length; i++) { + groupTwoGangList[i].firstSwitch = false; + groupTwoGangList[i].secondSwitch = false; + } + emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: false)); + + for (int i = 0; i < groupTwoGangList.length; i++) { + final response = await Future.wait([ + DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: groupTwoGangList[i].deviceId, code: 'switch_1', value: false), + groupTwoGangList[i].deviceId), + DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: groupTwoGangList[i].deviceId, code: 'switch_2', value: false), + groupTwoGangList[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 emit) async { + emit(ChangeSlidingSegmentState(value: event.value)); + } + + void _setCounterValue(SetCounterValue event, Emitter emit) async { + emit(LoadingNewSate(twoGangModel: deviceStatus)); + int seconds = 0; + try { + seconds = event.duration.inSeconds; + final response = await DevicesAPI.controlDevice( + DeviceControlModel(deviceId: twoGangId, code: event.deviceCode, value: seconds), + twoGangId); + + 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 emit) async { + emit(LoadingInitialState()); + try { + var response = await DevicesAPI.getDeviceStatus(twoGangId); + List statusModelList = []; + for (var status in response['status']) { + statusModelList.add(StatusModel.fromJson(status)); + } + deviceStatus = TwoGangModel.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 emit) { + _timer?.cancel(); + // _firstSwitchTimer?.cancel(); + // _secondSwitchTimer?.cancel(); + // _thirdSwitchTimer?.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 emit) { + if (event.remainingTime > 0) { + emit(TimerRunInProgress(event.remainingTime)); + } else { + _timer?.cancel(); + emit(TimerRunComplete()); + } + } +} diff --git a/lib/features/devices/bloc/two_gang_bloc/two_gang_event.dart b/lib/features/devices/bloc/two_gang_bloc/two_gang_event.dart new file mode 100644 index 0000000..6be514c --- /dev/null +++ b/lib/features/devices/bloc/two_gang_bloc/two_gang_event.dart @@ -0,0 +1,88 @@ +import 'package:equatable/equatable.dart'; + +abstract class TwoGangEvent extends Equatable { + const TwoGangEvent(); + + @override + List get props => []; +} + +class LoadingEvent extends TwoGangEvent {} + +class TwoGangUpdated extends TwoGangEvent {} + +class InitialEvent extends TwoGangEvent { + final bool groupScreen; + const InitialEvent({required this.groupScreen}); + @override + List get props => [groupScreen]; +} + +class ChangeFirstSwitchStatusEvent extends TwoGangEvent { + final bool value; + final String deviceId; + const ChangeFirstSwitchStatusEvent({required this.value, this.deviceId = ''}); + @override + List get props => [value, deviceId]; +} + +class ChangeSecondSwitchStatusEvent extends TwoGangEvent { + final bool value; + final String deviceId; + const ChangeSecondSwitchStatusEvent({required this.value, this.deviceId = ''}); + @override + List get props => [value, deviceId]; +} + + +class AllOffEvent extends TwoGangEvent {} + +class AllOnEvent extends TwoGangEvent {} + +class GroupAllOnEvent extends TwoGangEvent {} + +class GroupAllOffEvent extends TwoGangEvent {} + +class ChangeSlidingSegment extends TwoGangEvent { + final int value; + const ChangeSlidingSegment({required this.value}); + @override + List get props => [value]; +} + +class GetCounterEvent extends TwoGangEvent { + final String deviceCode; + const GetCounterEvent({required this.deviceCode}); + @override + List get props => [deviceCode]; +} + +class SetCounterValue extends TwoGangEvent { + final Duration duration; + final String deviceCode; + const SetCounterValue({required this.duration, required this.deviceCode}); + @override + List get props => [duration, deviceCode]; +} + +class StartTimer extends TwoGangEvent { + final int duration; + + const StartTimer(this.duration); + + @override + List get props => [duration]; +} + +class TickTimer extends TwoGangEvent { + final int remainingTime; + + const TickTimer(this.remainingTime); + + @override + List get props => [remainingTime]; +} + +class StopTimer extends TwoGangEvent {} + +class OnClose extends TwoGangEvent {} diff --git a/lib/features/devices/bloc/two_gang_bloc/two_gang_state.dart b/lib/features/devices/bloc/two_gang_bloc/two_gang_state.dart new file mode 100644 index 0000000..c967a36 --- /dev/null +++ b/lib/features/devices/bloc/two_gang_bloc/two_gang_state.dart @@ -0,0 +1,78 @@ +import 'package:equatable/equatable.dart'; +import 'package:syncrow_app/features/devices/model/groupTwoGangModel.dart'; +import 'package:syncrow_app/features/devices/model/two_gang_model.dart'; + + +class TwoGangState extends Equatable { + const TwoGangState(); + + @override + List get props => []; +} + +class InitialState extends TwoGangState {} + +class LoadingInitialState extends TwoGangState {} + +class UpdateState extends TwoGangState { + final TwoGangModel twoGangModel; + const UpdateState({required this.twoGangModel}); + + @override + List get props => [TwoGangModel]; +} + +class LoadingNewSate extends TwoGangState { + final TwoGangModel twoGangModel; + const LoadingNewSate({required this.twoGangModel}); + + @override + List get props => [TwoGangModel]; +} + +class UpdateGroupState extends TwoGangState { + final List twoGangList; + final bool allSwitches; + + const UpdateGroupState({required this.twoGangList, required this.allSwitches}); + + @override + List get props => [twoGangList, allSwitches]; +} + +class FailedState extends TwoGangState { + final String error; + + const FailedState({required this.error}); + + @override + List get props => [error]; +} + +class ChangeSlidingSegmentState extends TwoGangState { + final int value; + + const ChangeSlidingSegmentState({required this.value}); + + @override + List get props => [value]; +} + +class UpdateTimerState extends TwoGangState { + final int seconds; + const UpdateTimerState({required this.seconds}); + + @override + List get props => [seconds]; +} + +class TimerRunInProgress extends TwoGangState { + final int remainingTime; + + const TimerRunInProgress(this.remainingTime); + + @override + List get props => [remainingTime]; +} + +class TimerRunComplete extends TwoGangState {} diff --git a/lib/features/devices/model/groupTwoGangModel.dart b/lib/features/devices/model/groupTwoGangModel.dart new file mode 100644 index 0000000..f385b4e --- /dev/null +++ b/lib/features/devices/model/groupTwoGangModel.dart @@ -0,0 +1,13 @@ +class GroupTwoGangModel { + final String deviceId; + final String deviceName; + bool firstSwitch; + bool secondSwitch; + + GroupTwoGangModel({ + required this.deviceId, + required this.deviceName, + required this.firstSwitch, + required this.secondSwitch, + }); +} diff --git a/lib/features/devices/model/one_gang_model.dart b/lib/features/devices/model/one_gang_model.dart new file mode 100644 index 0000000..4e73231 --- /dev/null +++ b/lib/features/devices/model/one_gang_model.dart @@ -0,0 +1,30 @@ + +import 'package:syncrow_app/features/devices/model/status_model.dart'; + +class OneGangModel { + bool firstSwitch; + int firstCountDown; + + OneGangModel( + {required this.firstSwitch, + required this.firstCountDown, + }); + + factory OneGangModel.fromJson(List jsonList) { + late bool _switch; + late int _count; + + + for (int i = 0; i < jsonList.length; i++) { + if (jsonList[i].code == 'switch_1') { + _switch = jsonList[i].value ?? false; + } else if (jsonList[i].code == 'countdown_1') { + _count = jsonList[i].value ?? 0; + } + } + return OneGangModel( + firstSwitch: _switch, + firstCountDown: _count, + ); + } +} diff --git a/lib/features/devices/model/two_gang_model.dart b/lib/features/devices/model/two_gang_model.dart new file mode 100644 index 0000000..00f88d1 --- /dev/null +++ b/lib/features/devices/model/two_gang_model.dart @@ -0,0 +1,40 @@ +import 'package:syncrow_app/features/devices/model/status_model.dart'; + +class TwoGangModel { + bool firstSwitch; + bool secondSwitch; + int firstCountDown; + int secondCountDown; + + TwoGangModel( + {required this.firstSwitch, + required this.secondSwitch, + required this.firstCountDown, + required this.secondCountDown, + }); + + factory TwoGangModel.fromJson(List jsonList) { + late bool _firstSwitch; + late bool _secondSwitch; + late int _firstCount; + late int _secondCount; + + 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; + } + } + return TwoGangModel( + firstSwitch: _firstSwitch, + secondSwitch: _secondSwitch, + firstCountDown: _firstCount, + secondCountDown: _secondCount, + ); + } +} diff --git a/lib/features/devices/view/widgets/one_gang/one_gang_Interface.dart b/lib/features/devices/view/widgets/one_gang/one_gang_Interface.dart new file mode 100644 index 0000000..636a730 --- /dev/null +++ b/lib/features/devices/view/widgets/one_gang/one_gang_Interface.dart @@ -0,0 +1,68 @@ +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/one_gang/one_gang_screen.dart'; +import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_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 OneGangInterface extends StatelessWidget { + const OneGangInterface({super.key, this.gangSwitch}); + + final DeviceModel? gangSwitch; + @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: gangSwitch != null + ? DeviceAppbar( + deviceName: gangSwitch!.name!, + deviceUuid: gangSwitch!.uuid!, + ) + : AppBar( + backgroundColor: Colors.transparent, + centerTitle: true, + title: BodyLarge( + text: gangSwitch?.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: OneGangScreen(device: gangSwitch), + ), + ), + ), + ), + ); + } +} diff --git a/lib/features/devices/view/widgets/one_gang/one_gang_screen.dart b/lib/features/devices/view/widgets/one_gang/one_gang_screen.dart new file mode 100644 index 0000000..566946c --- /dev/null +++ b/lib/features/devices/view/widgets/one_gang/one_gang_screen.dart @@ -0,0 +1,168 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_state.dart'; +import 'package:syncrow_app/features/devices/model/device_model.dart'; +import 'package:syncrow_app/features/devices/model/one_gang_model.dart'; +import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart'; +import 'package:syncrow_app/features/devices/view/widgets/three_gang/gang_switch.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/context_extension.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; +import '../../../bloc/one_gang_bloc/one_gang_event.dart'; + +class OneGangScreen extends StatelessWidget { + const OneGangScreen({super.key, this.device}); + + final DeviceModel? device; + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => OneGangBloc(oneGangId : device?.uuid ?? '') + ..add(const InitialEvent(groupScreen:false)), + child: BlocBuilder( + builder: (context, state) { + OneGangModel oneGangModel = OneGangModel( + firstSwitch: false, + firstCountDown: 0, + ); + + if (state is LoadingNewSate) { + oneGangModel = state.oneGangModel; + } else if (state is UpdateState) { + oneGangModel = state.oneGangModel; + } + return state is LoadingInitialState ? + const Center( + child: + DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()), + ): + RefreshIndicator( + onRefresh: () async { + BlocProvider.of(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: oneGangModel.firstSwitch, + action: () { + BlocProvider.of(context).add( + ChangeFirstSwitchStatusEvent( + value: oneGangModel.firstSwitch)); + }, + ), + const SizedBox(height: 20), + const SizedBox( + width: 70, + child: BodySmall( + text:" Entrance Light", + fontColor: ColorsManager.textPrimaryColor, + textAlign: TextAlign.center, + ), + ), + ], + ), + ], + ), + ), + Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox( + width: 20, + ), + 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) => OneGangTimerScreen( + device: device, + deviceCode: 'countdown_1', + ))); + }, + 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, + ), + ), + ], + ), + + ], + ), + ), + Expanded(child: SizedBox()) + ], + ), + ), + ], + ), + ); + }, + ), + ); + + } +} diff --git a/lib/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart b/lib/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart new file mode 100644 index 0000000..51a5756 --- /dev/null +++ b/lib/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart @@ -0,0 +1,184 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_event.dart'; +import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_state.dart'; +import 'package:syncrow_app/features/devices/model/device_model.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 OneGangTimerScreen extends StatelessWidget { + final DeviceModel? device; + final String? deviceCode; + const OneGangTimerScreen({super.key,this.device,this.deviceCode}); + + @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: BlocProvider( + create: (context) => OneGangBloc(oneGangId: device!.uuid ?? '') + ..add(GetCounterEvent(deviceCode: deviceCode!)), + child: BlocBuilder( + builder: (context, state) { + Duration duration = Duration.zero; + int countNum = 0; + int tabNum = 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; + } + + if (state is ChangeSlidingSegmentState) { + tabNum = state.value; + } + return PopScope( + canPop: false, + onPopInvoked: (didPop) { + if (!didPop) { + BlocProvider.of(context).add(OnClose()); + Navigator.pop(context); + } + }, + child: Container( + width: MediaQuery.sizeOf(context).width, + height: MediaQuery.sizeOf(context).height, + padding: const EdgeInsets.all(24), + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage( + Assets.assetsImagesBackground, + ), + fit: BoxFit.cover, + opacity: 0.4, + ), + ), + child: state is LoadingInitialState || state is LoadingNewSate + ? const Center( + child: DefaultContainer( + width: 50, height: 50, child: CircularProgressIndicator()), + ) + : Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + width: MediaQuery.sizeOf(context).width, + decoration: const ShapeDecoration( + color: ColorsManager.slidingBlueColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)), + ), + ), + child: CupertinoSlidingSegmentedControl( + thumbColor: ColorsManager.slidingBlueColor, + onValueChanged: (value) { + BlocProvider.of(context) + .add(ChangeSlidingSegment(value: value ?? 0)); + }, + groupValue: + state is ChangeSlidingSegmentState ? state.value : 0, + backgroundColor: Colors.white, + children: { + 0: Container( + padding: const EdgeInsets.symmetric(vertical: 10), + child: BodySmall( + text: 'Countdown', + style: context.bodySmall.copyWith( + color: ColorsManager.blackColor, + fontSize: 12, + fontWeight: FontWeight.w400, + ), + ), + ), + 1: Container( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Text( + 'Schedule', + style: context.bodySmall.copyWith( + color: ColorsManager.blackColor, + fontSize: 12, + fontWeight: FontWeight.w400, + ), + ), + ), + }, + ), + ), + if (tabNum == 0) + countNum > 0 + ? BodyLarge( + text: _formatDuration(countNum), + fontColor: ColorsManager.slidingBlueColor, + fontSize: 40, + ) + : CupertinoTimerPicker( + mode: CupertinoTimerPickerMode.hm, + onTimerDurationChanged: (Duration newDuration) { + duration = newDuration; + }, + ), + if (tabNum == 0) + GestureDetector( + onTap: () { + if (state is LoadingNewSate) { + return; + } + if (countNum > 0) { + BlocProvider.of(context).add( + SetCounterValue( + deviceCode: deviceCode!, + duration: Duration.zero)); + } else if (duration != Duration.zero) { + BlocProvider.of(context).add( + SetCounterValue( + deviceCode: deviceCode!, duration: duration)); + } + }, + child: SvgPicture.asset( + countNum > 0 ? Assets.pauseIcon : Assets.playIcon)) + ], + ))); + }, + ), + ), + ), + ), + ); + } + String _formatDuration(int seconds) { + final hours = (seconds ~/ 3600).toString().padLeft(2, '0'); + final minutes = ((seconds % 3600) ~/ 60).toString().padLeft(2, '0'); + final secs = (seconds % 60).toString().padLeft(2, '0'); + return '$hours:$minutes:$secs'; + } +} diff --git a/lib/features/devices/view/widgets/room_page_switch.dart b/lib/features/devices/view/widgets/room_page_switch.dart index 980de66..cfb5445 100644 --- a/lib/features/devices/view/widgets/room_page_switch.dart +++ b/lib/features/devices/view/widgets/room_page_switch.dart @@ -11,6 +11,10 @@ import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart'; 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_gang/one_gang_screen.dart'; +import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_Interface.dart'; +import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_screen.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'; @@ -126,13 +130,24 @@ void showDeviceInterface(DeviceModel device, BuildContext context) { break; case DeviceType.LightBulb: navigateToInterface(LightInterface(light: device), context); + case DeviceType.OneGang: + Navigator.push( + context, + PageRouteBuilder( + pageBuilder: (context, animation1, animation2) => + OneGangInterface(gangSwitch: device))); + case DeviceType.TwoGang: + Navigator.push( + context, + PageRouteBuilder( + pageBuilder: (context, animation1, animation2) => + TwoGangInterface(gangSwitch: device))); case DeviceType.ThreeGang: Navigator.push( context, PageRouteBuilder( pageBuilder: (context, animation1, animation2) => ThreeGangInterface(gangSwitch: device))); - // navigateToInterface(ThreeGangInterface(gangSwitch: device), context); break; default: } diff --git a/lib/features/devices/view/widgets/three_gang/gang_switch.dart b/lib/features/devices/view/widgets/three_gang/gang_switch.dart index c0bd8f9..8b5dc55 100644 --- a/lib/features/devices/view/widgets/three_gang/gang_switch.dart +++ b/lib/features/devices/view/widgets/three_gang/gang_switch.dart @@ -1,8 +1,8 @@ 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/three_gang_bloc.dart'; -// import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_state.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'; diff --git a/lib/features/devices/view/widgets/two_gang/two_gang_Interface.dart b/lib/features/devices/view/widgets/two_gang/two_gang_Interface.dart new file mode 100644 index 0000000..029934f --- /dev/null +++ b/lib/features/devices/view/widgets/two_gang/two_gang_Interface.dart @@ -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_gang/two_gang_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 TwoGangInterface extends StatelessWidget { + const TwoGangInterface({super.key, this.gangSwitch}); + + final DeviceModel? gangSwitch; + @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: gangSwitch != null + ? DeviceAppbar( + deviceName: gangSwitch!.name!, + deviceUuid: gangSwitch!.uuid!, + ) + : AppBar( + backgroundColor: Colors.transparent, + centerTitle: true, + title: BodyLarge( + text: gangSwitch?.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: TwoGangScreen(device: gangSwitch), + ), + ), + ), + ), + ); + } +} diff --git a/lib/features/devices/view/widgets/two_gang/two_gang_list.dart b/lib/features/devices/view/widgets/two_gang/two_gang_list.dart new file mode 100644 index 0000000..065dd62 --- /dev/null +++ b/lib/features/devices/view/widgets/two_gang/two_gang_list.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_event.dart'; +import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_state.dart'; +import 'package:syncrow_app/features/devices/model/groupTwoGangModel.dart'; +import 'package:syncrow_app/features/devices/model/group_three_gang_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 TwoGangList extends StatelessWidget { + const TwoGangList({super.key, required this.twoGangList, required this.allSwitches}); + + final List twoGangList; + final bool allSwitches; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + 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(context).add(GroupAllOnEvent()); + }, + secondAction: () { + BlocProvider.of(context).add(GroupAllOffEvent()); + }, + ), + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: const EdgeInsets.all(0), + itemCount: twoGangList.length, + itemBuilder: (context, index) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 10), + BodySmall(text: '${twoGangList[index].deviceName} beside light'), + const SizedBox(height: 5), + DevicesDefaultSwitch( + switchValue: twoGangList[index].firstSwitch, + action: () { + BlocProvider.of(context).add(ChangeFirstSwitchStatusEvent( + value: twoGangList[index].firstSwitch, + deviceId: twoGangList[index].deviceId)); + }, + ), + const SizedBox(height: 10), + BodySmall(text: '${twoGangList[index].deviceName} ceiling light'), + const SizedBox(height: 5), + DevicesDefaultSwitch( + switchValue: twoGangList[index].secondSwitch, + action: () { + BlocProvider.of(context).add(ChangeSecondSwitchStatusEvent( + value: twoGangList[index].secondSwitch, + deviceId: twoGangList[index].deviceId)); + }, + ), + const SizedBox(height: 10), + BodySmall(text: '${twoGangList[index].deviceName} spotlight'), + const SizedBox(height: 5), + ], + ); + }, + ), + ], + ), + ); + }, + ); + } +} diff --git a/lib/features/devices/view/widgets/two_gang/two_gang_screen.dart b/lib/features/devices/view/widgets/two_gang/two_gang_screen.dart new file mode 100644 index 0000000..4bb158d --- /dev/null +++ b/lib/features/devices/view/widgets/two_gang/two_gang_screen.dart @@ -0,0 +1,340 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_event.dart'; +import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_state.dart'; +import 'package:syncrow_app/features/devices/model/device_model.dart'; +import 'package:syncrow_app/features/devices/model/groupTwoGangModel.dart'; +import 'package:syncrow_app/features/devices/model/two_gang_model.dart'; +import 'package:syncrow_app/features/devices/view/widgets/three_gang/gang_switch.dart'; +import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_list.dart'; +import 'package:syncrow_app/features/devices/view/widgets/two_gang/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/context_extension.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; + +class TwoGangScreen extends StatelessWidget { + const TwoGangScreen({super.key, this.device}); + + final DeviceModel? device; + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => TwoGangBloc(twoGangId: device?.uuid ?? '') + ..add(InitialEvent(groupScreen: device != null ? false : true)), + child: BlocBuilder( + builder: (context, state) { + TwoGangModel twoGangModel = TwoGangModel( + firstSwitch: false, + secondSwitch: false, + firstCountDown: 0, + secondCountDown: 0, + ); + + List groupTwoGangModel = []; + bool allSwitchesOn = false; + + if (state is LoadingNewSate) { + twoGangModel = state.twoGangModel; + } else if (state is UpdateState) { + twoGangModel = state.twoGangModel; + } else if (state is UpdateGroupState) { + groupTwoGangModel = state.twoGangList; + allSwitchesOn = state.allSwitches; + } + return state is LoadingInitialState + ? const Center( + child: + DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()), + ) + : device == null + ? TwoGangList( + twoGangList: groupTwoGangModel, + allSwitches: allSwitchesOn, + ) + : RefreshIndicator( + onRefresh: () async { + BlocProvider.of(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: twoGangModel.firstSwitch, + action: () { + BlocProvider.of(context).add( + ChangeFirstSwitchStatusEvent( + value: twoGangModel.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: twoGangModel.secondSwitch, + action: () { + BlocProvider.of(context).add( + ChangeSecondSwitchStatusEvent( + value: twoGangModel.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: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Card( + elevation: 3, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(100), + ), + child: GestureDetector( + onTap: () { + BlocProvider.of(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, + ), + 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) => + TwoGangScheduleScreen( + 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, + ), + 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(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()) + ], + ), + ), + ], + ), + ); + }, + ), + ); + } +} diff --git a/lib/features/devices/view/widgets/two_gang/two_schedule_screen.dart b/lib/features/devices/view/widgets/two_gang/two_schedule_screen.dart new file mode 100644 index 0000000..f4df531 --- /dev/null +++ b/lib/features/devices/view/widgets/two_gang/two_schedule_screen.dart @@ -0,0 +1,139 @@ +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_gang/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 TwoGangScheduleScreen extends StatelessWidget { + final DeviceModel device; + const TwoGangScheduleScreen({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) => TwoTimerScreen( + 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) => TwoTimerScreen( + 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, + ) + ], + ), + ), + ), + + ], + )), + ], + ), + ), + ), + )); + } +} diff --git a/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart b/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart new file mode 100644 index 0000000..720e80e --- /dev/null +++ b/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart @@ -0,0 +1,187 @@ +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_gang_bloc/two_gang_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_state.dart'; +import 'package:syncrow_app/features/devices/model/device_model.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'; + +import '../../../bloc/two_gang_bloc/two_gang_event.dart'; + + +class TwoTimerScreen extends StatelessWidget { + final DeviceModel device; + final String deviceCode; + const TwoTimerScreen({required this.device, required this.deviceCode, 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: BlocProvider( + create: (context) => TwoGangBloc(twoGangId: device.uuid ?? '') + ..add(GetCounterEvent(deviceCode: deviceCode)), + child: BlocBuilder( + builder: (context, state) { + Duration duration = Duration.zero; + int countNum = 0; + int tabNum = 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; + } + + if (state is ChangeSlidingSegmentState) { + tabNum = state.value; + } + return PopScope( + canPop: false, + onPopInvoked: (didPop) { + if (!didPop) { + BlocProvider.of(context).add(OnClose()); + Navigator.pop(context); + } + }, + child: Container( + width: MediaQuery.sizeOf(context).width, + height: MediaQuery.sizeOf(context).height, + padding: const EdgeInsets.all(24), + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage( + Assets.assetsImagesBackground, + ), + fit: BoxFit.cover, + opacity: 0.4, + ), + ), + child: state is LoadingInitialState || state is LoadingNewSate + ? const Center( + child: DefaultContainer( + width: 50, height: 50, child: CircularProgressIndicator()), + ) + : Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + width: MediaQuery.sizeOf(context).width, + decoration: const ShapeDecoration( + color: ColorsManager.slidingBlueColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)), + ), + ), + child: CupertinoSlidingSegmentedControl( + thumbColor: ColorsManager.slidingBlueColor, + onValueChanged: (value) { + BlocProvider.of(context) + .add(ChangeSlidingSegment(value: value ?? 0)); + }, + groupValue: + state is ChangeSlidingSegmentState ? state.value : 0, + backgroundColor: Colors.white, + children: { + 0: Container( + padding: const EdgeInsets.symmetric(vertical: 10), + child: BodySmall( + text: 'Countdown', + style: context.bodySmall.copyWith( + color: ColorsManager.blackColor, + fontSize: 12, + fontWeight: FontWeight.w400, + ), + ), + ), + 1: Container( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Text( + 'Schedule', + style: context.bodySmall.copyWith( + color: ColorsManager.blackColor, + fontSize: 12, + fontWeight: FontWeight.w400, + ), + ), + ), + }, + ), + ), + if (tabNum == 0) + countNum > 0 + ? BodyLarge( + text: _formatDuration(countNum), + fontColor: ColorsManager.slidingBlueColor, + fontSize: 40, + ) + : CupertinoTimerPicker( + mode: CupertinoTimerPickerMode.hm, + onTimerDurationChanged: (Duration newDuration) { + duration = newDuration; + }, + ), + if (tabNum == 0) + GestureDetector( + onTap: () { + if (state is LoadingNewSate) { + return; + } + if (countNum > 0) { + BlocProvider.of(context).add( + SetCounterValue( + deviceCode: deviceCode, + duration: Duration.zero)); + } else if (duration != Duration.zero) { + BlocProvider.of(context).add( + SetCounterValue( + deviceCode: deviceCode, duration: duration)); + } + }, + child: SvgPicture.asset( + countNum > 0 ? Assets.pauseIcon : Assets.playIcon)) + ], + ))); + }, + ), + ), + ), + ), + ); + } + + String _formatDuration(int seconds) { + final hours = (seconds ~/ 3600).toString().padLeft(2, '0'); + final minutes = ((seconds % 3600) ~/ 60).toString().padLeft(2, '0'); + final secs = (seconds % 60).toString().padLeft(2, '0'); + return '$hours:$minutes:$secs'; + } +} diff --git a/lib/generated/assets.dart b/lib/generated/assets.dart index caae2da..e592f1e 100644 --- a/lib/generated/assets.dart +++ b/lib/generated/assets.dart @@ -1029,4 +1029,10 @@ class Assets { static const String assetsPresenceState = "assets/icons/functions_icons/automation_functions/presence_state.svg"; + + + //assets/icons/functions_icons/automation_functions/presence_state.svg + + static const String oneGang = + "assets/icons/1gang.svg"; } diff --git a/lib/utils/resource_manager/constants.dart b/lib/utils/resource_manager/constants.dart index 774f726..a417454 100644 --- a/lib/utils/resource_manager/constants.dart +++ b/lib/utils/resource_manager/constants.dart @@ -43,6 +43,8 @@ enum DeviceType { DoorLock, Curtain, Blind, + OneGang, + TwoGang, ThreeGang, Gateway, CeilingSensor, @@ -68,6 +70,8 @@ Map devicesTypesMap = { "DL": DeviceType.DoorLock, "WPS": DeviceType.WallSensor, "3G": DeviceType.ThreeGang, + "2G": DeviceType.TwoGang, + "1G": DeviceType.OneGang, "CUR": DeviceType.Curtain, }; Map> devicesFunctionsMap = { @@ -155,6 +159,33 @@ Map> devicesFunctionsMap = { FunctionModel( code: 'indicator', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})), ], + DeviceType.OneGang:[ + FunctionModel( + code: 'switch_1', 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})), + ], + DeviceType.TwoGang:[ + 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}) + ), + ], + DeviceType.ThreeGang: [ FunctionModel( code: 'switch_1', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})),