mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2026-10-25 20:17:54 +00:00
Move fan speed and temperature mode logic to the DevicesCubit for better separation of concerns and improved code readability. Update widget to use BlocBuilder for state management and simplify control logic.
406 lines
12 KiB
Dart
406 lines
12 KiB
Dart
// ignore_for_file: constant_identifier_names, unused_import
|
|
|
|
import 'package:dio/dio.dart';
|
|
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/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/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<DevicesState> {
|
|
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() {
|
|
// If an instance already exists, return it
|
|
_instance ??= DevicesCubit._();
|
|
return _instance!;
|
|
}
|
|
|
|
DeviceModel? selectedDevice;
|
|
|
|
@override
|
|
Future<void> 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<DevicesCategoryModel>? allCategories;
|
|
|
|
selectCategory(int index) {
|
|
for (var i = 0; i < allCategories!.length; i++) {
|
|
if (i == index) {
|
|
allCategories![i].isSelected = true;
|
|
} else {
|
|
allCategories![i].isSelected = false;
|
|
}
|
|
}
|
|
emitSafe(DevicesCategoryChanged());
|
|
}
|
|
|
|
unselectAllCategories() {
|
|
for (var category in allCategories!) {
|
|
category.isSelected = false;
|
|
}
|
|
emitSafe(DevicesCategoryChanged());
|
|
}
|
|
|
|
Widget? get chosenCategoryView {
|
|
if (allCategories != null) {
|
|
for (var category in allCategories!) {
|
|
if (category.isSelected) {
|
|
switch (category.type) {
|
|
case DeviceType.AC:
|
|
return const ACsView();
|
|
case DeviceType.LightBulb:
|
|
return const LightsView();
|
|
case DeviceType.DoorLock:
|
|
return const DoorView();
|
|
case DeviceType.Curtain:
|
|
return const CurtainView();
|
|
// case DeviceType.ThreeGang:
|
|
// return const ThreeGangSwitchesView();
|
|
case DeviceType.Gateway:
|
|
return const GateWayView();
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
DevicesCategoryModel? get chosenCategory {
|
|
for (var category in allCategories!) {
|
|
if (category.isSelected) {
|
|
return category;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
selectDevice(DeviceModel device) {
|
|
for (var category in allCategories!) {
|
|
if (category.devices != null) {
|
|
for (var device in category.devices!) {
|
|
if (device.isSelected) {
|
|
category.isSelected = false;
|
|
emitSafe(DeviceSelected());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
device.isSelected = !device.isSelected;
|
|
emitSafe(DeviceSelected());
|
|
}
|
|
|
|
DeviceModel? getSelectedDevice() {
|
|
for (var category in allCategories!) {
|
|
if (category.devices != null) {
|
|
for (var device in category.devices!) {
|
|
if (device.isSelected) {
|
|
return device;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
changeCategorySwitchValue(DevicesCategoryModel 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);
|
|
|
|
emitSafe(CategorySwitchChanged());
|
|
}
|
|
|
|
turnOnOffDevice(DeviceModel device) {
|
|
device.isOnline = !device.isOnline!;
|
|
DevicesCategoryModel category = allCategories!.firstWhere((category) {
|
|
if (category.devices != null) {
|
|
return category.devices!.contains(device);
|
|
} else {
|
|
return false;
|
|
}
|
|
});
|
|
updateDevicesStatus(category);
|
|
emitSafe(DeviceSwitchChanged());
|
|
}
|
|
|
|
updateDevicesStatus(DevicesCategoryModel category) {
|
|
if (category.devices != null) {
|
|
if (category.devices!.isNotEmpty) {
|
|
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.isOnline != tempStatus) {
|
|
category.devicesStatus = null;
|
|
emitSafe(DeviceSwitchChanged());
|
|
return;
|
|
}
|
|
category.devicesStatus = tempStatus;
|
|
emitSafe(DeviceSwitchChanged());
|
|
}
|
|
} else {
|
|
category.devicesStatus = null;
|
|
emitSafe(DeviceSwitchChanged());
|
|
}
|
|
}
|
|
}
|
|
|
|
turnAllDevicesOff(DevicesCategoryModel category) {
|
|
if (category.devices != null) {
|
|
if (category.devices!.isNotEmpty) {
|
|
for (var device in category.devices!) {
|
|
device.isOnline = false;
|
|
}
|
|
changeCategorySwitchValue(category);
|
|
updateDevicesStatus(category);
|
|
emitSafe(CategorySwitchChanged());
|
|
}
|
|
}
|
|
}
|
|
|
|
turnAllDevicesOn(DevicesCategoryModel category) {
|
|
if (category.devices != null) {
|
|
if (category.devices!.isNotEmpty) {
|
|
for (var device in category.devices!) {
|
|
device.isOnline = true;
|
|
}
|
|
changeCategorySwitchValue(category);
|
|
updateDevicesStatus(category);
|
|
emitSafe(CategorySwitchChanged());
|
|
}
|
|
}
|
|
}
|
|
|
|
areAllDevicesOff(DevicesCategoryModel category) {
|
|
if (category.devices != null) {
|
|
for (var device in category.devices!) {
|
|
if (device.isOnline ?? false) {
|
|
category.devicesStatus = false;
|
|
emitSafe(CategorySwitchChanged());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
clearCategoriesSelection(BuildContext context) {
|
|
for (var category in allCategories!) {
|
|
category.isSelected = false;
|
|
if (category.devices != null) {
|
|
for (var device in category.devices!) {
|
|
device.isSelected = false;
|
|
}
|
|
}
|
|
}
|
|
Navigator.popUntil(context, (route) => route.isFirst);
|
|
|
|
emitSafe(DevicesCategoryChanged());
|
|
}
|
|
|
|
///////////////////////// API CALLS //////////////////////////
|
|
deviceControl(DeviceControlModel control, String deviceId) async {
|
|
emitSafe(DeviceControlLoading(
|
|
code: control.code,
|
|
));
|
|
try {
|
|
await DevicesAPI.controlDevice(control).then((value) {
|
|
emitSafe(DeviceControlSuccess(
|
|
code: control.code,
|
|
));
|
|
if (value['result'] ?? false) {
|
|
Future.delayed(const Duration(milliseconds: 400), () {
|
|
getDevicesStatues(
|
|
deviceId,
|
|
HomeCubit.getInstance().selectedSpace!.rooms!.indexOf(
|
|
HomeCubit.getInstance().selectedRoom!,
|
|
),
|
|
code: control.code,
|
|
);
|
|
});
|
|
}
|
|
});
|
|
} on DioException catch (e) {
|
|
emitSafe(DeviceControlError(ServerFailure.fromDioError(e).errMessage));
|
|
}
|
|
}
|
|
|
|
fetchGroups(int spaceId) async {
|
|
if (_isClosed) return;
|
|
|
|
try {
|
|
emitSafe(DevicesCategoriesLoading());
|
|
allCategories = await DevicesAPI.fetchGroups(spaceId);
|
|
emitSafe(DevicesCategoriesSuccess());
|
|
} on DioException catch (error) {
|
|
emitSafe(
|
|
DevicesCategoriesError(ServerFailure.fromDioError(error).errMessage),
|
|
);
|
|
}
|
|
}
|
|
|
|
fetchDevicesByRoomId(int roomId) async {
|
|
if (_isClosed) 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<StatusModel> 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);
|
|
if (newBrightness > 100) {
|
|
newBrightness = 100;
|
|
} else if (newBrightness < 0) {
|
|
newBrightness = 0;
|
|
}
|
|
// setBrightness(light, newBrightness);
|
|
}
|
|
|
|
Map<int, LightMode> lightModes = {
|
|
0: LightMode.Doze,
|
|
1: LightMode.Relax,
|
|
2: LightMode.Reading,
|
|
3: LightMode.Energizing,
|
|
};
|
|
|
|
// setLightingMode(DeviceModel light, LightMode mode) {
|
|
// light.lightingMode =
|
|
// lightModes.entries.firstWhere((element) => element.value == mode).key;
|
|
// emitSafe(LightModeChanged(mode));
|
|
// }
|
|
//
|
|
// toggleLight(DeviceModel light) {
|
|
// light.isOnline != null ? light.isOnline = !light.isOnline! : light.isOnline = true;
|
|
// emitSafe(LightToggled(light));
|
|
// }
|
|
//
|
|
// setColor(DeviceModel light, int color) {
|
|
// light.color = color;
|
|
// emitSafe(LightColorChanged(color));
|
|
// }
|
|
//
|
|
// int getBrightness(DeviceModel light) {
|
|
// return light.brightness.toInt();
|
|
// }
|
|
|
|
// setBrightness(DeviceModel light, double value) {
|
|
// value = (value / 5).ceil() * 5;
|
|
// if (value != light.brightness) {
|
|
// light.brightness = value;
|
|
// emitSafe(LightBrightnessChanged(value));
|
|
// }
|
|
// }
|
|
}
|
|
|
|
enum LightMode {
|
|
Doze,
|
|
Relax,
|
|
Reading,
|
|
Energizing,
|
|
}
|