From 936857515489272204211849c32dc6e7e8e1389f Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Sun, 31 Mar 2024 12:08:53 +0300 Subject: [PATCH 01/29] Add AC cubit and state classes Add AC cubit and state classes with initial state for managing air conditioning related functionality in the devices feature bloc. --- lib/features/devices/bloc/cubit/ac_cubit.dart | 51 +++++++++++++++++++ lib/features/devices/bloc/cubit/ac_state.dart | 6 +++ 2 files changed, 57 insertions(+) create mode 100644 lib/features/devices/bloc/cubit/ac_cubit.dart create mode 100644 lib/features/devices/bloc/cubit/ac_state.dart diff --git a/lib/features/devices/bloc/cubit/ac_cubit.dart b/lib/features/devices/bloc/cubit/ac_cubit.dart new file mode 100644 index 0000000..511e3a8 --- /dev/null +++ b/lib/features/devices/bloc/cubit/ac_cubit.dart @@ -0,0 +1,51 @@ +// import 'package:bloc/bloc.dart'; +// import 'package:flutter/foundation.dart'; +// import 'package:meta/meta.dart'; +// import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; +// import 'package:syncrow_app/features/devices/model/device_category_model.dart'; +// import 'package:syncrow_app/features/devices/model/device_model.dart'; + +// part 'ac_state.dart'; + +// class AcCubit extends Cubit { +// AcCubit() : super(AcInitial()); +// DeviceModel? getSelectedAC() { +// DevicesCategoryModel category = DevicesCubit.allCategories![0]; +// for (var device in category.devices) { +// if (device is && device.isSelected) { +// return device; +// } +// } +// return null; +// } + +// void setTempToAll(double temperature) { +// for (DeviceModel ac in category.devices) { +// if (ac is DeviceModel) { +// if (ac.temperature != temperature && +// ac.bounds.min <= temperature && +// temperature <= ac.bounds.max) { +// setACTemp(ac, temperature); +// } +// } +// } +// universalACTemp = temperature; +// emit(ACsTempChanged(temperature)); +// } + +// void setACTemp(DeviceModel model, double temp) { +// if (model.bounds.min <= temp && temp <= model.bounds.max) { +// model.temperature = temp; +// } +// emit(ACsTempChanged(temp)); +// } + +// double getTemp(int index) { +// var device = category.devices[index]; +// if (device is DeviceModel) { +// return device.temperature; +// } +// return 0.0; // or any default value you prefer +// } + +// } diff --git a/lib/features/devices/bloc/cubit/ac_state.dart b/lib/features/devices/bloc/cubit/ac_state.dart new file mode 100644 index 0000000..4bd7e43 --- /dev/null +++ b/lib/features/devices/bloc/cubit/ac_state.dart @@ -0,0 +1,6 @@ +// part of 'ac_cubit.dart'; + +// @immutable +// sealed class AcState {} + +// final class AcInitial extends AcState {} From 3031d1983632a1d5536294db4f967a913ed620b4 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Mon, 1 Apr 2024 09:56:55 +0300 Subject: [PATCH 02/29] Add three gang widgets for controlling three different switches - Added ThreeGangBody, ThreeGangSwitch, and ThreeGangSwitchesView widgets for controlling three different switches in the UI. - Updated constants file with functions for ThreeGang device type. --- .../widgets/three_gang/three_gang_body.dart | 260 ++++++++++++++++++ .../widgets/three_gang/three_gang_switch.dart | 71 +++++ .../three_gang/three_gang_switches.dart | 61 ++++ lib/utils/resource_manager/constants.dart | 95 ++++++- 4 files changed, 484 insertions(+), 3 deletions(-) create mode 100644 lib/features/devices/view/widgets/three_gang/three_gang_body.dart create mode 100644 lib/features/devices/view/widgets/three_gang/three_gang_switch.dart create mode 100644 lib/features/devices/view/widgets/three_gang/three_gang_switches.dart diff --git a/lib/features/devices/view/widgets/three_gang/three_gang_body.dart b/lib/features/devices/view/widgets/three_gang/three_gang_body.dart new file mode 100644 index 0000000..d5e5580 --- /dev/null +++ b/lib/features/devices/view/widgets/three_gang/three_gang_body.dart @@ -0,0 +1,260 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_app/features/devices/model/device_control_model.dart'; +import 'package:syncrow_app/features/devices/model/device_model.dart'; +import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_switch.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; +import 'package:syncrow_app/utils/context_extension.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; + +class ThreeGangBody extends StatelessWidget { + const ThreeGangBody({ + super.key, + required this.device, + }); + + final DeviceModel device; + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Expanded(child: SizedBox.shrink()), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + children: [ + ThreeGangSwitch( + control: DeviceControlModel( + deviceId: 'bfe10693d4fd263206ocq9', + code: 'switch_1', + value: true, + ), + ), + const SizedBox(height: 20), + const SizedBox( + width: 70, + child: BodySmall( + text: "Bedside Light", + fontColor: ColorsManager.textPrimaryColor, + textAlign: TextAlign.center, + ), + ), + ], + ), + Column( + children: [ + ThreeGangSwitch( + control: DeviceControlModel( + deviceId: 'bfe10693d4fd263206ocq9', + code: 'switch_2', + value: true, + ), + ), + const SizedBox(height: 20), + const SizedBox( + width: 70, + child: BodySmall( + text: "Ceiling Light", + fontColor: ColorsManager.textPrimaryColor, + textAlign: TextAlign.center, + ), + ), + ], + ), + Column( + children: [ + ThreeGangSwitch( + control: DeviceControlModel( + deviceId: 'bfe10693d4fd263206ocq9', + code: 'switch_3', + value: true, + ), + ), + const SizedBox(height: 20), + const SizedBox( + width: 70, + child: BodySmall( + text: "Spotlight", + fontColor: ColorsManager.textPrimaryColor, + textAlign: TextAlign.center, + ), + ), + ], + ), + ], + ), + Expanded( + child: Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Card( + elevation: 3, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(100), + ), + child: InkWell( + onTap: () {}, + child: Stack( + alignment: Alignment.center, + children: [ + Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(100), + ), + ), + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(100), + ), + child: Center( + child: BodySmall( + text: "On", + style: context.bodyMedium.copyWith( + color: + ColorsManager.primaryColorWithOpacity, + fontWeight: FontWeight.bold), + ), + ), + ), + ], + ), + ), + ), + const SizedBox(height: 10), + BodySmall( + text: "All On", + style: context.bodyMedium.copyWith( + color: ColorsManager.textPrimaryColor, + ), + ), + ], + ), + const SizedBox( + width: 20, + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Card( + elevation: 3, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(100), + ), + child: InkWell( + onTap: () {}, + child: Stack( + alignment: Alignment.center, + children: [ + Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(100), + ), + ), + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(100), + ), + child: Center( + child: Icon( + Icons.access_time, + color: ColorsManager.primaryColorWithOpacity, + size: 25, + ), + ), + ), + ], + ), + ), + ), + const SizedBox(height: 10), + BodySmall( + text: "Timer", + style: context.bodyMedium.copyWith( + color: ColorsManager.textPrimaryColor, + ), + ), + ], + ), + const SizedBox( + width: 20, + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Card( + elevation: 3, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(100), + ), + child: InkWell( + onTap: () {}, + child: Stack( + alignment: Alignment.center, + children: [ + Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(100), + ), + ), + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(100), + ), + child: Center( + child: BodySmall( + text: "Off", + style: context.bodyMedium.copyWith( + color: + ColorsManager.primaryColorWithOpacity, + fontWeight: FontWeight.bold), + ), + ), + ), + ], + ), + ), + ), + const SizedBox(height: 10), + BodySmall( + text: "All Off", + style: context.bodyMedium.copyWith( + color: ColorsManager.textPrimaryColor, + ), + ), + ], + ), + ], + ), + ), + ), + ], + ); + } +} diff --git a/lib/features/devices/view/widgets/three_gang/three_gang_switch.dart b/lib/features/devices/view/widgets/three_gang/three_gang_switch.dart new file mode 100644 index 0000000..841e1e3 --- /dev/null +++ b/lib/features/devices/view/widgets/three_gang/three_gang_switch.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; +import 'package:syncrow_app/features/devices/model/device_control_model.dart'; +import 'package:syncrow_app/generated/assets.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; + +class ThreeGangSwitch extends StatelessWidget { + const ThreeGangSwitch({ + super.key, + required this.control, + }); + + final DeviceControlModel control; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return state is DeviceControlLoading + ? const CircularProgressIndicator() + : InkWell( + overlayColor: MaterialStateProperty.all(Colors.transparent), + onTap: () { + DevicesCubit.get(context) + .deviceControl(control) + .then((value) { + print('Device control response: $value'); + if (control.value ?? true) { + control.value = false; + } else { + control.value = true; + } + }); + }, + child: Stack( + alignment: !control.value! + ? Alignment.topCenter + : Alignment.bottomCenter, + children: [ + Container( + decoration: BoxDecoration( + borderRadius: + const BorderRadius.all(Radius.circular(100.0)), + color: !control.value! + ? ColorsManager.primaryColorWithOpacity + : ColorsManager.switchOffColor, + ), + width: 60, + height: 115, + ), + Padding( + padding: const EdgeInsets.all(5.0), + child: SizedBox.square( + dimension: 60, + child: SvgPicture.asset( + !control.value! + ? Assets.iconsLightSwitchOn + : Assets.iconsLightSwitchOff, + fit: BoxFit.fill, + ), + ), + ), + ], + ), + ); + }, + ); + } +} diff --git a/lib/features/devices/view/widgets/three_gang/three_gang_switches.dart b/lib/features/devices/view/widgets/three_gang/three_gang_switches.dart new file mode 100644 index 0000000..492efc4 --- /dev/null +++ b/lib/features/devices/view/widgets/three_gang/three_gang_switches.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.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/model/device_model.dart'; +import 'package:syncrow_app/features/devices/model/function_model.dart'; +import 'package:syncrow_app/features/devices/view/widgets/ACs/category_view_app_bar.dart'; +import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_body.dart'; +import 'package:syncrow_app/generated/assets.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; +import 'package:syncrow_app/utils/resource_manager/constants.dart'; + +class ThreeGangSwitchesView extends StatelessWidget { + const ThreeGangSwitchesView({super.key}); + + @override + Widget build(BuildContext context) { + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarColor: ColorsManager.primaryColor.withOpacity(0.5), + statusBarIconBrightness: Brightness.light, + ), + child: SafeArea( + child: Scaffold( + backgroundColor: ColorsManager.backgroundColor, + extendBodyBehindAppBar: true, + extendBody: true, + appBar: const CategoryViewAppBar(), + body: BlocBuilder( + builder: (context, state) { + return Container( + width: MediaQuery.sizeOf(context).width, + height: MediaQuery.sizeOf(context).height, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage( + Assets.imagesBackground, + ), + fit: BoxFit.cover, + opacity: 0.4, + ), + ), + child: Padding( + padding: EdgeInsets.only( + top: Constants.appBarHeight, + left: Constants.defaultPadding, + right: Constants.defaultPadding, + bottom: Constants.bottomNavBarHeight, + ), + child: ThreeGangBody( + device: DeviceModel(), + ), + ), + ); + }, + )), + ), + ); + } +} diff --git a/lib/utils/resource_manager/constants.dart b/lib/utils/resource_manager/constants.dart index 1ec5ab8..5f0a973 100644 --- a/lib/utils/resource_manager/constants.dart +++ b/lib/utils/resource_manager/constants.dart @@ -1,4 +1,6 @@ //ignore_for_file: constant_identifier_names +import 'package:syncrow_app/features/devices/model/function_model.dart'; + abstract class Constants { static const String languageCode = "en"; @@ -16,12 +18,99 @@ abstract class Constants { enum DeviceType { AC, - Lights, + LightBulb, DoorLock, Curtain, + Blind, ThreeGang, Gateway, - Sensors, - Gang, + CeilingSensor, + WallSensor, Other, } + +Map devicesTypesMap = { + "AC": DeviceType.AC, + "LB": DeviceType.LightBulb, + "DL": DeviceType.DoorLock, + "WC": DeviceType.Curtain, + "WB": DeviceType.Blind, + "3G": DeviceType.ThreeGang, + "GW": DeviceType.Gateway, + "CPS": DeviceType.CeilingSensor, + "WPS": DeviceType.WallSensor, + "Other": DeviceType.Other, +}; +Map> devicesFunctionsMap = { + DeviceType.AC: [ + FunctionModel(code: 'switch', type: 'Boolean', values: '{}'), + FunctionModel( + code: 'mode', type: 'Enum', values: '{"range":["cold","hot","wind"]}'), + FunctionModel( + code: 'temp_set', + type: 'Integer', + values: '{"unit":"℃","min":200,"max":300,"scale":1,"step":5}'), + FunctionModel( + code: 'level', + type: 'Enum', + values: '{"range":["low","middle","high","auto"]}'), + FunctionModel(code: 'child_lock', type: 'Boolean', values: '{}'), + ], + DeviceType.Gateway: [ + FunctionModel(code: 'switch_alarm_sound', type: 'Boolean', values: '{}'), + FunctionModel( + code: 'master_state', + type: 'Enum', + values: '{"range":["normal","alarm"]}'), + FunctionModel(code: 'factory_reset', type: 'Boolean', values: '{}'), + FunctionModel( + code: 'alarm_active', type: 'String', values: '{"maxlen":255}'), + ], + DeviceType.CeilingSensor: [ + FunctionModel( + code: 'sensitivity', + type: 'Integer', + values: '{"unit":"","min":1,"max":10,"scale":0,"step":1}'), + ], + DeviceType.DoorLock: [ + FunctionModel(code: 'remote_no_pd_setkey', type: 'Raw', values: '{}'), + FunctionModel(code: 'remote_no_dp_key', type: 'Raw', values: '{}'), + FunctionModel(code: 'normal_open_switch', type: 'Boolean', values: '{}'), + ], + DeviceType.WallSensor: [ + FunctionModel( + code: 'far_detection', + type: 'Integer', + values: '{"unit":"cm","min":75,"max":600,"scale":0,"step":75}'), + FunctionModel( + code: 'presence_time', + type: 'Integer', + values: '{"unit":"Min","min":0,"max":65535,"scale":0,"step":1}'), + FunctionModel( + code: 'motion_sensitivity_value', + type: 'Integer', + values: '{"unit":"","min":1,"max":5,"scale":0,"step":1}'), + FunctionModel( + code: 'motionless_sensitivity', + type: 'Integer', + values: '{"unit":"","min":1,"max":5,"scale":0,"step":1}'), + FunctionModel(code: 'indicator', type: 'Boolean', values: '{}'), + ], + DeviceType.ThreeGang: [ + FunctionModel(code: 'switch_1', type: 'Boolean', values: '{}'), + FunctionModel(code: 'switch_2', type: 'Boolean', values: '{}'), + FunctionModel(code: 'switch_3', type: 'Boolean', values: '{}'), + FunctionModel( + code: 'countdown_1', + type: 'Integer', + values: '{"unit":"s","min":0,"max":43200,"scale":0,"step":1}'), + FunctionModel( + code: 'countdown_2', + type: 'Integer', + values: '{"unit":"s","min":0,"max":43200,"scale":0,"step":1}'), + FunctionModel( + code: 'countdown_3', + type: 'Integer', + values: '{"unit":"s","min":0,"max":43200,"scale":0,"step":1}'), + ], +}; From a20dfa37094745d34bfecd4efae5d642c0d0dbd6 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Mon, 1 Apr 2024 09:58:51 +0300 Subject: [PATCH 03/29] Refactor device status handling and update UI components - Update device status handling from 'status' to 'isOnline' for consistency - Remove unused imports and redundant code related to light switches - Refactor UI components to use 'isOnline' instead of 'status' for device status --- lib/features/app_layout/view/app_layout.dart | 17 ++ lib/features/devices/bloc/devices_cubit.dart | 63 +---- .../devices/model/device_category_model.dart | 24 +- lib/features/devices/model/device_model.dart | 142 +++++++--- .../devices/model/function_model.dart | 15 - .../lights/light_interface_switch.dart | 4 +- .../widgets/lights_switches/light_switch.dart | 71 ----- .../lights_switches/light_switches.dart | 87 ------ .../lights_switches/light_switches_body.dart | 260 ------------------ .../view/widgets/room_page_switch.dart | 4 +- .../shared_widgets/custom_switch.dart | 2 +- .../devices_default_switch.dart | 8 +- 12 files changed, 152 insertions(+), 545 deletions(-) delete mode 100644 lib/features/devices/view/widgets/lights_switches/light_switch.dart delete mode 100644 lib/features/devices/view/widgets/lights_switches/light_switches.dart delete mode 100644 lib/features/devices/view/widgets/lights_switches/light_switches_body.dart diff --git a/lib/features/app_layout/view/app_layout.dart b/lib/features/app_layout/view/app_layout.dart index dda35a1..9c2c733 100644 --- a/lib/features/app_layout/view/app_layout.dart +++ b/lib/features/app_layout/view/app_layout.dart @@ -1,5 +1,8 @@ +import 'dart:ffi'; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; @@ -7,7 +10,9 @@ import 'package:syncrow_app/features/app_layout/view/widgets/app_body.dart'; import 'package:syncrow_app/features/app_layout/view/widgets/default_app_bar.dart'; import 'package:syncrow_app/features/app_layout/view/widgets/default_nav_bar.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; +import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_switches.dart'; import 'package:syncrow_app/navigation/routing_constants.dart'; +import 'package:syncrow_app/utils/helpers/custom_page_route.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; class AppLayout extends StatelessWidget { @@ -53,6 +58,18 @@ class AppLayout extends StatelessWidget { appBar: DefaultAppBar(), body: AppBody(), bottomNavigationBar: DefaultNavBar(), + // floatingActionButton: FloatingActionButton( + // onPressed: () { + // Navigator.push( + // context, + // CustomPageRoute( + // builder: (context) => + // const ThreeGangSwitchesView(), + // ), + // ); + // }, + // child: const Icon(Icons.arrow_forward_ios_sharp), + // ), ); }, ), diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index ddb130b..fa44c92 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -12,7 +12,7 @@ import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/lights/lights_view.dart'; -import 'package:syncrow_app/features/devices/view/widgets/lights_switches/light_switches.dart'; +import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_switches.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_view.dart'; import 'package:syncrow_app/services/api/devices_api.dart'; import 'package:syncrow_app/services/api/network_exception.dart'; @@ -63,14 +63,14 @@ class DevicesCubit extends Cubit { switch (category.type) { case DeviceType.AC: return const ACsView(); - case DeviceType.Lights: + case DeviceType.LightBulb: return const LightsView(); case DeviceType.DoorLock: return const DoorView(); case DeviceType.Curtain: return const CurtainView(); case DeviceType.ThreeGang: - return const LightSwitchesView(); + return const ThreeGangSwitchesView(); case DeviceType.Gateway: return const GateWayView(); default: @@ -125,14 +125,14 @@ class DevicesCubit extends Cubit { category.devicesStatus = !category.devicesStatus!; if (category.devices != null) { for (var device in category.devices!) { - device.status = category.devicesStatus; + device.isOnline = category.devicesStatus; } } } else { category.devicesStatus = true; if (category.devices != null) { for (var device in category.devices!) { - device.status = true; + device.isOnline = true; } } } @@ -142,7 +142,7 @@ class DevicesCubit extends Cubit { } turnOnOffDevice(DeviceModel device) { - device.status = !device.status!; + device.isOnline = !device.isOnline!; DevicesCategoryModel category = allCategories!.firstWhere((category) { if (category.devices != null) { return category.devices!.contains(device); @@ -157,10 +157,10 @@ class DevicesCubit extends Cubit { updateDevicesStatus(DevicesCategoryModel category) { if (category.devices != null) { if (category.devices!.isNotEmpty) { - bool? tempStatus = category.devices![0].status; + bool? tempStatus = category.devices![0].isOnline; for (var ac in category.devices!) { //check if there any ac have a different status than the initial ==> turn off the universal switch - if (ac.status != tempStatus) { + if (ac.isOnline != tempStatus) { category.devicesStatus = null; emit(DeviceSwitchChanged()); return; @@ -179,7 +179,7 @@ class DevicesCubit extends Cubit { if (category.devices != null) { if (category.devices!.isNotEmpty) { for (var device in category.devices!) { - device.status = false; + device.isOnline = false; } changeCategorySwitchValue(category); updateDevicesStatus(category); @@ -192,7 +192,7 @@ class DevicesCubit extends Cubit { if (category.devices != null) { if (category.devices!.isNotEmpty) { for (var device in category.devices!) { - device.status = true; + device.isOnline = true; } changeCategorySwitchValue(category); updateDevicesStatus(category); @@ -204,7 +204,7 @@ class DevicesCubit extends Cubit { areAllDevicesOff(DevicesCategoryModel category) { if (category.devices != null) { for (var device in category.devices!) { - if (device.status ?? false) { + if (device.isOnline ?? false) { category.devicesStatus = false; emit(CategorySwitchChanged()); return; @@ -276,7 +276,7 @@ class DevicesCubit extends Cubit { // } // // toggleLight(DeviceModel light) { -// light.status != null ? light.status = !light.status! : light.status = true; +// light.isOnline != null ? light.isOnline = !light.isOnline! : light.isOnline = true; // emit(LightToggled(light)); // } // @@ -296,45 +296,6 @@ class DevicesCubit extends Cubit { // emit(LightBrightnessChanged(value)); // } // } - - ///ACs -// DeviceModel? getSelectedAC() { -// for (var ac in category.devices) { -// if (ac is DeviceModel && ac.isSelected) { -// return ac; -// } -// } -// return null; -// } -// -// void setTempToAll(double temperature) { -// for (DeviceModel ac in category.devices) { -// if (ac is DeviceModel) { -// if (ac.temperature != temperature && -// ac.bounds.min <= temperature && -// temperature <= ac.bounds.max) { -// setACTemp(ac, temperature); -// } -// } -// } -// universalACTemp = temperature; -// emit(ACsTempChanged(temperature)); -// } -// -// void setACTemp(DeviceModel model, double temp) { -// if (model.bounds.min <= temp && temp <= model.bounds.max) { -// model.temperature = temp; -// } -// emit(ACsTempChanged(temp)); -// } -// -// double getTemp(int index) { -// var device = category.devices[index]; -// if (device is DeviceModel) { -// return device.temperature; -// } -// return 0.0; // or any default value you prefer -// } } enum LightMode { diff --git a/lib/features/devices/model/device_category_model.dart b/lib/features/devices/model/device_category_model.dart index 1da69d8..00a1fa0 100644 --- a/lib/features/devices/model/device_category_model.dart +++ b/lib/features/devices/model/device_category_model.dart @@ -24,9 +24,9 @@ class DevicesCategoryModel { //sets the initial status of the devices if (devices != null) { if (devices!.isNotEmpty) { - bool tempStatus = devices!.first.status ?? false; + bool tempStatus = devices!.first.isOnline ?? false; for (var device in devices!) { - if (device.status != tempStatus) { + if (device.isOnline != tempStatus) { devicesStatus = false; break; } @@ -41,9 +41,9 @@ class DevicesCategoryModel { DevicesCategoryModel.fromJson(Map json) : name = json['groupName'], id = json['groupId'], - type = deviceTypeMap[json['groupName']] ?? DeviceType.Other, + type = devicesTypesMap[json['productType']] ?? DeviceType.Other, icon = deviceTypeIconMap[ - deviceTypeMap[json['groupName']] ?? DeviceType.Other] ?? + devicesTypesMap[json['productType']] ?? DeviceType.Other] ?? '', devices = [], isSelected = false; @@ -53,22 +53,14 @@ class DevicesCategoryModel { } } -Map deviceTypeMap = { - 'Ceiling Presence Sensors': DeviceType.Sensors, - 'Wall presence sensor': DeviceType.Sensors, - 'Door Locks': DeviceType.DoorLock, - 'Gateways': DeviceType.Gateway, - 'ACs': DeviceType.AC, - '3Gang': DeviceType.Gang, -}; - Map deviceTypeIconMap = { DeviceType.AC: Assets.iconsAC, - DeviceType.Lights: Assets.iconsLight, + DeviceType.LightBulb: Assets.iconsLight, DeviceType.DoorLock: Assets.iconsDoorLock, DeviceType.Curtain: Assets.iconsCurtain, DeviceType.Gateway: Assets.iconsGateway, - DeviceType.Sensors: Assets.iconsSensors, - DeviceType.Gang: Assets.iconsGang, + DeviceType.CeilingSensor: Assets.iconsSensors, + DeviceType.WallSensor: Assets.iconsSensors, + DeviceType.ThreeGang: Assets.iconsGang, DeviceType.Other: Assets.iconsAC, }; diff --git a/lib/features/devices/model/device_model.dart b/lib/features/devices/model/device_model.dart index e14493e..395e077 100644 --- a/lib/features/devices/model/device_model.dart +++ b/lib/features/devices/model/device_model.dart @@ -1,46 +1,116 @@ import 'package:syncrow_app/features/devices/model/function_model.dart'; -import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; class DeviceModel { - final int? id; - final String? name; - final DeviceType? type; - bool? status; - final String? image; - final double? timer; - late final String icon; + int? activeTime; + String? category; + String? categoryName; + int? createTime; + String? gatewayId; + String? icon; + String? id; + String? ip; + double? lat; + String? localKey; + double? lon; + String? model; + String? name; + String? nodeId; //rmeove + bool? isOnline; + String? ownerId; //remove + String? productId; //remove + String? productName; + bool? isSub; + String? timeZone; + int? updateTime; + String? uuid; + DeviceType? productType; bool isSelected = false; - late List functions; - DeviceModel({ - required this.id, - required this.name, - required this.type, - required this.status, - required this.image, - required this.timer, - required this.functions, + this.activeTime, + this.category, + this.categoryName, + this.createTime, + this.gatewayId, + this.icon, + this.id, + this.ip, + this.lat, + this.localKey, + this.lon, + this.model, + this.name, + this.nodeId, + this.isOnline, + this.ownerId, + this.productId, + this.productName, + this.isSub, + this.timeZone, + this.updateTime, + this.uuid, + this.productType, }) { - switch (type) { - case DeviceType.AC: - icon = Assets.iconsAC; - break; - case DeviceType.Lights: - icon = Assets.iconsLight; - break; - case DeviceType.DoorLock: - icon = Assets.iconsDoorLock; - break; - case DeviceType.Curtain: - icon = Assets.iconsCurtain; - break; - case DeviceType.Gateway: - icon = Assets.iconsGateway; - break; - default: - icon = ''; - } + functions = getFunctions(productType!); } + + factory DeviceModel.fromJson(Map json) { + return DeviceModel( + activeTime: json['activeTime'], + category: json['category'], + categoryName: json['categoryName'], + createTime: json['createTime'], + gatewayId: json['gatewayId'], + icon: json['icon'], + id: json['id'], + ip: json['ip'], + lat: double.tryParse(json['lat']), + localKey: json['localKey'], + lon: double.tryParse(json['lon']), + model: json['model'], + name: json['name'], + nodeId: json['nodeId'], + isOnline: json['online'], + ownerId: json['ownerId'], + productId: json['productId'], + productName: json['productName'], + isSub: json['sub'], + timeZone: json['timeZone'], + updateTime: json['updateTime'], + uuid: json['uuid'], + productType: devicesTypesMap[json['productName']] ?? DeviceType.Other, + ); + } + + Map toJson() { + return { + 'activeTime': activeTime, + 'category': category, + 'categoryName': categoryName, + 'createTime': createTime, + 'gatewayId': gatewayId, + 'icon': icon, + 'id': id, + 'ip': ip, + 'lat': lat, + 'localKey': localKey, + 'lon': lon, + 'model': model, + 'name': name, + 'nodeId': nodeId, + 'online': isOnline, + 'ownerId': ownerId, + 'productId': productId, + 'productName': productName, + 'sub': isSub, + 'timeZone': timeZone, + 'updateTime': updateTime, + 'uuid': uuid, + 'productType': productType, + }; + } + + List getFunctions(DeviceType type) => + devicesFunctionsMap[productType] ?? []; } diff --git a/lib/features/devices/model/function_model.dart b/lib/features/devices/model/function_model.dart index c187b32..b3d04d2 100644 --- a/lib/features/devices/model/function_model.dart +++ b/lib/features/devices/model/function_model.dart @@ -1,21 +1,10 @@ -//{ -// "code": "switch_1", -// "desc": "switch 1", -// "name": "switch 1", -// "type": "Boolean", -// "values": "{}" -// } class FunctionModel { String? code; - String? desc; - String? name; String? type; String? values; FunctionModel({ required this.code, - required this.desc, - required this.name, required this.type, required this.values, }); @@ -23,8 +12,6 @@ class FunctionModel { factory FunctionModel.fromJson(Map json) { return FunctionModel( code: json['code'], - desc: json['desc'], - name: json['name'], type: json['type'], values: json['values'], ); @@ -33,8 +20,6 @@ class FunctionModel { Map toJson() { return { 'code': code, - 'desc': desc, - 'name': name, 'type': type, 'values': values, }; diff --git a/lib/features/devices/view/widgets/lights/light_interface_switch.dart b/lib/features/devices/view/widgets/lights/light_interface_switch.dart index aa8ca07..fde3bc4 100644 --- a/lib/features/devices/view/widgets/lights/light_interface_switch.dart +++ b/lib/features/devices/view/widgets/lights/light_interface_switch.dart @@ -28,7 +28,7 @@ class LightInterfaceSwitch extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ BodyLarge( - text: light.status ?? false + text: light.isOnline ?? false ? StringsManager.on : StringsManager.off, style: @@ -37,7 +37,7 @@ class LightInterfaceSwitch extends StatelessWidget { Container( width: 35, decoration: ShapeDecoration( - color: light.status ?? false + color: light.isOnline ?? false ? ColorsManager.primaryColorWithOpacity : Colors.grey, shape: const CircleBorder(), diff --git a/lib/features/devices/view/widgets/lights_switches/light_switch.dart b/lib/features/devices/view/widgets/lights_switches/light_switch.dart deleted file mode 100644 index 75ab87f..0000000 --- a/lib/features/devices/view/widgets/lights_switches/light_switch.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; -import 'package:syncrow_app/features/devices/model/device_control_model.dart'; -import 'package:syncrow_app/generated/assets.dart'; -import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; - -class LightSwitch extends StatelessWidget { - const LightSwitch({ - super.key, - required this.control, - }); - - final DeviceControlModel control; - - @override - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - return state is DeviceControlLoading - ? const CircularProgressIndicator() - : InkWell( - overlayColor: MaterialStateProperty.all(Colors.transparent), - onTap: () { - DevicesCubit.get(context) - .deviceControl(control) - .then((value) { - print('Device control response: $value'); - if (control.value ?? true) { - control.value = false; - } else { - control.value = true; - } - }); - }, - child: Stack( - alignment: !control.value! - ? Alignment.topCenter - : Alignment.bottomCenter, - children: [ - Container( - decoration: BoxDecoration( - borderRadius: - const BorderRadius.all(Radius.circular(100.0)), - color: !control.value! - ? ColorsManager.primaryColorWithOpacity - : ColorsManager.switchOffColor, - ), - width: 60, - height: 115, - ), - Padding( - padding: const EdgeInsets.all(5.0), - child: SizedBox.square( - dimension: 60, - child: SvgPicture.asset( - !control.value! - ? Assets.iconsLightSwitchOn - : Assets.iconsLightSwitchOff, - fit: BoxFit.fill, - ), - ), - ), - ], - ), - ); - }, - ); - } -} diff --git a/lib/features/devices/view/widgets/lights_switches/light_switches.dart b/lib/features/devices/view/widgets/lights_switches/light_switches.dart deleted file mode 100644 index cadbd20..0000000 --- a/lib/features/devices/view/widgets/lights_switches/light_switches.dart +++ /dev/null @@ -1,87 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.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/model/device_model.dart'; -import 'package:syncrow_app/features/devices/model/function_model.dart'; -import 'package:syncrow_app/features/devices/view/widgets/ACs/category_view_app_bar.dart'; -import 'package:syncrow_app/features/devices/view/widgets/lights_switches/light_switches_body.dart'; -import 'package:syncrow_app/generated/assets.dart'; -import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; -import 'package:syncrow_app/utils/resource_manager/constants.dart'; - -class LightSwitchesView extends StatelessWidget { - const LightSwitchesView({super.key}); - - @override - Widget build(BuildContext context) { - return AnnotatedRegion( - value: SystemUiOverlayStyle( - statusBarColor: ColorsManager.primaryColor.withOpacity(0.5), - statusBarIconBrightness: Brightness.light, - ), - child: SafeArea( - child: Scaffold( - backgroundColor: ColorsManager.backgroundColor, - extendBodyBehindAppBar: true, - extendBody: true, - appBar: const CategoryViewAppBar(), - body: BlocBuilder( - builder: (context, state) { - return Container( - width: MediaQuery.sizeOf(context).width, - height: MediaQuery.sizeOf(context).height, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage( - Assets.imagesBackground, - ), - fit: BoxFit.cover, - opacity: 0.4, - ), - ), - child: Padding( - padding: EdgeInsets.only( - top: Constants.appBarHeight, - left: Constants.defaultPadding, - right: Constants.defaultPadding, - bottom: Constants.bottomNavBarHeight, - ), - child: LightSwitchesBody( - device: DeviceModel( - id: 2, - name: 'Bedroom Light', - type: DeviceType.Lights, - status: true, - timer: 0, - image: '', - functions: [ - FunctionModel( - code: 'switch_1', - desc: 'switch 1', - name: 'switch 1', - type: 'Boolean', - values: '{}'), - FunctionModel( - code: 'switch_2', - desc: 'switch 2', - name: 'switch 2', - type: 'Boolean', - values: '{}'), - FunctionModel( - code: 'switch_3', - desc: 'switch 3', - name: 'switch 3', - type: 'Boolean', - values: '{}'), - ]), - ), - ), - ); - }, - )), - ), - ); - } -} diff --git a/lib/features/devices/view/widgets/lights_switches/light_switches_body.dart b/lib/features/devices/view/widgets/lights_switches/light_switches_body.dart deleted file mode 100644 index 6815fd0..0000000 --- a/lib/features/devices/view/widgets/lights_switches/light_switches_body.dart +++ /dev/null @@ -1,260 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:syncrow_app/features/devices/model/device_control_model.dart'; -import 'package:syncrow_app/features/devices/model/device_model.dart'; -import 'package:syncrow_app/features/devices/view/widgets/lights_switches/light_switch.dart'; -import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; -import 'package:syncrow_app/utils/context_extension.dart'; -import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; - -class LightSwitchesBody extends StatelessWidget { - const LightSwitchesBody({ - super.key, - required this.device, - }); - - final DeviceModel device; - - @override - Widget build(BuildContext context) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Expanded(child: SizedBox.shrink()), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Column( - children: [ - LightSwitch( - control: DeviceControlModel( - deviceId: 'bfe10693d4fd263206ocq9', - code: 'switch_1', - value: true, - ), - ), - const SizedBox(height: 20), - const SizedBox( - width: 70, - child: BodySmall( - text: "Bedside Light", - fontColor: ColorsManager.textPrimaryColor, - textAlign: TextAlign.center, - ), - ), - ], - ), - Column( - children: [ - LightSwitch( - control: DeviceControlModel( - deviceId: 'bfe10693d4fd263206ocq9', - code: 'switch_2', - value: true, - ), - ), - const SizedBox(height: 20), - const SizedBox( - width: 70, - child: BodySmall( - text: "Ceiling Light", - fontColor: ColorsManager.textPrimaryColor, - textAlign: TextAlign.center, - ), - ), - ], - ), - Column( - children: [ - LightSwitch( - control: DeviceControlModel( - deviceId: 'bfe10693d4fd263206ocq9', - code: 'switch_3', - value: true, - ), - ), - const SizedBox(height: 20), - const SizedBox( - width: 70, - child: BodySmall( - text: "Spotlight", - fontColor: ColorsManager.textPrimaryColor, - textAlign: TextAlign.center, - ), - ), - ], - ), - ], - ), - Expanded( - child: Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Card( - elevation: 3, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(100), - ), - child: InkWell( - onTap: () {}, - child: Stack( - alignment: Alignment.center, - children: [ - Container( - width: 60, - height: 60, - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(100), - ), - ), - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(100), - ), - child: Center( - child: BodySmall( - text: "On", - style: context.bodyMedium.copyWith( - color: - ColorsManager.primaryColorWithOpacity, - fontWeight: FontWeight.bold), - ), - ), - ), - ], - ), - ), - ), - const SizedBox(height: 10), - BodySmall( - text: "All On", - style: context.bodyMedium.copyWith( - color: ColorsManager.textPrimaryColor, - ), - ), - ], - ), - const SizedBox( - width: 20, - ), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Card( - elevation: 3, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(100), - ), - child: InkWell( - onTap: () {}, - child: Stack( - alignment: Alignment.center, - children: [ - Container( - width: 60, - height: 60, - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(100), - ), - ), - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(100), - ), - child: Center( - child: Icon( - Icons.access_time, - color: ColorsManager.primaryColorWithOpacity, - size: 25, - ), - ), - ), - ], - ), - ), - ), - const SizedBox(height: 10), - BodySmall( - text: "Timer", - style: context.bodyMedium.copyWith( - color: ColorsManager.textPrimaryColor, - ), - ), - ], - ), - const SizedBox( - width: 20, - ), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Card( - elevation: 3, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(100), - ), - child: InkWell( - onTap: () {}, - child: Stack( - alignment: Alignment.center, - children: [ - Container( - width: 60, - height: 60, - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(100), - ), - ), - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(100), - ), - child: Center( - child: BodySmall( - text: "Off", - style: context.bodyMedium.copyWith( - color: - ColorsManager.primaryColorWithOpacity, - fontWeight: FontWeight.bold), - ), - ), - ), - ], - ), - ), - ), - const SizedBox(height: 10), - BodySmall( - text: "All Off", - style: context.bodyMedium.copyWith( - color: ColorsManager.textPrimaryColor, - ), - ), - ], - ), - ], - ), - ), - ), - ], - ); - } -} diff --git a/lib/features/devices/view/widgets/room_page_switch.dart b/lib/features/devices/view/widgets/room_page_switch.dart index 1cbbc35..dec23dc 100644 --- a/lib/features/devices/view/widgets/room_page_switch.dart +++ b/lib/features/devices/view/widgets/room_page_switch.dart @@ -33,7 +33,7 @@ class RoomPageSwitch extends StatelessWidget { // ), // ); - if (device.type == DeviceType.AC) { + if (device.productType == DeviceType.AC) { Navigator.push( context, CustomPageRoute( @@ -54,7 +54,7 @@ class RoomPageSwitch extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ SvgPicture.asset( - device.icon, + device.icon!, fit: BoxFit.contain, ), CustomSwitch( diff --git a/lib/features/shared_widgets/custom_switch.dart b/lib/features/shared_widgets/custom_switch.dart index 9e6c180..d9ece21 100644 --- a/lib/features/shared_widgets/custom_switch.dart +++ b/lib/features/shared_widgets/custom_switch.dart @@ -19,7 +19,7 @@ class CustomSwitch extends StatelessWidget { builder: (context, state) { bool? status; if (device != null) { - status = device!.status; + status = device!.isOnline; } else if (category != null) { status = category!.devicesStatus; } diff --git a/lib/features/shared_widgets/devices_default_switch.dart b/lib/features/shared_widgets/devices_default_switch.dart index 2d45c10..2f001c1 100644 --- a/lib/features/shared_widgets/devices_default_switch.dart +++ b/lib/features/shared_widgets/devices_default_switch.dart @@ -28,7 +28,7 @@ class DevicesDefaultSwitch extends StatelessWidget { child: Container( height: 60, decoration: BoxDecoration( - color: model.status ?? false + color: model.isOnline ?? false ? ColorsManager.primaryColor : Colors.white, borderRadius: const BorderRadius.only( @@ -39,7 +39,7 @@ class DevicesDefaultSwitch extends StatelessWidget { child: Center( child: BodyMedium( text: "ON", - fontColor: model.status ?? false ? Colors.white : null, + fontColor: model.isOnline ?? false ? Colors.white : null, fontWeight: FontWeight.bold, ), ), @@ -54,7 +54,7 @@ class DevicesDefaultSwitch extends StatelessWidget { child: Container( height: 60, decoration: BoxDecoration( - color: model.status ?? false + color: model.isOnline ?? false ? Colors.white : ColorsManager.primaryColor, borderRadius: const BorderRadius.only( @@ -65,7 +65,7 @@ class DevicesDefaultSwitch extends StatelessWidget { child: Center( child: BodyMedium( text: "OFF", - fontColor: model.status ?? false ? null : Colors.white, + fontColor: model.isOnline ?? false ? null : Colors.white, fontWeight: FontWeight.bold, ), ), From d1bc973b38a76dbd7b5b8802c8604770b6d3c4aa Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Mon, 1 Apr 2024 12:09:01 +0300 Subject: [PATCH 04/29] Refactor HomeCubit class for better instance management Create a private static instance variable and refactor methods for better instance management in the HomeCubit class. --- lib/features/app_layout/bloc/home_cubit.dart | 28 ++++- lib/features/app_layout/bloc/home_state.dart | 2 +- lib/features/app_layout/view/app_layout.dart | 73 ++++++------ .../view/widgets/app_bar_home_dropdown.dart | 108 +++++++++--------- .../app_layout/view/widgets/app_body.dart | 7 +- .../view/widgets/default_app_bar.dart | 8 +- .../view/widgets/default_nav_bar.dart | 6 +- lib/features/devices/bloc/devices_cubit.dart | 4 +- .../view/widgets/devices_view_body.dart | 24 ++-- .../devices/view/widgets/rooms_slider.dart | 54 +++++---- 10 files changed, 169 insertions(+), 145 deletions(-) diff --git a/lib/features/app_layout/bloc/home_cubit.dart b/lib/features/app_layout/bloc/home_cubit.dart index b0e1932..8f7f572 100644 --- a/lib/features/app_layout/bloc/home_cubit.dart +++ b/lib/features/app_layout/bloc/home_cubit.dart @@ -17,8 +17,10 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; part 'home_state.dart'; class HomeCubit extends Cubit { - HomeCubit() : super(SpacesInitial()) { - if (HomeCubit.spaces != null) { + // Create a private static instance variable + static HomeCubit? _instance; + HomeCubit._() : super(HomeInitial()) { + if (spaces != null) { if (selectedSpace == null) { fetchSpaces().then((value) { if (selectedSpace != null) { @@ -31,12 +33,17 @@ class HomeCubit extends Cubit { fetchSpaces(); // this is for the first time } } + static HomeCubit getInstance() { + // If an instance already exists, return it + _instance ??= HomeCubit._(); + return _instance!; + } static HomeCubit get(context) => BlocProvider.of(context); - static List? spaces; + List? spaces; - static SpaceModel? selectedSpace; + SpaceModel? selectedSpace; RoomModel? selectedRoom; @@ -46,7 +53,12 @@ class HomeCubit extends Cubit { var duration = const Duration(milliseconds: 300); - selectSpace(SpaceModel space) { + // selectSpace(SpaceModel space) async { + // selectedSpace = space; + // emit(SpaceSelected(space)); + // } + + changeSelectedSpace(SpaceModel space) { selectedSpace = space; emit(SpaceSelected(space)); } @@ -102,7 +114,11 @@ class HomeCubit extends Cubit { emit(GetSpacesLoading()); try { spaces = await SpacesAPI.getSpaces(); - selectedSpace = spaces!.isNotEmpty ? selectSpace(spaces!.first) : null; + selectedSpace = spaces!.isNotEmpty + ? + // selectSpace(spaces!.first) + selectedSpace = spaces!.first + : null; emit(GetSpacesLoaded(spaces!)); } on DioException catch (e) { emit(GetSpacesError(ServerFailure.fromDioError(e).errMessage)); diff --git a/lib/features/app_layout/bloc/home_state.dart b/lib/features/app_layout/bloc/home_state.dart index e5880c7..d1f5b7d 100644 --- a/lib/features/app_layout/bloc/home_state.dart +++ b/lib/features/app_layout/bloc/home_state.dart @@ -2,7 +2,7 @@ part of 'home_cubit.dart'; abstract class HomeState {} -class SpacesInitial extends HomeState {} +class HomeInitial extends HomeState {} class GetSpacesLoading extends HomeState {} diff --git a/lib/features/app_layout/view/app_layout.dart b/lib/features/app_layout/view/app_layout.dart index 9c2c733..4aa4c4b 100644 --- a/lib/features/app_layout/view/app_layout.dart +++ b/lib/features/app_layout/view/app_layout.dart @@ -23,13 +23,13 @@ class AppLayout extends StatelessWidget { return MultiBlocProvider( providers: [ BlocProvider( - create: (context) => HomeCubit(), + create: (context) => HomeCubit.getInstance(), ), BlocProvider( create: (context) => DevicesCubit(), ), ], - child: BlocListener( + child: BlocConsumer( listener: (context, state) { if (state is GetSpacesError) { ScaffoldMessenger.of(context).showSnackBar( @@ -41,42 +41,41 @@ class AppLayout extends StatelessWidget { .popUntil((route) => route.settings.name == Routes.authLogin); } }, - child: BlocBuilder( - builder: (context, state) { - return AnnotatedRegion( - value: SystemUiOverlayStyle( - statusBarColor: ColorsManager.primaryColor.withOpacity(0.5), - statusBarIconBrightness: Brightness.light, + builder: (context, state) { + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarColor: ColorsManager.primaryColor.withOpacity(0.5), + statusBarIconBrightness: Brightness.light, + ), + child: SafeArea( + child: BlocBuilder( + builder: (context, state) { + return Scaffold( + backgroundColor: ColorsManager.backgroundColor, + extendBodyBehindAppBar: true, + extendBody: true, + appBar: + state is GetSpacesLoaded ? const DefaultAppBar() : null, + body: const AppBody(), + bottomNavigationBar: const DefaultNavBar(), + // floatingActionButton: FloatingActionButton( + // onPressed: () { + // Navigator.push( + // context, + // CustomPageRoute( + // builder: (context) => + // const ThreeGangSwitchesView(), + // ), + // ); + // }, + // child: const Icon(Icons.arrow_forward_ios_sharp), + // ), + ); + }, ), - child: SafeArea( - child: BlocBuilder( - builder: (context, state) { - return const Scaffold( - backgroundColor: ColorsManager.backgroundColor, - extendBodyBehindAppBar: true, - extendBody: true, - appBar: DefaultAppBar(), - body: AppBody(), - bottomNavigationBar: DefaultNavBar(), - // floatingActionButton: FloatingActionButton( - // onPressed: () { - // Navigator.push( - // context, - // CustomPageRoute( - // builder: (context) => - // const ThreeGangSwitchesView(), - // ), - // ); - // }, - // child: const Icon(Icons.arrow_forward_ios_sharp), - // ), - ); - }, - ), - ), - ); - }, - ), + ), + ); + }, ), ); } diff --git a/lib/features/app_layout/view/widgets/app_bar_home_dropdown.dart b/lib/features/app_layout/view/widgets/app_bar_home_dropdown.dart index 2b89da6..197893a 100644 --- a/lib/features/app_layout/view/widgets/app_bar_home_dropdown.dart +++ b/lib/features/app_layout/view/widgets/app_bar_home_dropdown.dart @@ -9,70 +9,68 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import '../../../../generated/assets.dart'; class AppBarHomeDropdown extends StatelessWidget { - const AppBarHomeDropdown({ - super.key, - }); + const AppBarHomeDropdown({super.key}); @override Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { - return HomeCubit.selectedSpace == null - ? const Center(child: BodyMedium(text: 'No Home Selected')) - : Padding( - padding: const EdgeInsets.only(left: 10, right: 10), - child: DropdownButton( - icon: const Icon( - Icons.expand_more, - color: Colors.black, - size: 25, - ), - underline: const SizedBox.shrink(), - padding: const EdgeInsets.all(0), - borderRadius: BorderRadius.circular(20), - value: HomeCubit.selectedSpace!.id, - items: HomeCubit.spaces!.map((space) { - return DropdownMenuItem( - value: space.id, - child: SizedBox( - width: 100, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - SvgPicture.asset( - Assets.iconsHome, - width: 25, - height: 25, - colorFilter: const ColorFilter.mode( - ColorsManager.textPrimaryColor, - BlendMode.srcIn, - ), - ), - const SizedBox(width: 5), - Expanded( - child: BodyMedium( - text: space.name ?? "??", - style: context.bodyMedium.copyWith( - fontSize: 15, - color: ColorsManager.textPrimaryColor, - overflow: TextOverflow.ellipsis, - ), - ), - ), - ], + return Padding( + padding: const EdgeInsets.only(left: 10, right: 10), + child: DropdownButton( + icon: const Icon( + Icons.expand_more, + color: Colors.black, + size: 25, + ), + underline: const SizedBox.shrink(), + padding: const EdgeInsets.all(0), + borderRadius: BorderRadius.circular(20), + value: HomeCubit.getInstance().selectedSpace!.id, + items: HomeCubit.getInstance().spaces!.map((space) { + return DropdownMenuItem( + value: space.id, + child: SizedBox( + width: 100, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + SvgPicture.asset( + Assets.iconsHome, + width: 25, + height: 25, + colorFilter: const ColorFilter.mode( + ColorsManager.textPrimaryColor, + BlendMode.srcIn, ), ), - ); - }).toList(), - onChanged: (value) { - if (value != null) { - HomeCubit.get(context).selectSpace(HomeCubit.spaces! - .firstWhere((element) => element.id == value)); - } - }, + const SizedBox(width: 5), + Expanded( + child: BodyMedium( + text: space.name ?? "??", + style: context.bodyMedium.copyWith( + fontSize: 15, + color: ColorsManager.textPrimaryColor, + overflow: TextOverflow.ellipsis, + ), + ), + ), + ], + ), ), ); + }).toList(), + onChanged: (value) { + if (value != null) { + HomeCubit.getInstance().changeSelectedSpace( + HomeCubit.getInstance() + .spaces! + .firstWhere((element) => element.id == value)); + } + }, + ), + ); }, ); } diff --git a/lib/features/app_layout/view/widgets/app_body.dart b/lib/features/app_layout/view/widgets/app_body.dart index ef2a47d..34343b3 100644 --- a/lib/features/app_layout/view/widgets/app_body.dart +++ b/lib/features/app_layout/view/widgets/app_body.dart @@ -37,9 +37,10 @@ class AppBody extends StatelessWidget { } }, builder: (context, state) { - return state is! GetSpacesLoading || - state is! GetSpaceRoomsLoading - ? HomeCubit.get(context).pages[HomeCubit.pageIndex] + return state is! GetSpacesLoading + ? state is! GetSpaceRoomsLoading + ? HomeCubit.getInstance().pages[HomeCubit.pageIndex] + : const Center(child: CircularProgressIndicator()) : const Center(child: CircularProgressIndicator()); }, ), diff --git a/lib/features/app_layout/view/widgets/default_app_bar.dart b/lib/features/app_layout/view/widgets/default_app_bar.dart index 0575441..6335873 100644 --- a/lib/features/app_layout/view/widgets/default_app_bar.dart +++ b/lib/features/app_layout/view/widgets/default_app_bar.dart @@ -20,11 +20,9 @@ class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget { backgroundColor: Colors.transparent, leadingWidth: 150, toolbarHeight: Constants.appBarHeight, - leading: HomeCubit.spaces != null - ? HomeCubit.spaces!.isNotEmpty - ? HomeCubit.appBarLeading[ - HomeCubit.bottomNavItems[HomeCubit.pageIndex].label] - : const Center(child: BodySmall(text: 'Create Home')) + leading: HomeCubit.getInstance().spaces!.isNotEmpty + ? HomeCubit.appBarLeading[ + HomeCubit.bottomNavItems[HomeCubit.pageIndex].label] : null, actions: HomeCubit.appBarActions[ HomeCubit.bottomNavItems[HomeCubit.pageIndex].label], diff --git a/lib/features/app_layout/view/widgets/default_nav_bar.dart b/lib/features/app_layout/view/widgets/default_nav_bar.dart index 15aef6e..41aa2fd 100644 --- a/lib/features/app_layout/view/widgets/default_nav_bar.dart +++ b/lib/features/app_layout/view/widgets/default_nav_bar.dart @@ -15,7 +15,7 @@ class DefaultNavBar extends StatelessWidget { Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { - var cubit = HomeCubit.get(context); + var cubit = HomeCubit.getInstance(); return SizedBox( height: Constants.bottomNavBarHeight, child: BottomNavigationBar( @@ -25,8 +25,8 @@ class DefaultNavBar extends StatelessWidget { if (DevicesCubit.get(context).chosenCategoryView != null) { DevicesCubit().clearCategoriesSelection(context); } - if (HomeCubit.get(context).selectedRoom != null) { - HomeCubit.get(context).unselectRoom(); + if (HomeCubit.getInstance().selectedRoom != null) { + HomeCubit.getInstance().unselectRoom(); } }, currentIndex: HomeCubit.pageIndex, diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index fa44c92..2dd5ecf 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -22,8 +22,8 @@ part 'devices_state.dart'; class DevicesCubit extends Cubit { DevicesCubit() : super(DevicesInitial()) { - if (HomeCubit.selectedSpace != null) { - fetchGroups(HomeCubit.selectedSpace!.id!); + if (HomeCubit.getInstance().selectedSpace != null) { + fetchGroups(HomeCubit.getInstance().selectedSpace!.id!); } } bool _isClosed = false; diff --git a/lib/features/devices/view/widgets/devices_view_body.dart b/lib/features/devices/view/widgets/devices_view_body.dart index 7837d8b..949db78 100644 --- a/lib/features/devices/view/widgets/devices_view_body.dart +++ b/lib/features/devices/view/widgets/devices_view_body.dart @@ -42,15 +42,19 @@ class DevicesViewBody extends StatelessWidget { Expanded( child: PageView( controller: - HomeCubit.get(context).devicesPageController, + HomeCubit.getInstance().devicesPageController, onPageChanged: (index) { - HomeCubit.get(context).devicesPageChanged(index); + HomeCubit.getInstance().devicesPageChanged(index); }, children: [ const WizardPage(), - if (HomeCubit.selectedSpace != null) - if (HomeCubit.selectedSpace!.rooms != null) - ...HomeCubit.selectedSpace!.rooms!.map( + if (HomeCubit.getInstance().selectedSpace != null) + if (HomeCubit.getInstance().selectedSpace!.rooms != + null) + ...HomeCubit.getInstance() + .selectedSpace! + .rooms! + .map( (room) { return RoomPage( room: room, @@ -60,15 +64,19 @@ class DevicesViewBody extends StatelessWidget { ], ), ), - HomeCubit.selectedSpace != null + HomeCubit.getInstance().selectedSpace != null ? Padding( padding: const EdgeInsets.symmetric( vertical: 7, ), child: SmoothPageIndicator( controller: - HomeCubit.get(context).devicesPageController, - count: HomeCubit.selectedSpace!.rooms!.length + 1, + HomeCubit.getInstance().devicesPageController, + count: HomeCubit.getInstance() + .selectedSpace! + .rooms! + .length + + 1, effect: const WormEffect( paintStyle: PaintingStyle.stroke, dotHeight: 8, diff --git a/lib/features/devices/view/widgets/rooms_slider.dart b/lib/features/devices/view/widgets/rooms_slider.dart index 7d5795a..aeba2f4 100644 --- a/lib/features/devices/view/widgets/rooms_slider.dart +++ b/lib/features/devices/view/widgets/rooms_slider.dart @@ -18,51 +18,55 @@ class RoomsSlider extends StatelessWidget { return SizedBox( height: 40, child: PageView( - controller: HomeCubit.get(context).roomsPageController, + controller: HomeCubit.getInstance().roomsPageController, onPageChanged: (index) { - HomeCubit.get(context).roomSliderPageChanged(index); + HomeCubit.getInstance().roomSliderPageChanged(index); }, children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 15), child: InkWell( onTap: () { - HomeCubit.get(context).unselectRoom(); + HomeCubit.getInstance().unselectRoom(); }, child: TitleMedium( text: StringsManager.wizard, style: context.titleMedium.copyWith( fontSize: 25, - color: HomeCubit.get(context).selectedRoom == null + color: HomeCubit.getInstance().selectedRoom == null ? ColorsManager.textPrimaryColor : ColorsManager.textPrimaryColor.withOpacity(.2), ), ), ), ), - if (HomeCubit.selectedSpace != null) - if (HomeCubit.selectedSpace!.rooms != null) - ...HomeCubit.selectedSpace!.rooms!.map( - (room) => Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: InkWell( - onTap: () { - HomeCubit.get(context).roomSliderPageChanged( - HomeCubit.selectedSpace!.rooms!.indexOf(room)); - }, - child: TitleMedium( - text: room.name!, - style: context.titleMedium.copyWith( - fontSize: 25, - color: HomeCubit.get(context).selectedRoom == room - ? ColorsManager.textPrimaryColor - : ColorsManager.textPrimaryColor - .withOpacity(.2), + if (HomeCubit.getInstance().selectedSpace != null) + if (HomeCubit.getInstance().selectedSpace!.rooms != null) + ...HomeCubit.getInstance().selectedSpace!.rooms!.map( + (room) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 15), + child: InkWell( + onTap: () { + HomeCubit.getInstance().roomSliderPageChanged( + HomeCubit.getInstance() + .selectedSpace! + .rooms! + .indexOf(room)); + }, + child: TitleMedium( + text: room.name!, + style: context.titleMedium.copyWith( + fontSize: 25, + color: + HomeCubit.getInstance().selectedRoom == room + ? ColorsManager.textPrimaryColor + : ColorsManager.textPrimaryColor + .withOpacity(.2), + ), + ), ), ), - ), - ), - ) + ) ], ), ); From 1397778123563b897aa59506927a30310282eaba Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Mon, 1 Apr 2024 12:17:18 +0300 Subject: [PATCH 05/29] Refacorted imports --- lib/features/app_layout/view/app_layout.dart | 4 ---- lib/features/app_layout/view/widgets/default_app_bar.dart | 1 - .../devices/view/widgets/three_gang/three_gang_switches.dart | 1 - 3 files changed, 6 deletions(-) diff --git a/lib/features/app_layout/view/app_layout.dart b/lib/features/app_layout/view/app_layout.dart index 4aa4c4b..9291dcb 100644 --- a/lib/features/app_layout/view/app_layout.dart +++ b/lib/features/app_layout/view/app_layout.dart @@ -1,8 +1,6 @@ -import 'dart:ffi'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; @@ -10,9 +8,7 @@ import 'package:syncrow_app/features/app_layout/view/widgets/app_body.dart'; import 'package:syncrow_app/features/app_layout/view/widgets/default_app_bar.dart'; import 'package:syncrow_app/features/app_layout/view/widgets/default_nav_bar.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; -import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_switches.dart'; import 'package:syncrow_app/navigation/routing_constants.dart'; -import 'package:syncrow_app/utils/helpers/custom_page_route.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; class AppLayout extends StatelessWidget { diff --git a/lib/features/app_layout/view/widgets/default_app_bar.dart b/lib/features/app_layout/view/widgets/default_app_bar.dart index 6335873..6c67536 100644 --- a/lib/features/app_layout/view/widgets/default_app_bar.dart +++ b/lib/features/app_layout/view/widgets/default_app_bar.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; -import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget { diff --git a/lib/features/devices/view/widgets/three_gang/three_gang_switches.dart b/lib/features/devices/view/widgets/three_gang/three_gang_switches.dart index 492efc4..ef7616e 100644 --- a/lib/features/devices/view/widgets/three_gang/three_gang_switches.dart +++ b/lib/features/devices/view/widgets/three_gang/three_gang_switches.dart @@ -4,7 +4,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; -import 'package:syncrow_app/features/devices/model/function_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/category_view_app_bar.dart'; import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_body.dart'; import 'package:syncrow_app/generated/assets.dart'; From 5dc4f96a71af03423a8ead0008433661b9af43f3 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Tue, 2 Apr 2024 12:12:54 +0300 Subject: [PATCH 06/29] Add functionality to fetch devices by room ID Added a new method in DevicesCubit to fetch devices by room ID and updated related classes and API calls to support this functionality. --- lib/features/app_layout/bloc/home_cubit.dart | 20 +++++++--------- lib/features/devices/bloc/devices_cubit.dart | 24 +++++++++++++++++++ lib/features/devices/bloc/devices_state.dart | 11 +++++++++ lib/features/devices/model/room_model.dart | 15 ++++++++---- .../devices/view/widgets/room_page.dart | 8 ++----- lib/services/api/api_links_endpoints.dart | 1 + lib/services/api/http_service.dart | 3 --- lib/services/api/spaces_api.dart | 19 ++++++++++++++- 8 files changed, 75 insertions(+), 26 deletions(-) diff --git a/lib/features/app_layout/bloc/home_cubit.dart b/lib/features/app_layout/bloc/home_cubit.dart index 8f7f572..35dc9ba 100644 --- a/lib/features/app_layout/bloc/home_cubit.dart +++ b/lib/features/app_layout/bloc/home_cubit.dart @@ -20,17 +20,13 @@ class HomeCubit extends Cubit { // Create a private static instance variable static HomeCubit? _instance; HomeCubit._() : super(HomeInitial()) { - if (spaces != null) { - if (selectedSpace == null) { - fetchSpaces().then((value) { - if (selectedSpace != null) { - print('selectedSpace: ${selectedSpace!.name}'); - fetchRooms(selectedSpace!); - } - }); - } - } else { - fetchSpaces(); // this is for the first time + if (selectedSpace == null) { + fetchSpaces().then((value) { + if (selectedSpace != null) { + print('selectedSpace: ${selectedSpace!.name}'); + fetchRooms(selectedSpace!); + } + }); } } static HomeCubit getInstance() { @@ -128,7 +124,7 @@ class HomeCubit extends Cubit { fetchRooms(SpaceModel space) async { emit(GetSpaceRoomsLoading()); try { - space.rooms = await SpacesAPI.getRooms(space.id!); + space.rooms = await SpacesAPI.getRoomsBySpaceId(space.id!); if (space.rooms != null) { emit(GetSpaceRoomsLoaded(space.rooms!)); } else { diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index 2dd5ecf..1d3add2 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -16,6 +16,7 @@ import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_ import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_view.dart'; import 'package:syncrow_app/services/api/devices_api.dart'; import 'package:syncrow_app/services/api/network_exception.dart'; +import 'package:syncrow_app/services/api/spaces_api.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; part 'devices_state.dart'; @@ -24,6 +25,9 @@ class DevicesCubit extends Cubit { DevicesCubit() : super(DevicesInitial()) { if (HomeCubit.getInstance().selectedSpace != null) { fetchGroups(HomeCubit.getInstance().selectedSpace!.id!); + for (var room in HomeCubit.getInstance().selectedSpace!.rooms!) { + fetchDevicesByRoomId(room.id!); + } } } bool _isClosed = false; @@ -251,6 +255,26 @@ class DevicesCubit extends Cubit { } } + fetchDevicesByRoomId(int roomId) async { + if (_isClosed) return; + + try { + emit(GetDevicesLoading()); + int roomIndex = HomeCubit.getInstance() + .selectedSpace! + .rooms! + .indexWhere((element) => element.id == roomId); + HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices = + await SpacesAPI.getDevicesByRoomId(roomId); + + emit(GetDevicesSuccess()); + } on DioException catch (error) { + emit( + GetDevicesError(ServerFailure.fromDioError(error).errMessage), + ); + } + } + ///Lights onHorizontalDragUpdate(DeviceModel light, double dx, double screenWidth) { double newBrightness = (dx / (screenWidth - 15) * 100); diff --git a/lib/features/devices/bloc/devices_state.dart b/lib/features/devices/bloc/devices_state.dart index b7b3fa7..4fd8b2d 100644 --- a/lib/features/devices/bloc/devices_state.dart +++ b/lib/features/devices/bloc/devices_state.dart @@ -14,6 +14,17 @@ class DevicesFailure extends DevicesState {} class ChangeIndex extends DevicesState {} // Devices + +class GetDevicesLoading extends DevicesState {} + +class GetDevicesSuccess extends DevicesState {} + +class GetDevicesError extends DevicesState { + final String errorMsg; + + GetDevicesError(this.errorMsg); +} + class DevicesCategoryChanged extends DevicesState {} class CategorySwitchChanged extends DevicesState {} diff --git a/lib/features/devices/model/room_model.dart b/lib/features/devices/model/room_model.dart index 3937f17..8dfbff8 100644 --- a/lib/features/devices/model/room_model.dart +++ b/lib/features/devices/model/room_model.dart @@ -1,30 +1,37 @@ import 'package:syncrow_app/features/devices/model/device_category_model.dart'; +import 'package:syncrow_app/features/devices/model/device_model.dart'; class RoomModel { final int? id; final String? name; - final List? categories; + List? devices; RoomModel({ required this.id, required this.name, - required this.categories, + required this.devices, }); Map toJson() { return { 'id': id, 'name': name, - 'devices': categories, + 'devices': devices, }; } factory RoomModel.fromJson(Map json) { + List devices = []; + if (json['devices'] != null) { + for (var device in json['devices']) { + devices.add(DeviceModel.fromJson(device)); + } + } return RoomModel( id: json['roomId'], name: json['roomName'], - categories: json['devices'], + devices: devices, ); } } diff --git a/lib/features/devices/view/widgets/room_page.dart b/lib/features/devices/view/widgets/room_page.dart index 7f97b81..3e03f39 100644 --- a/lib/features/devices/view/widgets/room_page.dart +++ b/lib/features/devices/view/widgets/room_page.dart @@ -13,10 +13,6 @@ class RoomPage extends StatelessWidget { @override Widget build(BuildContext context) { - List devices = []; - for (var category in room.categories ?? []) { - devices.addAll(category.devices); - } return Padding( padding: const EdgeInsets.symmetric(horizontal: Constants.defaultPadding), child: SingleChildScrollView( @@ -32,9 +28,9 @@ class RoomPage extends StatelessWidget { padding: const EdgeInsets.only(top: 10), physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, - itemCount: devices.length, + itemCount: room.devices!.length, itemBuilder: (_, index) { - return RoomPageSwitch(device: devices[index]); + return RoomPageSwitch(device: room.devices![index]); }, ); }, diff --git a/lib/services/api/api_links_endpoints.dart b/lib/services/api/api_links_endpoints.dart index bfe22be..f249a1d 100644 --- a/lib/services/api/api_links_endpoints.dart +++ b/lib/services/api/api_links_endpoints.dart @@ -16,6 +16,7 @@ abstract class ApiEndpoints { // Devices static const String control = '$baseUrl/device/control'; + static const String devicesByRoom = '$baseUrl/device/room'; //groups static const String groups = '$baseUrl/group'; diff --git a/lib/services/api/http_service.dart b/lib/services/api/http_service.dart index a5f24bd..9551d4a 100644 --- a/lib/services/api/http_service.dart +++ b/lib/services/api/http_service.dart @@ -37,9 +37,6 @@ class HTTPService { path, queryParameters: queryParameters, ); - - // debugPrint("status code is ${response.statusCode}"); - // debugPrint("response data is ${response.data}"); return expectedResponseModel(response.data); } catch (error) { debugPrint("******* Error"); diff --git a/lib/services/api/spaces_api.dart b/lib/services/api/spaces_api.dart index 3f93385..ebf2597 100644 --- a/lib/services/api/spaces_api.dart +++ b/lib/services/api/spaces_api.dart @@ -1,6 +1,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:syncrow_app/features/app_layout/model/space_model.dart'; import 'package:syncrow_app/features/auth/model/user_model.dart'; +import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/room_model.dart'; import 'package:syncrow_app/services/api/api_links_endpoints.dart'; import 'package:syncrow_app/services/api/http_service.dart'; @@ -23,7 +24,7 @@ class SpacesAPI { } //get rooms by space id - static Future> getRooms(int spaceId) async { + static Future> getRoomsBySpaceId(int spaceId) async { final response = await _httpService.get( path: ApiEndpoints.rooms, queryParameters: {"homeId": spaceId}, @@ -38,4 +39,20 @@ class SpacesAPI { ); return response; } + + static Future> getDevicesByRoomId(int roomId) async { + final response = await _httpService.get( + path: ApiEndpoints.devicesByRoom, + queryParameters: {"roomId": roomId, "pageSize": 10}, + showServerMessage: false, + expectedResponseModel: (json) { + List devices = []; + for (var device in json['devices']) { + devices.add(DeviceModel.fromJson(device)); + } + return devices; + }, + ); + return response; + } } From 81625cd50e35ea5a530f9fd25964401776e79e01 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Tue, 2 Apr 2024 15:11:20 +0300 Subject: [PATCH 07/29] Add device icons based on device type and update network exception handling - Add logic to set device icons based on device type in DeviceModel.fromJson method - Update network exception handling to parse HTML response in ServerFailure class - Add html package as a dependency for parsing HTML responses -Added Devices Icons by updateing device types mapping --- lib/features/devices/model/device_model.dart | 27 +++++++++++++- .../view/widgets/devices_view_body.dart | 1 - .../view/widgets/room_page_switch.dart | 12 ------- .../devices/view/widgets/wizard_switches.dart | 5 +-- lib/services/api/network_exception.dart | 9 +++-- lib/utils/resource_manager/constants.dart | 35 +++++++++++++------ pubspec.lock | 16 +++++++++ pubspec.yaml | 1 + 8 files changed, 76 insertions(+), 30 deletions(-) diff --git a/lib/features/devices/model/device_model.dart b/lib/features/devices/model/device_model.dart index 395e077..0a28c51 100644 --- a/lib/features/devices/model/device_model.dart +++ b/lib/features/devices/model/device_model.dart @@ -1,4 +1,5 @@ import 'package:syncrow_app/features/devices/model/function_model.dart'; +import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; class DeviceModel { @@ -56,13 +57,37 @@ class DeviceModel { } factory DeviceModel.fromJson(Map json) { + print( + 'type : ${json['productId']} => ${devicesTypesMap[json['productId']]}'); + + String icon = ''; + DeviceType type = devicesTypesMap[json['productId']] ?? DeviceType.Other; + + if (type == DeviceType.LightBulb) { + icon = Assets.iconsLight; + } else if (type == DeviceType.CeilingSensor || + type == DeviceType.WallSensor) { + icon = Assets.iconsSensors; + } else if (type == DeviceType.AC) { + icon = Assets.iconsAC; + } else if (type == DeviceType.DoorLock) { + icon = Assets.iconsDoorLock; + } else if (type == DeviceType.Curtain) { + icon = Assets.iconsCurtain; + } else if (type == DeviceType.ThreeGang) { + icon = Assets.iconsLight; + } else if (type == DeviceType.Gateway) { + icon = Assets.iconsGateway; + } else { + icon = Assets.iconsLogo; + } return DeviceModel( activeTime: json['activeTime'], category: json['category'], categoryName: json['categoryName'], createTime: json['createTime'], gatewayId: json['gatewayId'], - icon: json['icon'], + icon: icon, id: json['id'], ip: json['ip'], lat: double.tryParse(json['lat']), diff --git a/lib/features/devices/view/widgets/devices_view_body.dart b/lib/features/devices/view/widgets/devices_view_body.dart index 949db78..6db83da 100644 --- a/lib/features/devices/view/widgets/devices_view_body.dart +++ b/lib/features/devices/view/widgets/devices_view_body.dart @@ -22,7 +22,6 @@ class DevicesViewBody extends StatelessWidget { builder: (context, state) { return BlocBuilder( builder: (context, state) { - //TODO : move to NavigationCubit if (state is DevicesLoading) { return const Center(child: CircularProgressIndicator()); } else { diff --git a/lib/features/devices/view/widgets/room_page_switch.dart b/lib/features/devices/view/widgets/room_page_switch.dart index dec23dc..885c334 100644 --- a/lib/features/devices/view/widgets/room_page_switch.dart +++ b/lib/features/devices/view/widgets/room_page_switch.dart @@ -21,18 +21,6 @@ class RoomPageSwitch extends StatelessWidget { Widget build(BuildContext context) { return InkWell( onTap: () { - //Navigate to the chosen category view without animation - - // Navigator.push( - // context, - // CustomPageRoute( - // builder: (context) { - // return DevicesCubit.get(context) - // .chosenCategoryView!; - // }, - // ), - // ); - if (device.productType == DeviceType.AC) { Navigator.push( context, diff --git a/lib/features/devices/view/widgets/wizard_switches.dart b/lib/features/devices/view/widgets/wizard_switches.dart index 8a200d2..3bed961 100644 --- a/lib/features/devices/view/widgets/wizard_switches.dart +++ b/lib/features/devices/view/widgets/wizard_switches.dart @@ -61,10 +61,7 @@ class WizartSwitches extends StatelessWidget { DevicesCubit.allCategories![index].icon!, fit: BoxFit.contain, ), - CustomSwitch( - category: - DevicesCubit.allCategories![index], - ), + // CustomSwitch( ], ), Expanded( diff --git a/lib/services/api/network_exception.dart b/lib/services/api/network_exception.dart index 0cec78b..d980e3b 100644 --- a/lib/services/api/network_exception.dart +++ b/lib/services/api/network_exception.dart @@ -1,4 +1,5 @@ import 'package:dio/dio.dart'; +import 'package:html/parser.dart' as parser; abstract class Failure { final String errMessage; @@ -28,8 +29,12 @@ class ServerFailure extends Failure { return ServerFailure("Bad certificate!"); case DioExceptionType.badResponse: - return ServerFailure.fromResponse(dioError.response!.statusCode!, - dioError.response!.data!["message"]); + { + var document = parser.parse(dioError.response!.data.toString()); + var message = document.body!.text; + return ServerFailure.fromResponse( + dioError.response!.statusCode!, message); + } case DioExceptionType.cancel: return ServerFailure("The request to ApiServer was canceled"); diff --git a/lib/utils/resource_manager/constants.dart b/lib/utils/resource_manager/constants.dart index 5f0a973..42f4825 100644 --- a/lib/utils/resource_manager/constants.dart +++ b/lib/utils/resource_manager/constants.dart @@ -29,17 +29,32 @@ enum DeviceType { Other, } +// Map devicesTypesMap = { +// "AC": DeviceType.AC, +// "LB": DeviceType.LightBulb, +// "DL": DeviceType.DoorLock, +// "WC": DeviceType.Curtain, +// "WB": DeviceType.Blind, +// "3G": DeviceType.ThreeGang, +// "GW": DeviceType.Gateway, +// "CPS": DeviceType.CeilingSensor, +// "WPS": DeviceType.WallSensor, +// "Other": DeviceType.Other, +// }; +//AC wzdcrqh0 +// GW wp8ticoo2bhumwgb +// CPS d3ci7gcn +// DL awu7anehyu5q1iu8 +// WPS awarhusb +// 3G 1a6vgvyi + Map devicesTypesMap = { - "AC": DeviceType.AC, - "LB": DeviceType.LightBulb, - "DL": DeviceType.DoorLock, - "WC": DeviceType.Curtain, - "WB": DeviceType.Blind, - "3G": DeviceType.ThreeGang, - "GW": DeviceType.Gateway, - "CPS": DeviceType.CeilingSensor, - "WPS": DeviceType.WallSensor, - "Other": DeviceType.Other, + "wzdcrqh0": DeviceType.AC, + "wp8ticoo2bhumwgb": DeviceType.Gateway, + "d3ci7gcn": DeviceType.CeilingSensor, + "awu7anehyu5q1iu8": DeviceType.DoorLock, + "awarhusb": DeviceType.WallSensor, + "1a6vgvyi": DeviceType.ThreeGang, }; Map> devicesFunctionsMap = { DeviceType.AC: [ diff --git a/pubspec.lock b/pubspec.lock index 7ddef2b..5371f83 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -97,6 +97,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" cupertino_icons: dependency: "direct main" description: @@ -357,6 +365,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.6.7" + html: + dependency: "direct main" + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" http: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 388ac93..e5759aa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,6 +36,7 @@ dependencies: firebase_analytics: ^10.8.7 firebase_crashlytics: ^3.4.16 smooth_page_indicator: ^1.1.0 + html: ^0.15.4 dev_dependencies: flutter_test: From ef419403337a42b30d3ee8ba347805f700823f93 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Tue, 2 Apr 2024 15:45:21 +0300 Subject: [PATCH 08/29] Add support for different device types in RoomPageSwitch -Update the navigation approch to be device type orianted to the corresponding interface when tapped. -Add three gang switch interface and related components --- lib/features/devices/bloc/devices_cubit.dart | 6 +- .../view/widgets/room_page_switch.dart | 58 ++++++++++++++++--- ...hree_gang_switch.dart => gang_switch.dart} | 4 +- ...witches.dart => three_gang_interface.dart} | 11 ++-- ...dy.dart => three_gang_interface_body.dart} | 12 ++-- 5 files changed, 68 insertions(+), 23 deletions(-) rename lib/features/devices/view/widgets/three_gang/{three_gang_switch.dart => gang_switch.dart} (97%) rename lib/features/devices/view/widgets/three_gang/{three_gang_switches.dart => three_gang_interface.dart} (88%) rename lib/features/devices/view/widgets/three_gang/{three_gang_body.dart => three_gang_interface_body.dart} (97%) diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index 1d3add2..da4e92d 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -12,7 +12,7 @@ import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/lights/lights_view.dart'; -import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_switches.dart'; +import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_view.dart'; import 'package:syncrow_app/services/api/devices_api.dart'; import 'package:syncrow_app/services/api/network_exception.dart'; @@ -73,8 +73,8 @@ class DevicesCubit extends Cubit { return const DoorView(); case DeviceType.Curtain: return const CurtainView(); - case DeviceType.ThreeGang: - return const ThreeGangSwitchesView(); + // case DeviceType.ThreeGang: + // return const ThreeGangSwitchesView(); case DeviceType.Gateway: return const GateWayView(); default: diff --git a/lib/features/devices/view/widgets/room_page_switch.dart b/lib/features/devices/view/widgets/room_page_switch.dart index 885c334..f4dff32 100644 --- a/lib/features/devices/view/widgets/room_page_switch.dart +++ b/lib/features/devices/view/widgets/room_page_switch.dart @@ -1,7 +1,11 @@ +import 'dart:js_util'; + import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface.dart'; +import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface.dart'; +import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface.dart'; import 'package:syncrow_app/features/shared_widgets/custom_switch.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; @@ -21,13 +25,53 @@ class RoomPageSwitch extends StatelessWidget { Widget build(BuildContext context) { return InkWell( onTap: () { - if (device.productType == DeviceType.AC) { - Navigator.push( - context, - CustomPageRoute( - builder: (context) => AcInterface(deviceModel: device), - ), - ); + // if (device.productType == DeviceType.AC) { + // Navigator.push( + // context, + // CustomPageRoute( + // builder: (context) => AcInterface(deviceModel: device), + // ), + // ); + // } + switch (device.productType) { + case DeviceType.AC: + Navigator.push( + context, + CustomPageRoute( + builder: (context) => AcInterface(deviceModel: device), + ), + ); + break; + case DeviceType.WallSensor: + break; + case DeviceType.CeilingSensor: + break; + case DeviceType.Curtain: + break; + case DeviceType.Blind: + break; + case DeviceType.DoorLock: + break; + case DeviceType.Gateway: + break; + case DeviceType.LightBulb: + Navigator.push( + context, + CustomPageRoute( + builder: (context) => LightInterface(light: device), + ), + ); + case DeviceType.ThreeGang: + Navigator.push( + context, + CustomPageRoute( + builder: (context) => ThreeGangInterface( + gangSwitch: device, + ), + ), + ); + break; + default: } }, child: DefaultContainer( diff --git a/lib/features/devices/view/widgets/three_gang/three_gang_switch.dart b/lib/features/devices/view/widgets/three_gang/gang_switch.dart similarity index 97% rename from lib/features/devices/view/widgets/three_gang/three_gang_switch.dart rename to lib/features/devices/view/widgets/three_gang/gang_switch.dart index 841e1e3..6e878a0 100644 --- a/lib/features/devices/view/widgets/three_gang/three_gang_switch.dart +++ b/lib/features/devices/view/widgets/three_gang/gang_switch.dart @@ -6,8 +6,8 @@ import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; -class ThreeGangSwitch extends StatelessWidget { - const ThreeGangSwitch({ +class GangSwitch extends StatelessWidget { + const GangSwitch({ super.key, required this.control, }); diff --git a/lib/features/devices/view/widgets/three_gang/three_gang_switches.dart b/lib/features/devices/view/widgets/three_gang/three_gang_interface.dart similarity index 88% rename from lib/features/devices/view/widgets/three_gang/three_gang_switches.dart rename to lib/features/devices/view/widgets/three_gang/three_gang_interface.dart index ef7616e..3cc77a8 100644 --- a/lib/features/devices/view/widgets/three_gang/three_gang_switches.dart +++ b/lib/features/devices/view/widgets/three_gang/three_gang_interface.dart @@ -5,14 +5,15 @@ import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/category_view_app_bar.dart'; -import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_body.dart'; +import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface_body.dart'; import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; -class ThreeGangSwitchesView extends StatelessWidget { - const ThreeGangSwitchesView({super.key}); +class ThreeGangInterface extends StatelessWidget { + const ThreeGangInterface({super.key, required this.gangSwitch}); + final DeviceModel gangSwitch; @override Widget build(BuildContext context) { return AnnotatedRegion( @@ -47,8 +48,8 @@ class ThreeGangSwitchesView extends StatelessWidget { right: Constants.defaultPadding, bottom: Constants.bottomNavBarHeight, ), - child: ThreeGangBody( - device: DeviceModel(), + child: ThreeGangInterfaceBody( + device: gangSwitch, ), ), ); diff --git a/lib/features/devices/view/widgets/three_gang/three_gang_body.dart b/lib/features/devices/view/widgets/three_gang/three_gang_interface_body.dart similarity index 97% rename from lib/features/devices/view/widgets/three_gang/three_gang_body.dart rename to lib/features/devices/view/widgets/three_gang/three_gang_interface_body.dart index d5e5580..b737dda 100644 --- a/lib/features/devices/view/widgets/three_gang/three_gang_body.dart +++ b/lib/features/devices/view/widgets/three_gang/three_gang_interface_body.dart @@ -1,13 +1,13 @@ import 'package:flutter/material.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; -import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_switch.dart'; +import 'package:syncrow_app/features/devices/view/widgets/three_gang/gang_switch.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; -class ThreeGangBody extends StatelessWidget { - const ThreeGangBody({ +class ThreeGangInterfaceBody extends StatelessWidget { + const ThreeGangInterfaceBody({ super.key, required this.device, }); @@ -27,7 +27,7 @@ class ThreeGangBody extends StatelessWidget { children: [ Column( children: [ - ThreeGangSwitch( + GangSwitch( control: DeviceControlModel( deviceId: 'bfe10693d4fd263206ocq9', code: 'switch_1', @@ -47,7 +47,7 @@ class ThreeGangBody extends StatelessWidget { ), Column( children: [ - ThreeGangSwitch( + GangSwitch( control: DeviceControlModel( deviceId: 'bfe10693d4fd263206ocq9', code: 'switch_2', @@ -67,7 +67,7 @@ class ThreeGangBody extends StatelessWidget { ), Column( children: [ - ThreeGangSwitch( + GangSwitch( control: DeviceControlModel( deviceId: 'bfe10693d4fd263206ocq9', code: 'switch_3', From 9cc479ba17ab2738b8ae91153c612dde71bd85d9 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Tue, 2 Apr 2024 18:09:23 +0300 Subject: [PATCH 09/29] Refactor email and password validation logic in LoginForm widget Update email and password validation logic in the LoginForm widget to only perform validation when the state is not AuthTokenError. This ensures that validation is skipped when there is an authentication token error. --- lib/features/app_layout/bloc/home_cubit.dart | 5 +-- lib/features/app_layout/view/app_layout.dart | 13 ++----- .../view/widgets/default_nav_bar.dart | 2 +- .../auth/view/widgets/login/login_form.dart | 34 +++++++++++-------- lib/features/devices/bloc/devices_cubit.dart | 9 ++++- lib/features/devices/model/device_model.dart | 6 ++-- lib/features/devices/model/room_model.dart | 1 - lib/features/devices/view/devices_view.dart | 8 ++--- .../devices/view/widgets/room_page.dart | 1 - .../view/widgets/room_page_switch.dart | 27 ++++++--------- .../devices/view/widgets/wizard_switches.dart | 1 - lib/navigation/router.dart | 8 ++++- lib/utils/bloc_observer.dart | 2 +- 13 files changed, 57 insertions(+), 60 deletions(-) diff --git a/lib/features/app_layout/bloc/home_cubit.dart b/lib/features/app_layout/bloc/home_cubit.dart index 35dc9ba..fae40b4 100644 --- a/lib/features/app_layout/bloc/home_cubit.dart +++ b/lib/features/app_layout/bloc/home_cubit.dart @@ -18,17 +18,18 @@ part 'home_state.dart'; class HomeCubit extends Cubit { // Create a private static instance variable - static HomeCubit? _instance; + HomeCubit._() : super(HomeInitial()) { if (selectedSpace == null) { fetchSpaces().then((value) { if (selectedSpace != null) { - print('selectedSpace: ${selectedSpace!.name}'); fetchRooms(selectedSpace!); } }); } } + + static HomeCubit? _instance; static HomeCubit getInstance() { // If an instance already exists, return it _instance ??= HomeCubit._(); diff --git a/lib/features/app_layout/view/app_layout.dart b/lib/features/app_layout/view/app_layout.dart index 9291dcb..c132c50 100644 --- a/lib/features/app_layout/view/app_layout.dart +++ b/lib/features/app_layout/view/app_layout.dart @@ -1,4 +1,3 @@ - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -7,7 +6,6 @@ import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/app_layout/view/widgets/app_body.dart'; import 'package:syncrow_app/features/app_layout/view/widgets/default_app_bar.dart'; import 'package:syncrow_app/features/app_layout/view/widgets/default_nav_bar.dart'; -import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/navigation/routing_constants.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; @@ -16,15 +14,8 @@ class AppLayout extends StatelessWidget { @override Widget build(BuildContext context) { - return MultiBlocProvider( - providers: [ - BlocProvider( - create: (context) => HomeCubit.getInstance(), - ), - BlocProvider( - create: (context) => DevicesCubit(), - ), - ], + return BlocProvider( + create: (context) => HomeCubit.getInstance(), child: BlocConsumer( listener: (context, state) { if (state is GetSpacesError) { diff --git a/lib/features/app_layout/view/widgets/default_nav_bar.dart b/lib/features/app_layout/view/widgets/default_nav_bar.dart index 41aa2fd..8711166 100644 --- a/lib/features/app_layout/view/widgets/default_nav_bar.dart +++ b/lib/features/app_layout/view/widgets/default_nav_bar.dart @@ -23,7 +23,7 @@ class DefaultNavBar extends StatelessWidget { onTap: (int index) { cubit.updatePageIndex(index); if (DevicesCubit.get(context).chosenCategoryView != null) { - DevicesCubit().clearCategoriesSelection(context); + DevicesCubit.getInstance().clearCategoriesSelection(context); } if (HomeCubit.getInstance().selectedRoom != null) { HomeCubit.getInstance().unselectRoom(); diff --git a/lib/features/auth/view/widgets/login/login_form.dart b/lib/features/auth/view/widgets/login/login_form.dart index fd3d7ab..ed76b7b 100644 --- a/lib/features/auth/view/widgets/login/login_form.dart +++ b/lib/features/auth/view/widgets/login/login_form.dart @@ -30,15 +30,17 @@ class LoginForm extends StatelessWidget { TextFormField( controller: AuthCubit.get(context).emailController, validator: (value) { - if (value != null) { - if (value.isEmpty) { - return 'Please enter your email'; - } - //Regex for email validation - if (!RegExp( - r'^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$') - .hasMatch(value)) { - return 'Please enter a valid email'; + if (state is! AuthTokenError) { + if (value != null) { + if (value.isEmpty) { + return 'Please enter your email'; + } + //Regex for email validation + if (!RegExp( + r'^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$') + .hasMatch(value)) { + return 'Please enter a valid email'; + } } } return null; @@ -57,13 +59,15 @@ class LoginForm extends StatelessWidget { TextFormField( controller: AuthCubit.get(context).passwordController, validator: (value) { - if (value != null) { - if (value.isNotEmpty) { - if (value.length < 6) { - return 'Password must be at least 8 characters'; + if (state is! AuthTokenError) { + if (value != null) { + if (value.isNotEmpty) { + if (value.length < 6) { + return 'Password must be at least 8 characters'; + } + } else { + return 'Please enter your password'; } - } else { - return 'Please enter your password'; } } return null; diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index da4e92d..3e11ae2 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -22,7 +22,7 @@ import 'package:syncrow_app/utils/resource_manager/constants.dart'; part 'devices_state.dart'; class DevicesCubit extends Cubit { - DevicesCubit() : super(DevicesInitial()) { + DevicesCubit._() : super(DevicesInitial()) { if (HomeCubit.getInstance().selectedSpace != null) { fetchGroups(HomeCubit.getInstance().selectedSpace!.id!); for (var room in HomeCubit.getInstance().selectedSpace!.rooms!) { @@ -32,6 +32,13 @@ class DevicesCubit extends Cubit { } bool _isClosed = false; + static DevicesCubit? _instance; + static DevicesCubit getInstance() { + // If an instance already exists, return it + _instance ??= DevicesCubit._(); + return _instance!; + } + @override Future close() { _isClosed = true; diff --git a/lib/features/devices/model/device_model.dart b/lib/features/devices/model/device_model.dart index 0a28c51..fec6858 100644 --- a/lib/features/devices/model/device_model.dart +++ b/lib/features/devices/model/device_model.dart @@ -57,9 +57,6 @@ class DeviceModel { } factory DeviceModel.fromJson(Map json) { - print( - 'type : ${json['productId']} => ${devicesTypesMap[json['productId']]}'); - String icon = ''; DeviceType type = devicesTypesMap[json['productId']] ?? DeviceType.Other; @@ -104,7 +101,8 @@ class DeviceModel { timeZone: json['timeZone'], updateTime: json['updateTime'], uuid: json['uuid'], - productType: devicesTypesMap[json['productName']] ?? DeviceType.Other, + productType: type, + // devicesTypesMap[json['productName']] ?? DeviceType.Other, ); } diff --git a/lib/features/devices/model/room_model.dart b/lib/features/devices/model/room_model.dart index 8dfbff8..79c043e 100644 --- a/lib/features/devices/model/room_model.dart +++ b/lib/features/devices/model/room_model.dart @@ -1,4 +1,3 @@ -import 'package:syncrow_app/features/devices/model/device_category_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; class RoomModel { diff --git a/lib/features/devices/view/devices_view.dart b/lib/features/devices/view/devices_view.dart index 4bad0e1..6ca3ae2 100644 --- a/lib/features/devices/view/devices_view.dart +++ b/lib/features/devices/view/devices_view.dart @@ -4,15 +4,15 @@ import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart'; class DevicesView extends StatelessWidget { - const DevicesView({super.key}); + const DevicesView({super.key}); // Fixing the syntax for super.key @override Widget build(BuildContext context) { return BlocBuilder( - builder: (context, state) => Container( + builder: (_, state) => Container( padding: const EdgeInsets.all(8), - width: MediaQuery.sizeOf(context).width, - height: MediaQuery.sizeOf(context).height, + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, child: const DevicesViewBody(), ), ); diff --git a/lib/features/devices/view/widgets/room_page.dart b/lib/features/devices/view/widgets/room_page.dart index 3e03f39..c4a93f1 100644 --- a/lib/features/devices/view/widgets/room_page.dart +++ b/lib/features/devices/view/widgets/room_page.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; -import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/model/room_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/room_page_switch.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; diff --git a/lib/features/devices/view/widgets/room_page_switch.dart b/lib/features/devices/view/widgets/room_page_switch.dart index f4dff32..f73fb22 100644 --- a/lib/features/devices/view/widgets/room_page_switch.dart +++ b/lib/features/devices/view/widgets/room_page_switch.dart @@ -1,5 +1,3 @@ -import 'dart:js_util'; - import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; @@ -25,23 +23,18 @@ class RoomPageSwitch extends StatelessWidget { Widget build(BuildContext context) { return InkWell( onTap: () { - // if (device.productType == DeviceType.AC) { - // Navigator.push( - // context, - // CustomPageRoute( - // builder: (context) => AcInterface(deviceModel: device), - // ), - // ); - // } switch (device.productType) { case DeviceType.AC: - Navigator.push( - context, - CustomPageRoute( - builder: (context) => AcInterface(deviceModel: device), - ), - ); - break; + { + print("AC"); + Navigator.push( + context, + CustomPageRoute( + builder: (context) => AcInterface(deviceModel: device), + ), + ); + break; + } case DeviceType.WallSensor: break; case DeviceType.CeilingSensor: diff --git a/lib/features/devices/view/widgets/wizard_switches.dart b/lib/features/devices/view/widgets/wizard_switches.dart index 3bed961..e1b8092 100644 --- a/lib/features/devices/view/widgets/wizard_switches.dart +++ b/lib/features/devices/view/widgets/wizard_switches.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:syncrow_app/features/shared_widgets/custom_switch.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/utils/context_extension.dart'; diff --git a/lib/navigation/router.dart b/lib/navigation/router.dart index 49647e9..f14a3fa 100644 --- a/lib/navigation/router.dart +++ b/lib/navigation/router.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/view/app_layout.dart'; import 'package:syncrow_app/features/auth/view/widgets/didnt_get_code/didnt_get_code_view.dart'; import 'package:syncrow_app/features/auth/view/widgets/login/login_view.dart'; @@ -7,6 +8,7 @@ import 'package:syncrow_app/features/auth/view/widgets/privacy_policy/privacy_po import 'package:syncrow_app/features/auth/view/widgets/sign_up/sign_up_view.dart'; import 'package:syncrow_app/features/auth/view/widgets/user_agreement/user_agreement_view.dart'; import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/view/devices_view.dart'; import 'package:syncrow_app/features/layout/view/layout_view.dart'; import 'package:syncrow_app/features/menu/view/menu_view.dart'; @@ -25,7 +27,11 @@ class Router { case Routes.devicesRoute: return MaterialPageRoute( - builder: (_) => const DevicesView(), settings: settings); + builder: (_) => BlocProvider( + create: (_) => DevicesCubit.getInstance(), + child: const DevicesView(), + ), + settings: settings); case Routes.profileRoute: return MaterialPageRoute( diff --git a/lib/utils/bloc_observer.dart b/lib/utils/bloc_observer.dart index 5becffe..f93399a 100644 --- a/lib/utils/bloc_observer.dart +++ b/lib/utils/bloc_observer.dart @@ -23,7 +23,7 @@ class MyBlocObserver extends BlocObserver { @override void onClose(BlocBase bloc) { - super.onClose(bloc); print('onClose -- ${bloc.runtimeType}'); + super.onClose(bloc); } } From 127d3a02958eed00c5da05e10b860407ea8de6d3 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Wed, 3 Apr 2024 01:55:50 +0300 Subject: [PATCH 10/29] Refactor code structure and update dependencies Clean up code structure, remove unused imports, and update dependencies. No functional changes made, only code organization improvements. --- lib/features/app_layout/bloc/home_cubit.dart | 6 +- .../view/widgets/default_nav_bar.dart | 66 ++++---- lib/features/devices/bloc/devices_cubit.dart | 24 +-- lib/features/devices/view/devices_view.dart | 33 ++-- .../view/widgets/ACs/ac_interface.dart | 2 + .../devices/view/widgets/ACs/acs_list.dart | 5 +- .../view/widgets/devices_view_body.dart | 153 ++++++++++-------- .../view/widgets/lights/light_interface.dart | 46 ++++-- .../view/widgets/room_page_switch.dart | 19 ++- .../three_gang/three_gang_interface.dart | 71 ++++---- lib/my_app.dart | 9 +- lib/navigation/router.dart | 10 +- lib/services/api/network_exception.dart | 8 +- 13 files changed, 258 insertions(+), 194 deletions(-) diff --git a/lib/features/app_layout/bloc/home_cubit.dart b/lib/features/app_layout/bloc/home_cubit.dart index fae40b4..6021f2a 100644 --- a/lib/features/app_layout/bloc/home_cubit.dart +++ b/lib/features/app_layout/bloc/home_cubit.dart @@ -5,6 +5,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_app/features/app_layout/model/space_model.dart'; import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdown.dart'; import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/room_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart'; import 'package:syncrow_app/features/menu/view/menu_view.dart'; @@ -260,7 +261,10 @@ class HomeCubit extends Cubit { final List pages = [ const DashboardView(), // const LayoutPage(), - const DevicesViewBody(), + BlocProvider( + create: (context) => DevicesCubit(), + child: const DevicesViewBody(), + ), const SceneView(), const MenuView(), ]; diff --git a/lib/features/app_layout/view/widgets/default_nav_bar.dart b/lib/features/app_layout/view/widgets/default_nav_bar.dart index 8711166..604d018 100644 --- a/lib/features/app_layout/view/widgets/default_nav_bar.dart +++ b/lib/features/app_layout/view/widgets/default_nav_bar.dart @@ -13,36 +13,44 @@ class DefaultNavBar extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - var cubit = HomeCubit.getInstance(); - return SizedBox( - height: Constants.bottomNavBarHeight, - child: BottomNavigationBar( - backgroundColor: Colors.transparent, - onTap: (int index) { - cubit.updatePageIndex(index); - if (DevicesCubit.get(context).chosenCategoryView != null) { - DevicesCubit.getInstance().clearCategoriesSelection(context); - } - if (HomeCubit.getInstance().selectedRoom != null) { - HomeCubit.getInstance().unselectRoom(); - } + return BlocProvider( + create: (context) => DevicesCubit(), + child: BlocBuilder( + builder: (context, state) { + return BlocBuilder( + builder: (context, state) { + var cubit = HomeCubit.getInstance(); + return SizedBox( + height: Constants.bottomNavBarHeight, + child: BottomNavigationBar( + backgroundColor: Colors.transparent, + onTap: (int index) { + cubit.updatePageIndex(index); + if (DevicesCubit.get(context).chosenCategoryView != null) { + DevicesCubit.get(context) + .clearCategoriesSelection(context); + } + if (HomeCubit.getInstance().selectedRoom != null) { + HomeCubit.getInstance().unselectRoom(); + } + }, + currentIndex: HomeCubit.pageIndex, + selectedItemColor: ColorsManager.primaryColor, + selectedLabelStyle: const TextStyle( + color: ColorsManager.primaryColor, + fontSize: 10, + ), + showUnselectedLabels: true, + unselectedItemColor: Colors.grey, + type: BottomNavigationBarType.fixed, + elevation: 0, + items: HomeCubit.bottomNavItems, + ), + ); }, - currentIndex: HomeCubit.pageIndex, - selectedItemColor: ColorsManager.primaryColor, - selectedLabelStyle: const TextStyle( - color: ColorsManager.primaryColor, - fontSize: 10, - ), - showUnselectedLabels: true, - unselectedItemColor: Colors.grey, - type: BottomNavigationBarType.fixed, - elevation: 0, - items: HomeCubit.bottomNavItems, - ), - ); - }, + ); + }, + ), ); } } diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index 3e11ae2..9432f11 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -22,7 +22,7 @@ import 'package:syncrow_app/utils/resource_manager/constants.dart'; part 'devices_state.dart'; class DevicesCubit extends Cubit { - DevicesCubit._() : super(DevicesInitial()) { + DevicesCubit() : super(DevicesInitial()) { if (HomeCubit.getInstance().selectedSpace != null) { fetchGroups(HomeCubit.getInstance().selectedSpace!.id!); for (var room in HomeCubit.getInstance().selectedSpace!.rooms!) { @@ -32,18 +32,18 @@ class DevicesCubit extends Cubit { } bool _isClosed = false; - static DevicesCubit? _instance; - static DevicesCubit getInstance() { - // If an instance already exists, return it - _instance ??= DevicesCubit._(); - return _instance!; - } + // static DevicesCubit? _instance; + // static DevicesCubit.get(context) { + // // If an instance already exists, return it + // _instance ??= DevicesCubit._(); + // return _instance!; + // } - @override - Future close() { - _isClosed = true; - return super.close(); - } + // @override + // Future close() { + // _isClosed = true; + // return super.close(); + // } static DevicesCubit get(context) => BlocProvider.of(context); diff --git a/lib/features/devices/view/devices_view.dart b/lib/features/devices/view/devices_view.dart index 6ca3ae2..6793026 100644 --- a/lib/features/devices/view/devices_view.dart +++ b/lib/features/devices/view/devices_view.dart @@ -1,20 +1,17 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; -import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart'; +// import 'package:flutter/material.dart'; +// import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart'; -class DevicesView extends StatelessWidget { - const DevicesView({super.key}); // Fixing the syntax for super.key +// class DevicesView extends StatelessWidget { +// const DevicesView({super.key}); - @override - Widget build(BuildContext context) { - return BlocBuilder( - builder: (_, state) => Container( - padding: const EdgeInsets.all(8), - width: MediaQuery.of(context).size.width, - height: MediaQuery.of(context).size.height, - child: const DevicesViewBody(), - ), - ); - } -} +// @override +// Widget build(BuildContext context) { +// print('built DevicesView'); +// return Container( +// padding: const EdgeInsets.all(8), +// width: MediaQuery.of(context).size.width, +// height: MediaQuery.of(context).size.height, +// child: const DevicesViewBody(), +// ); +// } +// } diff --git a/lib/features/devices/view/widgets/ACs/ac_interface.dart b/lib/features/devices/view/widgets/ACs/ac_interface.dart index e0af460..0bf1fb1 100644 --- a/lib/features/devices/view/widgets/ACs/ac_interface.dart +++ b/lib/features/devices/view/widgets/ACs/ac_interface.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface_controls.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart'; diff --git a/lib/features/devices/view/widgets/ACs/acs_list.dart b/lib/features/devices/view/widgets/ACs/acs_list.dart index f8175f6..2eb6e07 100644 --- a/lib/features/devices/view/widgets/ACs/acs_list.dart +++ b/lib/features/devices/view/widgets/ACs/acs_list.dart @@ -41,9 +41,8 @@ class ACsList extends StatelessWidget { itemCount: DevicesCubit.get(context).chosenCategory!.devices!.length, itemBuilder: (context, index) { - DeviceModel ac = DevicesCubit.get(context) - .chosenCategory! - .devices![index]; + DeviceModel ac = + DevicesCubit.get(context).chosenCategory!.devices![index]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/lib/features/devices/view/widgets/devices_view_body.dart b/lib/features/devices/view/widgets/devices_view_body.dart index 6db83da..5b3f9f4 100644 --- a/lib/features/devices/view/widgets/devices_view_body.dart +++ b/lib/features/devices/view/widgets/devices_view_body.dart @@ -18,80 +18,95 @@ class DevicesViewBody extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocBuilder( + return BlocConsumer( + listener: (context, state) { + if (state is GetDevicesError) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(state.errorMsg), + ), + ); + } else if (state is DevicesCategoriesError) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(state.errorMsg), + ), + ); + } else if (state is DeviceControlError) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(state.errorMsg), + ), + ); + } + }, builder: (context, state) { - return BlocBuilder( - builder: (context, state) { - if (state is DevicesLoading) { - return const Center(child: CircularProgressIndicator()); - } else { - return Padding( - padding: EdgeInsets.only( - top: Constants.appBarHeight, - bottom: Constants.bottomNavBarHeight, + if (state is DevicesLoading || + state is GetDevicesLoading || + state is DevicesCategoriesLoading) { + return const Center(child: CircularProgressIndicator()); + } else { + return Padding( + padding: EdgeInsets.only( + top: Constants.appBarHeight, + bottom: Constants.bottomNavBarHeight, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const DevicesViewHeader(), + const RoomsSlider(), + const SizedBox( + height: 10, ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const DevicesViewHeader(), - const RoomsSlider(), - const SizedBox( - height: 10, - ), - Expanded( - child: PageView( - controller: - HomeCubit.getInstance().devicesPageController, - onPageChanged: (index) { - HomeCubit.getInstance().devicesPageChanged(index); - }, - children: [ - const WizardPage(), - if (HomeCubit.getInstance().selectedSpace != null) - if (HomeCubit.getInstance().selectedSpace!.rooms != - null) - ...HomeCubit.getInstance() + Expanded( + child: PageView( + controller: HomeCubit.getInstance().devicesPageController, + onPageChanged: (index) { + HomeCubit.getInstance().devicesPageChanged(index); + }, + children: [ + const WizardPage(), + if (HomeCubit.getInstance().selectedSpace != null) + if (HomeCubit.getInstance().selectedSpace!.rooms != + null) + ...HomeCubit.getInstance().selectedSpace!.rooms!.map( + (room) { + return RoomPage( + room: room, + ); + }, + ) + ], + ), + ), + HomeCubit.getInstance().selectedSpace != null + ? Padding( + padding: const EdgeInsets.symmetric( + vertical: 7, + ), + child: SmoothPageIndicator( + controller: + HomeCubit.getInstance().devicesPageController, + count: HomeCubit.getInstance() .selectedSpace! .rooms! - .map( - (room) { - return RoomPage( - room: room, - ); - }, - ) - ], - ), - ), - HomeCubit.getInstance().selectedSpace != null - ? Padding( - padding: const EdgeInsets.symmetric( - vertical: 7, - ), - child: SmoothPageIndicator( - controller: - HomeCubit.getInstance().devicesPageController, - count: HomeCubit.getInstance() - .selectedSpace! - .rooms! - .length + - 1, - effect: const WormEffect( - paintStyle: PaintingStyle.stroke, - dotHeight: 8, - dotWidth: 8, - ), - ), - ) - : const Center( - child: BodyLarge(text: 'No Home Found'), + .length + + 1, + effect: const WormEffect( + paintStyle: PaintingStyle.stroke, + dotHeight: 8, + dotWidth: 8, ), - ], - ), - ); - } - }, - ); + ), + ) + : const Center( + child: BodyLarge(text: 'No Home Found'), + ), + ], + ), + ); + } }, ); } diff --git a/lib/features/devices/view/widgets/lights/light_interface.dart b/lib/features/devices/view/widgets/lights/light_interface.dart index e80ea44..e2ae653 100644 --- a/lib/features/devices/view/widgets/lights/light_interface.dart +++ b/lib/features/devices/view/widgets/lights/light_interface.dart @@ -1,10 +1,14 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface_contols.dart'; import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface_switch.dart'; import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface_timer.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; +import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; class LightInterface extends StatelessWidget { const LightInterface({super.key, required this.light}); @@ -15,16 +19,38 @@ class LightInterface extends StatelessWidget { Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { - return Padding( - padding: const EdgeInsets.only(top: 70, right: 20, left: 20), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - LightInterfaceSwitch(light: light), - LightInterfaceContols(light: light), - const LightInterfaceTimer(), - ], + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarColor: ColorsManager.primaryColor.withOpacity(0.5), + statusBarIconBrightness: Brightness.light, + ), + child: SafeArea( + child: Scaffold( + backgroundColor: ColorsManager.backgroundColor, + extendBodyBehindAppBar: true, + extendBody: true, + appBar: AppBar( + backgroundColor: Colors.transparent, + centerTitle: true, + title: BodyLarge( + text: light.name ?? "", + fontColor: ColorsManager.primaryColor, + fontWeight: FontsManager.bold, + ), + ), + body: Padding( + padding: const EdgeInsets.only(top: 70, right: 20, left: 20), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + LightInterfaceSwitch(light: light), + LightInterfaceContols(light: light), + const LightInterfaceTimer(), + ], + ), + ), + ), ), ), ); diff --git a/lib/features/devices/view/widgets/room_page_switch.dart b/lib/features/devices/view/widgets/room_page_switch.dart index f73fb22..484de84 100644 --- a/lib/features/devices/view/widgets/room_page_switch.dart +++ b/lib/features/devices/view/widgets/room_page_switch.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface.dart'; @@ -30,7 +32,10 @@ class RoomPageSwitch extends StatelessWidget { Navigator.push( context, CustomPageRoute( - builder: (context) => AcInterface(deviceModel: device), + builder: (context) => BlocProvider( + create: (context) => DevicesCubit(), + child: AcInterface(deviceModel: device), + ), ), ); break; @@ -51,15 +56,21 @@ class RoomPageSwitch extends StatelessWidget { Navigator.push( context, CustomPageRoute( - builder: (context) => LightInterface(light: device), + builder: (context) => BlocProvider( + create: (context) => DevicesCubit(), + child: LightInterface(light: device), + ), ), ); case DeviceType.ThreeGang: Navigator.push( context, CustomPageRoute( - builder: (context) => ThreeGangInterface( - gangSwitch: device, + builder: (context) => BlocProvider( + create: (context) => DevicesCubit(), + child: ThreeGangInterface( + gangSwitch: device, + ), ), ), ); diff --git a/lib/features/devices/view/widgets/three_gang/three_gang_interface.dart b/lib/features/devices/view/widgets/three_gang/three_gang_interface.dart index 3cc77a8..0841fdf 100644 --- a/lib/features/devices/view/widgets/three_gang/three_gang_interface.dart +++ b/lib/features/devices/view/widgets/three_gang/three_gang_interface.dart @@ -6,9 +6,11 @@ import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/category_view_app_bar.dart'; import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface_body.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; +import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; class ThreeGangInterface extends StatelessWidget { const ThreeGangInterface({super.key, required this.gangSwitch}); @@ -23,38 +25,43 @@ class ThreeGangInterface extends StatelessWidget { ), child: SafeArea( child: Scaffold( - backgroundColor: ColorsManager.backgroundColor, - extendBodyBehindAppBar: true, - extendBody: true, - appBar: const CategoryViewAppBar(), - body: BlocBuilder( - builder: (context, state) { - return Container( - width: MediaQuery.sizeOf(context).width, - height: MediaQuery.sizeOf(context).height, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage( - Assets.imagesBackground, - ), - fit: BoxFit.cover, - opacity: 0.4, - ), - ), - child: Padding( - padding: EdgeInsets.only( - top: Constants.appBarHeight, - left: Constants.defaultPadding, - right: Constants.defaultPadding, - bottom: Constants.bottomNavBarHeight, - ), - child: ThreeGangInterfaceBody( - device: gangSwitch, - ), - ), - ); - }, - )), + backgroundColor: ColorsManager.backgroundColor, + extendBodyBehindAppBar: true, + extendBody: true, + appBar: AppBar( + backgroundColor: Colors.transparent, + centerTitle: true, + title: BodyLarge( + text: gangSwitch.name ?? "", + fontColor: ColorsManager.primaryColor, + fontWeight: FontsManager.bold, + ), + ), + body: Container( + width: MediaQuery.sizeOf(context).width, + height: MediaQuery.sizeOf(context).height, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage( + Assets.imagesBackground, + ), + fit: BoxFit.cover, + opacity: 0.4, + ), + ), + child: Padding( + padding: EdgeInsets.only( + top: Constants.appBarHeight, + left: Constants.defaultPadding, + right: Constants.defaultPadding, + bottom: Constants.bottomNavBarHeight, + ), + child: ThreeGangInterfaceBody( + device: gangSwitch, + ), + ), + ), + ), ), ); } diff --git a/lib/my_app.dart b/lib/my_app.dart index 928ddd9..ace6a6e 100644 --- a/lib/my_app.dart +++ b/lib/my_app.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/theme_manager.dart'; @@ -18,12 +19,8 @@ class MyApp extends StatelessWidget { MediaQuery.sizeOf(context).height * Constants.appBarHeightPercentage; Constants.bottomNavBarHeight = MediaQuery.sizeOf(context).height * Constants.bottomNavBarHeightPercentage; - return MultiBlocProvider( - providers: [ - BlocProvider( - create: (context) => AuthCubit(), - ), - ], + return BlocProvider( + create: (context) => AuthCubit(), child: MaterialApp( debugShowCheckedModeBanner: false, color: ColorsManager.primaryColor, diff --git a/lib/navigation/router.dart b/lib/navigation/router.dart index f14a3fa..e5ed6db 100644 --- a/lib/navigation/router.dart +++ b/lib/navigation/router.dart @@ -25,13 +25,9 @@ class Router { return MaterialPageRoute( builder: (_) => const SplashView(), settings: settings); - case Routes.devicesRoute: - return MaterialPageRoute( - builder: (_) => BlocProvider( - create: (_) => DevicesCubit.getInstance(), - child: const DevicesView(), - ), - settings: settings); + // case Routes.devicesRoute: + // return MaterialPageRoute( + // builder: (_) => const DevicesView(), settings: settings); case Routes.profileRoute: return MaterialPageRoute( diff --git a/lib/services/api/network_exception.dart b/lib/services/api/network_exception.dart index d980e3b..1cc6a3d 100644 --- a/lib/services/api/network_exception.dart +++ b/lib/services/api/network_exception.dart @@ -30,10 +30,12 @@ class ServerFailure extends Failure { case DioExceptionType.badResponse: { - var document = parser.parse(dioError.response!.data.toString()); - var message = document.body!.text; + // var document = parser.parse(dioError.response!.data.toString()); + // var message = document.body!.text; return ServerFailure.fromResponse( - dioError.response!.statusCode!, message); + dioError.response!.statusCode!, dioError.response!.data.toString() + // message + ); } case DioExceptionType.cancel: return ServerFailure("The request to ApiServer was canceled"); From 313912a94148c92922437151c60d90a741f1bfac Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Wed, 3 Apr 2024 02:00:46 +0300 Subject: [PATCH 11/29] Fixed conditional rendering logic for app bar in AppLayout widget Update the condition to check for the presence of spaces in HomeCubit instance before displaying the DefaultAppBar component. This improves readability and maintainability of the code. --- lib/features/app_layout/view/app_layout.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/features/app_layout/view/app_layout.dart b/lib/features/app_layout/view/app_layout.dart index c132c50..d266660 100644 --- a/lib/features/app_layout/view/app_layout.dart +++ b/lib/features/app_layout/view/app_layout.dart @@ -41,8 +41,9 @@ class AppLayout extends StatelessWidget { backgroundColor: ColorsManager.backgroundColor, extendBodyBehindAppBar: true, extendBody: true, - appBar: - state is GetSpacesLoaded ? const DefaultAppBar() : null, + appBar: HomeCubit.getInstance().spaces != null + ? const DefaultAppBar() + : null, body: const AppBody(), bottomNavigationBar: const DefaultNavBar(), // floatingActionButton: FloatingActionButton( From 5ff5f65549ac7bdf333156b5c2364feb04f80629 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Wed, 3 Apr 2024 02:12:35 +0300 Subject: [PATCH 12/29] Refactor emit calls to use emitSafe method Replace direct calls to emit with emitSafe method to ensure emitting states only when the cubit is not closed. This helps prevent errors when emitting states after the cubit is closed. --- lib/features/devices/bloc/devices_cubit.dart | 69 +++++++++++--------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index 9432f11..7361415 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -39,11 +39,18 @@ class DevicesCubit extends Cubit { // return _instance!; // } - // @override - // Future close() { - // _isClosed = true; - // return super.close(); - // } + @override + Future close() { + _isClosed = true; + return super.close(); + } + + void emitSafe(DevicesState newState) { + final cubit = this; + if (!cubit.isClosed) { + cubit.emit(newState); + } + } static DevicesCubit get(context) => BlocProvider.of(context); @@ -57,14 +64,14 @@ class DevicesCubit extends Cubit { allCategories![i].isSelected = false; } } - emit(DevicesCategoryChanged()); + emitSafe(DevicesCategoryChanged()); } unselectAllCategories() { for (var category in allCategories!) { category.isSelected = false; } - emit(DevicesCategoryChanged()); + emitSafe(DevicesCategoryChanged()); } Widget? get chosenCategoryView { @@ -108,14 +115,14 @@ class DevicesCubit extends Cubit { for (var device in category.devices!) { if (device.isSelected) { category.isSelected = false; - emit(DeviceSelected()); + emitSafe(DeviceSelected()); return; } } } } device.isSelected = !device.isSelected; - emit(DeviceSelected()); + emitSafe(DeviceSelected()); } DeviceModel? getSelectedDevice() { @@ -149,7 +156,7 @@ class DevicesCubit extends Cubit { } updateDevicesStatus(category); - emit(CategorySwitchChanged()); + emitSafe(CategorySwitchChanged()); } turnOnOffDevice(DeviceModel device) { @@ -162,7 +169,7 @@ class DevicesCubit extends Cubit { } }); updateDevicesStatus(category); - emit(DeviceSwitchChanged()); + emitSafe(DeviceSwitchChanged()); } updateDevicesStatus(DevicesCategoryModel category) { @@ -173,15 +180,15 @@ class DevicesCubit extends Cubit { //check if there any ac have a different status than the initial ==> turn off the universal switch if (ac.isOnline != tempStatus) { category.devicesStatus = null; - emit(DeviceSwitchChanged()); + emitSafe(DeviceSwitchChanged()); return; } category.devicesStatus = tempStatus; - emit(DeviceSwitchChanged()); + emitSafe(DeviceSwitchChanged()); } } else { category.devicesStatus = null; - emit(DeviceSwitchChanged()); + emitSafe(DeviceSwitchChanged()); } } } @@ -194,7 +201,7 @@ class DevicesCubit extends Cubit { } changeCategorySwitchValue(category); updateDevicesStatus(category); - emit(CategorySwitchChanged()); + emitSafe(CategorySwitchChanged()); } } } @@ -207,7 +214,7 @@ class DevicesCubit extends Cubit { } changeCategorySwitchValue(category); updateDevicesStatus(category); - emit(CategorySwitchChanged()); + emitSafe(CategorySwitchChanged()); } } } @@ -217,7 +224,7 @@ class DevicesCubit extends Cubit { for (var device in category.devices!) { if (device.isOnline ?? false) { category.devicesStatus = false; - emit(CategorySwitchChanged()); + emitSafe(CategorySwitchChanged()); return; } } @@ -235,16 +242,16 @@ class DevicesCubit extends Cubit { } Navigator.popUntil(context, (route) => route.isFirst); - emit(DevicesCategoryChanged()); + emitSafe(DevicesCategoryChanged()); } deviceControl(DeviceControlModel control) async { - emit(DeviceControlLoading()); + emitSafe(DeviceControlLoading()); try { await DevicesAPI.controlDevice(control); - emit(DeviceControlSuccess()); + emitSafe(DeviceControlSuccess()); } on DioException catch (e) { - emit(DeviceControlError(ServerFailure.fromDioError(e).errMessage)); + emitSafe(DeviceControlError(ServerFailure.fromDioError(e).errMessage)); } } @@ -252,11 +259,11 @@ class DevicesCubit extends Cubit { if (_isClosed) return; try { - emit(DevicesCategoriesLoading()); + emitSafe(DevicesCategoriesLoading()); allCategories = await DevicesAPI.fetchGroups(spaceId); - emit(DevicesCategoriesSuccess()); + emitSafe(DevicesCategoriesSuccess()); } on DioException catch (error) { - emit( + emitSafe( DevicesCategoriesError(ServerFailure.fromDioError(error).errMessage), ); } @@ -266,7 +273,7 @@ class DevicesCubit extends Cubit { if (_isClosed) return; try { - emit(GetDevicesLoading()); + emitSafe(GetDevicesLoading()); int roomIndex = HomeCubit.getInstance() .selectedSpace! .rooms! @@ -274,9 +281,9 @@ class DevicesCubit extends Cubit { HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices = await SpacesAPI.getDevicesByRoomId(roomId); - emit(GetDevicesSuccess()); + emitSafe(GetDevicesSuccess()); } on DioException catch (error) { - emit( + emitSafe( GetDevicesError(ServerFailure.fromDioError(error).errMessage), ); } @@ -303,17 +310,17 @@ class DevicesCubit extends Cubit { // setLightingMode(DeviceModel light, LightMode mode) { // light.lightingMode = // lightModes.entries.firstWhere((element) => element.value == mode).key; -// emit(LightModeChanged(mode)); +// emitSafe(LightModeChanged(mode)); // } // // toggleLight(DeviceModel light) { // light.isOnline != null ? light.isOnline = !light.isOnline! : light.isOnline = true; -// emit(LightToggled(light)); +// emitSafe(LightToggled(light)); // } // // setColor(DeviceModel light, int color) { // light.color = color; -// emit(LightColorChanged(color)); +// emitSafe(LightColorChanged(color)); // } // // int getBrightness(DeviceModel light) { @@ -324,7 +331,7 @@ class DevicesCubit extends Cubit { // value = (value / 5).ceil() * 5; // if (value != light.brightness) { // light.brightness = value; -// emit(LightBrightnessChanged(value)); +// emitSafe(LightBrightnessChanged(value)); // } // } } From e49627d3e1c6aa87e85a8a2ce3b696faa94ec9ec Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Wed, 3 Apr 2024 11:07:55 +0300 Subject: [PATCH 13/29] Add status model and fetch device statuses Added a new StatusModel class to represent device statuses and implemented functionality to fetch and update device statuses in the DevicesCubit and DeviceModel classes. Also updated UI components to display device status information. --- lib/features/devices/bloc/devices_cubit.dart | 40 +++++++++++++++++++ lib/features/devices/bloc/devices_state.dart | 10 +++++ lib/features/devices/model/device_model.dart | 31 ++++++++------ lib/features/devices/model/status_model.dart | 23 +++++++++++ .../widgets/ACs/ac_interface_temp_unit.dart | 9 ++++- .../widgets/ACs/ac_mode_control_unit.dart | 40 ++++++++++--------- lib/services/api/api_links_endpoints.dart | 2 + lib/services/api/devices_api.dart | 11 +++++ 8 files changed, 134 insertions(+), 32 deletions(-) create mode 100644 lib/features/devices/model/status_model.dart diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index 7361415..db7794b 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -8,6 +8,7 @@ import 'package:syncrow_app/features/app_layout/model/space_model.dart'; import 'package:syncrow_app/features/devices/model/device_category_model.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; +import 'package:syncrow_app/features/devices/model/status_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart'; @@ -280,6 +281,13 @@ class DevicesCubit extends Cubit { .indexWhere((element) => element.id == roomId); HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices = await SpacesAPI.getDevicesByRoomId(roomId); + //get status for each device + for (var device in HomeCubit.getInstance() + .selectedSpace! + .rooms![roomIndex] + .devices!) { + getDevicesStatues(device.id!, roomIndex); + } emitSafe(GetDevicesSuccess()); } on DioException catch (error) { @@ -289,6 +297,38 @@ class DevicesCubit extends Cubit { } } + getDevicesStatues(String deviceId, int roomIndex) async { + if (_isClosed) return; + + try { + emitSafe(GetDeviceStatusLoading()); + int deviceIndex = HomeCubit.getInstance() + .selectedSpace! + .rooms![roomIndex] + .devices! + .indexWhere((element) => element.id == deviceId); + + List statuses = []; + var response = await DevicesAPI.getDeviceStatus(deviceId); + print('response : $response'); + + for (var status in response['result']['status']) { + statuses.add(StatusModel.fromJson(status)); + } + + HomeCubit.getInstance() + .selectedSpace! + .rooms![roomIndex] + .devices![deviceIndex] + .status = statuses; + emitSafe(GetDeviceStatusSuccess()); + } on DioException catch (error) { + emitSafe( + GetDeviceStatusError(ServerFailure.fromDioError(error).errMessage), + ); + } + } + ///Lights onHorizontalDragUpdate(DeviceModel light, double dx, double screenWidth) { double newBrightness = (dx / (screenWidth - 15) * 100); diff --git a/lib/features/devices/bloc/devices_state.dart b/lib/features/devices/bloc/devices_state.dart index 4fd8b2d..3375450 100644 --- a/lib/features/devices/bloc/devices_state.dart +++ b/lib/features/devices/bloc/devices_state.dart @@ -15,6 +15,16 @@ class ChangeIndex extends DevicesState {} // Devices +class GetDeviceStatusLoading extends DevicesState {} + +class GetDeviceStatusSuccess extends DevicesState {} + +class GetDeviceStatusError extends DevicesState { + final String errorMsg; + + GetDeviceStatusError(this.errorMsg); +} + class GetDevicesLoading extends DevicesState {} class GetDevicesSuccess extends DevicesState {} diff --git a/lib/features/devices/model/device_model.dart b/lib/features/devices/model/device_model.dart index fec6858..22a7c04 100644 --- a/lib/features/devices/model/device_model.dart +++ b/lib/features/devices/model/device_model.dart @@ -1,27 +1,29 @@ import 'package:syncrow_app/features/devices/model/function_model.dart'; +import 'package:syncrow_app/features/devices/model/status_model.dart'; import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; class DeviceModel { int? activeTime; - String? category; - String? categoryName; - int? createTime; - String? gatewayId; - String? icon; + String? category; //unused + String? categoryName; //unused + int? createTime; //unused + String? gatewayId; //unused + String? icon; //unused String? id; - String? ip; - double? lat; + String? ip; //unused + double? lat; //unused String? localKey; - double? lon; + double? lon; //unused String? model; String? name; - String? nodeId; //rmeove + String? nodeId; //remove bool? isOnline; - String? ownerId; //remove - String? productId; //remove + List status = []; + String? ownerId; //unused + String? productId; //unused String? productName; - bool? isSub; + bool? isSub; //unused String? timeZone; int? updateTime; String? uuid; @@ -44,6 +46,7 @@ class DeviceModel { this.name, this.nodeId, this.isOnline, + required this.status, this.ownerId, this.productId, this.productName, @@ -102,6 +105,10 @@ class DeviceModel { updateTime: json['updateTime'], uuid: json['uuid'], productType: type, + status: [], + // json['status'] + // .map((e) => StatusModel.fromJson(e)) + // .toList(), // devicesTypesMap[json['productName']] ?? DeviceType.Other, ); } diff --git a/lib/features/devices/model/status_model.dart b/lib/features/devices/model/status_model.dart new file mode 100644 index 0000000..0d22625 --- /dev/null +++ b/lib/features/devices/model/status_model.dart @@ -0,0 +1,23 @@ +class StatusModel { + String? code; + dynamic value; + + StatusModel({ + required this.code, + required this.value, + }); + + factory StatusModel.fromJson(Map json) { + return StatusModel( + code: json['code'], + value: json['value'], + ); + } + + Map toJson() { + return { + 'code': code, + 'value': value, + }; + } +} diff --git a/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart b/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart index 52c471a..e5cbcf0 100644 --- a/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart +++ b/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart @@ -72,7 +72,11 @@ class AcInterfaceTempUnit extends StatelessWidget { ), // min: DeviceModel.bounds.min, // max: DeviceModel.bounds.max, - // initialValue: DeviceModel.temperature, + initialValue: deviceModel.status + .firstWhere( + (element) => element.code == 'temp_current') + .value / + 10, onChange: (value) { String valueAsString = value.toStringAsFixed(1); if (valueAsString.endsWith(".0") || @@ -107,7 +111,8 @@ class AcInterfaceTempUnit extends StatelessWidget { children: [ BodyLarge( // text: "${DeviceModel.coolTo}° C", - text: '24° C', + text: + '${deviceModel.status.firstWhere((element) => element.code == 'temp_set').value / 10}° C', style: context.bodyLarge.copyWith( color: ColorsManager.primaryColor.withOpacity(0.6), diff --git a/lib/features/devices/view/widgets/ACs/ac_mode_control_unit.dart b/lib/features/devices/view/widgets/ACs/ac_mode_control_unit.dart index e1f9416..b82e685 100644 --- a/lib/features/devices/view/widgets/ACs/ac_mode_control_unit.dart +++ b/lib/features/devices/view/widgets/ACs/ac_mode_control_unit.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; @@ -17,18 +18,18 @@ class ACModeControlUnit extends StatefulWidget { } class _ACModeControlUnitState extends State { - var fanSpeeds = [ - Assets.iconsFan0, - Assets.iconsFan1, - Assets.iconsFan2, - Assets.iconsFan3, - ]; + Map fanSpeedsMap = { + 'auto': Assets.iconsFan0, + 'iconsFan1': Assets.iconsFan1, + 'iconsFan2': Assets.iconsFan2, + 'iconsFan3': Assets.iconsFan3, + }; - var tempModes = [ - Assets.iconsSunnyMode, - Assets.iconsColdMode, - Assets.iconsWindyMode, - ]; + Map tempModesMap = { + 'sunny': Assets.iconsSunnyMode, + 'cold': Assets.iconsColdMode, + 'windy': Assets.iconsWindyMode, + }; @override Widget build(BuildContext context) { @@ -43,11 +44,13 @@ class _ACModeControlUnitState extends State { // widget.model.fanSpeed == 3 ? 0 : widget.model.fanSpeed + 1; }); }, - child: const DefaultContainer( + child: DefaultContainer( height: 55, child: Center( - // child: SvgPicture.asset(fanSpeeds[widget.model.fanSpeed]), - ), + child: SvgPicture.asset(fanSpeedsMap[widget.model.status + .firstWhere((element) => element.code == 'level') + .value]!), + ), ), ), ), @@ -60,12 +63,13 @@ class _ACModeControlUnitState extends State { // widget.model.tempMode == 2 ? 0 : widget.model.tempMode + 1; }); }, - child: const DefaultContainer( + child: DefaultContainer( height: 55, child: Center( - // child: SvgPicture.asset(tempModes[widget.model.tempMode]), - - ), + child: SvgPicture.asset(tempModesMap[widget.model.status + .firstWhere((element) => element.code == 'mode') + .value]!), + ), ), ), ), diff --git a/lib/services/api/api_links_endpoints.dart b/lib/services/api/api_links_endpoints.dart index f249a1d..6e5efc0 100644 --- a/lib/services/api/api_links_endpoints.dart +++ b/lib/services/api/api_links_endpoints.dart @@ -17,6 +17,8 @@ abstract class ApiEndpoints { // Devices static const String control = '$baseUrl/device/control'; static const String devicesByRoom = '$baseUrl/device/room'; + // static const String deviceStatus = '$baseUrl/device/status/'; + static const String deviceStatus = '$baseUrl/device/'; //groups static const String groups = '$baseUrl/group'; diff --git a/lib/services/api/devices_api.dart b/lib/services/api/devices_api.dart index cf885e8..57e2ac1 100644 --- a/lib/services/api/devices_api.dart +++ b/lib/services/api/devices_api.dart @@ -34,4 +34,15 @@ class DevicesAPI { ); return response; } + + static Future> getDeviceStatus(String deviceId) async { + final response = await _httpService.get( + path: '${ApiEndpoints.deviceStatus}/$deviceId/functions/status', + showServerMessage: false, + expectedResponseModel: (json) { + return json; + }, + ); + return response; + } } From 65776527027c18d911e9bfad3f728d293a66882f Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Wed, 3 Apr 2024 18:53:54 +0300 Subject: [PATCH 14/29] Refactor AC mode control unit widget Move fan speed and temperature mode logic to the DevicesCubit for better separation of concerns and improved code readability. Update widget to use BlocBuilder for state management and simplify control logic. --- lib/features/devices/bloc/devices_cubit.dart | 51 ++++--- lib/features/devices/bloc/devices_state.dart | 24 +++- .../devices/model/device_control_model.dart | 2 +- .../view/widgets/ACs/ac_interface.dart | 125 ++++++++++-------- .../widgets/ACs/ac_mode_control_unit.dart | 125 ++++++++++-------- 5 files changed, 197 insertions(+), 130 deletions(-) diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index db7794b..6449d93 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -23,7 +23,7 @@ import 'package:syncrow_app/utils/resource_manager/constants.dart'; part 'devices_state.dart'; class DevicesCubit extends Cubit { - DevicesCubit() : super(DevicesInitial()) { + DevicesCubit._() : super(DevicesInitial()) { if (HomeCubit.getInstance().selectedSpace != null) { fetchGroups(HomeCubit.getInstance().selectedSpace!.id!); for (var room in HomeCubit.getInstance().selectedSpace!.rooms!) { @@ -33,16 +33,19 @@ class DevicesCubit extends Cubit { } bool _isClosed = false; - // static DevicesCubit? _instance; - // static DevicesCubit.get(context) { - // // If an instance already exists, return it - // _instance ??= DevicesCubit._(); - // return _instance!; - // } + static DevicesCubit? _instance; + static DevicesCubit getInstance() { + // If an instance already exists, return it + _instance ??= DevicesCubit._(); + return _instance!; + } + + DeviceModel? selectedDevice; @override Future close() { _isClosed = true; + _instance = null; return super.close(); } @@ -246,11 +249,28 @@ class DevicesCubit extends Cubit { emitSafe(DevicesCategoryChanged()); } - deviceControl(DeviceControlModel control) async { - emitSafe(DeviceControlLoading()); +///////////////////////// API CALLS ////////////////////////// + deviceControl(DeviceControlModel control, String deviceId) async { + emitSafe(DeviceControlLoading( + code: control.code, + )); try { - await DevicesAPI.controlDevice(control); - emitSafe(DeviceControlSuccess()); + await DevicesAPI.controlDevice(control).then((value) { + emitSafe(DeviceControlSuccess( + code: control.code, + )); + if (value['result'] ?? false) { + Future.delayed(const Duration(milliseconds: 400), () { + getDevicesStatues( + deviceId, + HomeCubit.getInstance().selectedSpace!.rooms!.indexOf( + HomeCubit.getInstance().selectedRoom!, + ), + code: control.code, + ); + }); + } + }); } on DioException catch (e) { emitSafe(DeviceControlError(ServerFailure.fromDioError(e).errMessage)); } @@ -297,11 +317,11 @@ class DevicesCubit extends Cubit { } } - getDevicesStatues(String deviceId, int roomIndex) async { + getDevicesStatues(String deviceId, int roomIndex, {String? code}) async { if (_isClosed) return; try { - emitSafe(GetDeviceStatusLoading()); + emitSafe(GetDeviceStatusLoading(code: code)); int deviceIndex = HomeCubit.getInstance() .selectedSpace! .rooms![roomIndex] @@ -310,7 +330,8 @@ class DevicesCubit extends Cubit { List statuses = []; var response = await DevicesAPI.getDeviceStatus(deviceId); - print('response : $response'); + // if (response['result']['status'].length > 4) + // print('response : ${response['result']['status'][4]}'); for (var status in response['result']['status']) { statuses.add(StatusModel.fromJson(status)); @@ -321,7 +342,7 @@ class DevicesCubit extends Cubit { .rooms![roomIndex] .devices![deviceIndex] .status = statuses; - emitSafe(GetDeviceStatusSuccess()); + emitSafe(GetDeviceStatusSuccess(code: code)); } on DioException catch (error) { emitSafe( GetDeviceStatusError(ServerFailure.fromDioError(error).errMessage), diff --git a/lib/features/devices/bloc/devices_state.dart b/lib/features/devices/bloc/devices_state.dart index 3375450..4f89268 100644 --- a/lib/features/devices/bloc/devices_state.dart +++ b/lib/features/devices/bloc/devices_state.dart @@ -15,9 +15,17 @@ class ChangeIndex extends DevicesState {} // Devices -class GetDeviceStatusLoading extends DevicesState {} +class GetDeviceStatusLoading extends DevicesState { + final String? code; -class GetDeviceStatusSuccess extends DevicesState {} + GetDeviceStatusLoading({this.code}); +} + +class GetDeviceStatusSuccess extends DevicesState { + final String? code; + + GetDeviceStatusSuccess({this.code}); +} class GetDeviceStatusError extends DevicesState { final String errorMsg; @@ -44,9 +52,17 @@ class DeviceSwitchChanged extends DevicesState {} class DeviceSelected extends DevicesState {} // Device Control -class DeviceControlLoading extends DevicesState {} +class DeviceControlLoading extends DevicesState { + final String? code; -class DeviceControlSuccess extends DevicesState {} + DeviceControlLoading({this.code}); +} + +class DeviceControlSuccess extends DevicesState { + final String? code; + + DeviceControlSuccess({this.code}); +} class DeviceControlError extends DevicesState { final String errorMsg; diff --git a/lib/features/devices/model/device_control_model.dart b/lib/features/devices/model/device_control_model.dart index 8f9edf7..58a6476 100644 --- a/lib/features/devices/model/device_control_model.dart +++ b/lib/features/devices/model/device_control_model.dart @@ -1,7 +1,7 @@ class DeviceControlModel { String? deviceId; String? code; - bool? value; + dynamic value; DeviceControlModel({ required this.deviceId, diff --git a/lib/features/devices/view/widgets/ACs/ac_interface.dart b/lib/features/devices/view/widgets/ACs/ac_interface.dart index 0bf1fb1..c0ac062 100644 --- a/lib/features/devices/view/widgets/ACs/ac_interface.dart +++ b/lib/features/devices/view/widgets/ACs/ac_interface.dart @@ -24,65 +24,78 @@ class AcInterface extends StatelessWidget { statusBarIconBrightness: Brightness.light, ), child: SafeArea( - child: Scaffold( - backgroundColor: ColorsManager.backgroundColor, - extendBodyBehindAppBar: true, - extendBody: true, - appBar: AppBar( - backgroundColor: Colors.transparent, - centerTitle: true, - title: BodyLarge( - text: deviceModel.name ?? "", - fontColor: ColorsManager.primaryColor, - fontWeight: FontsManager.bold, - ), - ), - body: Container( - width: MediaQuery.sizeOf(context).width, - height: MediaQuery.sizeOf(context).height, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage( - Assets.imagesBackground, + child: BlocConsumer( + listener: (context, state) { + if (state is DeviceControlError) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(state.errorMsg), ), - fit: BoxFit.cover, - opacity: 0.4, - ), - ), - child: Padding( - padding: EdgeInsets.only( - top: Constants.appBarHeight, - left: Constants.defaultPadding, - right: Constants.defaultPadding, - ), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - ConstrainedBox( - constraints: const BoxConstraints( - maxHeight: 380, - ), - child: AcInterfaceTempUnit( - deviceModel: deviceModel, - ), - ), - const SizedBox( - height: 10, - ), - ConstrainedBox( - constraints: const BoxConstraints( - maxHeight: 120, - ), - child: AcInterfaceControls( - deviceModel: deviceModel, - ), - ), - ], + ); + } + }, + builder: (context, state) { + return Scaffold( + backgroundColor: ColorsManager.backgroundColor, + extendBodyBehindAppBar: true, + extendBody: true, + appBar: AppBar( + backgroundColor: Colors.transparent, + centerTitle: true, + title: BodyLarge( + text: deviceModel.name ?? "", + fontColor: ColorsManager.primaryColor, + fontWeight: FontsManager.bold, ), ), - ), - ), + body: Container( + width: MediaQuery.sizeOf(context).width, + height: MediaQuery.sizeOf(context).height, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage( + Assets.imagesBackground, + ), + fit: BoxFit.cover, + opacity: 0.4, + ), + ), + child: Padding( + padding: EdgeInsets.only( + top: Constants.appBarHeight, + left: Constants.defaultPadding, + right: Constants.defaultPadding, + ), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ConstrainedBox( + constraints: const BoxConstraints( + maxHeight: 380, + ), + child: AcInterfaceTempUnit( + deviceModel: deviceModel, + ), + ), + const SizedBox( + height: 10, + ), + ConstrainedBox( + constraints: const BoxConstraints( + maxHeight: 120, + ), + child: AcInterfaceControls( + deviceModel: deviceModel, + ), + ), + ], + ), + ), + ), + ), + ); + }, ), ), ); diff --git a/lib/features/devices/view/widgets/ACs/ac_mode_control_unit.dart b/lib/features/devices/view/widgets/ACs/ac_mode_control_unit.dart index b82e685..1260eec 100644 --- a/lib/features/devices/view/widgets/ACs/ac_mode_control_unit.dart +++ b/lib/features/devices/view/widgets/ACs/ac_mode_control_unit.dart @@ -1,79 +1,96 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; +import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; - -import '../../../../../generated/assets.dart'; +import 'package:syncrow_app/utils/resource_manager/constants.dart'; class ACModeControlUnit extends StatefulWidget { const ACModeControlUnit({ super.key, - required this.model, + required this.acDevice, }); - final DeviceModel model; + final DeviceModel acDevice; @override State createState() => _ACModeControlUnitState(); } class _ACModeControlUnitState extends State { - Map fanSpeedsMap = { - 'auto': Assets.iconsFan0, - 'iconsFan1': Assets.iconsFan1, - 'iconsFan2': Assets.iconsFan2, - 'iconsFan3': Assets.iconsFan3, - }; - - Map tempModesMap = { - 'sunny': Assets.iconsSunnyMode, - 'cold': Assets.iconsColdMode, - 'windy': Assets.iconsWindyMode, - }; - @override Widget build(BuildContext context) { - //TODO Move the fanSpeeds and tempModes to the Cubit - return Row( - children: [ - Flexible( - child: InkWell( - onTap: () { - setState(() { - // widget.model.fanSpeed = - // widget.model.fanSpeed == 3 ? 0 : widget.model.fanSpeed + 1; - }); - }, - child: DefaultContainer( - height: 55, - child: Center( - child: SvgPicture.asset(fanSpeedsMap[widget.model.status - .firstWhere((element) => element.code == 'level') - .value]!), + return BlocBuilder( + builder: (context, state) { + FanSpeeds fanSpeed = fanSpeedsMap[widget.acDevice.status + .firstWhere((element) => element.code == 'level') + .value]!; + TempModes tempMode = tempModesMap[widget.acDevice.status + .firstWhere((element) => element.code == 'mode') + .value]!; + return Row( + children: [ + Flexible( + child: InkWell( + onTap: () { + // print( + // '\n\ncurrentFanSpeed:$fanSpeed \nchanged to:\t${fanSpeedsMap[getNextFanSpeedKey(fanSpeed)]!}\nKey:\t\t\"${reversedFanSpeedsMap[fanSpeedsMap[getNextFanSpeedKey(fanSpeed)]!]!}\"'); + + fanSpeed = fanSpeedsMap[getNextFanSpeedKey(fanSpeed)]!; + + DevicesCubit.getInstance().deviceControl( + DeviceControlModel( + deviceId: widget.acDevice.id, + code: 'level', + value: reversedFanSpeedsMap[fanSpeed]!), + widget.acDevice.id!); + }, + child: DefaultContainer( + height: 55, + child: Center( + child: state is GetDeviceStatusLoading && + state.code == 'level' || + state is DeviceControlSuccess && + state.code == 'level' || + state is DeviceControlLoading && + state.code == 'level' + ? const CircularProgressIndicator() + : SvgPicture.asset(fanSpeedsIconMap[fanSpeed]!)), + ), ), ), - ), - ), - const SizedBox(width: 10), - Flexible( - child: InkWell( - onTap: () { - setState(() { - // widget.model.tempMode = - // widget.model.tempMode == 2 ? 0 : widget.model.tempMode + 1; - }); - }, - child: DefaultContainer( - height: 55, - child: Center( - child: SvgPicture.asset(tempModesMap[widget.model.status - .firstWhere((element) => element.code == 'mode') - .value]!), + const SizedBox(width: 10), + Flexible( + child: InkWell( + onTap: () { + tempMode = tempModesMap[getNextItem(tempModesMap, tempMode)]!; + DevicesCubit.getInstance().deviceControl( + DeviceControlModel( + deviceId: widget.acDevice.id, + code: 'mode', + value: reversedTempModesMap[tempMode]!), + widget.acDevice.id!); + }, + child: DefaultContainer( + height: 55, + child: Center( + child: state is GetDeviceStatusLoading && + state.code == 'mode' || + state is DeviceControlSuccess && + state.code == 'mode' || + state is DeviceControlLoading && + state.code == 'mode' + ? const CircularProgressIndicator() + : SvgPicture.asset(tempModesIconMap[tempMode]!), + ), + ), ), ), - ), - ), - ], + ], + ); + }, ); } } From bff4b9493ce8c3314e1923be9bb51530d558e17e Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Wed, 3 Apr 2024 18:54:21 +0300 Subject: [PATCH 15/29] Refactor device control logic and add temperature and fan speed enums - Refactor device control logic in the app to improve readability and maintainability. - Add temperature modes (hot, cold, wind) and fan speeds (auto, low, middle, high) enums. - Update icon mappings and utility functions for temperature modes and fan speeds. --- lib/features/app_layout/bloc/home_cubit.dart | 35 ++++++---- .../view/widgets/default_nav_bar.dart | 6 +- .../widgets/ACs/ac_interface_controls.dart | 58 +++++++++------- .../widgets/ACs/ac_interface_temp_unit.dart | 6 +- .../view/widgets/ACs/ac_temp_widget.dart | 4 +- .../devices/view/widgets/ACs/acs_list.dart | 15 ++-- .../devices/view/widgets/ACs/acs_view.dart | 4 +- .../widgets/ACs/category_view_app_bar.dart | 4 +- .../view/widgets/ACs/universal_ac_temp.dart | 4 +- .../view/widgets/curtains/curtain_list.dart | 11 +-- .../view/widgets/lights/light_brightness.dart | 2 +- .../widgets/lights/light_interface_modes.dart | 6 +- .../lights/light_interface_recent_color.dart | 2 +- .../lights/light_interface_slider.dart | 2 +- .../lights/light_interface_switch.dart | 2 +- .../view/widgets/lights/lights_list.dart | 2 +- .../view/widgets/lights/lights_view.dart | 4 +- .../devices/view/widgets/room_page.dart | 2 +- .../view/widgets/room_page_switch.dart | 6 +- .../view/widgets/three_gang/gang_switch.dart | 20 +++--- .../three_gang/three_gang_interface.dart | 3 - .../view/widgets/universal_switch.dart | 4 +- .../devices/view/widgets/wizard_switches.dart | 4 +- .../shared_widgets/custom_switch.dart | 4 +- .../devices_default_switch.dart | 4 +- lib/my_app.dart | 1 - lib/navigation/router.dart | 3 - lib/services/api/devices_api.dart | 2 + lib/services/api/network_exception.dart | 1 - lib/utils/resource_manager/constants.dart | 69 +++++++++++++++++++ 30 files changed, 183 insertions(+), 107 deletions(-) diff --git a/lib/features/app_layout/bloc/home_cubit.dart b/lib/features/app_layout/bloc/home_cubit.dart index 6021f2a..cac7a5c 100644 --- a/lib/features/app_layout/bloc/home_cubit.dart +++ b/lib/features/app_layout/bloc/home_cubit.dart @@ -18,8 +18,6 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; part 'home_state.dart'; class HomeCubit extends Cubit { - // Create a private static instance variable - HomeCubit._() : super(HomeInitial()) { if (selectedSpace == null) { fetchSpaces().then((value) { @@ -37,6 +35,13 @@ class HomeCubit extends Cubit { return _instance!; } + void emitSafe(HomeState newState) { + final cubit = this; + if (!cubit.isClosed) { + cubit.emit(newState); + } + } + static HomeCubit get(context) => BlocProvider.of(context); List? spaces; @@ -58,7 +63,7 @@ class HomeCubit extends Cubit { changeSelectedSpace(SpaceModel space) { selectedSpace = space; - emit(SpaceSelected(space)); + emitSafe(SpaceSelected(space)); } roomSliderPageChanged(int index) { @@ -72,7 +77,7 @@ class HomeCubit extends Cubit { unselectRoom(); } else { selectedRoom = selectedSpace!.rooms![index - 1]; - emit(RoomSelected(selectedRoom!)); + emitSafe(RoomSelected(selectedRoom!)); } } @@ -87,7 +92,7 @@ class HomeCubit extends Cubit { unselectRoom(); } else { selectedRoom = selectedSpace!.rooms![index - 1]; - emit(RoomSelected(selectedRoom!)); + emitSafe(RoomSelected(selectedRoom!)); } } @@ -105,11 +110,11 @@ class HomeCubit extends Cubit { curve: Curves.linear, ); - emit(RoomUnSelected()); + emitSafe(RoomUnSelected()); } fetchSpaces() async { - emit(GetSpacesLoading()); + emitSafe(GetSpacesLoading()); try { spaces = await SpacesAPI.getSpaces(); selectedSpace = spaces!.isNotEmpty @@ -117,23 +122,23 @@ class HomeCubit extends Cubit { // selectSpace(spaces!.first) selectedSpace = spaces!.first : null; - emit(GetSpacesLoaded(spaces!)); + emitSafe(GetSpacesLoaded(spaces!)); } on DioException catch (e) { - emit(GetSpacesError(ServerFailure.fromDioError(e).errMessage)); + emitSafe(GetSpacesError(ServerFailure.fromDioError(e).errMessage)); } } fetchRooms(SpaceModel space) async { - emit(GetSpaceRoomsLoading()); + emitSafe(GetSpaceRoomsLoading()); try { space.rooms = await SpacesAPI.getRoomsBySpaceId(space.id!); if (space.rooms != null) { - emit(GetSpaceRoomsLoaded(space.rooms!)); + emitSafe(GetSpaceRoomsLoaded(space.rooms!)); } else { - emit(GetSpaceRoomsError("No rooms found")); + emitSafe(GetSpaceRoomsError("No rooms found")); } } on DioException catch (e) { - emit(GetSpacesError(ServerFailure.fromDioError(e).errMessage)); + emitSafe(GetSpacesError(ServerFailure.fromDioError(e).errMessage)); } } @@ -262,7 +267,7 @@ class HomeCubit extends Cubit { const DashboardView(), // const LayoutPage(), BlocProvider( - create: (context) => DevicesCubit(), + create: (context) => DevicesCubit.getInstance(), child: const DevicesViewBody(), ), const SceneView(), @@ -272,7 +277,7 @@ class HomeCubit extends Cubit { void updatePageIndex(int index) { pageIndex = index; - emit(NavChangePage()); + emitSafe(NavChangePage()); } } diff --git a/lib/features/app_layout/view/widgets/default_nav_bar.dart b/lib/features/app_layout/view/widgets/default_nav_bar.dart index 604d018..4076195 100644 --- a/lib/features/app_layout/view/widgets/default_nav_bar.dart +++ b/lib/features/app_layout/view/widgets/default_nav_bar.dart @@ -14,7 +14,7 @@ class DefaultNavBar extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => DevicesCubit(), + create: (context) => DevicesCubit.getInstance(), child: BlocBuilder( builder: (context, state) { return BlocBuilder( @@ -26,8 +26,8 @@ class DefaultNavBar extends StatelessWidget { backgroundColor: Colors.transparent, onTap: (int index) { cubit.updatePageIndex(index); - if (DevicesCubit.get(context).chosenCategoryView != null) { - DevicesCubit.get(context) + if (DevicesCubit.getInstance().chosenCategoryView != null) { + DevicesCubit.getInstance() .clearCategoriesSelection(context); } if (HomeCubit.getInstance().selectedRoom != null) { diff --git a/lib/features/devices/view/widgets/ACs/ac_interface_controls.dart b/lib/features/devices/view/widgets/ACs/ac_interface_controls.dart index 16968a5..0714bc1 100644 --- a/lib/features/devices/view/widgets/ACs/ac_interface_controls.dart +++ b/lib/features/devices/view/widgets/ACs/ac_interface_controls.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_mode_control_unit.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; @@ -16,38 +18,42 @@ class AcInterfaceControls extends StatelessWidget { @override Widget build(BuildContext context) { - return Column( - children: [ - ACModeControlUnit(model: deviceModel), - const SizedBox(height: 10), - Row( + return BlocBuilder( + builder: (context, state) { + return Column( children: [ - Flexible( - child: InkWell( - onTap: () {}, - child: DefaultContainer( - height: 55, - child: Center( - child: SvgPicture.asset(Assets.iconsAutomatedClock), + ACModeControlUnit(acDevice: deviceModel), + const SizedBox(height: 10), + Row( + children: [ + Flexible( + child: InkWell( + onTap: () {}, + child: DefaultContainer( + height: 55, + child: Center( + child: SvgPicture.asset(Assets.iconsAutomatedClock), + ), + ), ), ), - ), - ), - const SizedBox(width: 10), - Flexible( - child: InkWell( - onTap: () {}, - child: DefaultContainer( - height: 55, - child: Center( - child: SvgPicture.asset(Assets.iconsLock), + const SizedBox(width: 10), + Flexible( + child: InkWell( + onTap: () {}, + child: DefaultContainer( + height: 55, + child: Center( + child: SvgPicture.asset(Assets.iconsLock), + ), + ), ), ), - ), - ), + ], + ) ], - ) - ], + ); + }, ); } } diff --git a/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart b/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart index e5cbcf0..562b005 100644 --- a/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart +++ b/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart @@ -82,7 +82,7 @@ class AcInterfaceTempUnit extends StatelessWidget { if (valueAsString.endsWith(".0") || valueAsString.endsWith(".5")) { value = double.parse(valueAsString); - // DevicesCubit.get(context) + // DevicesCubit.getInstance() // .setACTemp(DeviceModel, value); } }, @@ -98,7 +98,7 @@ class AcInterfaceTempUnit extends StatelessWidget { dimension: 24, child: InkWell( onTap: () { - // DevicesCubit.get(context) + // DevicesCubit.getInstance() // .setACTemp(DeviceModel, DeviceModel.coolTo); // DeviceModel.coolTo -= .5; }, @@ -130,7 +130,7 @@ class AcInterfaceTempUnit extends StatelessWidget { dimension: 24, child: InkWell( onTap: () { - // DevicesCubit.get(context) + // DevicesCubit.getInstance() // .setACTemp(DeviceModel, DeviceModel.coolTo); // DeviceModel.coolTo += .5; }, diff --git a/lib/features/devices/view/widgets/ACs/ac_temp_widget.dart b/lib/features/devices/view/widgets/ACs/ac_temp_widget.dart index 136c705..0ae8eaf 100644 --- a/lib/features/devices/view/widgets/ACs/ac_temp_widget.dart +++ b/lib/features/devices/view/widgets/ACs/ac_temp_widget.dart @@ -31,7 +31,7 @@ class ACTempWidget extends StatelessWidget { dimension: 24, child: InkWell( onTap: () { - // DevicesCubit.get(context) + // DevicesCubit.getInstance() // .setACTemp(DeviceModel, DeviceModel.temperature - 0.5); }, child: SvgPicture.asset( @@ -51,7 +51,7 @@ class ACTempWidget extends StatelessWidget { dimension: 24, child: InkWell( onTap: () { - // DevicesCubit.get(context) + // DevicesCubit.getInstance() // .setACTemp(DeviceModel, DeviceModel.temperature + 0.5); }, child: SvgPicture.asset( diff --git a/lib/features/devices/view/widgets/ACs/acs_list.dart b/lib/features/devices/view/widgets/ACs/acs_list.dart index 2eb6e07..7c26a54 100644 --- a/lib/features/devices/view/widgets/ACs/acs_list.dart +++ b/lib/features/devices/view/widgets/ACs/acs_list.dart @@ -27,7 +27,7 @@ class ACsList extends StatelessWidget { const BodySmall(text: "All ACs"), const SizedBox(height: 5), UniversalSwitch( - category: DevicesCubit.get(context).chosenCategory!, + category: DevicesCubit.getInstance().chosenCategory!, ), const SizedBox(height: 10), const UniversalACTemp(), @@ -39,10 +39,11 @@ class ACsList extends StatelessWidget { physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.all(0), itemCount: - DevicesCubit.get(context).chosenCategory!.devices!.length, + DevicesCubit.getInstance().chosenCategory!.devices!.length, itemBuilder: (context, index) { - DeviceModel ac = - DevicesCubit.get(context).chosenCategory!.devices![index]; + DeviceModel ac = DevicesCubit.getInstance() + .chosenCategory! + .devices![index]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -51,14 +52,14 @@ class ACsList extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.end, children: [ BodySmall( - text: DevicesCubit.get(context) + text: DevicesCubit.getInstance() .chosenCategory! .devices![index] .name ?? ""), IconButton( onPressed: () { - DevicesCubit.get(context).selectDevice(ac); + DevicesCubit.getInstance().selectDevice(ac); }, icon: const Icon( Icons.arrow_forward_ios, @@ -83,7 +84,7 @@ class ACsList extends StatelessWidget { ), const SizedBox(height: 10), ACModeControlUnit( - model: ac, + acDevice: ac, ), const SizedBox(height: 10), ], diff --git a/lib/features/devices/view/widgets/ACs/acs_view.dart b/lib/features/devices/view/widgets/ACs/acs_view.dart index f22b8ed..358bbca 100644 --- a/lib/features/devices/view/widgets/ACs/acs_view.dart +++ b/lib/features/devices/view/widgets/ACs/acs_view.dart @@ -21,9 +21,9 @@ class ACsView extends StatelessWidget { return BlocBuilder( builder: (context, state) { DeviceModel? selectedAC; - if (DevicesCubit.get(context).getSelectedDevice() is DeviceModel) { + if (DevicesCubit.getInstance().getSelectedDevice() is DeviceModel) { selectedAC = - DevicesCubit.get(context).getSelectedDevice() as DeviceModel; + DevicesCubit.getInstance().getSelectedDevice() as DeviceModel; } return AnnotatedRegion( value: SystemUiOverlayStyle( diff --git a/lib/features/devices/view/widgets/ACs/category_view_app_bar.dart b/lib/features/devices/view/widgets/ACs/category_view_app_bar.dart index 4216a2f..4213086 100644 --- a/lib/features/devices/view/widgets/ACs/category_view_app_bar.dart +++ b/lib/features/devices/view/widgets/ACs/category_view_app_bar.dart @@ -20,7 +20,7 @@ class CategoryViewAppBar extends StatelessWidget toolbarHeight: Constants.appBarHeight, centerTitle: true, title: DisplayMedium( - text: DevicesCubit.get(context).chosenCategory!.name!, + text: DevicesCubit.getInstance().chosenCategory!.name!, style: context.displayMedium.copyWith( color: ColorsManager.primaryColor, fontWeight: FontWeight.bold, @@ -32,7 +32,7 @@ class CategoryViewAppBar extends StatelessWidget color: ColorsManager.textPrimaryColor, ), onPressed: () { - DevicesCubit.get(context).clearCategoriesSelection(context); + DevicesCubit.getInstance().clearCategoriesSelection(context); }, ), ); diff --git a/lib/features/devices/view/widgets/ACs/universal_ac_temp.dart b/lib/features/devices/view/widgets/ACs/universal_ac_temp.dart index 379dee1..3e86fc9 100644 --- a/lib/features/devices/view/widgets/ACs/universal_ac_temp.dart +++ b/lib/features/devices/view/widgets/ACs/universal_ac_temp.dart @@ -27,7 +27,7 @@ class UniversalACTemp extends StatelessWidget { dimension: 24, child: InkWell( onTap: () { - // DevicesCubit.get(context) + // DevicesCubit.getInstance() // .setTempToAll(DevicesCubit.universalACTemp - .5); }, child: SvgPicture.asset( @@ -47,7 +47,7 @@ class UniversalACTemp extends StatelessWidget { dimension: 24, child: InkWell( onTap: () { - // DevicesCubit.get(context) + // DevicesCubit.getInstance() // .setTempToAll(DevicesCubit.universalACTemp + .5); }, child: SvgPicture.asset( diff --git a/lib/features/devices/view/widgets/curtains/curtain_list.dart b/lib/features/devices/view/widgets/curtains/curtain_list.dart index eaf7f07..9659fdd 100644 --- a/lib/features/devices/view/widgets/curtains/curtain_list.dart +++ b/lib/features/devices/view/widgets/curtains/curtain_list.dart @@ -25,7 +25,7 @@ class CurtainList extends StatelessWidget { const BodySmall(text: "All Curtains"), const SizedBox(height: 5), UniversalSwitch( - category: DevicesCubit.get(context).chosenCategory!, + category: DevicesCubit.getInstance().chosenCategory!, ), // other ACs controls @@ -34,16 +34,17 @@ class CurtainList extends StatelessWidget { physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.all(0), itemCount: - DevicesCubit.get(context).chosenCategory!.devices!.length, + DevicesCubit.getInstance().chosenCategory!.devices!.length, itemBuilder: (context, index) { - DeviceModel curtain = - DevicesCubit.get(context).chosenCategory!.devices![index]; + DeviceModel curtain = DevicesCubit.getInstance() + .chosenCategory! + .devices![index]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 20), BodySmall( - text: DevicesCubit.get(context) + text: DevicesCubit.getInstance() .chosenCategory! .devices![index] .name ?? diff --git a/lib/features/devices/view/widgets/lights/light_brightness.dart b/lib/features/devices/view/widgets/lights/light_brightness.dart index e6b1864..1409ab3 100644 --- a/lib/features/devices/view/widgets/lights/light_brightness.dart +++ b/lib/features/devices/view/widgets/lights/light_brightness.dart @@ -20,7 +20,7 @@ class LightBrightness extends StatelessWidget { return BlocBuilder( builder: (context, state) { return GestureDetector( - // onHorizontalDragUpdate: (details) => DevicesCubit().get(context) + // onHorizontalDragUpdate: (details) => DevicesCubit.getInstance().get(context) // .onHorizontalDragUpdate(light, details.localPosition.dx, // MediaQuery.of(context).size.width - 15), child: Stack( diff --git a/lib/features/devices/view/widgets/lights/light_interface_modes.dart b/lib/features/devices/view/widgets/lights/light_interface_modes.dart index eff94c2..c020771 100644 --- a/lib/features/devices/view/widgets/lights/light_interface_modes.dart +++ b/lib/features/devices/view/widgets/lights/light_interface_modes.dart @@ -27,10 +27,10 @@ class LightInterfaceModes extends StatelessWidget { Wrap( spacing: 25, children: List.generate( - DevicesCubit.get(context).lightModes.length, + DevicesCubit.getInstance().lightModes.length, (index) => InkWell( - // onTap: () => DevicesCubit.get(context).setLightingMode( - // light, DevicesCubit.get(context).lightModes[index]!), + // onTap: () => DevicesCubit.getInstance().setLightingMode( + // light, DevicesCubit.getInstance().lightModes[index]!), child: Column( children: [ Container( diff --git a/lib/features/devices/view/widgets/lights/light_interface_recent_color.dart b/lib/features/devices/view/widgets/lights/light_interface_recent_color.dart index 614d09a..c1c1326 100644 --- a/lib/features/devices/view/widgets/lights/light_interface_recent_color.dart +++ b/lib/features/devices/view/widgets/lights/light_interface_recent_color.dart @@ -34,7 +34,7 @@ class LightInterfaceRecentColor extends StatelessWidget { 4, (index) => InkWell( // onTap: () { - // DevicesCubit.get(context) + // DevicesCubit.getInstance() // .setColor(light, light.recentColors[index]); // }, child: Container( diff --git a/lib/features/devices/view/widgets/lights/light_interface_slider.dart b/lib/features/devices/view/widgets/lights/light_interface_slider.dart index 8c7e305..e3ef363 100644 --- a/lib/features/devices/view/widgets/lights/light_interface_slider.dart +++ b/lib/features/devices/view/widgets/lights/light_interface_slider.dart @@ -60,7 +60,7 @@ class LightInterfaceSlider extends StatelessWidget { // value: light.brightness, value: 100, onChanged: (value) { - // DevicesCubit.get(context).setBrightness(light, value); + // DevicesCubit.getInstance().setBrightness(light, value); }, min: 0, max: 100, diff --git a/lib/features/devices/view/widgets/lights/light_interface_switch.dart b/lib/features/devices/view/widgets/lights/light_interface_switch.dart index fde3bc4..938d772 100644 --- a/lib/features/devices/view/widgets/lights/light_interface_switch.dart +++ b/lib/features/devices/view/widgets/lights/light_interface_switch.dart @@ -51,7 +51,7 @@ class LightInterfaceSwitch extends StatelessWidget { iconSize: MaterialStateProperty.all(25), ), onPressed: () { - // DevicesCubit.get(context).toggleLight(light); + // DevicesCubit.getInstance().toggleLight(light); }, icon: const Icon( Icons.power_settings_new, diff --git a/lib/features/devices/view/widgets/lights/lights_list.dart b/lib/features/devices/view/widgets/lights/lights_list.dart index 919ca0a..7d4f164 100644 --- a/lib/features/devices/view/widgets/lights/lights_list.dart +++ b/lib/features/devices/view/widgets/lights/lights_list.dart @@ -32,7 +32,7 @@ class LightsList extends StatelessWidget { BodySmall(text: lights[index].name ?? ""), IconButton( onPressed: () { - DevicesCubit.get(context).selectDevice(lights[index]); + DevicesCubit.getInstance().selectDevice(lights[index]); }, icon: const Icon( Icons.arrow_forward_ios, diff --git a/lib/features/devices/view/widgets/lights/lights_view.dart b/lib/features/devices/view/widgets/lights/lights_view.dart index eaa20dc..f16a444 100644 --- a/lib/features/devices/view/widgets/lights/lights_view.dart +++ b/lib/features/devices/view/widgets/lights/lights_view.dart @@ -19,9 +19,9 @@ class LightsView extends StatelessWidget { return BlocBuilder( builder: (context, state) { DeviceModel? selectedLight; - if (DevicesCubit.get(context).getSelectedDevice() is DeviceModel) { + if (DevicesCubit.getInstance().getSelectedDevice() is DeviceModel) { selectedLight = - DevicesCubit.get(context).getSelectedDevice() as DeviceModel; + DevicesCubit.getInstance().getSelectedDevice() as DeviceModel; } List lights = []; if (DevicesCubit.allCategories![1].devices != null) { diff --git a/lib/features/devices/view/widgets/room_page.dart b/lib/features/devices/view/widgets/room_page.dart index c4a93f1..8e8b5c0 100644 --- a/lib/features/devices/view/widgets/room_page.dart +++ b/lib/features/devices/view/widgets/room_page.dart @@ -28,7 +28,7 @@ class RoomPage extends StatelessWidget { physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, itemCount: room.devices!.length, - itemBuilder: (_, index) { + itemBuilder: (context, index) { return RoomPageSwitch(device: room.devices![index]); }, ); diff --git a/lib/features/devices/view/widgets/room_page_switch.dart b/lib/features/devices/view/widgets/room_page_switch.dart index 484de84..061be42 100644 --- a/lib/features/devices/view/widgets/room_page_switch.dart +++ b/lib/features/devices/view/widgets/room_page_switch.dart @@ -33,7 +33,7 @@ class RoomPageSwitch extends StatelessWidget { context, CustomPageRoute( builder: (context) => BlocProvider( - create: (context) => DevicesCubit(), + create: (context) => DevicesCubit.getInstance(), child: AcInterface(deviceModel: device), ), ), @@ -57,7 +57,7 @@ class RoomPageSwitch extends StatelessWidget { context, CustomPageRoute( builder: (context) => BlocProvider( - create: (context) => DevicesCubit(), + create: (context) => DevicesCubit.getInstance(), child: LightInterface(light: device), ), ), @@ -67,7 +67,7 @@ class RoomPageSwitch extends StatelessWidget { context, CustomPageRoute( builder: (context) => BlocProvider( - create: (context) => DevicesCubit(), + create: (context) => DevicesCubit.getInstance(), child: ThreeGangInterface( gangSwitch: device, ), diff --git a/lib/features/devices/view/widgets/three_gang/gang_switch.dart b/lib/features/devices/view/widgets/three_gang/gang_switch.dart index 6e878a0..a0a2826 100644 --- a/lib/features/devices/view/widgets/three_gang/gang_switch.dart +++ b/lib/features/devices/view/widgets/three_gang/gang_switch.dart @@ -23,16 +23,16 @@ class GangSwitch extends StatelessWidget { : InkWell( overlayColor: MaterialStateProperty.all(Colors.transparent), onTap: () { - DevicesCubit.get(context) - .deviceControl(control) - .then((value) { - print('Device control response: $value'); - if (control.value ?? true) { - control.value = false; - } else { - control.value = true; - } - }); + // DevicesCubit.getInstance() + // .deviceControl(control) + // .then((value) { + // print('Device control response: $value'); + // if (control.value ?? true) { + // control.value = false; + // } else { + // control.value = true; + // } + // }); }, child: Stack( alignment: !control.value! diff --git a/lib/features/devices/view/widgets/three_gang/three_gang_interface.dart b/lib/features/devices/view/widgets/three_gang/three_gang_interface.dart index 0841fdf..a12dfcb 100644 --- a/lib/features/devices/view/widgets/three_gang/three_gang_interface.dart +++ b/lib/features/devices/view/widgets/three_gang/three_gang_interface.dart @@ -1,10 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.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/model/device_model.dart'; -import 'package:syncrow_app/features/devices/view/widgets/ACs/category_view_app_bar.dart'; import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface_body.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/generated/assets.dart'; diff --git a/lib/features/devices/view/widgets/universal_switch.dart b/lib/features/devices/view/widgets/universal_switch.dart index 34a726d..1746ffc 100644 --- a/lib/features/devices/view/widgets/universal_switch.dart +++ b/lib/features/devices/view/widgets/universal_switch.dart @@ -25,7 +25,7 @@ class UniversalSwitch extends StatelessWidget { Expanded( child: InkWell( onTap: () { - DevicesCubit.get(context).turnAllDevicesOn(category); + DevicesCubit.getInstance().turnAllDevicesOn(category); }, child: Container( height: 60, @@ -57,7 +57,7 @@ class UniversalSwitch extends StatelessWidget { Expanded( child: InkWell( onTap: () { - DevicesCubit.get(context).turnAllDevicesOff(category); + DevicesCubit.getInstance().turnAllDevicesOff(category); }, child: Container( height: 60, diff --git a/lib/features/devices/view/widgets/wizard_switches.dart b/lib/features/devices/view/widgets/wizard_switches.dart index e1b8092..6dc6d93 100644 --- a/lib/features/devices/view/widgets/wizard_switches.dart +++ b/lib/features/devices/view/widgets/wizard_switches.dart @@ -34,12 +34,12 @@ class WizartSwitches extends StatelessWidget { itemBuilder: (_, index) { return InkWell( onTap: () { - DevicesCubit.get(context).selectCategory(index); + DevicesCubit.getInstance().selectCategory(index); //Navigate to the chosen category view without animation Navigator.push(context, CustomPageRoute(builder: (context) { - return DevicesCubit.get(context) + return DevicesCubit.getInstance() .chosenCategoryView!; })); }, diff --git a/lib/features/shared_widgets/custom_switch.dart b/lib/features/shared_widgets/custom_switch.dart index d9ece21..ea269f9 100644 --- a/lib/features/shared_widgets/custom_switch.dart +++ b/lib/features/shared_widgets/custom_switch.dart @@ -26,9 +26,9 @@ class CustomSwitch extends StatelessWidget { return GestureDetector( onTap: () { if (device != null) { - DevicesCubit.get(context).turnOnOffDevice(device!); + DevicesCubit.getInstance().turnOnOffDevice(device!); } else if (category != null) { - DevicesCubit.get(context).changeCategorySwitchValue(category!); + DevicesCubit.getInstance().changeCategorySwitchValue(category!); } }, child: Container( diff --git a/lib/features/shared_widgets/devices_default_switch.dart b/lib/features/shared_widgets/devices_default_switch.dart index 2f001c1..50a58b6 100644 --- a/lib/features/shared_widgets/devices_default_switch.dart +++ b/lib/features/shared_widgets/devices_default_switch.dart @@ -23,7 +23,7 @@ class DevicesDefaultSwitch extends StatelessWidget { Expanded( child: InkWell( onTap: () { - DevicesCubit.get(context).turnOnOffDevice(model); + DevicesCubit.getInstance().turnOnOffDevice(model); }, child: Container( height: 60, @@ -49,7 +49,7 @@ class DevicesDefaultSwitch extends StatelessWidget { Expanded( child: InkWell( onTap: () { - DevicesCubit.get(context).turnOnOffDevice(model); + DevicesCubit.getInstance().turnOnOffDevice(model); }, child: Container( height: 60, diff --git a/lib/my_app.dart b/lib/my_app.dart index ace6a6e..1ec3b08 100644 --- a/lib/my_app.dart +++ b/lib/my_app.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart'; -import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/theme_manager.dart'; diff --git a/lib/navigation/router.dart b/lib/navigation/router.dart index e5ed6db..4b84208 100644 --- a/lib/navigation/router.dart +++ b/lib/navigation/router.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/view/app_layout.dart'; import 'package:syncrow_app/features/auth/view/widgets/didnt_get_code/didnt_get_code_view.dart'; import 'package:syncrow_app/features/auth/view/widgets/login/login_view.dart'; @@ -8,8 +7,6 @@ import 'package:syncrow_app/features/auth/view/widgets/privacy_policy/privacy_po import 'package:syncrow_app/features/auth/view/widgets/sign_up/sign_up_view.dart'; import 'package:syncrow_app/features/auth/view/widgets/user_agreement/user_agreement_view.dart'; import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart'; -import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; -import 'package:syncrow_app/features/devices/view/devices_view.dart'; import 'package:syncrow_app/features/layout/view/layout_view.dart'; import 'package:syncrow_app/features/menu/view/menu_view.dart'; import 'package:syncrow_app/features/profile/view/profile_view.dart'; diff --git a/lib/services/api/devices_api.dart b/lib/services/api/devices_api.dart index 57e2ac1..c8c04c4 100644 --- a/lib/services/api/devices_api.dart +++ b/lib/services/api/devices_api.dart @@ -8,6 +8,8 @@ class DevicesAPI { static Future> controlDevice( DeviceControlModel controlModel) async { + // print( + // 'contoling [${controlModel.deviceId}] with code [${controlModel.code}] and value [${controlModel.value}'); final response = await _httpService.post( path: ApiEndpoints.control, body: controlModel.toJson(), diff --git a/lib/services/api/network_exception.dart b/lib/services/api/network_exception.dart index 1cc6a3d..cea8ad7 100644 --- a/lib/services/api/network_exception.dart +++ b/lib/services/api/network_exception.dart @@ -1,5 +1,4 @@ import 'package:dio/dio.dart'; -import 'package:html/parser.dart' as parser; abstract class Failure { final String errMessage; diff --git a/lib/utils/resource_manager/constants.dart b/lib/utils/resource_manager/constants.dart index 42f4825..04e05af 100644 --- a/lib/utils/resource_manager/constants.dart +++ b/lib/utils/resource_manager/constants.dart @@ -1,5 +1,6 @@ //ignore_for_file: constant_identifier_names import 'package:syncrow_app/features/devices/model/function_model.dart'; +import 'package:syncrow_app/generated/assets.dart'; abstract class Constants { static const String languageCode = "en"; @@ -129,3 +130,71 @@ Map> devicesFunctionsMap = { values: '{"unit":"s","min":0,"max":43200,"scale":0,"step":1}'), ], }; + +enum TempModes { hot, cold, wind } + +enum FanSpeeds { auto, low, middle, high } + +final Map fanSpeedsIconMap = { + FanSpeeds.auto: Assets.iconsFan0, + FanSpeeds.low: Assets.iconsFan1, + FanSpeeds.middle: Assets.iconsFan2, + FanSpeeds.high: Assets.iconsFan3, +}; + +final Map tempModesIconMap = { + TempModes.hot: Assets.iconsSunnyMode, + TempModes.cold: Assets.iconsColdMode, + TempModes.wind: Assets.iconsWindyMode, +}; + +final Map fanSpeedsMap = { + 'auto': FanSpeeds.auto, + 'low': FanSpeeds.low, + 'middle': FanSpeeds.middle, + 'high': FanSpeeds.high, +}; + +final Map tempModesMap = { + 'hot': TempModes.hot, + 'cold': TempModes.cold, + 'wind': TempModes.wind, +}; + +final Map reversedFanSpeedsMap = + fanSpeedsMap.map((key, value) => MapEntry(value, key)); + +final Map reversedTempModesMap = + tempModesMap.map((key, value) => MapEntry(value, key)); + +String getNextFanSpeedKey(FanSpeeds currentFanSpeed) { + const List speeds = FanSpeeds.values; + final int currentIndex = speeds.indexOf(currentFanSpeed); + + // Return null if currentFanSpeed is the last value + if (currentIndex == speeds.length - 1) { + return reversedFanSpeedsMap[FanSpeeds.auto]!; + } + + final FanSpeeds nextSpeed = speeds[currentIndex + 1]; + return reversedFanSpeedsMap[nextSpeed]!; +} + +K? getNextItem(Map map, V value) { + // Iterate over the map entries + for (var entry in map.entries) { + // If the current value matches the provided value + if (entry.value == value) { + // Get the index of the current entry + final index = map.keys.toList().indexOf(entry.key); + // If the index is not the last item, return the next item + if (index < map.length - 1) { + return map.keys.elementAt(index + 1); + } + // If it's the last item, return null + return map.keys.elementAt(0); + } + } + // If the value is not found, return null + return null; +} From 8d02eb2f407bfbfa69086491b28f871529e6b932 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Thu, 4 Apr 2024 00:00:48 +0300 Subject: [PATCH 16/29] Refactor DefaultNavBar widget build method Remove unnecessary BlocProvider and DevicesCubit logic from DefaultNavBar widget build method, simplify code structure. --- .../view/widgets/default_nav_bar.dart | 67 +++++++++---------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/lib/features/app_layout/view/widgets/default_nav_bar.dart b/lib/features/app_layout/view/widgets/default_nav_bar.dart index 4076195..e791ad2 100644 --- a/lib/features/app_layout/view/widgets/default_nav_bar.dart +++ b/lib/features/app_layout/view/widgets/default_nav_bar.dart @@ -13,44 +13,37 @@ class DefaultNavBar extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocProvider( - create: (context) => DevicesCubit.getInstance(), - child: BlocBuilder( - builder: (context, state) { - return BlocBuilder( - builder: (context, state) { - var cubit = HomeCubit.getInstance(); - return SizedBox( - height: Constants.bottomNavBarHeight, - child: BottomNavigationBar( - backgroundColor: Colors.transparent, - onTap: (int index) { - cubit.updatePageIndex(index); - if (DevicesCubit.getInstance().chosenCategoryView != null) { - DevicesCubit.getInstance() - .clearCategoriesSelection(context); - } - if (HomeCubit.getInstance().selectedRoom != null) { - HomeCubit.getInstance().unselectRoom(); - } - }, - currentIndex: HomeCubit.pageIndex, - selectedItemColor: ColorsManager.primaryColor, - selectedLabelStyle: const TextStyle( - color: ColorsManager.primaryColor, - fontSize: 10, - ), - showUnselectedLabels: true, - unselectedItemColor: Colors.grey, - type: BottomNavigationBarType.fixed, - elevation: 0, - items: HomeCubit.bottomNavItems, - ), - ); + return BlocBuilder( + builder: (context, state) { + var cubit = HomeCubit.getInstance(); + return SizedBox( + height: Constants.bottomNavBarHeight, + child: BottomNavigationBar( + backgroundColor: Colors.transparent, + onTap: (int index) { + cubit.updatePageIndex(index); + // if (DevicesCubit.getInstance().chosenCategoryView != null) { + // DevicesCubit.getInstance() + // .clearCategoriesSelection(context); + // } + if (HomeCubit.getInstance().selectedRoom != null) { + HomeCubit.getInstance().unselectRoom(); + } }, - ); - }, - ), + currentIndex: HomeCubit.pageIndex, + selectedItemColor: ColorsManager.primaryColor, + selectedLabelStyle: const TextStyle( + color: ColorsManager.primaryColor, + fontSize: 10, + ), + showUnselectedLabels: true, + unselectedItemColor: Colors.grey, + type: BottomNavigationBarType.fixed, + elevation: 0, + items: HomeCubit.bottomNavItems, + ), + ); + }, ); } } From 37d2c1b53fef9d17d4ab4d84e4647b310a1498d0 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Thu, 4 Apr 2024 00:01:02 +0300 Subject: [PATCH 17/29] apend --- .vscode/launch.json | 6 +++ .../gradle/wrapper/gradle-wrapper.properties | 5 +- lib/features/app_layout/view/app_layout.dart | 46 +++++++++---------- lib/features/devices/bloc/devices_cubit.dart | 7 +-- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index ecd784a..e64ae76 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,6 +11,12 @@ "type": "dart", "deviceId": "0147FC23-3D6C-406A-BE2C-9E67BAF3DA9B" }, + { + "name": "Iphone 15 Pro", + "request": "launch", + "type": "dart", + "deviceId": "9C9E6EEF-0E9C-4FA9-B201-CBA8AFB0D1D8" + }, { "name": "Iphone SE", "request": "launch", diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 3c472b9..60df464 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Wed Apr 03 23:37:40 EET 2024 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip +zipStoreBase=GRADLE_USER_HOME diff --git a/lib/features/app_layout/view/app_layout.dart b/lib/features/app_layout/view/app_layout.dart index d266660..6fbdb42 100644 --- a/lib/features/app_layout/view/app_layout.dart +++ b/lib/features/app_layout/view/app_layout.dart @@ -35,31 +35,27 @@ class AppLayout extends StatelessWidget { statusBarIconBrightness: Brightness.light, ), child: SafeArea( - child: BlocBuilder( - builder: (context, state) { - return Scaffold( - backgroundColor: ColorsManager.backgroundColor, - extendBodyBehindAppBar: true, - extendBody: true, - appBar: HomeCubit.getInstance().spaces != null - ? const DefaultAppBar() - : null, - body: const AppBody(), - bottomNavigationBar: const DefaultNavBar(), - // floatingActionButton: FloatingActionButton( - // onPressed: () { - // Navigator.push( - // context, - // CustomPageRoute( - // builder: (context) => - // const ThreeGangSwitchesView(), - // ), - // ); - // }, - // child: const Icon(Icons.arrow_forward_ios_sharp), - // ), - ); - }, + child: Scaffold( + backgroundColor: ColorsManager.backgroundColor, + extendBodyBehindAppBar: true, + extendBody: true, + appBar: HomeCubit.getInstance().spaces != null + ? const DefaultAppBar() + : null, + body: const AppBody(), + bottomNavigationBar: const DefaultNavBar(), + // floatingActionButton: FloatingActionButton( + // onPressed: () { + // Navigator.push( + // context, + // CustomPageRoute( + // builder: (context) => + // const ThreeGangSwitchesView(), + // ), + // ); + // }, + // child: const Icon(Icons.arrow_forward_ios_sharp), + // ), ), ), ); diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index 6449d93..d26659d 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -24,6 +24,7 @@ part 'devices_state.dart'; class DevicesCubit extends Cubit { DevicesCubit._() : super(DevicesInitial()) { + print('device cubit created'); if (HomeCubit.getInstance().selectedSpace != null) { fetchGroups(HomeCubit.getInstance().selectedSpace!.id!); for (var room in HomeCubit.getInstance().selectedSpace!.rooms!) { @@ -35,9 +36,9 @@ class DevicesCubit extends Cubit { static DevicesCubit? _instance; static DevicesCubit getInstance() { - // If an instance already exists, return it - _instance ??= DevicesCubit._(); - return _instance!; + print('device cubit instance found : ${_instance != null}'); + print('selected space : ${HomeCubit.getInstance().selectedSpace != null}'); + return _instance ??= DevicesCubit._(); } DeviceModel? selectedDevice; From 13bfcdfb4ddefd23d674e6e2a2f349073af0db92 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Thu, 4 Apr 2024 00:38:27 +0300 Subject: [PATCH 18/29] Update device icons and refactor AC interface widget - Update device icons to match new design requirements - Refactor AC interface widget to use a more descriptive variable name - Implement temperature control functionality in AC interface widget --- .../view/widgets/default_nav_bar.dart | 1 + lib/features/devices/model/device_model.dart | 2 +- .../view/widgets/ACs/ac_interface.dart | 2 +- .../widgets/ACs/ac_interface_temp_unit.dart | 35 ++++++++++++++----- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/lib/features/app_layout/view/widgets/default_nav_bar.dart b/lib/features/app_layout/view/widgets/default_nav_bar.dart index e791ad2..9cc9ddd 100644 --- a/lib/features/app_layout/view/widgets/default_nav_bar.dart +++ b/lib/features/app_layout/view/widgets/default_nav_bar.dart @@ -3,6 +3,7 @@ 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/devices_cubit.dart'; +import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; diff --git a/lib/features/devices/model/device_model.dart b/lib/features/devices/model/device_model.dart index 22a7c04..410fd15 100644 --- a/lib/features/devices/model/device_model.dart +++ b/lib/features/devices/model/device_model.dart @@ -75,7 +75,7 @@ class DeviceModel { } else if (type == DeviceType.Curtain) { icon = Assets.iconsCurtain; } else if (type == DeviceType.ThreeGang) { - icon = Assets.iconsLight; + icon = Assets.icons3GangSwitch; } else if (type == DeviceType.Gateway) { icon = Assets.iconsGateway; } else { diff --git a/lib/features/devices/view/widgets/ACs/ac_interface.dart b/lib/features/devices/view/widgets/ACs/ac_interface.dart index c0ac062..23c45f7 100644 --- a/lib/features/devices/view/widgets/ACs/ac_interface.dart +++ b/lib/features/devices/view/widgets/ACs/ac_interface.dart @@ -75,7 +75,7 @@ class AcInterface extends StatelessWidget { maxHeight: 380, ), child: AcInterfaceTempUnit( - deviceModel: deviceModel, + acDevice: deviceModel, ), ), const SizedBox( diff --git a/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart b/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart index 562b005..e29ee08 100644 --- a/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart +++ b/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:sleek_circular_slider/sleek_circular_slider.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; +import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; @@ -10,20 +11,25 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dar import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; +import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; class AcInterfaceTempUnit extends StatelessWidget { const AcInterfaceTempUnit({ super.key, - required this.deviceModel, + required this.acDevice, }); - final DeviceModel deviceModel; + final DeviceModel acDevice; @override Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { + double setToTemp = acDevice.status + .firstWhere((element) => element.code == 'temp_set') + .value / + 10; return DefaultContainer( child: Column( children: [ @@ -72,7 +78,7 @@ class AcInterfaceTempUnit extends StatelessWidget { ), // min: DeviceModel.bounds.min, // max: DeviceModel.bounds.max, - initialValue: deviceModel.status + initialValue: acDevice.status .firstWhere( (element) => element.code == 'temp_current') .value / @@ -98,9 +104,14 @@ class AcInterfaceTempUnit extends StatelessWidget { dimension: 24, child: InkWell( onTap: () { - // DevicesCubit.getInstance() - // .setACTemp(DeviceModel, DeviceModel.coolTo); - // DeviceModel.coolTo -= .5; + if (setToTemp > 20) { + DevicesCubit.getInstance().deviceControl( + DeviceControlModel( + deviceId: acDevice.id, + code: 'temp_set', + value: (setToTemp - 0.5) * 10), + acDevice.id!); + } }, child: SvgPicture.asset( Assets.iconsMinus, @@ -111,8 +122,7 @@ class AcInterfaceTempUnit extends StatelessWidget { children: [ BodyLarge( // text: "${DeviceModel.coolTo}° C", - text: - '${deviceModel.status.firstWhere((element) => element.code == 'temp_set').value / 10}° C', + text: '$setToTemp° C', style: context.bodyLarge.copyWith( color: ColorsManager.primaryColor.withOpacity(0.6), @@ -133,6 +143,15 @@ class AcInterfaceTempUnit extends StatelessWidget { // DevicesCubit.getInstance() // .setACTemp(DeviceModel, DeviceModel.coolTo); // DeviceModel.coolTo += .5; + + if (setToTemp < 30) { + DevicesCubit.getInstance().deviceControl( + DeviceControlModel( + deviceId: acDevice.id, + code: 'temp_set', + value: (setToTemp + 0.5) * 10), + acDevice.id!); + } }, child: SvgPicture.asset( Assets.iconsPlus, From 20ded336d3222571d8116578682111ccddf6bf39 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Thu, 4 Apr 2024 00:45:54 +0300 Subject: [PATCH 19/29] Refactor AC interface temp unit control logic Refactor the control logic in the AC interface temp unit widget to handle device control actions more efficiently and improve code readability. --- .../widgets/ACs/ac_interface_temp_unit.dart | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart b/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart index e29ee08..1310107 100644 --- a/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart +++ b/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart @@ -88,8 +88,12 @@ class AcInterfaceTempUnit extends StatelessWidget { if (valueAsString.endsWith(".0") || valueAsString.endsWith(".5")) { value = double.parse(valueAsString); - // DevicesCubit.getInstance() - // .setACTemp(DeviceModel, value); + DevicesCubit.getInstance().deviceControl( + DeviceControlModel( + deviceId: acDevice.id, + code: 'temp_set', + value: value * 10), + acDevice.id!); } }, ), @@ -104,6 +108,15 @@ class AcInterfaceTempUnit extends StatelessWidget { dimension: 24, child: InkWell( onTap: () { + //TODO refactor the loading check + if (state is GetDeviceStatusLoading && + state.code == 'temp_set' || + state is DeviceControlSuccess && + state.code == 'temp_set' || + state is DeviceControlLoading && + state.code == 'temp_set') { + return; + } if (setToTemp > 20) { DevicesCubit.getInstance().deviceControl( DeviceControlModel( @@ -124,8 +137,14 @@ class AcInterfaceTempUnit extends StatelessWidget { // text: "${DeviceModel.coolTo}° C", text: '$setToTemp° C', style: context.bodyLarge.copyWith( - color: - ColorsManager.primaryColor.withOpacity(0.6), + color: state is GetDeviceStatusLoading && + state.code == 'temp_set' || + state is DeviceControlSuccess && + state.code == 'temp_set' || + state is DeviceControlLoading && + state.code == 'temp_set' + ? Colors.grey + : ColorsManager.primaryColor.withOpacity(0.6), fontWeight: FontsManager.bold, fontSize: 30, height: 0), @@ -140,10 +159,14 @@ class AcInterfaceTempUnit extends StatelessWidget { dimension: 24, child: InkWell( onTap: () { - // DevicesCubit.getInstance() - // .setACTemp(DeviceModel, DeviceModel.coolTo); - // DeviceModel.coolTo += .5; - + if (state is GetDeviceStatusLoading && + state.code == 'temp_set' || + state is DeviceControlSuccess && + state.code == 'temp_set' || + state is DeviceControlLoading && + state.code == 'temp_set') { + return; + } if (setToTemp < 30) { DevicesCubit.getInstance().deviceControl( DeviceControlModel( From 1f4fb940bc17eb9365fc04147b49b558d3c9cabd Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Thu, 4 Apr 2024 00:50:27 +0300 Subject: [PATCH 20/29] apend --- .../devices/view/widgets/ACs/ac_interface_temp_unit.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart b/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart index 1310107..dab1d71 100644 --- a/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart +++ b/lib/features/devices/view/widgets/ACs/ac_interface_temp_unit.dart @@ -78,6 +78,8 @@ class AcInterfaceTempUnit extends StatelessWidget { ), // min: DeviceModel.bounds.min, // max: DeviceModel.bounds.max, + min: 20, + max: 30, initialValue: acDevice.status .firstWhere( (element) => element.code == 'temp_current') From 245ab82208b6bce504335dc07891ff13e12360ef Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Thu, 4 Apr 2024 01:14:55 +0300 Subject: [PATCH 21/29] Refactor GangSwitch widget and ThreeGangInterfaceBody Refactor GangSwitch widget and ThreeGangInterfaceBody for better readability and maintainability. Update widget structure and logic for improved functionality and code organization. --- .../view/widgets/three_gang/gang_switch.dart | 94 ++-- .../three_gang/three_gang_interface_body.dart | 438 +++++++++--------- 2 files changed, 280 insertions(+), 252 deletions(-) diff --git a/lib/features/devices/view/widgets/three_gang/gang_switch.dart b/lib/features/devices/view/widgets/three_gang/gang_switch.dart index a0a2826..ff78992 100644 --- a/lib/features/devices/view/widgets/three_gang/gang_switch.dart +++ b/lib/features/devices/view/widgets/three_gang/gang_switch.dart @@ -3,68 +3,78 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart'; +import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; class GangSwitch extends StatelessWidget { const GangSwitch({ super.key, + required this.threeGangSwitch, required this.control, }); + final DeviceModel threeGangSwitch; + final DeviceControlModel control; @override Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { - return state is DeviceControlLoading - ? const CircularProgressIndicator() - : InkWell( - overlayColor: MaterialStateProperty.all(Colors.transparent), - onTap: () { - // DevicesCubit.getInstance() - // .deviceControl(control) - // .then((value) { - // print('Device control response: $value'); - // if (control.value ?? true) { - // control.value = false; - // } else { - // control.value = true; - // } - // }); - }, - child: Stack( - alignment: !control.value! - ? Alignment.topCenter - : Alignment.bottomCenter, - children: [ - Container( - decoration: BoxDecoration( - borderRadius: - const BorderRadius.all(Radius.circular(100.0)), - color: !control.value! - ? ColorsManager.primaryColorWithOpacity - : ColorsManager.switchOffColor, - ), - width: 60, - height: 115, - ), - Padding( - padding: const EdgeInsets.all(5.0), - child: SizedBox.square( - dimension: 60, - child: SvgPicture.asset( - !control.value! + return InkWell( + overlayColor: MaterialStateProperty.all(Colors.transparent), + onTap: () { + var tempControl = DeviceControlModel( + deviceId: control.deviceId, + code: control.code!, + value: !control.value!); + DevicesCubit.getInstance().deviceControl( + tempControl, + control.deviceId!, + ); + }, + child: Stack( + alignment: + !control.value! ? Alignment.topCenter : Alignment.bottomCenter, + children: [ + Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(100.0)), + color: threeGangSwitch.status + .firstWhere((element) => element.code == control.code) + .value! + ? ColorsManager.primaryColorWithOpacity + : ColorsManager.switchOffColor, + ), + width: 60, + height: 115, + ), + Padding( + padding: const EdgeInsets.all(5.0), + child: SizedBox.square( + dimension: 60, + child: state is GetDeviceStatusLoading && + state.code == control.code || + state is DeviceControlSuccess && + state.code == control.code || + state is DeviceControlLoading && + state.code == control.code + ? const SizedBox( + width: 10, + height: 10, + child: Center(child: CircularProgressIndicator())) + : SvgPicture.asset( + control.value! ? Assets.iconsLightSwitchOn : Assets.iconsLightSwitchOff, fit: BoxFit.fill, ), - ), - ), - ], ), - ); + ), + ], + ), + ); }, ); } diff --git a/lib/features/devices/view/widgets/three_gang/three_gang_interface_body.dart b/lib/features/devices/view/widgets/three_gang/three_gang_interface_body.dart index b737dda..031df63 100644 --- a/lib/features/devices/view/widgets/three_gang/three_gang_interface_body.dart +++ b/lib/features/devices/view/widgets/three_gang/three_gang_interface_body.dart @@ -1,4 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/three_gang/gang_switch.dart'; @@ -16,245 +18,261 @@ class ThreeGangInterfaceBody extends StatelessWidget { @override Widget build(BuildContext context) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Expanded(child: SizedBox.shrink()), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - crossAxisAlignment: CrossAxisAlignment.center, + return BlocBuilder( + builder: (context, state) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Column( - children: [ - GangSwitch( - control: DeviceControlModel( - deviceId: 'bfe10693d4fd263206ocq9', - code: 'switch_1', - value: true, - ), - ), - const SizedBox(height: 20), - const SizedBox( - width: 70, - child: BodySmall( - text: "Bedside Light", - fontColor: ColorsManager.textPrimaryColor, - textAlign: TextAlign.center, - ), - ), - ], - ), - Column( - children: [ - GangSwitch( - control: DeviceControlModel( - deviceId: 'bfe10693d4fd263206ocq9', - code: 'switch_2', - value: true, - ), - ), - const SizedBox(height: 20), - const SizedBox( - width: 70, - child: BodySmall( - text: "Ceiling Light", - fontColor: ColorsManager.textPrimaryColor, - textAlign: TextAlign.center, - ), - ), - ], - ), - Column( - children: [ - GangSwitch( - control: DeviceControlModel( - deviceId: 'bfe10693d4fd263206ocq9', - code: 'switch_3', - value: true, - ), - ), - const SizedBox(height: 20), - const SizedBox( - width: 70, - child: BodySmall( - text: "Spotlight", - fontColor: ColorsManager.textPrimaryColor, - textAlign: TextAlign.center, - ), - ), - ], - ), - ], - ), - Expanded( - child: Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, + const Expanded(child: SizedBox.shrink()), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, crossAxisAlignment: CrossAxisAlignment.center, children: [ Column( - mainAxisSize: MainAxisSize.min, children: [ - Card( - elevation: 3, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(100), - ), - child: InkWell( - onTap: () {}, - child: Stack( - alignment: Alignment.center, - children: [ - Container( - width: 60, - height: 60, - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(100), - ), - ), - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(100), - ), - child: Center( - child: BodySmall( - text: "On", - style: context.bodyMedium.copyWith( - color: - ColorsManager.primaryColorWithOpacity, - fontWeight: FontWeight.bold), - ), - ), - ), - ], - ), + GangSwitch( + threeGangSwitch: device, + control: DeviceControlModel( + deviceId: device.id, + // code: 'switch_1', + code: device.status[0].code, + // value: true, + value: device.status[0].value, ), ), - const SizedBox(height: 10), - BodySmall( - text: "All On", - style: context.bodyMedium.copyWith( - color: ColorsManager.textPrimaryColor, + const SizedBox(height: 20), + const SizedBox( + width: 70, + child: BodySmall( + text: "Bedside Light", + fontColor: ColorsManager.textPrimaryColor, + textAlign: TextAlign.center, ), ), ], ), - const SizedBox( - width: 20, - ), Column( - mainAxisSize: MainAxisSize.min, children: [ - Card( - elevation: 3, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(100), - ), - child: InkWell( - onTap: () {}, - child: Stack( - alignment: Alignment.center, - children: [ - Container( - width: 60, - height: 60, - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(100), - ), - ), - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(100), - ), - child: Center( - child: Icon( - Icons.access_time, - color: ColorsManager.primaryColorWithOpacity, - size: 25, - ), - ), - ), - ], - ), + GangSwitch( + threeGangSwitch: device, + control: DeviceControlModel( + // deviceId: 'bfe10693d4fd263206ocq9', + // code: 'switch_2', + // value: true, + deviceId: device.id, + code: device.status[1].code, + value: device.status[1].value, ), ), - const SizedBox(height: 10), - BodySmall( - text: "Timer", - style: context.bodyMedium.copyWith( - color: ColorsManager.textPrimaryColor, + const SizedBox(height: 20), + const SizedBox( + width: 70, + child: BodySmall( + text: "Ceiling Light", + fontColor: ColorsManager.textPrimaryColor, + textAlign: TextAlign.center, ), ), ], ), - const SizedBox( - width: 20, - ), Column( - mainAxisSize: MainAxisSize.min, children: [ - Card( - elevation: 3, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(100), - ), - child: InkWell( - onTap: () {}, - child: Stack( - alignment: Alignment.center, - children: [ - Container( - width: 60, - height: 60, - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(100), - ), - ), - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(100), - ), - child: Center( - child: BodySmall( - text: "Off", - style: context.bodyMedium.copyWith( - color: - ColorsManager.primaryColorWithOpacity, - fontWeight: FontWeight.bold), - ), - ), - ), - ], - ), + GangSwitch( + threeGangSwitch: device, + control: DeviceControlModel( + // deviceId: 'bfe10693d4fd263206ocq9', + // code: 'switch_3', + // value: true, + deviceId: device.id, + code: device.status[2].code, + value: device.status[2].value, ), ), - const SizedBox(height: 10), - BodySmall( - text: "All Off", - style: context.bodyMedium.copyWith( - color: ColorsManager.textPrimaryColor, + const SizedBox(height: 20), + const SizedBox( + width: 70, + child: BodySmall( + text: "Spotlight", + fontColor: ColorsManager.textPrimaryColor, + textAlign: TextAlign.center, ), ), ], ), ], ), - ), - ), - ], + Expanded( + child: Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Card( + elevation: 3, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(100), + ), + child: InkWell( + onTap: () {}, + child: Stack( + alignment: Alignment.center, + children: [ + Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(100), + ), + ), + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(100), + ), + child: Center( + child: BodySmall( + text: "On", + style: context.bodyMedium.copyWith( + color: ColorsManager + .primaryColorWithOpacity, + fontWeight: FontWeight.bold), + ), + ), + ), + ], + ), + ), + ), + const SizedBox(height: 10), + BodySmall( + text: "All On", + style: context.bodyMedium.copyWith( + color: ColorsManager.textPrimaryColor, + ), + ), + ], + ), + const SizedBox( + width: 20, + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Card( + elevation: 3, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(100), + ), + child: InkWell( + onTap: () {}, + child: Stack( + alignment: Alignment.center, + children: [ + Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(100), + ), + ), + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(100), + ), + child: Center( + child: Icon( + Icons.access_time, + color: + ColorsManager.primaryColorWithOpacity, + size: 25, + ), + ), + ), + ], + ), + ), + ), + const SizedBox(height: 10), + BodySmall( + text: "Timer", + style: context.bodyMedium.copyWith( + color: ColorsManager.textPrimaryColor, + ), + ), + ], + ), + const SizedBox( + width: 20, + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Card( + elevation: 3, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(100), + ), + child: InkWell( + onTap: () {}, + child: Stack( + alignment: Alignment.center, + children: [ + Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(100), + ), + ), + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(100), + ), + child: Center( + child: BodySmall( + text: "Off", + style: context.bodyMedium.copyWith( + color: ColorsManager + .primaryColorWithOpacity, + fontWeight: FontWeight.bold), + ), + ), + ), + ], + ), + ), + ), + const SizedBox(height: 10), + BodySmall( + text: "All Off", + style: context.bodyMedium.copyWith( + color: ColorsManager.textPrimaryColor, + ), + ), + ], + ), + ], + ), + ), + ), + ], + ); + }, ); } } From 65112976b24339747db0e9c40cd280ab680619b3 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Thu, 4 Apr 2024 01:18:02 +0300 Subject: [PATCH 22/29] Update device control logic for three gang interface Refactor onTap functions in ThreeGangInterfaceBody to control all three switches simultaneously based on the user interaction. Split the logic for turning on and off the switches into separate functions for better readability and maintenance. --- .../three_gang/three_gang_interface_body.dart | 54 ++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/lib/features/devices/view/widgets/three_gang/three_gang_interface_body.dart b/lib/features/devices/view/widgets/three_gang/three_gang_interface_body.dart index 031df63..aef7ba0 100644 --- a/lib/features/devices/view/widgets/three_gang/three_gang_interface_body.dart +++ b/lib/features/devices/view/widgets/three_gang/three_gang_interface_body.dart @@ -117,7 +117,32 @@ class ThreeGangInterfaceBody extends StatelessWidget { borderRadius: BorderRadius.circular(100), ), child: InkWell( - onTap: () {}, + onTap: () { + DevicesCubit.getInstance().deviceControl( + DeviceControlModel( + deviceId: device.id, + code: 'switch_1', + value: true, + ), + device.id!, + ); + DevicesCubit.getInstance().deviceControl( + DeviceControlModel( + deviceId: device.id, + code: 'switch_2', + value: true, + ), + device.id!, + ); + DevicesCubit.getInstance().deviceControl( + DeviceControlModel( + deviceId: device.id, + code: 'switch_3', + value: true, + ), + device.id!, + ); + }, child: Stack( alignment: Alignment.center, children: [ @@ -224,7 +249,32 @@ class ThreeGangInterfaceBody extends StatelessWidget { borderRadius: BorderRadius.circular(100), ), child: InkWell( - onTap: () {}, + onTap: () { + DevicesCubit.getInstance().deviceControl( + DeviceControlModel( + deviceId: device.id, + code: 'switch_1', + value: false, + ), + device.id!, + ); + DevicesCubit.getInstance().deviceControl( + DeviceControlModel( + deviceId: device.id, + code: 'switch_2', + value: false, + ), + device.id!, + ); + DevicesCubit.getInstance().deviceControl( + DeviceControlModel( + deviceId: device.id, + code: 'switch_3', + value: false, + ), + device.id!, + ); + }, child: Stack( alignment: Alignment.center, children: [ From 81242c69cbd953ec53415b68ed66e6257ab81ee3 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Thu, 4 Apr 2024 01:35:30 +0300 Subject: [PATCH 23/29] Update CustomSwitch widget to handle device status and control Refactored CustomSwitch widget to properly handle device status and control based on the device's status values. Added necessary checks and updated UI accordingly. --- .../shared_widgets/custom_switch.dart | 119 +++++++++--------- 1 file changed, 63 insertions(+), 56 deletions(-) diff --git a/lib/features/shared_widgets/custom_switch.dart b/lib/features/shared_widgets/custom_switch.dart index ea269f9..cdb9eab 100644 --- a/lib/features/shared_widgets/custom_switch.dart +++ b/lib/features/shared_widgets/custom_switch.dart @@ -2,80 +2,87 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_category_model.dart'; +import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; +import 'package:collection/collection.dart'; class CustomSwitch extends StatelessWidget { - const CustomSwitch({super.key, this.category, this.device}) - : assert(category != null || device != null); - - final DevicesCategoryModel? category; - - final DeviceModel? device; + const CustomSwitch({super.key, required this.device}); + final DeviceModel device; @override Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { bool? status; - if (device != null) { - status = device!.isOnline; - } else if (category != null) { - status = category!.devicesStatus; + if (device.status.isNotEmpty) { + status = device.status + .firstWhereOrNull((status) => status.code == "switch") + ?.value; } - return GestureDetector( - onTap: () { - if (device != null) { - DevicesCubit.getInstance().turnOnOffDevice(device!); - } else if (category != null) { - DevicesCubit.getInstance().changeCategorySwitchValue(category!); - } - }, - child: Container( - width: 45.0, - height: 28.0, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(24.0), - color: status != null - ? status - ? ColorsManager.primaryColor - : const Color(0xFFD9D9D9) - : const Color(0xFFD9D9D9), - ), - child: Center( - child: Container( - width: 40.0, - height: 23.0, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(24.0), - color: Colors.white, - ), - child: Padding( - padding: const EdgeInsets.all(2.0), - child: Container( - alignment: status != null + return status == null + ? const SizedBox() + : GestureDetector( + onTap: () { + DevicesCubit.getInstance().deviceControl( + DeviceControlModel( + deviceId: device.id, + code: device.status + .firstWhere((status) => status.code == "switch") + .code, + value: !device.status + .firstWhere((status) => status.code == "switch") + .value!, + ), + device.id!, + ); + }, + child: Container( + width: 45.0, + height: 28.0, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(24.0), + color: status != null ? status - ? Alignment.centerRight - : Alignment.centerLeft - : Alignment.centerLeft, + ? ColorsManager.primaryColor + : const Color(0xFFD9D9D9) + : const Color(0xFFD9D9D9), + ), + child: Center( child: Container( - width: 20.0, - height: 20.0, + width: 40.0, + height: 23.0, decoration: BoxDecoration( - shape: BoxShape.circle, - color: status != null - ? status - ? ColorsManager.primaryColor - : Colors.grey - : Colors.grey, + borderRadius: BorderRadius.circular(24.0), + color: Colors.white, + ), + child: Padding( + padding: const EdgeInsets.all(2.0), + child: Container( + alignment: status != null + ? status + ? Alignment.centerRight + : Alignment.centerLeft + : Alignment.centerLeft, + child: Container( + width: 20.0, + height: 20.0, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: status != null + ? status + ? ColorsManager.primaryColor + : Colors.grey + : Colors.grey, + ), + ), + ), ), ), ), ), - ), - ), - ), - ); + ); }, ); } From a0c553f9ae4de822f256c690b17fb7d6eed28ad5 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Thu, 4 Apr 2024 14:53:58 +0300 Subject: [PATCH 24/29] Refactor ServerFailure class to use 'message' field from response Update ServerFailure class to extract error message from 'message' field in response data instead of converting the entire data to a string. --- lib/services/api/network_exception.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/api/network_exception.dart b/lib/services/api/network_exception.dart index cea8ad7..4784fa9 100644 --- a/lib/services/api/network_exception.dart +++ b/lib/services/api/network_exception.dart @@ -32,7 +32,7 @@ class ServerFailure extends Failure { // var document = parser.parse(dioError.response!.data.toString()); // var message = document.body!.text; return ServerFailure.fromResponse( - dioError.response!.statusCode!, dioError.response!.data.toString() + dioError.response!.statusCode!, dioError.response!.data['message'] // message ); } From 8c80283f9c87d3e05810ed585ac7602e5c16ba63 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Thu, 4 Apr 2024 15:51:41 +0300 Subject: [PATCH 25/29] Update DefaultNavBar widget and ServerFailure class Refactor DefaultNavBar widget to update page index on item tap. Update ServerFailure class to handle 400 status code with list of errors. --- .../app_layout/view/widgets/default_nav_bar.dart | 8 +++++--- lib/services/api/network_exception.dart | 9 ++++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/features/app_layout/view/widgets/default_nav_bar.dart b/lib/features/app_layout/view/widgets/default_nav_bar.dart index 9cc9ddd..c5140b1 100644 --- a/lib/features/app_layout/view/widgets/default_nav_bar.dart +++ b/lib/features/app_layout/view/widgets/default_nav_bar.dart @@ -27,9 +27,11 @@ class DefaultNavBar extends StatelessWidget { // DevicesCubit.getInstance() // .clearCategoriesSelection(context); // } - if (HomeCubit.getInstance().selectedRoom != null) { - HomeCubit.getInstance().unselectRoom(); - } + // if (HomeCubit.getInstance().selectedRoom != null) { + // HomeCubit.getInstance().unselectRoom(); + // } + + HomeCubit.getInstance().updatePageIndex(index); }, currentIndex: HomeCubit.pageIndex, selectedItemColor: ColorsManager.primaryColor, diff --git a/lib/services/api/network_exception.dart b/lib/services/api/network_exception.dart index 4784fa9..36b9f9f 100644 --- a/lib/services/api/network_exception.dart +++ b/lib/services/api/network_exception.dart @@ -51,8 +51,15 @@ class ServerFailure extends Failure { } factory ServerFailure.fromResponse(int statusCode, dynamic response) { - if (statusCode == 400 || statusCode == 401 || statusCode == 403) { + if (statusCode == 401 || statusCode == 403) { return ServerFailure(response); + } else if (statusCode == 400) { + //response is list of errors + List errors = []; + response.forEach((element) { + errors.add(element); + }); + return ServerFailure(errors.join('\n')); } else if (statusCode == 404) { return ServerFailure("Your request not found, Please try later!"); } else if (statusCode == 500) { From af7b497cdbf728f709daf93047b050552f91178b Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Thu, 4 Apr 2024 15:51:58 +0300 Subject: [PATCH 26/29] apend --- lib/features/app_layout/bloc/home_cubit.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/features/app_layout/bloc/home_cubit.dart b/lib/features/app_layout/bloc/home_cubit.dart index cac7a5c..8fee3a4 100644 --- a/lib/features/app_layout/bloc/home_cubit.dart +++ b/lib/features/app_layout/bloc/home_cubit.dart @@ -97,7 +97,7 @@ class HomeCubit extends Cubit { } unselectRoom() { - selectedRoom = null; + // selectedRoom = null; devicesPageController.animateToPage( 0, duration: duration, @@ -113,6 +113,7 @@ class HomeCubit extends Cubit { emitSafe(RoomUnSelected()); } +//////////////////////////////////////// API //////////////////////////////////////// fetchSpaces() async { emitSafe(GetSpacesLoading()); try { @@ -142,7 +143,7 @@ class HomeCubit extends Cubit { } } - ////////////////////////////////////////Nav//////////////////////////////////////// + /////////////////////////////////////// Nav /////////////////////////////////////// static clear() { pageIndex = 0; From 6dfce18703a659b32f9108abee3a050b51faa5a8 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Sun, 7 Apr 2024 12:50:12 +0300 Subject: [PATCH 27/29] Refactor UI structure in curtain and light widgets Simplify UI structure in curtain_view.dart and light_interface.dart by rearranging the widget tree for better readability and maintainability. --- lib/features/devices/bloc/devices_cubit.dart | 21 +++++---- .../view/widgets/curtains/curtain_view.dart | 14 +++--- .../view/widgets/lights/light_interface.dart | 46 +++++++++---------- .../devices/view/widgets/wizard_switches.dart | 2 +- 4 files changed, 41 insertions(+), 42 deletions(-) diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index d26659d..7b17513 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -24,7 +24,6 @@ part 'devices_state.dart'; class DevicesCubit extends Cubit { DevicesCubit._() : super(DevicesInitial()) { - print('device cubit created'); if (HomeCubit.getInstance().selectedSpace != null) { fetchGroups(HomeCubit.getInstance().selectedSpace!.id!); for (var room in HomeCubit.getInstance().selectedSpace!.rooms!) { @@ -256,20 +255,21 @@ class DevicesCubit extends Cubit { code: control.code, )); try { - await DevicesAPI.controlDevice(control).then((value) { + await DevicesAPI.controlDevice(control).then((response) { emitSafe(DeviceControlSuccess( code: control.code, )); - if (value['result'] ?? false) { + if (response['success'] ?? false) { Future.delayed(const Duration(milliseconds: 400), () { getDevicesStatues( - deviceId, - HomeCubit.getInstance().selectedSpace!.rooms!.indexOf( - HomeCubit.getInstance().selectedRoom!, - ), - code: control.code, - ); + deviceId, + HomeCubit.getInstance().selectedSpace!.rooms!.indexOf( + HomeCubit.getInstance().selectedRoom!, + ), + code: control.code); }); + } else { + emitSafe(DeviceControlError('Failed to control the device')); } }); } on DioException catch (e) { @@ -291,8 +291,9 @@ class DevicesCubit extends Cubit { } } - fetchDevicesByRoomId(int roomId) async { + fetchDevicesByRoomId(int? roomId) async { if (_isClosed) return; + if (roomId == null) return; try { emitSafe(GetDevicesLoading()); diff --git a/lib/features/devices/view/widgets/curtains/curtain_view.dart b/lib/features/devices/view/widgets/curtains/curtain_view.dart index 30d7e74..c67b0c6 100644 --- a/lib/features/devices/view/widgets/curtains/curtain_view.dart +++ b/lib/features/devices/view/widgets/curtains/curtain_view.dart @@ -20,13 +20,13 @@ class CurtainView extends StatelessWidget { statusBarColor: ColorsManager.primaryColor.withOpacity(0.5), statusBarIconBrightness: Brightness.light, ), - child: SafeArea( - child: Scaffold( - backgroundColor: ColorsManager.backgroundColor, - extendBodyBehindAppBar: true, - extendBody: true, - appBar: const CategoryViewAppBar(), - body: Container( + child: Scaffold( + backgroundColor: ColorsManager.backgroundColor, + extendBodyBehindAppBar: true, + extendBody: true, + appBar: const CategoryViewAppBar(), + body: SafeArea( + child: Container( width: MediaQuery.sizeOf(context).width, height: MediaQuery.sizeOf(context).height, decoration: const BoxDecoration( diff --git a/lib/features/devices/view/widgets/lights/light_interface.dart b/lib/features/devices/view/widgets/lights/light_interface.dart index e2ae653..2b34853 100644 --- a/lib/features/devices/view/widgets/lights/light_interface.dart +++ b/lib/features/devices/view/widgets/lights/light_interface.dart @@ -24,31 +24,29 @@ class LightInterface extends StatelessWidget { statusBarColor: ColorsManager.primaryColor.withOpacity(0.5), statusBarIconBrightness: Brightness.light, ), - child: SafeArea( - child: Scaffold( - backgroundColor: ColorsManager.backgroundColor, - extendBodyBehindAppBar: true, - extendBody: true, - appBar: AppBar( - backgroundColor: Colors.transparent, - centerTitle: true, - title: BodyLarge( - text: light.name ?? "", - fontColor: ColorsManager.primaryColor, - fontWeight: FontsManager.bold, - ), + child: Scaffold( + backgroundColor: ColorsManager.backgroundColor, + extendBodyBehindAppBar: true, + extendBody: true, + appBar: AppBar( + backgroundColor: Colors.transparent, + centerTitle: true, + title: BodyLarge( + text: light.name ?? "", + fontColor: ColorsManager.primaryColor, + fontWeight: FontsManager.bold, ), - body: Padding( - padding: const EdgeInsets.only(top: 70, right: 20, left: 20), - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - LightInterfaceSwitch(light: light), - LightInterfaceContols(light: light), - const LightInterfaceTimer(), - ], - ), + ), + body: Padding( + padding: const EdgeInsets.only(top: 70, right: 20, left: 20), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + LightInterfaceSwitch(light: light), + LightInterfaceContols(light: light), + const LightInterfaceTimer(), + ], ), ), ), diff --git a/lib/features/devices/view/widgets/wizard_switches.dart b/lib/features/devices/view/widgets/wizard_switches.dart index 6dc6d93..7d5de2b 100644 --- a/lib/features/devices/view/widgets/wizard_switches.dart +++ b/lib/features/devices/view/widgets/wizard_switches.dart @@ -34,7 +34,7 @@ class WizartSwitches extends StatelessWidget { itemBuilder: (_, index) { return InkWell( onTap: () { - DevicesCubit.getInstance().selectCategory(index); + // DevicesCubit.getInstance().selectCategory(index); //Navigate to the chosen category view without animation Navigator.push(context, From 696ff25b6ae11353660ed5b8fa1cb2df74870b45 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Sun, 7 Apr 2024 12:57:26 +0300 Subject: [PATCH 28/29] Update import paths from relative to abslute path accross the entire application. --- lib/features/app_layout/view/widgets/app_body.dart | 2 +- lib/features/dashboard/view/widgets/consumption.dart | 2 +- .../dashboard/view/widgets/live_monitor_tab.dart | 2 +- .../devices/view/widgets/ACs/ac_temp_widget.dart | 2 +- lib/features/devices/view/widgets/ACs/acs_view.dart | 5 ++--- .../devices/view/widgets/ACs/universal_ac_temp.dart | 9 ++++----- .../widgets/lights/light_interface_recent_color.dart | 6 +++--- .../view/widgets/lights/light_interface_timer.dart | 2 +- 8 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/features/app_layout/view/widgets/app_body.dart b/lib/features/app_layout/view/widgets/app_body.dart index 34343b3..8e3fa72 100644 --- a/lib/features/app_layout/view/widgets/app_body.dart +++ b/lib/features/app_layout/view/widgets/app_body.dart @@ -3,7 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; -import '../../../../generated/assets.dart'; +import 'package:syncrow_app/generated/assets.dart'; class AppBody extends StatelessWidget { const AppBody({ diff --git a/lib/features/dashboard/view/widgets/consumption.dart b/lib/features/dashboard/view/widgets/consumption.dart index 6cd1e84..9e5a1a7 100644 --- a/lib/features/dashboard/view/widgets/consumption.dart +++ b/lib/features/dashboard/view/widgets/consumption.dart @@ -3,7 +3,7 @@ import 'package:syncrow_app/features/dashboard/view/widgets/card_title.dart'; import 'package:syncrow_app/features/shared_widgets/united_text.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; -import '../../../../generated/assets.dart'; +import 'package:syncrow_app/generated/assets.dart'; class Consumption extends StatelessWidget { const Consumption({ diff --git a/lib/features/dashboard/view/widgets/live_monitor_tab.dart b/lib/features/dashboard/view/widgets/live_monitor_tab.dart index 1763089..1b4fb2e 100644 --- a/lib/features/dashboard/view/widgets/live_monitor_tab.dart +++ b/lib/features/dashboard/view/widgets/live_monitor_tab.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:syncrow_app/features/dashboard/view/widgets/live_monitor_widget.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; -import '../../../../generated/assets.dart'; +import 'package:syncrow_app/generated/assets.dart'; class LiveMonitorTab extends StatelessWidget { const LiveMonitorTab({ diff --git a/lib/features/devices/view/widgets/ACs/ac_temp_widget.dart b/lib/features/devices/view/widgets/ACs/ac_temp_widget.dart index 0ae8eaf..1517119 100644 --- a/lib/features/devices/view/widgets/ACs/ac_temp_widget.dart +++ b/lib/features/devices/view/widgets/ACs/ac_temp_widget.dart @@ -8,7 +8,7 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; -import '../../../../../generated/assets.dart'; +import 'package:syncrow_app/generated/assets.dart'; class ACTempWidget extends StatelessWidget { const ACTempWidget( diff --git a/lib/features/devices/view/widgets/ACs/acs_view.dart b/lib/features/devices/view/widgets/ACs/acs_view.dart index 358bbca..5d03f8b 100644 --- a/lib/features/devices/view/widgets/ACs/acs_view.dart +++ b/lib/features/devices/view/widgets/ACs/acs_view.dart @@ -6,10 +6,9 @@ import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_list.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/category_view_app_bar.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; - -import '../../../../../generated/assets.dart'; -import '../../../../../utils/resource_manager/color_manager.dart'; +import 'package:syncrow_app/generated/assets.dart'; class ACsView extends StatelessWidget { const ACsView({super.key}); diff --git a/lib/features/devices/view/widgets/ACs/universal_ac_temp.dart b/lib/features/devices/view/widgets/ACs/universal_ac_temp.dart index 3e86fc9..f2566c3 100644 --- a/lib/features/devices/view/widgets/ACs/universal_ac_temp.dart +++ b/lib/features/devices/view/widgets/ACs/universal_ac_temp.dart @@ -2,12 +2,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; +import 'package:syncrow_app/features/shared_widgets/default_container.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/utils/context_extension.dart'; - -import '../../../../../generated/assets.dart'; -import '../../../../../utils/resource_manager/color_manager.dart'; -import '../../../../shared_widgets/default_container.dart'; -import '../../../../shared_widgets/text_widgets/body_large.dart'; +import 'package:syncrow_app/generated/assets.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; class UniversalACTemp extends StatelessWidget { const UniversalACTemp({ diff --git a/lib/features/devices/view/widgets/lights/light_interface_recent_color.dart b/lib/features/devices/view/widgets/lights/light_interface_recent_color.dart index c1c1326..ad0509e 100644 --- a/lib/features/devices/view/widgets/lights/light_interface_recent_color.dart +++ b/lib/features/devices/view/widgets/lights/light_interface_recent_color.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; -import '../../../../../generated/assets.dart'; -import '../../../../../utils/resource_manager/strings_manager.dart'; -import '../../../../shared_widgets/text_widgets/body_medium.dart'; +import 'package:syncrow_app/generated/assets.dart'; +import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; class LightInterfaceRecentColor extends StatelessWidget { const LightInterfaceRecentColor({ diff --git a/lib/features/devices/view/widgets/lights/light_interface_timer.dart b/lib/features/devices/view/widgets/lights/light_interface_timer.dart index 5b949b2..1b3902d 100644 --- a/lib/features/devices/view/widgets/lights/light_interface_timer.dart +++ b/lib/features/devices/view/widgets/lights/light_interface_timer.dart @@ -3,7 +3,7 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; -import '../../../../shared_widgets/default_container.dart'; +import 'package:syncrow_app/features/shared_widgets/default_container.dart'; class LightInterfaceTimer extends StatelessWidget { const LightInterfaceTimer({ From 2ae0c07830248805a775c3d83c9ba30855b6ffa9 Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Sat, 13 Apr 2024 18:05:19 +0300 Subject: [PATCH 29/29] Update import statements from relative tok apsulote paths. --- .../app_layout/view/widgets/app_bar_home_dropdown.dart | 3 +-- .../devices/view/widgets/ACs/ac_interface_controls.dart | 3 +-- .../devices/view/widgets/ACs/category_view_app_bar.dart | 3 +-- lib/features/devices/view/widgets/devices_view_body.dart | 3 +-- .../view/widgets/lights/light_interface_switch.dart | 3 +-- lib/features/devices/view/widgets/lights/lights_list.dart | 5 ++--- .../devices/view/widgets/lights/lights_view_list.dart | 7 +++---- lib/features/devices/view/widgets/universal_switch.dart | 5 ++--- lib/features/devices/view/widgets/wizard_switches.dart | 3 +-- lib/features/menu/bloc/menu_cubit.dart | 5 ++--- lib/features/menu/view/widgets/profile_tab.dart | 3 +-- lib/features/shared_widgets/devices_default_switch.dart | 3 +-- lib/services/api/network_exception.dart | 4 ++-- 13 files changed, 19 insertions(+), 31 deletions(-) diff --git a/lib/features/app_layout/view/widgets/app_bar_home_dropdown.dart b/lib/features/app_layout/view/widgets/app_bar_home_dropdown.dart index 197893a..4fc6965 100644 --- a/lib/features/app_layout/view/widgets/app_bar_home_dropdown.dart +++ b/lib/features/app_layout/view/widgets/app_bar_home_dropdown.dart @@ -3,11 +3,10 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; +import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; -import '../../../../generated/assets.dart'; - class AppBarHomeDropdown extends StatelessWidget { const AppBarHomeDropdown({super.key}); diff --git a/lib/features/devices/view/widgets/ACs/ac_interface_controls.dart b/lib/features/devices/view/widgets/ACs/ac_interface_controls.dart index 0714bc1..9d39be6 100644 --- a/lib/features/devices/view/widgets/ACs/ac_interface_controls.dart +++ b/lib/features/devices/view/widgets/ACs/ac_interface_controls.dart @@ -5,8 +5,7 @@ import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_mode_control_unit.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; - -import '../../../../../generated/assets.dart'; +import 'package:syncrow_app/generated/assets.dart'; class AcInterfaceControls extends StatelessWidget { const AcInterfaceControls({ diff --git a/lib/features/devices/view/widgets/ACs/category_view_app_bar.dart b/lib/features/devices/view/widgets/ACs/category_view_app_bar.dart index 4213086..f543407 100644 --- a/lib/features/devices/view/widgets/ACs/category_view_app_bar.dart +++ b/lib/features/devices/view/widgets/ACs/category_view_app_bar.dart @@ -2,10 +2,9 @@ import 'package:flutter/material.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/display_medium.dart'; import 'package:syncrow_app/utils/context_extension.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; -import '../../../../../utils/resource_manager/color_manager.dart'; - class CategoryViewAppBar extends StatelessWidget implements PreferredSizeWidget { const CategoryViewAppBar({ diff --git a/lib/features/devices/view/widgets/devices_view_body.dart b/lib/features/devices/view/widgets/devices_view_body.dart index 5b3f9f4..6edb972 100644 --- a/lib/features/devices/view/widgets/devices_view_body.dart +++ b/lib/features/devices/view/widgets/devices_view_body.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/view/widgets/devices_view_header.dart'; import 'package:syncrow_app/features/devices/view/widgets/room_page.dart'; import 'package:syncrow_app/features/devices/view/widgets/rooms_slider.dart'; @@ -9,8 +10,6 @@ import 'package:syncrow_app/features/devices/view/widgets/wizard_page.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; -import '../../bloc/devices_cubit.dart'; - class DevicesViewBody extends StatelessWidget { const DevicesViewBody({ super.key, diff --git a/lib/features/devices/view/widgets/lights/light_interface_switch.dart b/lib/features/devices/view/widgets/lights/light_interface_switch.dart index 938d772..7defc52 100644 --- a/lib/features/devices/view/widgets/lights/light_interface_switch.dart +++ b/lib/features/devices/view/widgets/lights/light_interface_switch.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; +import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; -import '../../../../shared_widgets/default_container.dart'; - class LightInterfaceSwitch extends StatelessWidget { const LightInterfaceSwitch({ super.key, diff --git a/lib/features/devices/view/widgets/lights/lights_list.dart b/lib/features/devices/view/widgets/lights/lights_list.dart index 7d4f164..ec675d7 100644 --- a/lib/features/devices/view/widgets/lights/lights_list.dart +++ b/lib/features/devices/view/widgets/lights/lights_list.dart @@ -2,9 +2,8 @@ import 'package:flutter/material.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/lights/light_brightness.dart'; - -import '../../../../shared_widgets/devices_default_switch.dart'; -import '../../../../shared_widgets/text_widgets/body_small.dart'; +import 'package:syncrow_app/features/shared_widgets/devices_default_switch.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; class LightsList extends StatelessWidget { const LightsList({ diff --git a/lib/features/devices/view/widgets/lights/lights_view_list.dart b/lib/features/devices/view/widgets/lights/lights_view_list.dart index 2348dd1..25a3795 100644 --- a/lib/features/devices/view/widgets/lights/lights_view_list.dart +++ b/lib/features/devices/view/widgets/lights/lights_view_list.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/lights/lights_list.dart'; +import 'package:syncrow_app/features/devices/view/widgets/universal_switch.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; -import '../../../../shared_widgets/text_widgets/body_small.dart'; -import '../../../bloc/devices_cubit.dart'; -import '../universal_switch.dart'; - class LightsViewList extends StatelessWidget { const LightsViewList({ super.key, diff --git a/lib/features/devices/view/widgets/universal_switch.dart b/lib/features/devices/view/widgets/universal_switch.dart index 1746ffc..9112514 100644 --- a/lib/features/devices/view/widgets/universal_switch.dart +++ b/lib/features/devices/view/widgets/universal_switch.dart @@ -2,11 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_category_model.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; -import '../../../../utils/resource_manager/color_manager.dart'; -import '../../../shared_widgets/text_widgets/body_medium.dart'; - class UniversalSwitch extends StatelessWidget { const UniversalSwitch({ super.key, diff --git a/lib/features/devices/view/widgets/wizard_switches.dart b/lib/features/devices/view/widgets/wizard_switches.dart index 7d5de2b..a00d19a 100644 --- a/lib/features/devices/view/widgets/wizard_switches.dart +++ b/lib/features/devices/view/widgets/wizard_switches.dart @@ -1,13 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/helpers/custom_page_route.dart'; -import '../../bloc/devices_cubit.dart'; - class WizartSwitches extends StatelessWidget { const WizartSwitches({ super.key, diff --git a/lib/features/menu/bloc/menu_cubit.dart b/lib/features/menu/bloc/menu_cubit.dart index 56a8714..89ece3f 100644 --- a/lib/features/menu/bloc/menu_cubit.dart +++ b/lib/features/menu/bloc/menu_cubit.dart @@ -1,7 +1,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; - -import '../model/list_item_model.dart'; -import '../model/menu_list_model.dart'; +import 'package:syncrow_app/features/menu/model/list_item_model.dart'; +import 'package:syncrow_app/features/menu/model/menu_list_model.dart'; part 'menu_state.dart'; diff --git a/lib/features/menu/view/widgets/profile_tab.dart b/lib/features/menu/view/widgets/profile_tab.dart index 16dc836..bfc7a16 100644 --- a/lib/features/menu/view/widgets/profile_tab.dart +++ b/lib/features/menu/view/widgets/profile_tab.dart @@ -1,10 +1,9 @@ import 'package:flutter/material.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; +import 'package:syncrow_app/features/shared_widgets/syncrow_logo.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; -import '../../../shared_widgets/syncrow_logo.dart'; - class ProfileTab extends StatelessWidget { const ProfileTab({ super.key, diff --git a/lib/features/shared_widgets/devices_default_switch.dart b/lib/features/shared_widgets/devices_default_switch.dart index 50a58b6..80511d8 100644 --- a/lib/features/shared_widgets/devices_default_switch.dart +++ b/lib/features/shared_widgets/devices_default_switch.dart @@ -1,11 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; -import '../devices/bloc/devices_cubit.dart'; - class DevicesDefaultSwitch extends StatelessWidget { const DevicesDefaultSwitch({ super.key, diff --git a/lib/services/api/network_exception.dart b/lib/services/api/network_exception.dart index 36b9f9f..f8940de 100644 --- a/lib/services/api/network_exception.dart +++ b/lib/services/api/network_exception.dart @@ -31,8 +31,8 @@ class ServerFailure extends Failure { { // var document = parser.parse(dioError.response!.data.toString()); // var message = document.body!.text; - return ServerFailure.fromResponse( - dioError.response!.statusCode!, dioError.response!.data['message'] + return ServerFailure.fromResponse(dioError.response!.statusCode!, + dioError.response!.data['message'].toString() // message ); }