From 5a9c96b0a86e3cf352821a29d7c4d699d2fe3f8a Mon Sep 17 00:00:00 2001 From: Mohammad Salameh Date: Tue, 5 Mar 2024 12:36:57 +0300 Subject: [PATCH] Built Curtains List view Modified Category Model(default value of devices status is now null) Added a category getter in each devices cubit ( AcCubit, LightsCubit ...) --- lib/features/devices/bloc/ac/ac_cubit.dart | 9 +- .../devices/bloc/curtains/curtains_cubit.dart | 13 +++ .../devices/bloc/curtains/curtains_state.dart | 5 ++ lib/features/devices/bloc/devices_cubit.dart | 43 ++++++---- lib/features/devices/model/curtain_model.dart | 42 ++++++++++ .../devices/model/device_category_model.dart | 4 +- .../devices/view/widgets/ACs/acs_list.dart | 16 ++-- .../view/widgets/curtains/curtain_list.dart | 84 +++++++++++++++++++ .../view/widgets/curtains/curtain_view.dart | 56 ++++++++++++- 9 files changed, 240 insertions(+), 32 deletions(-) create mode 100644 lib/features/devices/bloc/curtains/curtains_cubit.dart create mode 100644 lib/features/devices/bloc/curtains/curtains_state.dart create mode 100644 lib/features/devices/model/curtain_model.dart create mode 100644 lib/features/devices/view/widgets/curtains/curtain_list.dart diff --git a/lib/features/devices/bloc/ac/ac_cubit.dart b/lib/features/devices/bloc/ac/ac_cubit.dart index e35be05..6e36957 100644 --- a/lib/features/devices/bloc/ac/ac_cubit.dart +++ b/lib/features/devices/bloc/ac/ac_cubit.dart @@ -2,6 +2,7 @@ import 'package:flutter/cupertino.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/ac_model.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'; @@ -11,8 +12,10 @@ class AcCubit extends Cubit { static AcCubit get(context) => BlocProvider.of(context); + static DevicesCategoryModel category = DevicesCubit.categories[0]; + ACModel? getSelectedAC() { - for (var ac in DevicesCubit.categories[0].devices) { + for (var ac in category.devices) { if (ac is ACModel && ac.isSelected) { return ac; } @@ -21,7 +24,7 @@ class AcCubit extends Cubit { } void setTempToAll(double temperature) { - for (DeviceModel ac in DevicesCubit.categories[0].devices) { + for (DeviceModel ac in category.devices) { if (ac is ACModel) { if (ac.temperature != temperature && ac.bounds.min <= temperature && @@ -42,7 +45,7 @@ class AcCubit extends Cubit { } double getTemp(int index) { - var device = DevicesCubit.categories[0].devices[index]; + var device = category.devices[index]; if (device is ACModel) { return device.temperature; } diff --git a/lib/features/devices/bloc/curtains/curtains_cubit.dart b/lib/features/devices/bloc/curtains/curtains_cubit.dart new file mode 100644 index 0000000..5b0900d --- /dev/null +++ b/lib/features/devices/bloc/curtains/curtains_cubit.dart @@ -0,0 +1,13 @@ +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'; + +part 'curtains_state.dart'; + +class CurtainsCubit extends Cubit { + CurtainsCubit() : super(CurtainsInitial()); + + static CurtainsCubit get(context) => BlocProvider.of(context); + + static DevicesCategoryModel category = DevicesCubit.categories[4]; +} diff --git a/lib/features/devices/bloc/curtains/curtains_state.dart b/lib/features/devices/bloc/curtains/curtains_state.dart new file mode 100644 index 0000000..5c30d86 --- /dev/null +++ b/lib/features/devices/bloc/curtains/curtains_state.dart @@ -0,0 +1,5 @@ +part of 'curtains_cubit.dart'; + +abstract class CurtainsState {} + +class CurtainsInitial extends CurtainsState {} diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index 9ee4b30..7963077 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -303,35 +303,44 @@ class DevicesCubit extends Cubit { } updateDevicesStatus(DevicesCategoryModel category) { - bool? tempStatus = category.devices[0].status; - 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) { - category.devicesStatus = null; + if (category.devices.isNotEmpty) { + bool? tempStatus = category.devices[0].status; + 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) { + category.devicesStatus = null; + emit(DeviceSwitchChanged()); + return; + } + category.devicesStatus = tempStatus; emit(DeviceSwitchChanged()); - return; } - category.devicesStatus = tempStatus; + } else { + category.devicesStatus = null; emit(DeviceSwitchChanged()); } } turnAllDevicesOff(DevicesCategoryModel category) { - for (var device in category.devices) { - device.status = false; + if (category.devices.isNotEmpty) { + for (var device in category.devices) { + device.status = false; + } + changeCategorySwitchValue(category); + updateDevicesStatus(category); + emit(CategorySwitchChanged()); } - changeCategorySwitchValue(category); - updateDevicesStatus(category); - emit(CategorySwitchChanged()); } turnAllDevicesOn(DevicesCategoryModel category) { - for (var device in category.devices) { - device.status = true; + if (category.devices.isNotEmpty) { + for (var device in category.devices) { + device.status = true; + } + changeCategorySwitchValue(category); + updateDevicesStatus(category); + emit(CategorySwitchChanged()); } - changeCategorySwitchValue(category); - updateDevicesStatus(category); - emit(CategorySwitchChanged()); } areAllDevicesOff(DevicesCategoryModel category) { diff --git a/lib/features/devices/model/curtain_model.dart b/lib/features/devices/model/curtain_model.dart new file mode 100644 index 0000000..276cd34 --- /dev/null +++ b/lib/features/devices/model/curtain_model.dart @@ -0,0 +1,42 @@ +import 'package:syncrow_app/features/devices/model/device_model.dart'; + +class CurtainModel extends DeviceModel { + late int openPercentage; + + CurtainModel({ + required this.openPercentage, + required super.id, + required super.name, + required super.type, + required super.status, + required super.location, + required super.image, + required super.timer, + }); + + Map toJson() { + return { + 'openPercentage': openPercentage, + 'timer': timer, + 'id': id, + 'name': name, + 'status': status, + 'type': type, + 'location': location, + 'image': image, + }; + } + + factory CurtainModel.fromJson(Map json) { + return CurtainModel( + id: json['id'], + name: json['name'], + status: json['status'], + openPercentage: json['openPercentage'], + timer: json['timer'], + type: json['type'], + location: json['location'], + image: json['image'], + ); + } +} diff --git a/lib/features/devices/model/device_category_model.dart b/lib/features/devices/model/device_category_model.dart index 1023ad8..756e4ca 100644 --- a/lib/features/devices/model/device_category_model.dart +++ b/lib/features/devices/model/device_category_model.dart @@ -9,7 +9,7 @@ class DevicesCategoryModel { final Widget page; - bool? devicesStatus = false; + bool? devicesStatus; final List devices; final DeviceType type; @@ -32,8 +32,6 @@ class DevicesCategoryModel { } } devicesStatus = tempStatus; - } else { - devicesStatus = false; } } } diff --git a/lib/features/devices/view/widgets/ACs/acs_list.dart b/lib/features/devices/view/widgets/ACs/acs_list.dart index 438ceb5..4b3c638 100644 --- a/lib/features/devices/view/widgets/ACs/acs_list.dart +++ b/lib/features/devices/view/widgets/ACs/acs_list.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/AC/ac_cubit.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/view/widgets/ACs/ac_mode_control_unit.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_temp_widget.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/universal_ac_temp.dart'; @@ -18,7 +18,6 @@ class ACsList extends StatelessWidget { @override Widget build(BuildContext context) { - DevicesCategoryModel category = DevicesCubit.categories[0]; return BlocBuilder( builder: (context, state) { return SingleChildScrollView( @@ -30,7 +29,7 @@ class ACsList extends StatelessWidget { const BodySmall(text: "All ACs"), const SizedBox(height: 5), UniversalSwitch( - category: category, + category: AcCubit.category, ), const SizedBox(height: 10), const UniversalACTemp(), @@ -41,9 +40,9 @@ class ACsList extends StatelessWidget { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), padding: const EdgeInsets.all(0), - itemCount: category.devices.length, + itemCount: AcCubit.category.devices.length, itemBuilder: (context, index) { - ACModel ac = category.devices[index] as ACModel; + ACModel ac = AcCubit.category.devices[index] as ACModel; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -51,7 +50,8 @@ class ACsList extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.end, children: [ - BodySmall(text: category.devices[index].name ?? ""), + BodySmall( + text: AcCubit.category.devices[index].name ?? ""), IconButton( onPressed: () { DevicesCubit.get(context).selectDevice(ac); @@ -70,7 +70,7 @@ class ACsList extends StatelessWidget { ], ), const SizedBox(height: 5), - if (category.devices[index] is ACModel) + if (AcCubit.category.devices[index] is ACModel) DevicesDefaultSwitch( model: ac, ), @@ -79,7 +79,7 @@ class ACsList extends StatelessWidget { ac, ), const SizedBox(height: 10), - if (category.devices[index] is ACModel) + if (AcCubit.category.devices[index] is ACModel) ACModeControlUnit( model: ac, ), diff --git a/lib/features/devices/view/widgets/curtains/curtain_list.dart b/lib/features/devices/view/widgets/curtains/curtain_list.dart new file mode 100644 index 0000000..667849f --- /dev/null +++ b/lib/features/devices/view/widgets/curtains/curtain_list.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/curtains/curtains_cubit.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; +import 'package:syncrow_app/features/devices/model/curtain_model.dart'; +import 'package:syncrow_app/features/devices/view/widgets/universal_switch.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 CurtainList extends StatelessWidget { + const CurtainList({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + // universal AC controller + const SizedBox(height: 10), + //TODO: move to strings manager + const BodySmall(text: "All Curtains"), + const SizedBox(height: 5), + UniversalSwitch( + category: CurtainsCubit.category, + ), + + // other ACs controls + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: const EdgeInsets.all(0), + itemCount: CurtainsCubit.category.devices.length, + itemBuilder: (context, index) { + CurtainModel ac = + CurtainsCubit.category.devices[index] as CurtainModel; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + BodySmall( + text: + CurtainsCubit.category.devices[index].name ?? + ""), + IconButton( + onPressed: () { + DevicesCubit.get(context).selectDevice(ac); + }, + icon: const Icon( + Icons.arrow_forward_ios, + ), + style: ButtonStyle( + padding: MaterialStateProperty.all( + const EdgeInsets.all(0), + ), + iconSize: MaterialStateProperty.all(15), + alignment: Alignment.bottomRight, + ), + ), + ], + ), + const SizedBox(height: 5), + if (CurtainsCubit.category.devices[index] is CurtainModel) + DevicesDefaultSwitch( + model: ac, + ), + ], + ); + }, + ), + ], + ), + ); + }, + ); + } +} diff --git a/lib/features/devices/view/widgets/curtains/curtain_view.dart b/lib/features/devices/view/widgets/curtains/curtain_view.dart index e85496f..ac28052 100644 --- a/lib/features/devices/view/widgets/curtains/curtain_view.dart +++ b/lib/features/devices/view/widgets/curtains/curtain_view.dart @@ -1,10 +1,64 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/app_layout/view/widgets/default_app_bar.dart'; +import 'package:syncrow_app/features/devices/bloc/curtains/curtains_cubit.dart'; +import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; +import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_list.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 CurtainView extends StatelessWidget { const CurtainView({super.key}); @override Widget build(BuildContext context) { - return const Placeholder(); + return BlocProvider( + create: (context) => CurtainsCubit(), + child: BlocBuilder( + builder: (context, state) { + return BlocBuilder( + builder: (context, state) { + 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: DefaultAppBar(context), + 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: const CurtainList(), + ), + ), + ), + ), + ); + }, + ); + }, + ), + ); } }