Files
syncrow-app/lib/features/devices/bloc/devices_cubit.dart
2024-06-25 10:38:39 +03:00

494 lines
14 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_list_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/doors_list_view.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/services/api/home_management_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 &&
HomeCubit.getInstance().spaces!.isNotEmpty) {
// fetchGroups(HomeCubit.getInstance().selectedSpace!.id!);
for (var room in HomeCubit.getInstance().selectedSpace!.rooms!) {
fetchDevicesByRoomId(room.id!);
}
}
}
static DevicesCubit? _instance;
static DevicesCubit getInstance() {
return _instance ??= DevicesCubit._();
}
@override
Future<void> close() {
_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 DoorsListView();
case DeviceType.Curtain:
return const CurtainListView();
// case DeviceType.ThreeGang:
// return const ThreeGangSwitchesView();
case DeviceType.Gateway:
return const GateWayView();
default:
return null;
}
}
}
}
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) {
// 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 {
var response = await DevicesAPI.controlDevice(control, deviceId);
if (response['success'] ?? false) {
emitSafe(DeviceControlSuccess(code: control.code));
//this delay is to give tuya server time to update the status
Future.delayed(const Duration(milliseconds: 400), () {
fetchDevicesStatues(
deviceId,
HomeCubit.getInstance()
.selectedSpace!
.rooms!
.indexOf(HomeCubit.getInstance().selectedRoom!),
code: control.code);
});
} else {
emitSafe(DeviceControlError('Failed to control the device'));
}
} catch (failure) {
emitSafe(DeviceControlError(failure.toString()));
return;
}
}
fetchGroups(String spaceId) async {
emitSafe(DevicesCategoriesLoading());
try {
allCategories = await DevicesAPI.fetchGroups(spaceId);
} catch (e) {
emitSafe(DevicesCategoriesError(e.toString()));
return;
}
if (allCategories!.isNotEmpty && allCategories != null) {
emitSafe(DevicesCategoriesSuccess());
} else {
emitSafe(DevicesCategoriesError('No Groups found'));
}
}
fetchDevicesByRoomId(String? roomId) async {
if (roomId == null) return;
emitSafe(GetDevicesLoading());
int roomIndex = HomeCubit.getInstance()
.selectedSpace!
.rooms!
.indexWhere((element) => element.id == roomId);
try {
HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices =
await DevicesAPI.getDevicesByRoomId(roomId);
} catch (e) {
emitSafe(GetDevicesError(e.toString()));
return;
}
final devices =
HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices;
emitSafe(GetDevicesSuccess(devices));
//get status for each device
//TODO get devices status per page via page controller instead of getting all devices status at once
// List<DeviceModel> devices = HomeCubit.getInstance().selectedSpace!.rooms![roomIndex].devices!;
// if (devices.isNotEmpty) {
// for (var device in devices) {
// fetchDevicesStatues(device.uuid!, roomIndex);
// }
// }
}
fetchDevicesStatues(String deviceUuid, int roomIndex, {String? code}) async {
emitSafe(GetDeviceStatusLoading(code: code));
int deviceIndex = HomeCubit.getInstance()
.selectedSpace!
.rooms![roomIndex]
.devices!
.indexWhere((element) => element.uuid == deviceUuid);
List<StatusModel> statuses = [];
try {
var response = await DevicesAPI.getDeviceStatus(deviceUuid);
for (var status in response['status']) {
statuses.add(StatusModel.fromJson(status));
}
} catch (e) {
emitSafe(GetDeviceStatusError(e.toString()));
return;
}
HomeCubit.getInstance()
.selectedSpace!
.rooms![roomIndex]
.devices![deviceIndex]
.status = statuses;
emitSafe(GetDeviceStatusSuccess(code: code));
}
///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));
// }
// }
//////////////////////////////////CURTAINS//////////////////////////////////////
double curtainWidth = 270;
double curtainOpeningSpace = 195;
double blindWindowHight = 310;
double blindOpeningSpace = 245;
double _openPercentage = 0;
bool isMoving = false;
openCurtain(DeviceType type) async {
if (state is CurtainsIsOpening) {
return;
}
isMoving = true;
while (_openPercentage < 100.0) {
if (state is CurtainsIsClosing) {
//listen to interruption by the closing process
pauseCurtain();
break;
}
emit(CurtainsIsOpening());
if (isMoving) {
await Future.delayed(const Duration(milliseconds: 200), () {
_openPercentage += 10.0;
//25.5 is the 10% of the curtain opening space, its used to update the
// animated container of thecurtain
type == DeviceType.Curtain
? curtainWidth -= curtainOpeningSpace / 10
: blindWindowHight -= blindOpeningSpace / 10;
if (_openPercentage >= 100.0) {
pauseCurtain();
}
});
} else {
pauseCurtain();
break;
}
}
}
closeCurtain(DeviceType type) async {
if (state is CurtainsIsClosing) {
return;
}
isMoving = true;
while (_openPercentage > 0.0) {
if (state is CurtainsIsOpening) {
// interrupted by the opening process
pauseCurtain();
break;
}
emit(CurtainsIsClosing());
if (isMoving) {
await Future.delayed(const Duration(milliseconds: 200), () {
_openPercentage -= 10.0;
//25.5 is the 10% of the curtain opening space, its used to update the
type == DeviceType.Curtain
? curtainWidth += curtainOpeningSpace / 10
: blindWindowHight += 24.5;
if (_openPercentage <= 0.0) {
pauseCurtain();
}
});
} else {
pauseCurtain();
break;
}
}
}
pauseCurtain() {
isMoving = false;
emit(CurtainsStopped());
}
}
enum LightMode {
Doze,
Relax,
Reading,
Energizing,
}