From 2ec81bda9c1466a0072680bb15cae5a934daf242 Mon Sep 17 00:00:00 2001 From: mohammad Date: Sat, 1 Mar 2025 15:08:51 +0300 Subject: [PATCH 1/3] connect the real time for all devices --- .../bloc/curtain_bloc/curtain_bloc.dart | 82 +- .../bloc/curtain_bloc/curtain_event.dart | 1 + lib/features/devices/bloc/devices_cubit.dart | 13 +- .../door_sensor_bloc/door_sensor_bloc.dart | 72 +- .../garage_door_bloc/garage_door_bloc.dart | 85 +- .../garage_door_bloc/garage_door_event.dart | 2 + .../bloc/one_gang_bloc/one_gang_bloc.dart | 63 +- .../bloc/one_touch_bloc/one_touch_bloc.dart | 61 +- .../three_touch_bloc/three_touch_bloc.dart | 177 ++- .../bloc/two_gang_bloc/two_gang_bloc.dart | 152 ++- .../bloc/two_touch_bloc/two_touch_bloc.dart | 77 +- .../water_heater_bloc/water_heater_bloc.dart | 67 +- .../garage_door/garage_door_screen.dart | 1095 +++++++++++------ .../widgets/one_gang/one_gang_screen.dart | 59 +- 14 files changed, 1295 insertions(+), 711 deletions(-) diff --git a/lib/features/devices/bloc/curtain_bloc/curtain_bloc.dart b/lib/features/devices/bloc/curtain_bloc/curtain_bloc.dart index bc6620e..791526b 100644 --- a/lib/features/devices/bloc/curtain_bloc/curtain_bloc.dart +++ b/lib/features/devices/bloc/curtain_bloc/curtain_bloc.dart @@ -1,4 +1,5 @@ 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/curtain_bloc/curtain_event.dart'; @@ -31,6 +32,7 @@ class CurtainBloc extends Bloc { on(_fetchWizardStatus); on(_groupAllOff); on(_groupAllOn); + on(_updateCurtain); } Future _onOpenCurtain( @@ -162,7 +164,10 @@ class CurtainBloc extends Bloc { void _fetchStatus(InitCurtain event, Emitter emit) async { try { emit(CurtainLoadingState()); + _listenToChanges(curtainId); + var response = await DevicesAPI.getDeviceStatus(curtainId); + List statusModelList = []; for (var status in response['status']) { statusModelList.add(StatusModel.fromJson(status)); @@ -170,7 +175,6 @@ class CurtainBloc extends Bloc { openPercentage = double.tryParse(statusModelList[1].value.toString())!; curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace; blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace; - // _listenToChanges(); emit(CurtainsOpening( curtainWidth: curtainWidth, blindHeight: blindHeight, @@ -181,38 +185,76 @@ class CurtainBloc extends Bloc { return; } } - // Real-time Database - // StreamSubscription? _streamSubscription; - // Timer? _timer; - // void _listenToChanges() { + + StreamSubscription? _streamSubscription; + + void _listenToChanges(curtainId) { + try { + _streamSubscription?.cancel(); + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$curtainId'); + Stream stream = ref.onValue; + + _streamSubscription = stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + List statusList = []; + + usersMap['status'].forEach((element) { + statusList + .add(StatusModel(code: element['code'], value: element['value'])); + }); + openPercentage = double.tryParse(statusList[1].value.toString())!; + curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace; + blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace; + add(UpdateCurtainEvent()); + }); + } catch (_) {} + } + + @override + Future close() async { + _streamSubscription?.cancel(); + _streamSubscription = null; + return super.close(); + } + + // _listenToChanges(curtainId) { // try { - // _streamSubscription?.cancel(); + // print('curtainId=$curtainId'); // DatabaseReference ref = // FirebaseDatabase.instance.ref('device-status/$curtainId'); // Stream stream = ref.onValue; - // _streamSubscription = stream.listen((DatabaseEvent event) async { + // 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 = CurtainModel.fromJson(statusList); - // if (!isClosed) {} + // List statusModelList = []; + // for (var status in usersMap['status']) { + // statusModelList.add(StatusModel.fromJson(status)); + // print('statusModelList==${statusModelList}'); + // } + + // openPercentage = double.tryParse(statusModelList[1].value.toString())!; + // curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace; + // blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace; + // add(UpdateCurtainEvent()); // }); // } catch (_) {} // } - // @override - // Future close() async { - // _streamSubscription?.cancel(); - // _streamSubscription = null; - // return super.close(); - // } + + _updateCurtain(UpdateCurtainEvent event, Emitter emit) { + curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace; + blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace; + emit(CurtainsOpening( + curtainWidth: curtainWidth, + blindHeight: blindHeight, + openPercentage: openPercentage, + )); + } List groupList = []; bool allSwitchesOn = true; diff --git a/lib/features/devices/bloc/curtain_bloc/curtain_event.dart b/lib/features/devices/bloc/curtain_bloc/curtain_event.dart index 4ee52e3..c4042fb 100644 --- a/lib/features/devices/bloc/curtain_bloc/curtain_event.dart +++ b/lib/features/devices/bloc/curtain_bloc/curtain_event.dart @@ -33,6 +33,7 @@ class InitCurtain extends CurtainEvent {} class PauseCurtain extends CurtainEvent {} class useCurtainEvent extends CurtainEvent {} class InitialWizardEvent extends CurtainEvent {} +class UpdateCurtainEvent extends CurtainEvent {} class ChangeFirstWizardSwitchStatusEvent extends CurtainEvent { diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index 1053235..eeb7b94 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -86,7 +86,7 @@ class DevicesCubit extends Cubit { } Map usersMap = event.snapshot.value as Map; - //print('object-----${usersMap['status']}'); + print('object-----${usersMap['status']}'); List statusList = []; usersMap['status'].forEach((element) { statusList @@ -463,7 +463,15 @@ class DevicesCubit extends Cubit { projectId: project?.uuid ?? TempConst.projectIdDev); allDevices = devices; for (var deviceId in allDevices) { - if (deviceId.type == "3G" || deviceId.type == "AC") { + if (deviceId.type == "3G" || + deviceId.type == "2G" || + deviceId.type == "1G" || + deviceId.type == "3GT" || + deviceId.type == "2GT" || + deviceId.type == "1GT" || + deviceId.type == "WH" || + deviceId.type == "CUR" || + deviceId.type == "AC") { _listenToChanges(deviceId.uuid); } } @@ -561,7 +569,6 @@ class DevicesCubit extends Cubit { } } - Future towGangToggle( DeviceControlModel control, String deviceUuid) async { emit(SwitchControlLoading(code: control.code)); diff --git a/lib/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart b/lib/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart index 20f2758..7a72749 100644 --- a/lib/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart +++ b/lib/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart @@ -1,5 +1,6 @@ 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/devices/bloc/door_sensor_bloc/door_sensor_event.dart'; import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_state.dart'; @@ -40,7 +41,7 @@ class DoorSensorBloc extends Bloc { ); emit(UpdateState(doorSensor: deviceStatus)); Future.delayed(const Duration(milliseconds: 500)); - // _listenToChanges(); + _listenToChanges(); } catch (e) { emit(DoorSensorFailedState(errorMessage: e.toString())); return; @@ -136,41 +137,42 @@ class DoorSensorBloc extends Bloc { String errorMessage = errorData['message']; } } + // real-time database - // Timer? _timer; - // StreamSubscription? _streamSubscription; - // void _listenToChanges() { - // try { - // _streamSubscription?.cancel(); - // DatabaseReference ref = - // FirebaseDatabase.instance.ref('device-status/$DSId'); - // Stream stream = ref.onValue; + Timer? _timer; + StreamSubscription? _streamSubscription; + void _listenToChanges() { + try { + _streamSubscription?.cancel(); + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$DSId'); + Stream stream = ref.onValue; - // _streamSubscription = 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 = DoorSensorModel.fromJson(statusList); - // if (!isClosed) { - // add( - // DoorSensorSwitch(switchD: deviceStatus.doorContactState), - // ); - // } - // }); - // } catch (_) {} - // } + _streamSubscription = 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 = DoorSensorModel.fromJson(statusList); + if (!isClosed) { + add( + DoorSensorSwitch(switchD: deviceStatus.doorContactState), + ); + } + }); + } catch (_) {} + } - // @override - // Future close() async { - // _streamSubscription?.cancel(); - // _streamSubscription = null; - // return super.close(); - // } + @override + Future close() async { + _streamSubscription?.cancel(); + _streamSubscription = null; + return super.close(); + } } diff --git a/lib/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart b/lib/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart index b36e634..a8716b1 100644 --- a/lib/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart +++ b/lib/features/devices/bloc/garage_door_bloc/garage_door_bloc.dart @@ -1,5 +1,6 @@ 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/garage_door_bloc/garage_door_event.dart'; @@ -41,6 +42,8 @@ class GarageDoorBloc extends Bloc { on(_changeFirstWizardSwitch); on(_toggleAlarmEvent); on(deleteSchedule); + + on(_updateState); } void _onClose(OnClose event, Emitter emit) { _timer?.cancel(); @@ -79,7 +82,7 @@ class GarageDoorBloc extends Bloc { toggleDoor = deviceStatus.switch1; emit(UpdateState(garageSensor: deviceStatus)); Future.delayed(const Duration(milliseconds: 500)); - // _listenToChanges(); + _listenToChanges(); } catch (e) { emit(GarageDoorFailedState(errorMessage: e.toString())); return; @@ -179,39 +182,57 @@ class GarageDoorBloc extends Bloc { } // Real-time db - // StreamSubscription? _streamSubscription; - // void _listenToChanges() { - // try { - // _streamSubscription?.cancel(); - // DatabaseReference ref = - // FirebaseDatabase.instance.ref('device-status/$GDId'); - // Stream stream = ref.onValue; + StreamSubscription? _streamSubscription; + void _listenToChanges() { + try { + _streamSubscription?.cancel(); + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$GDId'); + Stream stream = ref.onValue; - // _streamSubscription = 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 = GarageDoorModel.fromJson(statusList); - // // if (!isClosed) { - // // add(ToggleSelectedEvent()); - // // } - // }); - // } catch (_) {} - // } + _streamSubscription = stream.listen((DatabaseEvent event) async { + if (_timer != null) { + await Future.delayed(const Duration(seconds: 1)); + } - // @override - // Future close() async { - // _streamSubscription?.cancel(); - // _streamSubscription = null; - // return super.close(); - // } + if (event.snapshot.value != null) { + Map usersMap = + event.snapshot.value as Map; + List statusList = []; + + usersMap['status'].forEach((element) { + statusList.add( + StatusModel(code: element['code'], value: element['value'])); + }); + deviceStatus.tr_timecon = statusList + .firstWhere((status) => status.code == "tr_timecon", + orElse: () => StatusModel(code: "tr_timecon", value: 0)) + .value as int; + + deviceStatus.switch1 = statusList + .firstWhere((status) => status.code == "switch_1", + orElse: () => StatusModel(code: "switch_1", value: false)) + .value as bool; + secondSelected = deviceStatus.tr_timecon; + toggleDoor = deviceStatus.switch1; + add(UpdateStateEvent()); + } + }); + } catch (_) {} + } + + Future _updateState( + UpdateStateEvent event, Emitter emit) async { + emit(GarageDoorLoadingState()); + emit(UpdateState(garageSensor: deviceStatus)); + } + + @override + Future close() async { + _streamSubscription?.cancel(); + _streamSubscription = null; + return super.close(); + } List> days = [ {"day": "Sun", "key": "Sun"}, diff --git a/lib/features/devices/bloc/garage_door_bloc/garage_door_event.dart b/lib/features/devices/bloc/garage_door_bloc/garage_door_event.dart index 83e7b07..dbbb67f 100644 --- a/lib/features/devices/bloc/garage_door_bloc/garage_door_event.dart +++ b/lib/features/devices/bloc/garage_door_bloc/garage_door_event.dart @@ -109,6 +109,8 @@ class GetScheduleEvent extends GarageDoorEvent {} class ScheduleSaveapp extends GarageDoorEvent {} +class UpdateStateEvent extends GarageDoorEvent {} + class ToggleScheduleEvent extends GarageDoorEvent { final String id; final bool toggle; 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 index c5ff33d..afde6fa 100644 --- a/lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart +++ b/lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart @@ -1,5 +1,6 @@ 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/one_gang_bloc/one_gang_state.dart'; @@ -60,48 +61,46 @@ class OneGangBloc extends Bloc { } deviceStatus = OneGangModel.fromJson(statusModelList); emit(UpdateState(oneGangModel: deviceStatus)); - // _listenToChanges(); + _listenToChanges(oneGangId); } catch (e) { emit(FailedState(error: e.toString())); return; } } + // Real-time db - // StreamSubscription? _streamSubscription; - // void _listenToChanges() { - // try { - // _streamSubscription?.cancel(); - // DatabaseReference ref = - // FirebaseDatabase.instance.ref('device-status/$oneGangId'); - // Stream stream = ref.onValue; + StreamSubscription? _streamSubscription; + void _listenToChanges(String id) { + try { + _streamSubscription?.cancel(); + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$id'); + Stream stream = ref.onValue; - // _streamSubscription = 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 (_) {} - // } + _streamSubscription = stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + List statusList = []; - // @override - // Future close() async { - // _streamSubscription?.cancel(); - // _streamSubscription = null; - // return super.close(); - // } + usersMap['status'].forEach((element) { + statusList + .add(StatusModel(code: element['code'], value: element['value'])); + }); + deviceStatus = OneGangModel.fromJson(statusList); + add(OneGangUpdated()); + }); + } catch (_) {} + } + + @override + Future close() async { + _streamSubscription?.cancel(); + _streamSubscription = null; + return super.close(); + } _oneGangUpdated(OneGangUpdated event, Emitter emit) { + emit(LoadingInitialState()); emit(UpdateState(oneGangModel: deviceStatus)); } diff --git a/lib/features/devices/bloc/one_touch_bloc/one_touch_bloc.dart b/lib/features/devices/bloc/one_touch_bloc/one_touch_bloc.dart index d18a248..1780264 100644 --- a/lib/features/devices/bloc/one_touch_bloc/one_touch_bloc.dart +++ b/lib/features/devices/bloc/one_touch_bloc/one_touch_bloc.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'package:dio/dio.dart'; +import 'package:firebase_database/firebase_database.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; @@ -63,39 +64,55 @@ class OneTouchBloc extends Bloc { statusModelList.add(StatusModel.fromJson(status)); } deviceStatus = OneTouchModel.fromJson(statusModelList); + _listenToChanges(oneTouchId); + emit(UpdateState(oneTouchModel: deviceStatus)); - // _listenToChanges(); } catch (e) { emit(FailedState(error: e.toString())); return; } } - // Real-time db - // _listenToChanges() { - // try { - // DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$oneTouchId'); - // 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 = []; + StreamSubscription? _streamSubscription; + void _listenToChanges(String id) { + try { + _streamSubscription?.cancel(); + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$id'); + Stream stream = ref.onValue; - // usersMap['status'].forEach((element) { - // statusList.add(StatusModel(code: element['code'], value: element['value'])); - // }); + _streamSubscription = stream.listen((DatabaseEvent event) { + if (event.snapshot.value != null) { + Map usersMap = + event.snapshot.value as Map; + List statusList = []; - // deviceStatus = OneTouchModel.fromJson(statusList); - // if (!isClosed) { - // add(OneTouchUpdated()); - // } - // }); - // } catch (_) {} - // } + usersMap['status'].forEach((element) { + statusList.add( + StatusModel(code: element['code'], value: element['value'])); + }); + var switchStatus = statusList.firstWhere( + (status) => status.code == "switch_1", + orElse: () => StatusModel(code: "switch_1", value: false)); + + deviceStatus.firstSwitch = switchStatus.value as bool; + add(OneTouchUpdated()); + } + }); + } catch (e) { + print("Error listening to changes: $e"); + } + } + + @override + Future close() async { + _streamSubscription?.cancel(); + _streamSubscription = null; + return super.close(); + } _oneTouchUpdated(OneTouchUpdated event, Emitter emit) { + emit(LoadingNewSate(oneTouchModel: deviceStatus)); emit(UpdateState(oneTouchModel: deviceStatus)); } diff --git a/lib/features/devices/bloc/three_touch_bloc/three_touch_bloc.dart b/lib/features/devices/bloc/three_touch_bloc/three_touch_bloc.dart index 8b5af81..4693612 100644 --- a/lib/features/devices/bloc/three_touch_bloc/three_touch_bloc.dart +++ b/lib/features/devices/bloc/three_touch_bloc/three_touch_bloc.dart @@ -1,5 +1,6 @@ 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'; @@ -37,7 +38,8 @@ class ThreeTouchBloc extends Bloc { List groupThreeTouchList = []; bool allSwitchesOn = true; - ThreeTouchBloc({required this.threeTouchId, required this.switchCode}) : super(InitialState()) { + ThreeTouchBloc({required this.threeTouchId, required this.switchCode}) + : super(InitialState()) { on(_fetchThreeTouchStatus); on(_threeTouchUpdated); on(_changeFirstSwitch); @@ -62,7 +64,8 @@ class ThreeTouchBloc extends Bloc { on(_changeStatus); } - void _fetchThreeTouchStatus(InitialEvent event, Emitter emit) async { + void _fetchThreeTouchStatus( + InitialEvent event, Emitter emit) async { emit(LoadingInitialState()); try { threeTouchGroup = event.groupScreen; @@ -74,7 +77,8 @@ class ThreeTouchBloc extends Bloc { HomeCubit.getInstance().selectedSpace?.id ?? '', '3GT'); for (int i = 0; i < devicesList.length; i++) { - var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); + var response = + await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); List statusModelList = []; for (var status in response['status']) { statusModelList.add(StatusModel.fromJson(status)); @@ -91,13 +95,16 @@ class ThreeTouchBloc extends Bloc { if (groupThreeTouchList.isNotEmpty) { groupThreeTouchList.firstWhere((element) { - if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) { + if (!element.firstSwitch || + !element.secondSwitch || + !element.thirdSwitch) { allSwitchesOn = false; } return true; }); } - emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: allSwitchesOn)); + emit(UpdateGroupState( + threeTouchList: groupThreeTouchList, allSwitches: allSwitchesOn)); } else { var response = await DevicesAPI.getDeviceStatus(threeTouchId); List statusModelList = []; @@ -106,7 +113,7 @@ class ThreeTouchBloc extends Bloc { } deviceStatus = ThreeTouchModel.fromJson(statusModelList); emit(UpdateState(threeTouchModel: deviceStatus)); - // _listenToChanges(); + _listenToChanges(); } } catch (e) { emit(FailedState(error: e.toString())); @@ -114,35 +121,39 @@ class ThreeTouchBloc extends Bloc { } } - // _listenToChanges() { - // try { - // DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$threeTouchId'); - // Stream stream = ref.onValue; + _listenToChanges() { + try { + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$threeTouchId'); + 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 = []; + 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'])); - // }); + usersMap['status'].forEach((element) { + statusList + .add(StatusModel(code: element['code'], value: element['value'])); + }); - // deviceStatus = ThreeTouchModel.fromJson(statusList); - // if (!isClosed) { - // add(ThreeTouchUpdated()); - // } - // }); - // } catch (_) {} - // } + deviceStatus = ThreeTouchModel.fromJson(statusList); + if (!isClosed) { + add(ThreeTouchUpdated()); + } + }); + } catch (_) {} + } _threeTouchUpdated(ThreeTouchUpdated event, Emitter emit) { emit(UpdateState(threeTouchModel: deviceStatus)); } - void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter emit) async { + void _changeFirstSwitch( + ChangeFirstSwitchStatusEvent event, Emitter emit) async { emit(LoadingNewSate(threeTouchModel: deviceStatus)); try { if (threeTouchGroup) { @@ -151,11 +162,15 @@ class ThreeTouchBloc extends Bloc { if (element.deviceId == event.deviceId) { element.firstSwitch = !event.value; } - if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) { + if (!element.firstSwitch || + !element.secondSwitch || + !element.thirdSwitch) { allSwitchesValue = false; } }); - emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: allSwitchesValue)); + emit(UpdateGroupState( + threeTouchList: groupThreeTouchList, + allSwitches: allSwitchesValue)); } else { deviceStatus.firstSwitch = !event.value; emit(UpdateState(threeTouchModel: deviceStatus)); @@ -182,8 +197,8 @@ class ThreeTouchBloc extends Bloc { } } - void _changeSecondSwitch( - ChangeSecondSwitchStatusEvent event, Emitter emit) async { + void _changeSecondSwitch(ChangeSecondSwitchStatusEvent event, + Emitter emit) async { emit(LoadingNewSate(threeTouchModel: deviceStatus)); try { if (threeTouchGroup) { @@ -192,11 +207,15 @@ class ThreeTouchBloc extends Bloc { if (element.deviceId == event.deviceId) { element.secondSwitch = !event.value; } - if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) { + if (!element.firstSwitch || + !element.secondSwitch || + !element.thirdSwitch) { allSwitchesValue = false; } }); - emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: allSwitchesValue)); + emit(UpdateGroupState( + threeTouchList: groupThreeTouchList, + allSwitches: allSwitchesValue)); } else { deviceStatus.secondSwitch = !event.value; emit(UpdateState(threeTouchModel: deviceStatus)); @@ -222,7 +241,8 @@ class ThreeTouchBloc extends Bloc { } } - void _changeThirdSwitch(ChangeThirdSwitchStatusEvent event, Emitter emit) async { + void _changeThirdSwitch( + ChangeThirdSwitchStatusEvent event, Emitter emit) async { emit(LoadingNewSate(threeTouchModel: deviceStatus)); try { if (threeTouchGroup) { @@ -231,11 +251,15 @@ class ThreeTouchBloc extends Bloc { if (element.deviceId == event.deviceId) { element.thirdSwitch = !event.value; } - if (!element.firstSwitch || !element.secondSwitch || !element.thirdSwitch) { + if (!element.firstSwitch || + !element.secondSwitch || + !element.thirdSwitch) { allSwitchesValue = false; } }); - emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: allSwitchesValue)); + emit(UpdateGroupState( + threeTouchList: groupThreeTouchList, + allSwitches: allSwitchesValue)); } else { deviceStatus.thirdSwitch = !event.value; emit(UpdateState(threeTouchModel: deviceStatus)); @@ -274,15 +298,21 @@ class ThreeTouchBloc extends Bloc { final response = await Future.wait([ DevicesAPI.controlDevice( DeviceControlModel( - deviceId: threeTouchId, code: 'switch_1', value: deviceStatus.firstSwitch), + deviceId: threeTouchId, + code: 'switch_1', + value: deviceStatus.firstSwitch), threeTouchId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: threeTouchId, code: 'switch_2', value: deviceStatus.secondSwitch), + deviceId: threeTouchId, + code: 'switch_2', + value: deviceStatus.secondSwitch), threeTouchId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: threeTouchId, code: 'switch_3', value: deviceStatus.thirdSwitch), + deviceId: threeTouchId, + code: 'switch_3', + value: deviceStatus.thirdSwitch), threeTouchId), ]); @@ -308,15 +338,21 @@ class ThreeTouchBloc extends Bloc { final response = await Future.wait([ DevicesAPI.controlDevice( DeviceControlModel( - deviceId: threeTouchId, code: 'switch_1', value: deviceStatus.firstSwitch), + deviceId: threeTouchId, + code: 'switch_1', + value: deviceStatus.firstSwitch), threeTouchId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: threeTouchId, code: 'switch_2', value: deviceStatus.secondSwitch), + deviceId: threeTouchId, + code: 'switch_2', + value: deviceStatus.secondSwitch), threeTouchId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: threeTouchId, code: 'switch_3', value: deviceStatus.thirdSwitch), + deviceId: threeTouchId, + code: 'switch_3', + value: deviceStatus.thirdSwitch), threeTouchId), ]); @@ -338,8 +374,10 @@ class ThreeTouchBloc extends Bloc { groupThreeTouchList[i].secondSwitch = true; groupThreeTouchList[i].thirdSwitch = true; } - emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: true)); - List allDeviceIds = groupThreeTouchList.map((device) => device.deviceId).toList(); + emit(UpdateGroupState( + threeTouchList: groupThreeTouchList, allSwitches: true)); + List allDeviceIds = + groupThreeTouchList.map((device) => device.deviceId).toList(); final response1 = await DevicesAPI.deviceBatchController( code: 'switch_1', devicesUuid: allDeviceIds, @@ -368,7 +406,8 @@ class ThreeTouchBloc extends Bloc { } } - void _groupAllOff(GroupAllOffEvent event, Emitter emit) async { + void _groupAllOff( + GroupAllOffEvent event, Emitter emit) async { emit(LoadingNewSate(threeTouchModel: deviceStatus)); try { for (int i = 0; i < groupThreeTouchList.length; i++) { @@ -376,8 +415,10 @@ class ThreeTouchBloc extends Bloc { groupThreeTouchList[i].secondSwitch = false; groupThreeTouchList[i].thirdSwitch = false; } - List allDeviceIds = groupThreeTouchList.map((device) => device.deviceId).toList(); - emit(UpdateGroupState(threeTouchList: groupThreeTouchList, allSwitches: false)); + List allDeviceIds = + groupThreeTouchList.map((device) => device.deviceId).toList(); + emit(UpdateGroupState( + threeTouchList: groupThreeTouchList, allSwitches: false)); final response1 = await DevicesAPI.deviceBatchController( code: 'switch_1', devicesUuid: allDeviceIds, @@ -406,17 +447,20 @@ class ThreeTouchBloc extends Bloc { } } - void _changeSliding(ChangeSlidingSegment event, Emitter emit) async { + void _changeSliding( + ChangeSlidingSegment event, Emitter emit) async { emit(ChangeSlidingSegmentState(value: event.value)); } - void _setCounterValue(SetCounterValue event, Emitter emit) async { + void _setCounterValue( + SetCounterValue event, Emitter 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), + DeviceControlModel( + deviceId: threeTouchId, code: event.deviceCode, value: seconds), threeTouchId); if (response['success'] ?? false) { @@ -443,7 +487,8 @@ class ThreeTouchBloc extends Bloc { } } - void _getCounterValue(GetCounterEvent event, Emitter emit) async { + void _getCounterValue( + GetCounterEvent event, Emitter emit) async { emit(LoadingInitialState()); try { var response = await DevicesAPI.getDeviceStatus(threeTouchId); @@ -553,7 +598,8 @@ class ThreeTouchBloc extends Bloc { deviceId: threeTouchId, ); List jsonData = response; - listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); + listSchedule = + jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); emit(InitialState()); } on DioException catch (e) { final errorData = e.response!.data; @@ -564,12 +610,13 @@ class ThreeTouchBloc extends Bloc { int? getTimeStampWithoutSeconds(DateTime? dateTime) { if (dateTime == null) return null; - DateTime dateTimeWithoutSeconds = - DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); + DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month, + dateTime.day, dateTime.hour, dateTime.minute); return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; } - Future toggleChange(ToggleScheduleEvent event, Emitter emit) async { + Future toggleChange( + ToggleScheduleEvent event, Emitter emit) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.changeSchedule( @@ -588,7 +635,8 @@ class ThreeTouchBloc extends Bloc { } } - Future deleteSchedule(DeleteScheduleEvent event, Emitter emit) async { + Future deleteSchedule( + DeleteScheduleEvent event, Emitter emit) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.deleteSchedule( @@ -608,13 +656,15 @@ class ThreeTouchBloc extends Bloc { } } - void toggleSelectedIndex(ToggleSelectedEvent event, Emitter emit) { + void toggleSelectedIndex( + ToggleSelectedEvent event, Emitter emit) { emit(LoadingInitialState()); selectedTabIndex = event.index; emit(ChangeSlidingSegmentState(value: selectedTabIndex)); } - void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter emit) { + void toggleCreateSchedule( + ToggleCreateScheduleEvent event, Emitter emit) { emit(LoadingInitialState()); createSchedule = !createSchedule; selectedDays.clear(); @@ -632,7 +682,8 @@ class ThreeTouchBloc extends Bloc { String statusSelected = ''; String optionSelected = ''; - Future _changeStatus(ChangeStatusEvent event, Emitter emit) async { + Future _changeStatus( + ChangeStatusEvent event, Emitter emit) async { try { emit(LoadingInitialState()); final Map> controlMap = { @@ -666,11 +717,15 @@ class ThreeTouchBloc extends Bloc { final selectedControl = controlMap[optionSelected]?[statusSelected]; if (selectedControl != null) { await DevicesAPI.controlDevice( - DeviceControlModel(deviceId: threeTouchId, code: optionSelected, value: selectedControl), + DeviceControlModel( + deviceId: threeTouchId, + code: optionSelected, + value: selectedControl), threeTouchId, ); } else { - emit(const FailedState(error: 'Invalid statusSelected or optionSelected')); + emit(const FailedState( + error: 'Invalid statusSelected or optionSelected')); } } on DioException catch (e) { final errorData = e.response!.data; 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 index 5435148..d7eb6cd 100644 --- a/lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart +++ b/lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart @@ -1,5 +1,6 @@ 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_gang_bloc/two_gang_event.dart'; @@ -34,7 +35,8 @@ class TwoGangBloc extends Bloc { bool createSchedule = false; List listSchedule = []; - TwoGangBloc({required this.twoGangId, required this.switchCode}) : super(InitialState()) { + TwoGangBloc({required this.twoGangId, required this.switchCode}) + : super(InitialState()) { on(_fetchTwoGangStatus); on(_twoGangUpdated); on(_changeFirstSwitch); @@ -64,13 +66,15 @@ class TwoGangBloc extends Bloc { int selectedTabIndex = 0; - void toggleSelectedIndex(ToggleSelectedEvent event, Emitter emit) { + void toggleSelectedIndex( + ToggleSelectedEvent event, Emitter emit) { emit(LoadingInitialState()); selectedTabIndex = event.index; emit(ChangeSlidingSegmentState(value: selectedTabIndex)); } - void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter emit) { + void toggleCreateSchedule( + ToggleCreateScheduleEvent event, Emitter emit) { emit(LoadingInitialState()); createSchedule = !createSchedule; selectedDays.clear(); @@ -78,7 +82,8 @@ class TwoGangBloc extends Bloc { emit(UpdateCreateScheduleState(createSchedule)); } - void _fetchTwoGangStatus(InitialEvent event, Emitter emit) async { + void _fetchTwoGangStatus( + InitialEvent event, Emitter emit) async { emit(LoadingInitialState()); try { var response = await DevicesAPI.getDeviceStatus(twoGangId); @@ -88,42 +93,50 @@ class TwoGangBloc extends Bloc { } deviceStatus = TwoGangModel.fromJson(statusModelList); emit(UpdateState(twoGangModel: deviceStatus)); - // _listenToChanges(); + _listenToChanges(twoGangId); } catch (e) { emit(FailedState(error: e.toString())); return; } } - // _listenToChanges() { - // try { - // DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$twoGangId'); - // Stream stream = ref.onValue; + StreamSubscription? _streamSubscription; + void _listenToChanges(String id) { + try { + _streamSubscription?.cancel(); + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$id'); + Stream stream = ref.onValue; + _streamSubscription = stream.listen((DatabaseEvent event) { + Map usersMap = + event.snapshot.value as Map; + List statusList = []; - // 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); + add(TwoGangUpdated()); + }); + } catch (_) {} + } - // usersMap['status'].forEach((element) { - // statusList.add(StatusModel(code: element['code'], value: element['value'])); - // }); - - // deviceStatus = TwoGangModel.fromJson(statusList); - // if (!isClosed) { - // add(TwoGangUpdated()); - // } - // }); - // } catch (_) {} - // } + @override + Future close() async { + _streamSubscription?.cancel(); + _streamSubscription = null; + return super.close(); + } _twoGangUpdated(TwoGangUpdated event, Emitter emit) { + emit(LoadingNewSate(twoGangModel: deviceStatus)); + emit(UpdateState(twoGangModel: deviceStatus)); } - void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter emit) async { + void _changeFirstSwitch( + ChangeFirstSwitchStatusEvent event, Emitter emit) async { emit(LoadingNewSate(twoGangModel: deviceStatus)); try { deviceStatus.firstSwitch = !event.value; @@ -134,7 +147,8 @@ class TwoGangBloc extends Bloc { _timer = Timer(const Duration(milliseconds: 100), () async { final response = await DevicesAPI.controlDevice( - DeviceControlModel(deviceId: twoGangId, code: 'switch_1', value: !event.value), + DeviceControlModel( + deviceId: twoGangId, code: 'switch_1', value: !event.value), twoGangId); if (!response['success']) { @@ -146,7 +160,8 @@ class TwoGangBloc extends Bloc { } } - void _changeSecondSwitch(ChangeSecondSwitchStatusEvent event, Emitter emit) async { + void _changeSecondSwitch( + ChangeSecondSwitchStatusEvent event, Emitter emit) async { emit(LoadingNewSate(twoGangModel: deviceStatus)); try { deviceStatus.secondSwitch = !event.value; @@ -156,7 +171,8 @@ class TwoGangBloc extends Bloc { } _timer = Timer(const Duration(milliseconds: 100), () async { final response = await DevicesAPI.controlDevice( - DeviceControlModel(deviceId: twoGangId, code: 'switch_2', value: !event.value), + DeviceControlModel( + deviceId: twoGangId, code: 'switch_2', value: !event.value), twoGangId); if (!response['success']) { @@ -179,11 +195,15 @@ class TwoGangBloc extends Bloc { final response = await Future.wait([ DevicesAPI.controlDevice( DeviceControlModel( - deviceId: twoGangId, code: 'switch_1', value: deviceStatus.firstSwitch), + deviceId: twoGangId, + code: 'switch_1', + value: deviceStatus.firstSwitch), twoGangId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: twoGangId, code: 'switch_2', value: deviceStatus.secondSwitch), + deviceId: twoGangId, + code: 'switch_2', + value: deviceStatus.secondSwitch), twoGangId), ]); @@ -206,11 +226,15 @@ class TwoGangBloc extends Bloc { final response = await Future.wait([ DevicesAPI.controlDevice( DeviceControlModel( - deviceId: twoGangId, code: 'switch_1', value: deviceStatus.firstSwitch), + deviceId: twoGangId, + code: 'switch_1', + value: deviceStatus.firstSwitch), twoGangId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: twoGangId, code: 'switch_2', value: deviceStatus.secondSwitch), + deviceId: twoGangId, + code: 'switch_2', + value: deviceStatus.secondSwitch), twoGangId), ]); if (response.every((element) => !element['success'])) { @@ -231,7 +255,8 @@ class TwoGangBloc extends Bloc { groupTwoGangList[i].secondSwitch = true; } emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: true)); - List allDeviceIds = groupTwoGangList.map((device) => device.deviceId).toList(); + List allDeviceIds = + groupTwoGangList.map((device) => device.deviceId).toList(); final response1 = await DevicesAPI.deviceBatchController( code: 'switch_1', @@ -266,7 +291,8 @@ class TwoGangBloc extends Bloc { emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: false)); - List allDeviceIds = groupTwoGangList.map((device) => device.deviceId).toList(); + List allDeviceIds = + groupTwoGangList.map((device) => device.deviceId).toList(); final response1 = await DevicesAPI.deviceBatchController( code: 'switch_1', @@ -291,17 +317,20 @@ class TwoGangBloc extends Bloc { } } - void _changeSliding(ChangeSlidingSegment event, Emitter emit) async { + void _changeSliding( + ChangeSlidingSegment event, Emitter emit) async { emit(ChangeSlidingSegmentState(value: event.value)); } - void _setCounterValue(SetCounterValue event, Emitter emit) async { + 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), + DeviceControlModel( + deviceId: twoGangId, code: event.deviceCode, value: seconds), twoGangId); if (response['success'] ?? false) { @@ -326,7 +355,8 @@ class TwoGangBloc extends Bloc { } } - void _getCounterValue(GetCounterEvent event, Emitter emit) async { + void _getCounterValue( + GetCounterEvent event, Emitter emit) async { emit(LoadingInitialState()); try { add(GetScheduleEvent()); @@ -434,7 +464,8 @@ class TwoGangBloc extends Bloc { deviceId: twoGangId, ); List jsonData = response; - listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); + listSchedule = + jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); emit(InitialState()); } on DioException catch (e) { final errorData = e.response!.data; @@ -445,12 +476,13 @@ class TwoGangBloc extends Bloc { int? getTimeStampWithoutSeconds(DateTime? dateTime) { if (dateTime == null) return null; - DateTime dateTimeWithoutSeconds = - DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); + DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month, + dateTime.day, dateTime.hour, dateTime.minute); return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; } - Future toggleRepeat(ToggleScheduleEvent event, Emitter emit) async { + Future toggleRepeat( + ToggleScheduleEvent event, Emitter emit) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.changeSchedule( @@ -469,7 +501,8 @@ class TwoGangBloc extends Bloc { } } - Future deleteSchedule(DeleteScheduleEvent event, Emitter emit) async { + Future deleteSchedule( + DeleteScheduleEvent event, Emitter emit) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.deleteSchedule( @@ -489,7 +522,8 @@ class TwoGangBloc extends Bloc { } } - void _fetchTwoGangWizardStatus(InitialWizardEvent event, Emitter emit) async { + void _fetchTwoGangWizardStatus( + InitialWizardEvent event, Emitter emit) async { emit(LoadingInitialState()); try { devicesList = []; @@ -499,7 +533,8 @@ class TwoGangBloc extends Bloc { HomeCubit.getInstance().selectedSpace?.id ?? '', '2G'); for (int i = 0; i < devicesList.length; i++) { - var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); + var response = + await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); List statusModelList = []; for (var status in response['status']) { statusModelList.add(StatusModel.fromJson(status)); @@ -522,15 +557,16 @@ class TwoGangBloc extends Bloc { return true; }); } - emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesOn)); + emit(UpdateGroupState( + twoGangList: groupTwoGangList, allSwitches: allSwitchesOn)); } catch (e) { emit(FailedState(error: e.toString())); return; } } - void _changeFirstWizardSwitch( - ChangeFirstWizardSwitchStatusEvent event, Emitter emit) async { + void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event, + Emitter emit) async { emit(LoadingNewSate(twoGangModel: deviceStatus)); try { bool allSwitchesValue = true; @@ -543,9 +579,11 @@ class TwoGangBloc extends Bloc { } }); - emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesValue)); + emit(UpdateGroupState( + twoGangList: groupTwoGangList, allSwitches: allSwitchesValue)); - List allDeviceIds = groupTwoGangList.map((device) => device.deviceId).toList(); + List allDeviceIds = + groupTwoGangList.map((device) => device.deviceId).toList(); final response = await DevicesAPI.deviceBatchController( code: 'switch_1', devicesUuid: allDeviceIds, @@ -560,8 +598,8 @@ class TwoGangBloc extends Bloc { } } - void _changeSecondWizardSwitch( - ChangeSecondWizardSwitchStatusEvent event, Emitter emit) async { + void _changeSecondWizardSwitch(ChangeSecondWizardSwitchStatusEvent event, + Emitter emit) async { emit(LoadingNewSate(twoGangModel: deviceStatus)); try { bool allSwitchesValue = true; @@ -573,9 +611,11 @@ class TwoGangBloc extends Bloc { allSwitchesValue = false; } }); - List allDeviceIds = groupTwoGangList.map((device) => device.deviceId).toList(); + List allDeviceIds = + groupTwoGangList.map((device) => device.deviceId).toList(); - emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesValue)); + emit(UpdateGroupState( + twoGangList: groupTwoGangList, allSwitches: allSwitchesValue)); final response = await DevicesAPI.deviceBatchController( code: 'switch_2', diff --git a/lib/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart b/lib/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart index 9a62a5e..b153dde 100644 --- a/lib/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart +++ b/lib/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart @@ -1,5 +1,6 @@ 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'; @@ -98,52 +99,62 @@ class TwoTouchBloc extends Bloc { } deviceStatus = TwoTouchModel.fromJson(statusModelList); emit(UpdateState(twoTouchModel: deviceStatus)); - // _listenToChanges(); + _listenToChanges(); } catch (e) { emit(FailedState(error: e.toString())); return; } } - // StreamSubscription? _streamSubscription; + StreamSubscription? _streamSubscription; - // void _listenToChanges() { - // try { - // _streamSubscription?.cancel(); - // DatabaseReference ref = - // FirebaseDatabase.instance.ref('device-status/$twoTouchId'); - // Stream stream = ref.onValue; + void _listenToChanges() { + try { + _streamSubscription?.cancel(); + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$twoTouchId'); + Stream stream = ref.onValue; - // _streamSubscription = 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'])); - // }); - // print('=========${usersMap['status']}'); - // deviceStatus = TwoTouchModel.fromJson(statusList); - // if (!isClosed) { - // add(TwoTouchUpdated()); - // } - // }); - // } catch (_) {} - // } + _streamSubscription = stream.listen((DatabaseEvent event) async { + if (_timer != null) { + await Future.delayed(const Duration(seconds: 1)); + } + if (event.snapshot.value != null) { + Map usersMap = + event.snapshot.value as Map; + List statusList = []; - // @override - // Future close() async { - // _streamSubscription?.cancel(); - // _streamSubscription = null; - // return super.close(); - // } + usersMap['status'].forEach((element) { + statusList.add( + StatusModel(code: element['code'], value: element['value'])); + }); + var switch1Status = statusList.firstWhere( + (status) => status.code == "switch_1", + orElse: () => StatusModel(code: "switch_1", value: false)); + var switch2Status = statusList.firstWhere( + (status) => status.code == "switch_2", + orElse: () => StatusModel(code: "switch_2", value: false)); + deviceStatus.firstSwitch = switch1Status.value as bool; + deviceStatus.secondSwitch = switch2Status.value as bool; + add(TwoTouchUpdated()); + } + }); + } catch (e) { + print("Error listening to changes: $e"); + } + } + + @override + Future close() async { + _streamSubscription?.cancel(); + _streamSubscription = null; + return super.close(); + } _twoTouchUpdated(TwoTouchUpdated event, Emitter emit) { + emit(LoadingInitialState()); emit(UpdateState(twoTouchModel: deviceStatus)); } diff --git a/lib/features/devices/bloc/water_heater_bloc/water_heater_bloc.dart b/lib/features/devices/bloc/water_heater_bloc/water_heater_bloc.dart index 2316b61..736cef4 100644 --- a/lib/features/devices/bloc/water_heater_bloc/water_heater_bloc.dart +++ b/lib/features/devices/bloc/water_heater_bloc/water_heater_bloc.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'package:dio/dio.dart'; +import 'package:firebase_database/firebase_database.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; @@ -73,7 +74,7 @@ class WaterHeaterBloc extends Bloc { statusModelList, ); emit(UpdateState(whModel: deviceStatus)); - // _listenToChanges(); + _listenToChanges(); } catch (e) { emit(WHFailedState(errorMessage: e.toString())); return; @@ -81,41 +82,39 @@ class WaterHeaterBloc extends Bloc { } //real-time db - // StreamSubscription? _streamSubscription; - // void _listenToChanges() { - // try { - // _streamSubscription?.cancel(); - // DatabaseReference ref = - // FirebaseDatabase.instance.ref('device-status/$whId'); - // Stream stream = ref.onValue; - - // _streamSubscription = 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 = WHModel.fromJson(statusList); - // if (!isClosed) { - // add(WaterHeaterUpdated()); - // } - // }); - // } catch (_) {} - // } - - // @override - // Future close() async { - // _streamSubscription?.cancel(); - // _streamSubscription = null; - // return super.close(); - // } + StreamSubscription? _streamSubscription; + void _listenToChanges() { + try { + _streamSubscription?.cancel(); + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$whId'); + Stream stream = ref.onValue; + _streamSubscription = 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 = WHModel.fromJson(statusList); + if (!isClosed) { + add(WaterHeaterUpdated()); + } + }); + } catch (_) {} + } + @override + Future close() async { + _streamSubscription?.cancel(); + _streamSubscription = null; + return super.close(); + } _waterHeaterUpdated( WaterHeaterUpdated event, Emitter emit) async { diff --git a/lib/features/devices/view/widgets/garage_door/garage_door_screen.dart b/lib/features/devices/view/widgets/garage_door/garage_door_screen.dart index 0a84a9f..8a6c53c 100644 --- a/lib/features/devices/view/widgets/garage_door/garage_door_screen.dart +++ b/lib/features/devices/view/widgets/garage_door/garage_door_screen.dart @@ -15,6 +15,444 @@ import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; import 'package:syncrow_app/generated/assets.dart'; +// class GarageDoorScreen extends StatelessWidget { +// final DeviceModel? device; + +// const GarageDoorScreen({super.key, this.device}); + +// @override +// Widget build(BuildContext context) { +// return DefaultScaffold( +// appBar: DeviceAppbar( +// deviceName: device!.name!, +// deviceUuid: device!.uuid!, +// ), +// title: 'Garage Door Opener', +// child: BlocProvider( +// create: (context) => GarageDoorBloc(GDId: device?.uuid ?? '') +// ..add(const GarageDoorInitial()), +// child: BlocBuilder( +// builder: (context, state) { +// final garageBloc = BlocProvider.of(context); +// bool isDoorOpen = false; +// int selectedTime = 0; +// print('state=$state'); +// if (state is UpdateState) { +// isDoorOpen = garageBloc.toggleDoor; +// selectedTime = garageBloc.secondSelected; +// } +// return state is GarageDoorLoadingState +// ? const Center( +// child: DefaultContainer( +// width: 50, +// height: 50, +// child: CircularProgressIndicator()), +// ) +// : RefreshIndicator( +// onRefresh: () async { +// garageBloc.add(const GarageDoorInitial()); +// }, +// child: ListView( +// children: [ +// SizedBox( +// height: MediaQuery.sizeOf(context).height * 0.8, +// child: Column( +// children: [ +// Expanded( +// flex: 5, +// child: InkWell( +// overlayColor: WidgetStateProperty.all( +// Colors.transparent), +// onTap: () {}, +// child: Row( +// mainAxisAlignment: MainAxisAlignment.center, +// crossAxisAlignment: +// CrossAxisAlignment.center, +// children: [ +// Container( +// decoration: BoxDecoration( +// borderRadius: +// BorderRadius.circular(890), +// boxShadow: [ +// BoxShadow( +// color: Colors.white +// .withOpacity(0.1), +// blurRadius: 24, +// offset: const Offset(-5, -5), +// blurStyle: BlurStyle.outer, +// ), +// BoxShadow( +// color: Colors.black +// .withOpacity(0.11), +// blurRadius: 25, +// offset: const Offset(5, 5), +// blurStyle: BlurStyle.outer, +// ), +// BoxShadow( +// color: Colors.black +// .withOpacity(0.13), +// blurRadius: 30, +// offset: const Offset(5, 5), +// blurStyle: BlurStyle.inner, +// ), +// ], +// ), +// child: InkWell( +// onTap: () { +// garageBloc.add(ToggleDoorEvent( +// toggle: +// garageBloc.toggleDoor)); +// }, +// child: GradientWidget( +// doorStatus: isDoorOpen, +// seconds: selectedTime, +// // doorStatus: garageBloc.toggleDoor, +// // seconds:garageBloc.secondSelected, +// ), +// )), +// ], +// ), +// ), +// ), +// Expanded( +// flex: 3, +// child: Column( +// children: [ +// Flexible( +// child: Row( +// children: [ +// Expanded( +// child: DefaultContainer( +// onTap: () { +// Navigator.of(context).push( +// MaterialPageRoute( +// builder: (context) => +// TimerScheduleScreen( +// device: device!, +// switchCode: +// 'switch_1', +// deviceCode: +// 'countdown_1', +// )), +// ); +// }, +// child: Column( +// crossAxisAlignment: +// CrossAxisAlignment.center, +// mainAxisAlignment: +// MainAxisAlignment.center, +// children: [ +// ConstrainedBox( +// constraints: +// const BoxConstraints( +// maxHeight: 46, +// maxWidth: 50), +// child: SvgPicture.asset( +// Assets +// .garageSchedule), +// ), +// const Flexible( +// child: SizedBox( +// height: 15, +// )), +// const Flexible( +// child: FittedBox( +// child: BodySmall( +// text: 'Schedule', +// textAlign: +// TextAlign.center, +// ), +// ), +// ), +// ], +// ), +// ), +// ), +// const SizedBox( +// width: 10, +// ), +// Expanded( +// child: DefaultContainer( +// onTap: () { +// Navigator.of(context).push( +// MaterialPageRoute( +// builder: (context) => +// TimerPage( +// device: device!, +// switchCode: +// 'switch_1', +// deviceCode: +// 'countdown_1', +// )), +// ); +// }, +// child: Column( +// crossAxisAlignment: +// CrossAxisAlignment.center, +// mainAxisAlignment: +// MainAxisAlignment.center, +// children: [ +// ConstrainedBox( +// constraints: +// const BoxConstraints( +// maxHeight: 46, +// maxWidth: 50), +// child: SvgPicture.asset( +// Assets +// .garageCountdown), +// ), +// const Flexible( +// child: SizedBox( +// height: 15, +// )), +// const Flexible( +// child: FittedBox( +// child: BodySmall( +// text: 'Countdown', +// textAlign: +// TextAlign.center, +// ), +// ), +// ), +// ], +// ), +// ), +// ), +// ], +// ), +// ), +// const SizedBox( +// height: 10, +// ), +// Flexible( +// child: Row( +// children: [ +// Expanded( +// child: DefaultContainer( +// onTap: () { +// Navigator.of(context).push( +// MaterialPageRoute( +// builder: (context) => +// GarageRecordsScreen( +// GDId: device! +// .uuid!)), +// ); +// }, +// child: Column( +// crossAxisAlignment: +// CrossAxisAlignment.center, +// mainAxisAlignment: +// MainAxisAlignment.center, +// children: [ +// ConstrainedBox( +// constraints: +// const BoxConstraints( +// maxHeight: 46, +// maxWidth: 50), +// child: SvgPicture.asset( +// Assets +// .doorRecordsIcon), +// ), +// const Flexible( +// child: SizedBox( +// height: 15, +// )), +// const Flexible( +// child: FittedBox( +// child: BodySmall( +// text: 'Records', +// textAlign: +// TextAlign.center, +// ), +// ), +// ), +// ], +// ), +// ), +// ), +// const SizedBox( +// width: 10, +// ), +// Expanded( +// child: DefaultContainer( +// onTap: () { +// Navigator.of(context).push( +// MaterialPageRoute( +// builder: (context) => +// PreferencesPage( +// GDId: device! +// .uuid!)), +// ); +// }, +// child: Column( +// crossAxisAlignment: +// CrossAxisAlignment.center, +// mainAxisAlignment: +// MainAxisAlignment.center, +// children: [ +// ConstrainedBox( +// constraints: +// const BoxConstraints( +// maxHeight: 46, +// maxWidth: 50), +// child: SvgPicture.asset(Assets +// .garagePreferencesIcon), +// ), +// const Flexible( +// child: SizedBox( +// height: 15, +// )), +// const Flexible( +// child: FittedBox( +// child: BodySmall( +// text: 'Preferences', +// textAlign: +// TextAlign.center, +// ), +// ), +// ), +// ], +// ), +// ), +// ), +// ], +// ), +// ) +// ], +// )), +// ], +// ), +// ), +// ], +// ), +// ); +// }, +// ), +// ), +// ); +// } +// } + +// class GradientWidget extends StatefulWidget { +// const GradientWidget({required this.seconds, required this.doorStatus}); +// final int seconds; +// final bool doorStatus; + +// @override +// State createState() => _GradientWidgetState(); +// } + +// class _GradientWidgetState extends State +// with SingleTickerProviderStateMixin { +// late ScrollController _scrollController; +// late AnimationController _animationController; +// late Animation _itemExtentAnimation; + +// @override +// void initState() { +// super.initState(); +// _scrollController = ScrollController(); +// _animationController = AnimationController( +// vsync: this, +// duration: Duration(seconds: widget.seconds), +// ); +// _itemExtentAnimation = Tween( +// begin: widget.doorStatus ? 0 : 15, end: widget.doorStatus ? 15 : 0) +// .animate( +// CurvedAnimation( +// parent: _animationController, +// curve: Curves.easeInOut, +// ), +// )..addListener(() { +// setState(() {}); +// }); + +// WidgetsBinding.instance.addPostFrameCallback((_) { +// if (widget.doorStatus) { +// _openAnimation(); +// } else { +// _closeAnimation(); +// } +// }); +// } + +// void _openAnimation() { +// _animationController.forward(); +// } + +// void _closeAnimation() { +// _animationController.reverse(); +// } + +// @override +// void dispose() { +// _scrollController.dispose(); +// _animationController.dispose(); +// super.dispose(); +// } + +// @override +// Widget build(BuildContext context) { +// return Container( +// width: 300, +// height: 300, +// padding: EdgeInsets.only(right: 10), +// child: Stack( +// children: [ +// SvgPicture.asset( +// Assets.openGarageIcon, +// fit: BoxFit.fill, +// ), +// Column( +// crossAxisAlignment: CrossAxisAlignment.center, +// mainAxisAlignment: MainAxisAlignment.center, +// children: [ +// Expanded(child: Container()), +// Expanded( +// flex: 2, +// child: Center( +// child: Container( +// height: 104, +// child: ListView.builder( +// itemExtent: _itemExtentAnimation.value, +// controller: _scrollController, +// itemCount: 4, +// itemBuilder: (context, index) { +// return Center(child: GradientWidget1()); +// }, +// ), +// ), +// ), +// ), +// ], +// ), +// ], +// ), +// ); +// } +// } + +// class GradientWidget1 extends StatelessWidget { +// @override +// Widget build(BuildContext context) { +// return Container( +// width: 97, +// height: 15, +// decoration: const BoxDecoration( +// gradient: LinearGradient( +// begin: Alignment.topCenter, +// end: Alignment.bottomCenter, +// colors: [ +// Color(0xFF017297), +// Color(0xFF024C67), +// ], +// stops: [0.0, 1.0], +// ), +// ), +// ); +// } +// } + class GarageDoorScreen extends StatelessWidget { final DeviceModel? device; @@ -31,400 +469,228 @@ class GarageDoorScreen extends StatelessWidget { child: BlocProvider( create: (context) => GarageDoorBloc(GDId: device?.uuid ?? '') ..add(const GarageDoorInitial()), - child: BlocBuilder( - builder: (context, state) { - final garageBloc = BlocProvider.of(context); - return state is GarageDoorLoadingState - ? const Center( - child: DefaultContainer( - width: 50, - height: 50, - child: CircularProgressIndicator()), - ) - : RefreshIndicator( - onRefresh: () async { - garageBloc.add(const GarageDoorInitial()); - }, - child: ListView( - children: [ - SizedBox( - height: MediaQuery.sizeOf(context).height * 0.8, - child: Column( - children: [ - Expanded( - flex: 5, - child: InkWell( - overlayColor: WidgetStateProperty.all( - Colors.transparent), - onTap: () {}, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: - CrossAxisAlignment.center, - children: [ - Container( - decoration: BoxDecoration( - borderRadius: - BorderRadius.circular(890), - boxShadow: [ - BoxShadow( - color: Colors.white - .withOpacity(0.1), - blurRadius: 24, - offset: const Offset(-5, -5), - blurStyle: BlurStyle.outer, - ), - BoxShadow( - color: Colors.black - .withOpacity(0.11), - blurRadius: 25, - offset: const Offset(5, 5), - blurStyle: BlurStyle.outer, - ), - BoxShadow( - color: Colors.black - .withOpacity(0.13), - blurRadius: 30, - offset: const Offset(5, 5), - blurStyle: BlurStyle.inner, - ), - ], - ), - child: InkWell( - onTap: () { - garageBloc.add(ToggleDoorEvent( - toggle: - garageBloc.toggleDoor)); - }, - child: GradientWidget( - doorStatus: garageBloc.toggleDoor, - seconds: - garageBloc.secondSelected, - ), - )), - ], - ), - ), - ), - Expanded( - flex: 3, - child: Column( - children: [ - Flexible( - child: Row( - children: [ - Expanded( - child: DefaultContainer( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => - TimerScheduleScreen( - device: device!, - switchCode: - 'switch_1', - deviceCode: - 'countdown_1', - )), - ); - }, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - ConstrainedBox( - constraints: - const BoxConstraints( - maxHeight: 46, - maxWidth: 50), - child: SvgPicture.asset( - Assets - .garageSchedule), - ), - const Flexible( - child: SizedBox( - height: 15, - )), - const Flexible( - child: FittedBox( - child: BodySmall( - text: 'Schedule', - textAlign: - TextAlign.center, - ), - ), - ), - ], - ), - ), - ), - const SizedBox( - width: 10, - ), - Expanded( - child: DefaultContainer( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => - TimerPage( - device: device!, - switchCode: - 'switch_1', - deviceCode: - 'countdown_1', - )), - ); - }, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - ConstrainedBox( - constraints: - const BoxConstraints( - maxHeight: 46, - maxWidth: 50), - child: SvgPicture.asset( - Assets - .garageCountdown), - ), - const Flexible( - child: SizedBox( - height: 15, - )), - const Flexible( - child: FittedBox( - child: BodySmall( - text: 'Countdown', - textAlign: - TextAlign.center, - ), - ), - ), - ], - ), - ), - ), - ], - ), - ), - const SizedBox( - height: 10, - ), - Flexible( - child: Row( - children: [ - Expanded( - child: DefaultContainer( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => - GarageRecordsScreen( - GDId: device! - .uuid!)), - ); - }, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - ConstrainedBox( - constraints: - const BoxConstraints( - maxHeight: 46, - maxWidth: 50), - child: SvgPicture.asset( - Assets - .doorRecordsIcon), - ), - const Flexible( - child: SizedBox( - height: 15, - )), - const Flexible( - child: FittedBox( - child: BodySmall( - text: 'Records', - textAlign: - TextAlign.center, - ), - ), - ), - ], - ), - ), - ), - const SizedBox( - width: 10, - ), - Expanded( - child: DefaultContainer( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => - PreferencesPage( - GDId: device! - .uuid!)), - ); - }, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - ConstrainedBox( - constraints: - const BoxConstraints( - maxHeight: 46, - maxWidth: 50), - child: SvgPicture.asset(Assets - .garagePreferencesIcon), - ), - const Flexible( - child: SizedBox( - height: 15, - )), - const Flexible( - child: FittedBox( - child: BodySmall( - text: 'Preferences', - textAlign: - TextAlign.center, - ), - ), - ), - ], - ), - ), - ), - ], - ), - ) - ], - )), - ], - ), - ), - ], - ), - ); + child: _GarageDoorContent(device: device), + ), + ); + } +} + +class _GarageDoorContent extends StatelessWidget { + final DeviceModel? device; + + const _GarageDoorContent({this.device}); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is GarageDoorLoadingState) { + return const _LoadingIndicator(); + } + + return RefreshIndicator( + onRefresh: () async { + context.read().add(const GarageDoorInitial()); }, + child: _MainContent(device: device, state: state), + ); + }, + ); + } +} + +class _LoadingIndicator extends StatelessWidget { + const _LoadingIndicator(); + + @override + Widget build(BuildContext context) { + return const Center( + child: DefaultContainer( + width: 50, height: 50, child: CircularProgressIndicator()), + ); + } +} + +class _MainContent extends StatelessWidget { + final DeviceModel? device; + final GarageDoorSensorState? state; + + const _MainContent({this.device, this.state}); + + @override + Widget build(BuildContext context) { + final garageBloc = BlocProvider.of(context); + final isDoorOpen = garageBloc.toggleDoor; + final selectedTime = garageBloc.secondSelected; + + return ListView( + children: [ + SizedBox( + height: MediaQuery.sizeOf(context).height * 0.8, + child: Column( + children: [ + Expanded( + flex: 5, + child: _GarageDoorControl( + isDoorOpen: isDoorOpen, + selectedTime: selectedTime, + ), + ), + Expanded( + flex: 3, + child: _ActionGrid(device: device), + ), + ], + ), + ), + ], + ); + } +} + +class _GarageDoorControl extends StatelessWidget { + final bool isDoorOpen; + final int selectedTime; + + const _GarageDoorControl({ + required this.isDoorOpen, + required this.selectedTime, + }); + + @override + Widget build(BuildContext context) { + return Center( + child: GestureDetector( + onTap: () => context.read().add( + ToggleDoorEvent(toggle: !isDoorOpen), + ), + child: _AnimatedGarageDoor( + isOpen: isDoorOpen, + duration: Duration(seconds: selectedTime), ), ), ); } } -class GradientWidget extends StatefulWidget { - const GradientWidget({required this.seconds, required this.doorStatus}); - final int seconds; - final bool doorStatus; +class _AnimatedGarageDoor extends StatefulWidget { + final bool isOpen; + final Duration duration; + + const _AnimatedGarageDoor({ + required this.isOpen, + required this.duration, + }); @override - State createState() => _GradientWidgetState(); + State<_AnimatedGarageDoor> createState() => _AnimatedGarageDoorState(); } -class _GradientWidgetState extends State +class _AnimatedGarageDoorState extends State<_AnimatedGarageDoor> with SingleTickerProviderStateMixin { - late ScrollController _scrollController; - late AnimationController _animationController; - late Animation _itemExtentAnimation; + late AnimationController _controller; @override void initState() { super.initState(); - _scrollController = ScrollController(); - _animationController = AnimationController( + _controller = AnimationController( vsync: this, - duration: Duration(seconds: widget.seconds), - ); - _itemExtentAnimation = Tween( - begin: widget.doorStatus ? 0 : 15, end: widget.doorStatus ? 15 : 0) - .animate( - CurvedAnimation( - parent: _animationController, - curve: Curves.easeInOut, - ), - )..addListener(() { - setState(() {}); - }); + duration: widget.duration, + )..addListener(() => setState(() {})); - WidgetsBinding.instance.addPostFrameCallback((_) { - if (widget.doorStatus) { - _openAnimation(); - } else { - _closeAnimation(); - } - }); + widget.isOpen ? _controller.forward() : _controller.reverse(); } - void _openAnimation() { - _animationController.forward(); - } - - void _closeAnimation() { - _animationController.reverse(); + @override + void didUpdateWidget(covariant _AnimatedGarageDoor oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.isOpen != oldWidget.isOpen) { + widget.isOpen ? _controller.forward() : _controller.reverse(); + } } @override void dispose() { - _scrollController.dispose(); - _animationController.dispose(); + _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Container( - width: 300, - height: 300, - padding: EdgeInsets.only(right: 10), + width: 290, + height: 280, + decoration: _buildContainerDecoration(), child: Stack( children: [ - SvgPicture.asset( - Assets.openGarageIcon, - fit: BoxFit.fill, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded(child: Container()), - Expanded( - flex: 2, - child: Center( - child: Container( - height: 104, - child: ListView.builder( - itemExtent: _itemExtentAnimation.value, - controller: _scrollController, - itemCount: 4, - itemBuilder: (context, index) { - return Center(child: GradientWidget1()); - }, - ), - ), - ), - ), - ], - ), + SvgPicture.asset(Assets.openGarageIcon, fit: BoxFit.fill), + _DoorPanels(animationValue: _controller.value), ], ), ); } + + BoxDecoration _buildContainerDecoration() { + return BoxDecoration( + borderRadius: BorderRadius.circular(890), + boxShadow: [ + BoxShadow( + color: Colors.white.withOpacity(0.1), + blurRadius: 24, + offset: const Offset(-5, -5), + blurStyle: BlurStyle.outer, + ), + BoxShadow( + color: Colors.black.withOpacity(0.11), + blurRadius: 25, + offset: const Offset(5, 5), + blurStyle: BlurStyle.outer, + ), + BoxShadow( + color: Colors.black.withOpacity(0.13), + blurRadius: 30, + offset: const Offset(5, 5), + blurStyle: BlurStyle.inner, + ), + ], + ); + } } -class GradientWidget1 extends StatelessWidget { +class _DoorPanels extends StatelessWidget { + final double animationValue; + + const _DoorPanels({required this.animationValue}); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Spacer(), + Expanded( + flex: 1, + child: Center( + child: Column( + children: List.generate( + 4, + (index) => Transform.translate( + offset: Offset(0, -animationValue * 15 * index), + child: const GradientBar(), + ), + ), + ), + ), + ), + ], + ); + } +} + +class GradientBar extends StatelessWidget { + const GradientBar({super.key}); + @override Widget build(BuildContext context) { return Container( @@ -434,11 +700,118 @@ class GradientWidget1 extends StatelessWidget { gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, - colors: [ - Color(0xFF017297), - Color(0xFF024C67), - ], - stops: [0.0, 1.0], + colors: [Color(0xFF017297), Color(0xFF024C67)], + ), + ), + ); + } +} + +class _ActionGrid extends StatelessWidget { + final DeviceModel? device; + + const _ActionGrid({this.device}); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Flexible( + child: Row( + children: [ + _ActionButton( + icon: Assets.garageSchedule, + label: 'Schedule', + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (_) => TimerScheduleScreen( + device: device!, + switchCode: 'switch_1', + deviceCode: 'countdown_1', + ), + ), + ), + ), + const SizedBox(width: 10), + _ActionButton( + icon: Assets.garageCountdown, + label: 'Countdown', + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (_) => TimerPage( + device: device!, + switchCode: 'switch_1', + deviceCode: 'countdown_1', + ), + ), + ), + ), + ], + ), + ), + const SizedBox(height: 10), + Flexible( + child: Row( + children: [ + _ActionButton( + icon: Assets.doorRecordsIcon, + label: 'Records', + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (_) => GarageRecordsScreen(GDId: device!.uuid!), + ), + ), + ), + const SizedBox(width: 10), + _ActionButton( + icon: Assets.garagePreferencesIcon, + label: 'Preferences', + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (_) => PreferencesPage(GDId: device!.uuid!), + ), + ), + ), + ], + ), + ) + ], + ); + } +} + +class _ActionButton extends StatelessWidget { + final String icon; + final String label; + final VoidCallback onTap; + + const _ActionButton({ + required this.icon, + required this.label, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + return Expanded( + child: DefaultContainer( + onTap: onTap, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 46, maxWidth: 50), + child: SvgPicture.asset(icon), + ), + const SizedBox(height: 15), + FittedBox( + child: BodySmall(text: label, textAlign: TextAlign.center), + ), + ], ), ), ); 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 index 5474ece..7013cca 100644 --- a/lib/features/devices/view/widgets/one_gang/one_gang_screen.dart +++ b/lib/features/devices/view/widgets/one_gang/one_gang_screen.dart @@ -20,8 +20,9 @@ class OneGangScreen extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => OneGangBloc(switchCode: 'switch_1', oneGangId: device?.uuid ?? '') - ..add(const InitialEvent(groupScreen: false)), + create: (context) => + OneGangBloc(switchCode: 'switch_1', oneGangId: device?.uuid ?? '') + ..add(const InitialEvent(groupScreen: false)), child: BlocBuilder( builder: (context, state) { OneGangModel oneGangModel = OneGangModel( @@ -36,13 +37,15 @@ class OneGangScreen extends StatelessWidget { } return state is LoadingInitialState ? const Center( - child: - DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()), + child: DefaultContainer( + width: 50, + height: 50, + child: CircularProgressIndicator()), ) : RefreshIndicator( onRefresh: () async { - BlocProvider.of(context) - .add(InitialEvent(groupScreen: device != null ? false : true)); + BlocProvider.of(context).add(InitialEvent( + groupScreen: device != null ? false : true)); }, child: ListView( children: [ @@ -55,7 +58,8 @@ class OneGangScreen extends StatelessWidget { const Expanded(child: SizedBox.shrink()), Expanded( child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, + mainAxisAlignment: + MainAxisAlignment.spaceAround, crossAxisAlignment: CrossAxisAlignment.center, children: [ Column( @@ -64,9 +68,10 @@ class OneGangScreen extends StatelessWidget { threeGangSwitch: device!, value: oneGangModel.firstSwitch, action: () { - BlocProvider.of(context).add( - ChangeFirstSwitchStatusEvent( - value: oneGangModel.firstSwitch)); + BlocProvider.of(context) + .add(ChangeFirstSwitchStatusEvent( + value: oneGangModel + .firstSwitch)); }, ), const SizedBox(height: 20), @@ -74,7 +79,8 @@ class OneGangScreen extends StatelessWidget { width: 70, child: BodySmall( text: " Entrance Light", - fontColor: ColorsManager.textPrimaryColor, + fontColor: + ColorsManager.textPrimaryColor, textAlign: TextAlign.center, ), ), @@ -94,20 +100,24 @@ class OneGangScreen extends StatelessWidget { Card( elevation: 3, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(100), + borderRadius: + BorderRadius.circular(100), ), child: GestureDetector( onTap: () { Navigator.push( context, PageRouteBuilder( - pageBuilder: - (context, animation1, animation2) => - TimerScheduleScreen( - switchCode: 'switch_1', - device: device!, - deviceCode: 'countdown_1', - ))); + pageBuilder: (context, + animation1, + animation2) => + TimerScheduleScreen( + switchCode: + 'switch_1', + device: device!, + deviceCode: + 'countdown_1', + ))); }, child: Stack( alignment: Alignment.center, @@ -117,7 +127,9 @@ class OneGangScreen extends StatelessWidget { height: 60, decoration: BoxDecoration( color: Colors.grey[300], - borderRadius: BorderRadius.circular(100), + borderRadius: + BorderRadius.circular( + 100), ), ), Container( @@ -125,12 +137,15 @@ class OneGangScreen extends StatelessWidget { height: 40, decoration: BoxDecoration( color: Colors.white, - borderRadius: BorderRadius.circular(100), + borderRadius: + BorderRadius.circular( + 100), ), child: Center( child: Icon( Icons.access_time, - color: ColorsManager.primaryColorWithOpacity, + color: ColorsManager + .primaryColorWithOpacity, size: 25, ), ), From 7e2e591d717d073fba4f7dee4609d7510cbd3a6a Mon Sep 17 00:00:00 2001 From: mohammad Date: Sat, 1 Mar 2025 15:19:15 +0300 Subject: [PATCH 2/3] remove unused code --- lib/features/devices/bloc/devices_cubit.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index eeb7b94..36b0a59 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -86,7 +86,7 @@ class DevicesCubit extends Cubit { } Map usersMap = event.snapshot.value as Map; - print('object-----${usersMap['status']}'); + // print('object-----${usersMap['status']}'); List statusList = []; usersMap['status'].forEach((element) { statusList @@ -660,7 +660,6 @@ class DevicesCubit extends Cubit { code: 'switch_1', value: toggledValue, deviceId: deviceUuid); final response = await DevicesAPI.controlDevice(controlRequest, deviceUuid); - print(response); if (response['result'] != true) { throw Exception('Failed to toggle switch_1'); } From d95588ce84458f5731e0e1239ae5435c9e36683b Mon Sep 17 00:00:00 2001 From: mohammad Date: Mon, 3 Mar 2025 17:34:15 +0300 Subject: [PATCH 3/3] remove unused code --- lib/features/devices/bloc/one_touch_bloc/one_touch_bloc.dart | 3 +-- lib/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/features/devices/bloc/one_touch_bloc/one_touch_bloc.dart b/lib/features/devices/bloc/one_touch_bloc/one_touch_bloc.dart index 1780264..85866e4 100644 --- a/lib/features/devices/bloc/one_touch_bloc/one_touch_bloc.dart +++ b/lib/features/devices/bloc/one_touch_bloc/one_touch_bloc.dart @@ -99,8 +99,7 @@ class OneTouchBloc extends Bloc { add(OneTouchUpdated()); } }); - } catch (e) { - print("Error listening to changes: $e"); + } catch (_) { } } diff --git a/lib/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart b/lib/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart index b153dde..0f13524 100644 --- a/lib/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart +++ b/lib/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart @@ -141,8 +141,7 @@ class TwoTouchBloc extends Bloc { add(TwoTouchUpdated()); } }); - } catch (e) { - print("Error listening to changes: $e"); + } catch (_) { } }