From 2dc5a1e7edbeae832ca9795519450b3ab877a4e6 Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Mon, 26 Aug 2024 21:46:01 +0300 Subject: [PATCH] push living room refactor --- .../helper/route_controls_based_code.dart | 2 +- .../view/ceiling_sensor_controls.dart | 22 ++-- .../gateway/view/gateway_view.dart | 2 +- .../bloc/living_room_bloc.dart | 104 +++++++++++++++--- .../bloc/living_room_state.dart | 6 +- .../helper/living_room_helper.dart | 6 +- .../models/living_room_model.dart | 56 ++++++++++ .../view/living_room_device_control.dart | 78 +++++++------ .../cieling_light.dart | 0 .../widgets/living_toggle_widget.dart | 80 ++++++++++++++ .../{control_list => widgets}/spot_light.dart | 0 .../{control_list => widgets}/wall_light.dart | 0 12 files changed, 287 insertions(+), 69 deletions(-) create mode 100644 lib/pages/device_managment/living_room_switch/models/living_room_model.dart rename lib/pages/device_managment/living_room_switch/{control_list => widgets}/cieling_light.dart (100%) create mode 100644 lib/pages/device_managment/living_room_switch/widgets/living_toggle_widget.dart rename lib/pages/device_managment/living_room_switch/{control_list => widgets}/spot_light.dart (100%) rename lib/pages/device_managment/living_room_switch/{control_list => widgets}/wall_light.dart (100%) diff --git a/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart b/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart index 6076f95f..e4595870 100644 --- a/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart +++ b/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart @@ -12,7 +12,7 @@ mixin RouteControlsBasedCode { switch (device.productType) { case '3G': return LivingRoomDeviceControl( - device: device, + deviceId: device.uuid!, ); case 'GW': return GateWayControls( diff --git a/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart b/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart index 0ab34b0a..0d7271b9 100644 --- a/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart +++ b/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart @@ -11,7 +11,8 @@ import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presen import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; -class CeilingSensorControls extends StatelessWidget with HelperResponsiveLayout { +class CeilingSensorControls extends StatelessWidget + with HelperResponsiveLayout { const CeilingSensorControls({super.key, required this.device}); final AllDevicesModel device; @@ -21,8 +22,8 @@ class CeilingSensorControls extends StatelessWidget with HelperResponsiveLayout final isLarge = isLargeScreenSize(context); final isMedium = isMediumScreenSize(context); return BlocProvider( - create: (context) => - CeilingSensorBloc(deviceId: device.uuid ?? '')..add(CeilingInitialEvent()), + create: (context) => CeilingSensorBloc(deviceId: device.uuid ?? '') + ..add(CeilingInitialEvent()), child: BlocBuilder( builder: (context, state) { if (state is CeilingLoadingInitialState) { @@ -86,17 +87,20 @@ class CeilingSensorControls extends StatelessWidget with HelperResponsiveLayout ), ), PresenceUpdateData( - value: (state.ceilingSensorModel.noBodyTime.toDouble() / 3600).roundToDouble(), + value: + (state.ceilingSensorModel.noBodyTime.toDouble() / 3600) + .roundToDouble(), title: 'Nobody Time:', minValue: 0, maxValue: 300000, steps: 5000, description: 'hr', - action: (int value) => - context.read().add(CeilingChangeValueEvent( - code: 'none_body_time', - value: value, - ))), + action: (int value) => context + .read() + .add(CeilingChangeValueEvent( + code: 'none_body_time', + value: value, + ))), GestureDetector( onTap: () {}, child: const PresenceStaticWidget( diff --git a/lib/pages/device_managment/gateway/view/gateway_view.dart b/lib/pages/device_managment/gateway/view/gateway_view.dart index 248884da..2901ba34 100644 --- a/lib/pages/device_managment/gateway/view/gateway_view.dart +++ b/lib/pages/device_managment/gateway/view/gateway_view.dart @@ -34,7 +34,7 @@ class GateWayControls extends StatelessWidget with HelperResponsiveLayout { : isMedium ? 2 : 1, - mainAxisExtent: 150, + mainAxisExtent: 133, crossAxisSpacing: 12, mainAxisSpacing: 12, ), diff --git a/lib/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart b/lib/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart index 55c8ad84..8adc11cb 100644 --- a/lib/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart +++ b/lib/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart @@ -1,15 +1,21 @@ -import 'dart:async'; +// ignore_for_file: invalid_use_of_visible_for_testing_member +import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart'; +import 'package:syncrow_web/pages/device_managment/living_room_switch/models/living_room_model.dart'; import 'package:syncrow_web/services/devices_mang_api.dart'; part 'living_room_event.dart'; part 'living_room_state.dart'; class LivingRoomBloc extends Bloc { - LivingRoomBloc() : super(LivingRoomInitial()) { + late LivingRoomStatusModel deviceStatus; + final String deviceId; + Timer? _timer; + + LivingRoomBloc({required this.deviceId}) : super(LivingRoomInitial()) { on(_onFetchDeviceStatus); on(_livingRoomControl); } @@ -20,7 +26,9 @@ class LivingRoomBloc extends Bloc { try { final status = await DevicesManagementApi().getDeviceStatus(event.deviceId); - emit(LivingRoomDeviceStatusLoaded(status)); + deviceStatus = + LivingRoomStatusModel.fromJson(event.deviceId, status.status); + emit(LivingRoomDeviceStatusLoaded(deviceStatus)); } catch (e) { emit(LivingRoomDeviceManagementError(e.toString())); } @@ -28,22 +36,84 @@ class LivingRoomBloc extends Bloc { FutureOr _livingRoomControl( LivingRoomControl event, Emitter emit) async { - emit(LivingRoomControlLoading()); - try { - final status = Status(code: event.code, value: event.value); - final response = - await DevicesManagementApi().deviceControl(event.deviceId, status); + final oldValue = _getValueByCode(event.code); - if (response) { - await Future.delayed(const Duration(milliseconds: 500)); - final newStatus = - await DevicesManagementApi().getDeviceStatus(event.deviceId); - emit(LivingRoomDeviceStatusLoaded(newStatus)); - } else { - emit(const LivingRoomControlError('Failed to control the device.')); + _updateLocalValue(event.code, event.value); + + emit(LivingRoomDeviceStatusLoaded(deviceStatus)); + + await _runDebounce( + deviceId: event.deviceId, + code: event.code, + value: event.value, + oldValue: oldValue, + emit: emit, + ); + } + + Future _runDebounce({ + required String deviceId, + required String code, + required dynamic value, + required dynamic oldValue, + required Emitter emit, + }) async { + if (_timer != null) { + _timer!.cancel(); + } + _timer = Timer(const Duration(seconds: 1), () async { + try { + final response = await DevicesManagementApi() + .deviceControl(deviceId, Status(code: code, value: value)); + if (!response) { + _revertValueAndEmit(deviceId, code, oldValue, emit); + } + } catch (e) { + _revertValueAndEmit(deviceId, code, oldValue, emit); } - } catch (e) { - emit(LivingRoomControlError('Error controlling the device: $e')); + }); + } + + void _revertValueAndEmit(String deviceId, String code, dynamic oldValue, + Emitter emit) { + _updateLocalValue(code, oldValue); + emit(LivingRoomDeviceStatusLoaded(deviceStatus)); + emit(const LivingRoomControlError('Failed to control the device.')); + } + + void _updateLocalValue(String code, dynamic value) { + switch (code) { + case 'switch_1': + if (value is bool) { + deviceStatus = deviceStatus.copyWith(switch1: value); + } + break; + case 'switch_2': + if (value is bool) { + deviceStatus = deviceStatus.copyWith(switch2: value); + } + break; + case 'switch_3': + if (value is bool) { + deviceStatus = deviceStatus.copyWith(switch3: value); + } + break; + default: + break; + } + emit(LivingRoomDeviceStatusLoaded(deviceStatus)); + } + + dynamic _getValueByCode(String code) { + switch (code) { + case 'switch_1': + return deviceStatus.switch1; + case 'switch_2': + return deviceStatus.switch2; + case 'switch_3': + return deviceStatus.switch3; + default: + return null; } } } diff --git a/lib/pages/device_managment/living_room_switch/bloc/living_room_state.dart b/lib/pages/device_managment/living_room_switch/bloc/living_room_state.dart index 3579183d..4b3a5347 100644 --- a/lib/pages/device_managment/living_room_switch/bloc/living_room_state.dart +++ b/lib/pages/device_managment/living_room_switch/bloc/living_room_state.dart @@ -12,7 +12,7 @@ final class LivingRoomInitial extends LivingRoomState {} class LivingRoomDeviceStatusLoading extends LivingRoomState {} class LivingRoomDeviceStatusLoaded extends LivingRoomState { - final DeviceStatus status; + final LivingRoomStatusModel status; const LivingRoomDeviceStatusLoaded(this.status); @@ -29,8 +29,6 @@ class LivingRoomDeviceManagementError extends LivingRoomState { List get props => [message]; } -class LivingRoomControlSuccess extends LivingRoomState {} - class LivingRoomControlError extends LivingRoomState { final String message; @@ -39,5 +37,3 @@ class LivingRoomControlError extends LivingRoomState { @override List get props => [message]; } - -class LivingRoomControlLoading extends LivingRoomState {} diff --git a/lib/pages/device_managment/living_room_switch/helper/living_room_helper.dart b/lib/pages/device_managment/living_room_switch/helper/living_room_helper.dart index 2f978315..8e3f4985 100644 --- a/lib/pages/device_managment/living_room_switch/helper/living_room_helper.dart +++ b/lib/pages/device_managment/living_room_switch/helper/living_room_helper.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/control_list/cieling_light.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/control_list/spot_light.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/control_list/wall_light.dart'; +import 'package:syncrow_web/pages/device_managment/living_room_switch/widgets/cieling_light.dart'; +import 'package:syncrow_web/pages/device_managment/living_room_switch/widgets/spot_light.dart'; +import 'package:syncrow_web/pages/device_managment/living_room_switch/widgets/wall_light.dart'; mixin LivingRoomHelper { Widget livingRoomControlWidgets( diff --git a/lib/pages/device_managment/living_room_switch/models/living_room_model.dart b/lib/pages/device_managment/living_room_switch/models/living_room_model.dart new file mode 100644 index 00000000..4bb5eada --- /dev/null +++ b/lib/pages/device_managment/living_room_switch/models/living_room_model.dart @@ -0,0 +1,56 @@ +import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart'; + +class LivingRoomStatusModel { + final String uuid; + final bool switch1; + final bool switch2; + final bool switch3; + + LivingRoomStatusModel({ + required this.uuid, + required this.switch1, + required this.switch2, + required this.switch3, + }); + + factory LivingRoomStatusModel.fromJson(String id, List jsonList) { + late bool switch1; + late bool switch2; + late bool switch3; + + for (var status in jsonList) { + switch (status.code) { + case 'switch_1': + switch1 = status.value ?? false; // default to false if null + break; + case 'switch_2': + switch2 = status.value ?? false; // default to false if null + break; + case 'switch_3': + switch3 = status.value ?? false; // default to false if null + break; + } + } + + return LivingRoomStatusModel( + uuid: id, + switch1: switch1, + switch2: switch2, + switch3: switch3, + ); + } + + LivingRoomStatusModel copyWith({ + String? uuid, + bool? switch1, + bool? switch2, + bool? switch3, + }) { + return LivingRoomStatusModel( + uuid: uuid ?? this.uuid, + switch1: switch1 ?? this.switch1, + switch2: switch2 ?? this.switch2, + switch3: switch3 ?? this.switch3, + ); + } +} diff --git a/lib/pages/device_managment/living_room_switch/view/living_room_device_control.dart b/lib/pages/device_managment/living_room_switch/view/living_room_device_control.dart index d9f9b417..9afcc08e 100644 --- a/lib/pages/device_managment/living_room_switch/view/living_room_device_control.dart +++ b/lib/pages/device_managment/living_room_switch/view/living_room_device_control.dart @@ -1,30 +1,30 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart'; -import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; import 'package:syncrow_web/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/helper/living_room_helper.dart'; -import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/pages/device_managment/living_room_switch/models/living_room_model.dart'; +import 'package:syncrow_web/pages/device_managment/living_room_switch/widgets/living_toggle_widget.dart'; +import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; -class LivingRoomDeviceControl extends StatelessWidget with LivingRoomHelper { - const LivingRoomDeviceControl({super.key, required this.device}); +class LivingRoomDeviceControl extends StatelessWidget + with HelperResponsiveLayout { + final String deviceId; - final AllDevicesModel device; + const LivingRoomDeviceControl({super.key, required this.deviceId}); @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => - LivingRoomBloc()..add(LivingRoomFetchDeviceStatus(device.uuid!)), + create: (context) => LivingRoomBloc(deviceId: deviceId) + ..add(LivingRoomFetchDeviceStatus(deviceId)), child: BlocBuilder( builder: (context, state) { if (state is LivingRoomDeviceStatusLoading) { return const Center(child: CircularProgressIndicator()); } else if (state is LivingRoomDeviceStatusLoaded) { - return _buildStatusControls(state.status.status); - } else if ((state is LivingRoomDeviceManagementError) || - (state is LivingRoomControlError)) { - return const Center(child: Text('Error fetching status')); + return _buildStatusControls(context, state.status); + } else if (state is LivingRoomDeviceManagementError || + state is LivingRoomControlError) { + return Center(child: Text(state.toString())); } else { return const Center(child: CircularProgressIndicator()); } @@ -33,32 +33,44 @@ class LivingRoomDeviceControl extends StatelessWidget with LivingRoomHelper { ); } - Widget _buildStatusControls(List statuses) { - return GridView.builder( - padding: const EdgeInsets.symmetric(horizontal: 40), + Widget _buildStatusControls( + BuildContext context, LivingRoomStatusModel status) { + final isLarge = isLargeScreenSize(context); + final isMedium = isMediumScreenSize(context); + return GridView( + padding: const EdgeInsets.symmetric(horizontal: 50), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: isLarge + ? 3 + : isMedium + ? 2 + : 1, mainAxisExtent: 133, crossAxisSpacing: 12, mainAxisSpacing: 12, ), - itemCount: 3, - itemBuilder: (context, index) { - final status = statuses[index]; - - return Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: ColorsManager.greyColor.withOpacity(0.2), - border: Border.all(color: ColorsManager.boxDivider), - ), - padding: const EdgeInsets.all(16), - child: livingRoomControlWidgets( - value: status.value, code: status.code, deviceId: device.uuid!), - ); - }, + children: [ + ToggleWidget( + value: status.switch1, + code: 'switch_1', + deviceId: deviceId, + label: 'Wall Light', + ), + ToggleWidget( + value: status.switch2, + code: 'switch_2', + deviceId: deviceId, + label: 'Ceiling Light', + ), + ToggleWidget( + value: status.switch3, + code: 'switch_3', + deviceId: deviceId, + label: 'Spotlight', + ), + ], ); } } diff --git a/lib/pages/device_managment/living_room_switch/control_list/cieling_light.dart b/lib/pages/device_managment/living_room_switch/widgets/cieling_light.dart similarity index 100% rename from lib/pages/device_managment/living_room_switch/control_list/cieling_light.dart rename to lib/pages/device_managment/living_room_switch/widgets/cieling_light.dart diff --git a/lib/pages/device_managment/living_room_switch/widgets/living_toggle_widget.dart b/lib/pages/device_managment/living_room_switch/widgets/living_toggle_widget.dart new file mode 100644 index 00000000..701d412b --- /dev/null +++ b/lib/pages/device_managment/living_room_switch/widgets/living_toggle_widget.dart @@ -0,0 +1,80 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_web/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; + +class ToggleWidget extends StatelessWidget { + final bool value; + final String code; + final String deviceId; + final String label; + + const ToggleWidget({ + super.key, + required this.value, + required this.code, + required this.deviceId, + required this.label, + }); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: ColorsManager.greyColor.withOpacity(0.2), + border: Border.all(color: ColorsManager.boxDivider), + ), + padding: const EdgeInsets.all(16), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ClipOval( + child: Container( + color: ColorsManager.whiteColors, + child: SvgPicture.asset( + Assets.lightPulp, + width: 60, + height: 60, + fit: BoxFit.cover, + ), + )), + SizedBox( + height: 20, + width: 35, + child: CupertinoSwitch( + value: value, + activeColor: ColorsManager.dialogBlueTitle, + onChanged: (newValue) { + context.read().add( + LivingRoomControl( + deviceId: deviceId, + code: code, + value: newValue, + ), + ); + }, + ), + ), + ], + ), + const Spacer(), + Text( + label, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14, + ), + ), + ], + ), + ); + } +} diff --git a/lib/pages/device_managment/living_room_switch/control_list/spot_light.dart b/lib/pages/device_managment/living_room_switch/widgets/spot_light.dart similarity index 100% rename from lib/pages/device_managment/living_room_switch/control_list/spot_light.dart rename to lib/pages/device_managment/living_room_switch/widgets/spot_light.dart diff --git a/lib/pages/device_managment/living_room_switch/control_list/wall_light.dart b/lib/pages/device_managment/living_room_switch/widgets/wall_light.dart similarity index 100% rename from lib/pages/device_managment/living_room_switch/control_list/wall_light.dart rename to lib/pages/device_managment/living_room_switch/widgets/wall_light.dart