finished rooms call with all devices and single devices call

This commit is contained in:
ashrafzarkanisala
2024-06-23 20:12:38 +03:00
parent b58af41b88
commit 759888857d
8 changed files with 446 additions and 72 deletions
@@ -0,0 +1,158 @@
import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_event.dart';
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_state.dart';
import 'package:syncrow_app/features/devices/model/device_category_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/home_management_api.dart';
class DeviceManagerBloc extends Bloc<DeviceManagerEvent, DeviceManagerState> {
DeviceManagerBloc() : super(DeviceManagerInitial()) {
on<FetchAllDevices>(_onFetchAllDevices);
on<FetchDevicesByRoomId>(_onFetchDevicesByRoomId);
on<SelectCategory>(_onSelectCategory);
on<UnselectAllCategories>(_onUnselectAllCategories);
on<SelectDevice>(_onSelectDevice);
on<ChangeCategorySwitchValue>(_onChangeCategorySwitchValue);
on<TurnOnOffDevice>(_onTurnOnOffDevice);
on<ClearCategoriesSelection>(_onClearCategoriesSelection);
// on<DeviceControl>(_onDeviceControl);
}
static List<DevicesCategoryModel>? allCategories;
Future<void> _onFetchAllDevices(
FetchAllDevices event, Emitter<DeviceManagerState> emit) async {
emit(GetDevicesLoading());
try {
final allDevices = await HomeManagementAPI.fetchDevicesByUserId();
emit(GetDevicesSuccess(allDevices));
} catch (e) {
emit(GetDevicesError(e.toString()));
}
}
Future<void> _onFetchDevicesByRoomId(
FetchDevicesByRoomId event, Emitter<DeviceManagerState> emit) async {
emit(GetDevicesLoading());
try {
final devices = await DevicesAPI.getDevicesByRoomId(event.roomId);
emit(GetDevicesSuccess(devices));
} catch (e) {
emit(GetDevicesError(e.toString()));
}
}
void _onSelectCategory(
SelectCategory event, Emitter<DeviceManagerState> emit) {
for (var i = 0; i < allCategories!.length; i++) {
allCategories![i].isSelected = i == event.index;
}
emit(DevicesCategoryChanged());
}
void _onUnselectAllCategories(
UnselectAllCategories event, Emitter<DeviceManagerState> emit) {
for (var category in allCategories!) {
category.isSelected = false;
}
emit(DevicesCategoryChanged());
}
void _onSelectDevice(SelectDevice event, Emitter<DeviceManagerState> emit) {
for (var category in allCategories!) {
if (category.devices != null) {
for (var device in category.devices!) {
if (device.isSelected) {
category.isSelected = false;
emit(DeviceSelected());
return;
}
}
}
}
event.device.isSelected = !event.device.isSelected;
emit(DeviceSelected());
}
void _onChangeCategorySwitchValue(
ChangeCategorySwitchValue event, Emitter<DeviceManagerState> emit) {
var category = event.category;
if (category.devicesStatus != null) {
category.devicesStatus = !category.devicesStatus!;
if (category.devices != null) {
for (var device in category.devices!) {
device.isOnline = category.devicesStatus;
}
}
} else {
category.devicesStatus = true;
if (category.devices != null) {
for (var device in category.devices!) {
device.isOnline = true;
}
}
}
_updateDevicesStatus(category, emit);
}
void _onTurnOnOffDevice(
TurnOnOffDevice event, Emitter<DeviceManagerState> emit) {
var device = event.device;
device.isOnline = !device.isOnline!;
DevicesCategoryModel category = allCategories!.firstWhere((category) {
return category.devices != null && category.devices!.contains(device);
});
_updateDevicesStatus(category, emit);
}
void _onClearCategoriesSelection(
ClearCategoriesSelection event, Emitter<DeviceManagerState> emit) {
for (var category in allCategories!) {
category.isSelected = false;
if (category.devices != null) {
for (var device in category.devices!) {
device.isSelected = false;
}
}
}
Navigator.popUntil(event.context, (route) => route.isFirst);
emit(DevicesCategoryChanged());
}
// Future<void> _onDeviceControl(
// DeviceControl event, Emitter<DeviceManagerState> emit) async {
// emit(DeviceControlLoading(code: event.control.code));
// try {
// var response =
// await DevicesAPI.controlDevice(event.control, event.deviceId);
// if (response['success'] ?? false) {
// emit(DeviceControlSuccess(code: event.control.code));
// await Future.delayed(const Duration(milliseconds: 400), () {
// add(FetchDevicesByRoomId(event.deviceId));
// });
// } else {
// emit(DeviceControlError('Failed to control the device'));
// }
// } catch (e) {
// emit(DeviceControlError(e.toString()));
// }
// }
void _updateDevicesStatus(
DevicesCategoryModel category, Emitter<DeviceManagerState> emit) {
if (category.devices != null && category.devices!.isNotEmpty) {
bool? tempStatus = category.devices![0].isOnline;
for (var device in category.devices!) {
if (device.isOnline != tempStatus) {
category.devicesStatus = null;
break;
}
category.devicesStatus = tempStatus;
}
emit(CategorySwitchChanged());
}
}
}
@@ -0,0 +1,80 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.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';
abstract class DeviceManagerEvent extends Equatable {
const DeviceManagerEvent();
@override
List<Object> get props => [];
}
class FetchAllDevices extends DeviceManagerEvent {}
class FetchDevicesByRoomId extends DeviceManagerEvent {
final String roomId;
const FetchDevicesByRoomId(this.roomId);
@override
List<Object> get props => [roomId];
}
class SelectCategory extends DeviceManagerEvent {
final int index;
const SelectCategory(this.index);
@override
List<Object> get props => [index];
}
class UnselectAllCategories extends DeviceManagerEvent {}
class SelectDevice extends DeviceManagerEvent {
final DeviceModel device;
const SelectDevice(this.device);
@override
List<Object> get props => [device];
}
class ChangeCategorySwitchValue extends DeviceManagerEvent {
final DevicesCategoryModel category;
const ChangeCategorySwitchValue(this.category);
@override
List<Object> get props => [category];
}
class TurnOnOffDevice extends DeviceManagerEvent {
final DeviceModel device;
const TurnOnOffDevice(this.device);
@override
List<Object> get props => [device];
}
class ClearCategoriesSelection extends DeviceManagerEvent {
final BuildContext context;
const ClearCategoriesSelection(this.context);
@override
List<Object> get props => [context];
}
class DeviceControl extends DeviceManagerEvent {
final DeviceControlModel control;
final String deviceId;
const DeviceControl(this.control, this.deviceId);
@override
List<Object> get props => [control, deviceId];
}
@@ -0,0 +1,112 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
abstract class DeviceManagerState extends Equatable {
const DeviceManagerState();
@override
List<Object> get props => [];
}
class DeviceManagerInitial extends DeviceManagerState {}
class DevicesCategoryChanged extends DeviceManagerState {}
class DeviceSelected extends DeviceManagerState {}
class DeviceControlLoading extends DeviceManagerState {
final String code;
const DeviceControlLoading({required this.code});
@override
List<Object> get props => [code];
}
class DeviceControlSuccess extends DeviceManagerState {
final String code;
const DeviceControlSuccess({required this.code});
@override
List<Object> get props => [code];
}
class DeviceControlError extends DeviceManagerState {
final String message;
const DeviceControlError(this.message);
@override
List<Object> get props => [message];
}
class DevicesCategoriesLoading extends DeviceManagerState {}
class DevicesCategoriesSuccess extends DeviceManagerState {}
class DevicesCategoriesError extends DeviceManagerState {
final String error;
const DevicesCategoriesError(this.error);
@override
List<Object> get props => [error];
}
class GetDevicesLoading extends DeviceManagerState {}
class GetDevicesSuccess extends DeviceManagerState {
final List<DeviceModel>? devices;
const GetDevicesSuccess(this.devices);
@override
List<Object> get props => [devices ?? []];
}
class GetDevicesError extends DeviceManagerState {
final String error;
const GetDevicesError(this.error);
@override
List<Object> get props => [error];
}
class GetDeviceStatusLoading extends DeviceManagerState {
final String? code;
const GetDeviceStatusLoading({this.code});
@override
List<Object> get props => [code ?? ''];
}
class GetDeviceStatusSuccess extends DeviceManagerState {
final String? code;
const GetDeviceStatusSuccess({this.code});
@override
List<Object> get props => [code ?? ''];
}
class GetDeviceStatusError extends DeviceManagerState {
final String error;
const GetDeviceStatusError(this.error);
@override
List<Object> get props => [error];
}
class CategorySwitchChanged extends DeviceManagerState {}
class DeviceSwitchChanged extends DeviceManagerState {}
class CurtainsIsOpening extends DeviceManagerState {}
class CurtainsIsClosing extends DeviceManagerState {}
class CurtainsStopped extends DeviceManagerState {}
+15 -4
View File
@@ -99,6 +99,20 @@ class DevicesCubit extends Cubit<DevicesState> {
return null;
}
// Getter to retrieve all devices from HomeCubit
List<DeviceModel> get allDevices {
List<DeviceModel> devices = [];
if (HomeCubit.getInstance().selectedSpace != null &&
HomeCubit.getInstance().selectedSpace!.rooms != null) {
for (var room in HomeCubit.getInstance().selectedSpace!.rooms!) {
if (room.devices != null) {
devices.addAll(room.devices!);
}
}
}
return devices;
}
// DevicesCategoryModel? get chosenCategory {
// for (var category in allCategories!) {
// if (category.isSelected) {
@@ -290,9 +304,6 @@ class DevicesCubit extends Cubit<DevicesState> {
fetchDevicesByRoomId(String? roomId) async {
if (roomId == null) return;
if (roomId == '-1') {
return fetchAllDevices(roomId);
}
emitSafe(GetDevicesLoading());
int roomIndex = HomeCubit.getInstance()
@@ -320,7 +331,7 @@ class DevicesCubit extends Cubit<DevicesState> {
// }
}
void fetchAllDevices(String roomId) async {
void fetchAllDevices() async {
emitSafe(GetDevicesLoading());
try {
final allDevices = await HomeManagementAPI.fetchDevicesByUserId();
@@ -1,12 +1,25 @@
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_event.dart';
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_event.dart';
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_state.dart';
class TabBarBloc extends Bloc<TabBarEvent, TabBarState> {
TabBarBloc() : super(const Initial()) {
on<TabChanged>((event, emit) {
emit(TabSelected(
selectedTabIndex: event.selectedIndex, roomId: event.roomId));
});
final DeviceManagerBloc deviceManagerBloc;
TabBarBloc(this.deviceManagerBloc) : super(const Initial()) {
on<TabChanged>(_handleTabChanged);
}
FutureOr<void> _handleTabChanged(
TabChanged event, Emitter<TabBarState> emit) {
if (event.roomId == "-1") {
deviceManagerBloc.add(FetchAllDevices());
} else {
deviceManagerBloc.add(FetchDevicesByRoomId(event.roomId));
}
emit(TabSelected(
roomId: event.roomId, selectedTabIndex: event.selectedIndex));
}
}
@@ -34,7 +34,7 @@ class _SceneControlDevicesViewState extends State<SceneControlDevicesView>
0,
RoomModel(
name: 'All Devices',
devices: [],
devices: DevicesCubit.getInstance().allDevices,
id: '-1',
type: SpaceType.Room,
),
@@ -57,7 +57,7 @@ class _SceneControlDevicesViewState extends State<SceneControlDevicesView>
TabChanged(selectedIndex: value, roomId: rooms?[value].id ?? ''));
/// fetch devices
context.read<DevicesCubit>().fetchDevicesByRoomId(rooms![value].id!);
// context.read<DevicesCubit>().fetchDevicesByRoomId(rooms![value].id!);
return;
}
}
@@ -1,6 +1,7 @@
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/bloc/device_manager_bloc/device_manager_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_state.dart';
import 'package:syncrow_app/features/devices/model/room_model.dart';
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_bloc.dart';
import 'package:syncrow_app/features/scene/bloc/tab_change/tab_change_state.dart';
@@ -8,18 +9,16 @@ import 'package:syncrow_app/features/scene/view/widgets/scene_list_tile.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/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';
class SceneDevicesBody extends StatelessWidget {
const SceneDevicesBody({
super.key,
required TabController tabController,
required this.rooms,
}) : _tabController = tabController;
}) : _tabController = tabController;
final TabController _tabController;
final List<RoomModel>? rooms;
@@ -27,11 +26,10 @@ class SceneDevicesBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<TabBarBloc, TabBarState>(
builder: (context, state) {
builder: (context, tabState) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
/// Tab bar
TabBar(
controller: _tabController,
dividerColor: Colors.transparent,
@@ -42,7 +40,8 @@ class SceneDevicesBody extends StatelessWidget {
text: e.name ?? '',
textAlign: TextAlign.start,
style: context.bodyLarge.copyWith(
color: (state is TabSelected) && state.roomId == e.id
color: (tabState is TabSelected) &&
tabState.roomId == e.id
? ColorsManager.textPrimaryColor
: ColorsManager.textPrimaryColor.withOpacity(0.2),
),
@@ -52,59 +51,10 @@ class SceneDevicesBody extends StatelessWidget {
isScrollable: true,
tabAlignment: TabAlignment.start,
),
/// Tab bar view
Expanded(
child: TabBarView(
controller: _tabController,
children: rooms!
.map((e) => BlocBuilder<DevicesCubit, DevicesState>(
builder: (context, state) {
if (state is GetDevicesLoading) {
return const Center(
child: CircularProgressIndicator());
} else if (state is GetDevicesSuccess) {
return ListView.builder(
itemCount: state.devices!.length,
itemBuilder: (context, index) {
final device = state.devices![index];
return DefaultContainer(
child: SceneListTile(
minLeadingWidth: 40,
leadingWidget: Image.network(
device.icon ?? '',
errorBuilder:
(context, error, stackTrace) =>
Image.asset(
Assets.assetsIconsLogo,
width: 20,
),
),
titleWidget: BodyMedium(
text: device.name ?? '',
style: context.titleSmall.copyWith(
color:
ColorsManager.secondaryTextColor,
fontWeight: FontWeight.w400,
fontSize: 20,
),
),
trailingWidget: const Icon(
Icons.arrow_forward_ios_rounded,
size: 16,
weight: 0.2,
),
),
);
},
);
} else if (state is GetDevicesError) {
return Center(child: Text(state.errorMsg));
}
return const SizedBox();
},
))
.toList(),
children: rooms!.map((e) => _buildRoomTab(e, context)).toList(),
),
),
],
@@ -112,4 +62,49 @@ class SceneDevicesBody extends StatelessWidget {
},
);
}
Widget _buildRoomTab(RoomModel room, BuildContext context) {
return BlocBuilder<DeviceManagerBloc, DeviceManagerState>(
builder: (context, state) {
if (state is GetDevicesLoading) {
return const Center(child: CircularProgressIndicator());
} else if (state is GetDevicesSuccess) {
return ListView.builder(
itemCount: state.devices?.length ?? 0,
itemBuilder: (context, index) {
final device = state.devices![index];
return DefaultContainer(
child: SceneListTile(
minLeadingWidth: 40,
leadingWidget: Image.network(
device.icon ?? '',
errorBuilder: (context, error, stackTrace) => Image.asset(
Assets.assetsIconsLogo,
width: 20,
),
),
titleWidget: BodyMedium(
text: device.name ?? '',
style: context.titleSmall.copyWith(
color: ColorsManager.secondaryTextColor,
fontWeight: FontWeight.w400,
fontSize: 20,
),
),
trailingWidget: const Icon(
Icons.arrow_forward_ios_rounded,
size: 16,
weight: 0.2,
),
),
);
},
);
} else if (state is GetDevicesError) {
return Center(child: Text(state.error));
}
return const SizedBox();
},
);
}
}
+9 -4
View File
@@ -5,6 +5,8 @@ import 'package:syncrow_app/features/auth/view/otp_view.dart';
import 'package:syncrow_app/features/auth/view/login_view.dart';
import 'package:syncrow_app/features/auth/view/sign_up_view.dart';
import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart';
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/device_manager_bloc/device_manager_event.dart';
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
import 'package:syncrow_app/features/layout/view/layout_view.dart';
import 'package:syncrow_app/features/menu/view/menu_view.dart';
@@ -75,12 +77,15 @@ class Router {
return MaterialPageRoute(
builder: (_) => MultiBlocProvider(
providers: [
BlocProvider<TabBarBloc>(
create: (BuildContext context) => TabBarBloc()
BlocProvider(
create: (BuildContext context) =>
DeviceManagerBloc()..add(FetchAllDevices()),
),
BlocProvider(
create: (BuildContext context) => TabBarBloc(
context.read<DeviceManagerBloc>())
..add(const TabChanged(selectedIndex: 0, roomId: '-1')),
),
BlocProvider<DevicesCubit>(
create: (context) => DevicesCubit.getInstance()),
],
child: const SceneControlDevicesView(),
),