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/bloc/home_cubit.dart b/lib/features/app_layout/bloc/home_cubit.dart index b0e1932..8fee3a4 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'; @@ -17,26 +18,35 @@ 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) { - if (selectedSpace == null) { - fetchSpaces().then((value) { - if (selectedSpace != null) { - print('selectedSpace: ${selectedSpace!.name}'); - fetchRooms(selectedSpace!); - } - }); - } - } else { - fetchSpaces(); // this is for the first time + HomeCubit._() : super(HomeInitial()) { + if (selectedSpace == null) { + fetchSpaces().then((value) { + if (selectedSpace != null) { + fetchRooms(selectedSpace!); + } + }); + } + } + + static HomeCubit? _instance; + static HomeCubit getInstance() { + // If an instance already exists, return it + _instance ??= HomeCubit._(); + return _instance!; + } + + void emitSafe(HomeState newState) { + final cubit = this; + if (!cubit.isClosed) { + cubit.emit(newState); } } static HomeCubit get(context) => BlocProvider.of(context); - static List? spaces; + List? spaces; - static SpaceModel? selectedSpace; + SpaceModel? selectedSpace; RoomModel? selectedRoom; @@ -46,9 +56,14 @@ 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)); + emitSafe(SpaceSelected(space)); } roomSliderPageChanged(int index) { @@ -62,7 +77,7 @@ class HomeCubit extends Cubit { unselectRoom(); } else { selectedRoom = selectedSpace!.rooms![index - 1]; - emit(RoomSelected(selectedRoom!)); + emitSafe(RoomSelected(selectedRoom!)); } } @@ -77,12 +92,12 @@ class HomeCubit extends Cubit { unselectRoom(); } else { selectedRoom = selectedSpace!.rooms![index - 1]; - emit(RoomSelected(selectedRoom!)); + emitSafe(RoomSelected(selectedRoom!)); } } unselectRoom() { - selectedRoom = null; + // selectedRoom = null; devicesPageController.animateToPage( 0, duration: duration, @@ -95,35 +110,40 @@ class HomeCubit extends Cubit { curve: Curves.linear, ); - emit(RoomUnSelected()); + emitSafe(RoomUnSelected()); } +//////////////////////////////////////// API //////////////////////////////////////// fetchSpaces() async { - emit(GetSpacesLoading()); + emitSafe(GetSpacesLoading()); try { spaces = await SpacesAPI.getSpaces(); - selectedSpace = spaces!.isNotEmpty ? selectSpace(spaces!.first) : null; - emit(GetSpacesLoaded(spaces!)); + selectedSpace = spaces!.isNotEmpty + ? + // selectSpace(spaces!.first) + selectedSpace = spaces!.first + : null; + 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.getRooms(space.id!); + 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)); } } - ////////////////////////////////////////Nav//////////////////////////////////////// + /////////////////////////////////////// Nav /////////////////////////////////////// static clear() { pageIndex = 0; @@ -247,7 +267,10 @@ class HomeCubit extends Cubit { final List pages = [ const DashboardView(), // const LayoutPage(), - const DevicesViewBody(), + BlocProvider( + create: (context) => DevicesCubit.getInstance(), + child: const DevicesViewBody(), + ), const SceneView(), const MenuView(), ]; @@ -255,7 +278,7 @@ class HomeCubit extends Cubit { void updatePageIndex(int index) { pageIndex = index; - emit(NavChangePage()); + emitSafe(NavChangePage()); } } 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 dda35a1..6fbdb42 100644 --- a/lib/features/app_layout/view/app_layout.dart +++ b/lib/features/app_layout/view/app_layout.dart @@ -6,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'; @@ -15,16 +14,9 @@ class AppLayout extends StatelessWidget { @override Widget build(BuildContext context) { - return MultiBlocProvider( - providers: [ - BlocProvider( - create: (context) => HomeCubit(), - ), - BlocProvider( - create: (context) => DevicesCubit(), - ), - ], - child: BlocListener( + return BlocProvider( + create: (context) => HomeCubit.getInstance(), + child: BlocConsumer( listener: (context, state) { if (state is GetSpacesError) { ScaffoldMessenger.of(context).showSnackBar( @@ -36,30 +28,38 @@ 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: 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: SafeArea( - child: BlocBuilder( - builder: (context, state) { - return const Scaffold( - backgroundColor: ColorsManager.backgroundColor, - extendBodyBehindAppBar: true, - extendBody: true, - appBar: DefaultAppBar(), - body: AppBody(), - bottomNavigationBar: DefaultNavBar(), - ); - }, - ), - ), - ); - }, - ), + ), + ); + }, ), ); } 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..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,76 +3,73 @@ 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, - }); + 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..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({ @@ -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..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 { @@ -20,11 +19,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..c5140b1 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'; @@ -15,19 +16,22 @@ 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( backgroundColor: Colors.transparent, onTap: (int index) { cubit.updatePageIndex(index); - if (DevicesCubit.get(context).chosenCategoryView != null) { - DevicesCubit().clearCategoriesSelection(context); - } - if (HomeCubit.get(context).selectedRoom != null) { - HomeCubit.get(context).unselectRoom(); - } + // if (DevicesCubit.getInstance().chosenCategoryView != null) { + // DevicesCubit.getInstance() + // .clearCategoriesSelection(context); + // } + // if (HomeCubit.getInstance().selectedRoom != null) { + // HomeCubit.getInstance().unselectRoom(); + // } + + HomeCubit.getInstance().updatePageIndex(index); }, currentIndex: HomeCubit.pageIndex, selectedItemColor: ColorsManager.primaryColor, 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/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/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 {} diff --git a/lib/features/devices/bloc/devices_cubit.dart b/lib/features/devices/bloc/devices_cubit.dart index ddb130b..7b17513 100644 --- a/lib/features/devices/bloc/devices_cubit.dart +++ b/lib/features/devices/bloc/devices_cubit.dart @@ -8,32 +8,54 @@ 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'; 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_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'; +import 'package:syncrow_app/services/api/spaces_api.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; part 'devices_state.dart'; class DevicesCubit extends Cubit { - DevicesCubit() : super(DevicesInitial()) { - if (HomeCubit.selectedSpace != null) { - fetchGroups(HomeCubit.selectedSpace!.id!); + 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; + static DevicesCubit? _instance; + static DevicesCubit getInstance() { + print('device cubit instance found : ${_instance != null}'); + print('selected space : ${HomeCubit.getInstance().selectedSpace != null}'); + return _instance ??= DevicesCubit._(); + } + + DeviceModel? selectedDevice; + @override Future close() { _isClosed = true; + _instance = null; return super.close(); } + void emitSafe(DevicesState newState) { + final cubit = this; + if (!cubit.isClosed) { + cubit.emit(newState); + } + } + static DevicesCubit get(context) => BlocProvider.of(context); static List? allCategories; @@ -46,14 +68,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 { @@ -63,14 +85,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(); + // case DeviceType.ThreeGang: + // return const ThreeGangSwitchesView(); case DeviceType.Gateway: return const GateWayView(); default: @@ -97,14 +119,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() { @@ -125,24 +147,24 @@ 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; } } } updateDevicesStatus(category); - emit(CategorySwitchChanged()); + emitSafe(CategorySwitchChanged()); } 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); @@ -151,26 +173,26 @@ class DevicesCubit extends Cubit { } }); updateDevicesStatus(category); - emit(DeviceSwitchChanged()); + emitSafe(DeviceSwitchChanged()); } 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()); + emitSafe(DeviceSwitchChanged()); return; } category.devicesStatus = tempStatus; - emit(DeviceSwitchChanged()); + emitSafe(DeviceSwitchChanged()); } } else { category.devicesStatus = null; - emit(DeviceSwitchChanged()); + emitSafe(DeviceSwitchChanged()); } } } @@ -179,11 +201,11 @@ 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); - emit(CategorySwitchChanged()); + emitSafe(CategorySwitchChanged()); } } } @@ -192,11 +214,11 @@ 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); - emit(CategorySwitchChanged()); + emitSafe(CategorySwitchChanged()); } } } @@ -204,9 +226,9 @@ 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()); + emitSafe(CategorySwitchChanged()); return; } } @@ -224,16 +246,34 @@ class DevicesCubit extends Cubit { } Navigator.popUntil(context, (route) => route.isFirst); - emit(DevicesCategoryChanged()); + emitSafe(DevicesCategoryChanged()); } - deviceControl(DeviceControlModel control) async { - emit(DeviceControlLoading()); +///////////////////////// API CALLS ////////////////////////// + deviceControl(DeviceControlModel control, String deviceId) async { + emitSafe(DeviceControlLoading( + code: control.code, + )); try { - await DevicesAPI.controlDevice(control); - emit(DeviceControlSuccess()); + await DevicesAPI.controlDevice(control).then((response) { + emitSafe(DeviceControlSuccess( + code: control.code, + )); + if (response['success'] ?? false) { + Future.delayed(const Duration(milliseconds: 400), () { + getDevicesStatues( + deviceId, + HomeCubit.getInstance().selectedSpace!.rooms!.indexOf( + HomeCubit.getInstance().selectedRoom!, + ), + code: control.code); + }); + } else { + emitSafe(DeviceControlError('Failed to control the device')); + } + }); } on DioException catch (e) { - emit(DeviceControlError(ServerFailure.fromDioError(e).errMessage)); + emitSafe(DeviceControlError(ServerFailure.fromDioError(e).errMessage)); } } @@ -241,16 +281,77 @@ 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), ); } } + fetchDevicesByRoomId(int? roomId) async { + if (_isClosed) return; + if (roomId == null) return; + + try { + emitSafe(GetDevicesLoading()); + int roomIndex = HomeCubit.getInstance() + .selectedSpace! + .rooms! + .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) { + emitSafe( + GetDevicesError(ServerFailure.fromDioError(error).errMessage), + ); + } + } + + getDevicesStatues(String deviceId, int roomIndex, {String? code}) async { + if (_isClosed) return; + + try { + emitSafe(GetDeviceStatusLoading(code: code)); + int deviceIndex = HomeCubit.getInstance() + .selectedSpace! + .rooms![roomIndex] + .devices! + .indexWhere((element) => element.id == deviceId); + + List statuses = []; + var response = await DevicesAPI.getDeviceStatus(deviceId); + // if (response['result']['status'].length > 4) + // print('response : ${response['result']['status'][4]}'); + + for (var status in response['result']['status']) { + statuses.add(StatusModel.fromJson(status)); + } + + HomeCubit.getInstance() + .selectedSpace! + .rooms![roomIndex] + .devices![deviceIndex] + .status = statuses; + emitSafe(GetDeviceStatusSuccess(code: code)); + } on DioException catch (error) { + emitSafe( + GetDeviceStatusError(ServerFailure.fromDioError(error).errMessage), + ); + } + } + ///Lights onHorizontalDragUpdate(DeviceModel light, double dx, double screenWidth) { double newBrightness = (dx / (screenWidth - 15) * 100); @@ -272,17 +373,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.status != null ? light.status = !light.status! : light.status = true; -// emit(LightToggled(light)); +// light.isOnline != null ? light.isOnline = !light.isOnline! : light.isOnline = true; +// emitSafe(LightToggled(light)); // } // // setColor(DeviceModel light, int color) { // light.color = color; -// emit(LightColorChanged(color)); +// emitSafe(LightColorChanged(color)); // } // // int getBrightness(DeviceModel light) { @@ -293,48 +394,9 @@ class DevicesCubit extends Cubit { // value = (value / 5).ceil() * 5; // if (value != light.brightness) { // light.brightness = value; -// emit(LightBrightnessChanged(value)); +// emitSafe(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/bloc/devices_state.dart b/lib/features/devices/bloc/devices_state.dart index b7b3fa7..4f89268 100644 --- a/lib/features/devices/bloc/devices_state.dart +++ b/lib/features/devices/bloc/devices_state.dart @@ -14,6 +14,35 @@ class DevicesFailure extends DevicesState {} class ChangeIndex extends DevicesState {} // Devices + +class GetDeviceStatusLoading extends DevicesState { + final String? code; + + GetDeviceStatusLoading({this.code}); +} + +class GetDeviceStatusSuccess extends DevicesState { + final String? code; + + GetDeviceStatusSuccess({this.code}); +} + +class GetDeviceStatusError extends DevicesState { + final String errorMsg; + + GetDeviceStatusError(this.errorMsg); +} + +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 {} @@ -23,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_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_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/model/device_model.dart b/lib/features/devices/model/device_model.dart index e14493e..410fd15 100644 --- a/lib/features/devices/model/device_model.dart +++ b/lib/features/devices/model/device_model.dart @@ -1,46 +1,146 @@ 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 { - 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; //unused + String? categoryName; //unused + int? createTime; //unused + String? gatewayId; //unused + String? icon; //unused + String? id; + String? ip; //unused + double? lat; //unused + String? localKey; + double? lon; //unused + String? model; + String? name; + String? nodeId; //remove + bool? isOnline; + List status = []; + String? ownerId; //unused + String? productId; //unused + String? productName; + bool? isSub; //unused + String? timeZone; + int? updateTime; + String? uuid; + DeviceType? productType; bool isSelected = false; - late List functions; - DeviceModel({ - required this.id, - required this.name, - required this.type, + 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, required this.status, - required this.image, - required this.timer, - required this.functions, + 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) { + 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.icons3GangSwitch; + } 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: 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: type, + status: [], + // json['status'] + // .map((e) => StatusModel.fromJson(e)) + // .toList(), + // 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/model/room_model.dart b/lib/features/devices/model/room_model.dart index 3937f17..79c043e 100644 --- a/lib/features/devices/model/room_model.dart +++ b/lib/features/devices/model/room_model.dart @@ -1,30 +1,36 @@ -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/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/devices_view.dart b/lib/features/devices/view/devices_view.dart index 4bad0e1..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}); +// class DevicesView extends StatelessWidget { +// const DevicesView({super.key}); - @override - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) => Container( - padding: const EdgeInsets.all(8), - width: MediaQuery.sizeOf(context).width, - height: MediaQuery.sizeOf(context).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..23c45f7 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'; @@ -22,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( + acDevice: 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_interface_controls.dart b/lib/features/devices/view/widgets/ACs/ac_interface_controls.dart index 16968a5..9d39be6 100644 --- a/lib/features/devices/view/widgets/ACs/ac_interface_controls.dart +++ b/lib/features/devices/view/widgets/ACs/ac_interface_controls.dart @@ -1,10 +1,11 @@ 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'; - -import '../../../../../generated/assets.dart'; +import 'package:syncrow_app/generated/assets.dart'; class AcInterfaceControls extends StatelessWidget { const AcInterfaceControls({ @@ -16,38 +17,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 52c471a..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 @@ -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,14 +78,24 @@ class AcInterfaceTempUnit extends StatelessWidget { ), // min: DeviceModel.bounds.min, // max: DeviceModel.bounds.max, - // initialValue: DeviceModel.temperature, + min: 20, + max: 30, + initialValue: acDevice.status + .firstWhere( + (element) => element.code == 'temp_current') + .value / + 10, onChange: (value) { String valueAsString = value.toStringAsFixed(1); if (valueAsString.endsWith(".0") || valueAsString.endsWith(".5")) { value = double.parse(valueAsString); - // DevicesCubit.get(context) - // .setACTemp(DeviceModel, value); + DevicesCubit.getInstance().deviceControl( + DeviceControlModel( + deviceId: acDevice.id, + code: 'temp_set', + value: value * 10), + acDevice.id!); } }, ), @@ -94,9 +110,23 @@ class AcInterfaceTempUnit extends StatelessWidget { dimension: 24, child: InkWell( onTap: () { - // DevicesCubit.get(context) - // .setACTemp(DeviceModel, DeviceModel.coolTo); - // DeviceModel.coolTo -= .5; + //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( + deviceId: acDevice.id, + code: 'temp_set', + value: (setToTemp - 0.5) * 10), + acDevice.id!); + } }, child: SvgPicture.asset( Assets.iconsMinus, @@ -107,10 +137,16 @@ class AcInterfaceTempUnit extends StatelessWidget { children: [ BodyLarge( // text: "${DeviceModel.coolTo}° C", - text: '24° 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), @@ -125,9 +161,22 @@ class AcInterfaceTempUnit extends StatelessWidget { dimension: 24, child: InkWell( onTap: () { - // DevicesCubit.get(context) - // .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( + deviceId: acDevice.id, + code: 'temp_set', + value: (setToTemp + 0.5) * 10), + acDevice.id!); + } }, child: SvgPicture.asset( Assets.iconsPlus, 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..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,75 +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 { - var fanSpeeds = [ - Assets.iconsFan0, - Assets.iconsFan1, - Assets.iconsFan2, - Assets.iconsFan3, - ]; - - var tempModes = [ - Assets.iconsSunnyMode, - Assets.iconsColdMode, - 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: const DefaultContainer( - height: 55, - child: Center( - // child: SvgPicture.asset(fanSpeeds[widget.model.fanSpeed]), - ), - ), - ), - ), - const SizedBox(width: 10), - Flexible( - child: InkWell( - onTap: () { - setState(() { - // widget.model.tempMode = - // widget.model.tempMode == 2 ? 0 : widget.model.tempMode + 1; - }); - }, - child: const DefaultContainer( - height: 55, - child: Center( - // child: SvgPicture.asset(tempModes[widget.model.tempMode]), + 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: () { + 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]!), + ), + ), + ), + ), + ], + ); + }, ); } } 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..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( @@ -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 f8175f6..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,9 +39,9 @@ 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) + DeviceModel ac = DevicesCubit.getInstance() .chosenCategory! .devices![index]; return Column( @@ -52,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, @@ -84,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..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}); @@ -21,9 +20,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..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({ @@ -20,7 +19,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 +31,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..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({ @@ -27,7 +26,7 @@ class UniversalACTemp extends StatelessWidget { dimension: 24, child: InkWell( onTap: () { - // DevicesCubit.get(context) + // DevicesCubit.getInstance() // .setTempToAll(DevicesCubit.universalACTemp - .5); }, child: SvgPicture.asset( @@ -47,7 +46,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/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/devices_view_body.dart b/lib/features/devices/view/widgets/devices_view_body.dart index 7837d8b..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, @@ -18,73 +17,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) { - //TODO : move to NavigationCubit - 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.get(context).devicesPageController, - onPageChanged: (index) { - HomeCubit.get(context).devicesPageChanged(index); - }, - children: [ - const WizardPage(), - if (HomeCubit.selectedSpace != null) - if (HomeCubit.selectedSpace!.rooms != null) - ...HomeCubit.selectedSpace!.rooms!.map( - (room) { - return RoomPage( - room: room, - ); - }, - ) - ], - ), - ), - HomeCubit.selectedSpace != null - ? Padding( - padding: const EdgeInsets.symmetric( - vertical: 7, - ), - child: SmoothPageIndicator( - controller: - HomeCubit.get(context).devicesPageController, - count: HomeCubit.selectedSpace!.rooms!.length + 1, - effect: const WormEffect( - paintStyle: PaintingStyle.stroke, - dotHeight: 8, - dotWidth: 8, - ), - ), + 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, + ); + }, ) - : const Center( - child: BodyLarge(text: 'No Home Found'), - ), - ], + ], + ), ), - ); - } - }, - ); + 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'), + ), + ], + ), + ); + } }, ); } 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.dart b/lib/features/devices/view/widgets/lights/light_interface.dart index e80ea44..2b34853 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,36 @@ 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: 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/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..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({ @@ -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 aa8ca07..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, @@ -28,7 +27,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 +36,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(), @@ -51,7 +50,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/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({ diff --git a/lib/features/devices/view/widgets/lights/lights_list.dart b/lib/features/devices/view/widgets/lights/lights_list.dart index 919ca0a..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({ @@ -32,7 +31,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/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/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.dart b/lib/features/devices/view/widgets/room_page.dart index 7f97b81..8e8b5c0 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'; @@ -13,10 +12,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 +27,9 @@ class RoomPage extends StatelessWidget { padding: const EdgeInsets.only(top: 10), physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, - itemCount: devices.length, - itemBuilder: (_, index) { - return RoomPageSwitch(device: devices[index]); + itemCount: room.devices!.length, + 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 1cbbc35..061be42 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 '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'; +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,25 +25,57 @@ 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.type == DeviceType.AC) { - Navigator.push( - context, - CustomPageRoute( - builder: (context) => AcInterface(deviceModel: device), - ), - ); + switch (device.productType) { + case DeviceType.AC: + { + print("AC"); + Navigator.push( + context, + CustomPageRoute( + builder: (context) => BlocProvider( + create: (context) => DevicesCubit.getInstance(), + child: 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) => BlocProvider( + create: (context) => DevicesCubit.getInstance(), + child: LightInterface(light: device), + ), + ), + ); + case DeviceType.ThreeGang: + Navigator.push( + context, + CustomPageRoute( + builder: (context) => BlocProvider( + create: (context) => DevicesCubit.getInstance(), + child: ThreeGangInterface( + gangSwitch: device, + ), + ), + ), + ); + break; + default: } }, child: DefaultContainer( @@ -54,7 +90,7 @@ class RoomPageSwitch extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ SvgPicture.asset( - device.icon, + device.icon!, fit: BoxFit.contain, ), CustomSwitch( 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), + ), + ), ), ), - ), - ), - ) + ) ], ), ); diff --git a/lib/features/devices/view/widgets/three_gang/gang_switch.dart b/lib/features/devices/view/widgets/three_gang/gang_switch.dart new file mode 100644 index 0000000..ff78992 --- /dev/null +++ b/lib/features/devices/view/widgets/three_gang/gang_switch.dart @@ -0,0 +1,81 @@ +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/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 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.dart b/lib/features/devices/view/widgets/three_gang/three_gang_interface.dart new file mode 100644 index 0000000..a12dfcb --- /dev/null +++ b/lib/features/devices/view/widgets/three_gang/three_gang_interface.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'package:syncrow_app/features/devices/model/device_model.dart'; +import 'package:syncrow_app/features/devices/view/widgets/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}); + + final DeviceModel gangSwitch; + @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: 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/features/devices/view/widgets/three_gang/three_gang_interface_body.dart b/lib/features/devices/view/widgets/three_gang/three_gang_interface_body.dart new file mode 100644 index 0000000..aef7ba0 --- /dev/null +++ b/lib/features/devices/view/widgets/three_gang/three_gang_interface_body.dart @@ -0,0 +1,328 @@ +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'; +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 ThreeGangInterfaceBody extends StatelessWidget { + const ThreeGangInterfaceBody({ + super.key, + required this.device, + }); + + final DeviceModel device; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const Expanded(child: SizedBox.shrink()), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + children: [ + 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: 20), + const SizedBox( + width: 70, + child: BodySmall( + text: "Bedside Light", + fontColor: ColorsManager.textPrimaryColor, + textAlign: TextAlign.center, + ), + ), + ], + ), + Column( + children: [ + 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: 20), + const SizedBox( + width: 70, + child: BodySmall( + text: "Ceiling Light", + fontColor: ColorsManager.textPrimaryColor, + textAlign: TextAlign.center, + ), + ), + ], + ), + Column( + children: [ + 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: 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: () { + 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: [ + 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: () { + 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: [ + 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/universal_switch.dart b/lib/features/devices/view/widgets/universal_switch.dart index 34a726d..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, @@ -25,7 +24,7 @@ class UniversalSwitch extends StatelessWidget { Expanded( child: InkWell( onTap: () { - DevicesCubit.get(context).turnAllDevicesOn(category); + DevicesCubit.getInstance().turnAllDevicesOn(category); }, child: Container( height: 60, @@ -57,7 +56,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 8a200d2..a00d19a 100644 --- a/lib/features/devices/view/widgets/wizard_switches.dart +++ b/lib/features/devices/view/widgets/wizard_switches.dart @@ -1,14 +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/shared_widgets/custom_switch.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, @@ -35,12 +33,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!; })); }, @@ -61,10 +59,7 @@ class WizartSwitches extends StatelessWidget { DevicesCubit.allCategories![index].icon!, fit: BoxFit.contain, ), - CustomSwitch( - category: - DevicesCubit.allCategories![index], - ), + // CustomSwitch( ], ), Expanded( 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/custom_switch.dart b/lib/features/shared_widgets/custom_switch.dart index 9e6c180..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!.status; - } 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.get(context).turnOnOffDevice(device!); - } else if (category != null) { - DevicesCubit.get(context).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, + ), + ), + ), ), ), ), ), - ), - ), - ), - ); + ); }, ); } diff --git a/lib/features/shared_widgets/devices_default_switch.dart b/lib/features/shared_widgets/devices_default_switch.dart index 2d45c10..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, @@ -23,12 +22,12 @@ class DevicesDefaultSwitch extends StatelessWidget { Expanded( child: InkWell( onTap: () { - DevicesCubit.get(context).turnOnOffDevice(model); + DevicesCubit.getInstance().turnOnOffDevice(model); }, child: Container( height: 60, decoration: BoxDecoration( - color: model.status ?? false + color: model.isOnline ?? false ? ColorsManager.primaryColor : Colors.white, borderRadius: const BorderRadius.only( @@ -39,7 +38,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, ), ), @@ -49,12 +48,12 @@ class DevicesDefaultSwitch extends StatelessWidget { Expanded( child: InkWell( onTap: () { - DevicesCubit.get(context).turnOnOffDevice(model); + DevicesCubit.getInstance().turnOnOffDevice(model); }, child: Container( height: 60, decoration: BoxDecoration( - color: model.status ?? false + color: model.isOnline ?? false ? Colors.white : ColorsManager.primaryColor, borderRadius: const BorderRadius.only( @@ -65,7 +64,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, ), ), diff --git a/lib/my_app.dart b/lib/my_app.dart index 928ddd9..1ec3b08 100644 --- a/lib/my_app.dart +++ b/lib/my_app.dart @@ -18,12 +18,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 49647e9..4b84208 100644 --- a/lib/navigation/router.dart +++ b/lib/navigation/router.dart @@ -7,7 +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/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'; @@ -23,9 +22,9 @@ class Router { return MaterialPageRoute( builder: (_) => const SplashView(), settings: settings); - case Routes.devicesRoute: - return MaterialPageRoute( - builder: (_) => 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/api_links_endpoints.dart b/lib/services/api/api_links_endpoints.dart index bfe22be..6e5efc0 100644 --- a/lib/services/api/api_links_endpoints.dart +++ b/lib/services/api/api_links_endpoints.dart @@ -16,6 +16,9 @@ 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..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(), @@ -34,4 +36,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; + } } 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/network_exception.dart b/lib/services/api/network_exception.dart index 0cec78b..f8940de 100644 --- a/lib/services/api/network_exception.dart +++ b/lib/services/api/network_exception.dart @@ -28,8 +28,14 @@ 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!, + dioError.response!.data['message'].toString() + // message + ); + } case DioExceptionType.cancel: return ServerFailure("The request to ApiServer was canceled"); @@ -45,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) { 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; + } } 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); } } diff --git a/lib/utils/resource_manager/constants.dart b/lib/utils/resource_manager/constants.dart index 1ec5ab8..04e05af 100644 --- a/lib/utils/resource_manager/constants.dart +++ b/lib/utils/resource_manager/constants.dart @@ -1,4 +1,7 @@ //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"; @@ -16,12 +19,182 @@ 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, +// }; +//AC wzdcrqh0 +// GW wp8ticoo2bhumwgb +// CPS d3ci7gcn +// DL awu7anehyu5q1iu8 +// WPS awarhusb +// 3G 1a6vgvyi + +Map devicesTypesMap = { + "wzdcrqh0": DeviceType.AC, + "wp8ticoo2bhumwgb": DeviceType.Gateway, + "d3ci7gcn": DeviceType.CeilingSensor, + "awu7anehyu5q1iu8": DeviceType.DoorLock, + "awarhusb": DeviceType.WallSensor, + "1a6vgvyi": DeviceType.ThreeGang, +}; +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}'), + ], +}; + +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; +} 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: