mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-07-16 01:56:19 +00:00
394 lines
12 KiB
Dart
394 lines
12 KiB
Dart
import 'dart:async';
|
|
import 'package:firebase_database/firebase_database.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/bloc/curtain_bloc/curtain_event.dart';
|
|
import 'package:syncrow_app/features/devices/bloc/curtain_bloc/curtain_state.dart';
|
|
import 'package:syncrow_app/features/devices/model/curtain_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/group_curtain_model.dart';
|
|
import 'package:syncrow_app/features/devices/model/status_model.dart';
|
|
import 'package:syncrow_app/services/api/devices_api.dart';
|
|
import 'package:syncrow_app/utils/resource_manager/constants.dart';
|
|
|
|
class CurtainBloc extends Bloc<CurtainEvent, CurtainState> {
|
|
double curtainWidth = 270;
|
|
double curtainOpeningSpace = 195;
|
|
double blindHeight = 310;
|
|
double blindOpeningSpace = 245;
|
|
double openPercentage = 0;
|
|
bool isMoving = false;
|
|
final String curtainId;
|
|
|
|
CurtainBloc(
|
|
this.curtainId,
|
|
) : super(CurtainInitial()) {
|
|
on<InitCurtain>(_fetchStatus);
|
|
on<OpenCurtain>(_onOpenCurtain);
|
|
on<CloseCurtain>(_onCloseCurtain);
|
|
on<PauseCurtain>(_onPauseCurtain);
|
|
on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
|
|
on<InitialWizardEvent>(_fetchWizardStatus);
|
|
on<GroupAllOffEvent>(_groupAllOff);
|
|
on<GroupAllOnEvent>(_groupAllOn);
|
|
on<UpdateCurtainEvent>(_updateCurtain);
|
|
}
|
|
|
|
Future<void> _onOpenCurtain(
|
|
OpenCurtain event, Emitter<CurtainState> emit) async {
|
|
isMoving = true;
|
|
while (openPercentage < 100.0) {
|
|
if (state is CurtainsClosing) {
|
|
_pauseCurtain(emit);
|
|
break;
|
|
}
|
|
emit(CurtainsOpening(
|
|
curtainWidth: curtainWidth,
|
|
blindHeight: blindHeight,
|
|
openPercentage: openPercentage,
|
|
));
|
|
if (isMoving) {
|
|
await Future.delayed(const Duration(milliseconds: 200), () async {
|
|
openPercentage += 10.0;
|
|
event.deviceType == DeviceType.Curtain
|
|
? curtainWidth -= curtainOpeningSpace / 10
|
|
: blindHeight -= blindOpeningSpace / 10;
|
|
if (openPercentage >= 100.0) {
|
|
_pauseCurtain(emit);
|
|
}
|
|
});
|
|
if (openPercentage >= 100.0) {
|
|
await DevicesAPI.controlDevice(
|
|
DeviceControlModel(
|
|
deviceId: curtainId,
|
|
code: 'control',
|
|
value: 'close',
|
|
),
|
|
curtainId,
|
|
);
|
|
await DevicesAPI.controlDevice(
|
|
DeviceControlModel(
|
|
deviceId: curtainId,
|
|
code: 'percent_control',
|
|
value: 100,
|
|
),
|
|
curtainId,
|
|
);
|
|
}
|
|
} else {
|
|
_pauseCurtain(emit);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> _onCloseCurtain(
|
|
CloseCurtain event, Emitter<CurtainState> emit) async {
|
|
isMoving = true;
|
|
while (openPercentage > 0.0) {
|
|
if (state is CurtainsOpening) {
|
|
_pauseCurtain(emit);
|
|
break;
|
|
}
|
|
emit(CurtainsClosing(
|
|
curtainWidth: curtainWidth,
|
|
blindHeight: blindHeight,
|
|
openPercentage: openPercentage,
|
|
));
|
|
if (isMoving) {
|
|
await Future.delayed(const Duration(milliseconds: 200), () async {
|
|
openPercentage -= 10.0;
|
|
event.deviceType == DeviceType.Curtain
|
|
? curtainWidth += curtainOpeningSpace / 10
|
|
: blindHeight += blindOpeningSpace / 10;
|
|
if (openPercentage <= 0.0) {
|
|
_pauseCurtain(emit);
|
|
}
|
|
});
|
|
if (openPercentage == 0.0) {
|
|
await DevicesAPI.controlDevice(
|
|
DeviceControlModel(
|
|
deviceId: curtainId,
|
|
code: 'percent_control',
|
|
value: 0,
|
|
),
|
|
curtainId,
|
|
);
|
|
await DevicesAPI.controlDevice(
|
|
DeviceControlModel(
|
|
deviceId: curtainId,
|
|
code: 'control',
|
|
value: 'open',
|
|
),
|
|
curtainId,
|
|
);
|
|
}
|
|
} else {
|
|
_pauseCurtain(emit);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> _onPauseCurtain(
|
|
PauseCurtain event, Emitter<CurtainState> emit) async {
|
|
_pauseCurtain(emit);
|
|
await DevicesAPI.controlDevice(
|
|
DeviceControlModel(
|
|
deviceId: curtainId,
|
|
code: 'control',
|
|
value: 'stop',
|
|
),
|
|
curtainId,
|
|
);
|
|
await DevicesAPI.controlDevice(
|
|
DeviceControlModel(
|
|
deviceId: curtainId,
|
|
code: 'percent_control',
|
|
value: openPercentage.ceil(),
|
|
),
|
|
curtainId,
|
|
);
|
|
}
|
|
|
|
Future<void> _pauseCurtain(Emitter<CurtainState> emit) async {
|
|
isMoving = false;
|
|
emit(CurtainsPaused(
|
|
curtainWidth: curtainWidth,
|
|
blindHeight: blindHeight,
|
|
openPercentage: openPercentage,
|
|
));
|
|
}
|
|
|
|
void _fetchStatus(InitCurtain event, Emitter<CurtainState> emit) async {
|
|
try {
|
|
emit(CurtainLoadingState());
|
|
_listenToChanges(curtainId);
|
|
|
|
var response = await DevicesAPI.getDeviceStatus(curtainId);
|
|
|
|
List<StatusModel> statusModelList = [];
|
|
for (var status in response['status']) {
|
|
statusModelList.add(StatusModel.fromJson(status));
|
|
}
|
|
openPercentage = double.tryParse(statusModelList[1].value.toString())!;
|
|
curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
|
|
blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
|
|
emit(CurtainsOpening(
|
|
curtainWidth: curtainWidth,
|
|
blindHeight: blindHeight,
|
|
openPercentage: openPercentage,
|
|
));
|
|
} catch (e) {
|
|
emit(FailedState());
|
|
return;
|
|
}
|
|
}
|
|
|
|
StreamSubscription<DatabaseEvent>? _streamSubscription;
|
|
|
|
void _listenToChanges(curtainId) {
|
|
try {
|
|
_streamSubscription?.cancel();
|
|
DatabaseReference ref =
|
|
FirebaseDatabase.instance.ref('device-status/$curtainId');
|
|
Stream<DatabaseEvent> stream = ref.onValue;
|
|
|
|
_streamSubscription = stream.listen((DatabaseEvent event) {
|
|
Map<dynamic, dynamic> usersMap =
|
|
event.snapshot.value as Map<dynamic, dynamic>;
|
|
List<StatusModel> statusList = [];
|
|
|
|
usersMap['status'].forEach((element) {
|
|
statusList
|
|
.add(StatusModel(code: element['code'], value: element['value']));
|
|
});
|
|
openPercentage = double.tryParse(statusList[1].value.toString())!;
|
|
curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
|
|
blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
|
|
add(UpdateCurtainEvent());
|
|
});
|
|
} catch (_) {}
|
|
}
|
|
|
|
@override
|
|
Future<void> close() async {
|
|
_streamSubscription?.cancel();
|
|
_streamSubscription = null;
|
|
return super.close();
|
|
}
|
|
|
|
// _listenToChanges(curtainId) {
|
|
// try {
|
|
// print('curtainId=$curtainId');
|
|
// DatabaseReference ref =
|
|
// FirebaseDatabase.instance.ref('device-status/$curtainId');
|
|
// Stream<DatabaseEvent> stream = ref.onValue;
|
|
|
|
// stream.listen((DatabaseEvent event) async {
|
|
// if (_timer != null) {
|
|
// await Future.delayed(const Duration(seconds: 2));
|
|
// }
|
|
// Map<dynamic, dynamic> usersMap =
|
|
// event.snapshot.value as Map<dynamic, dynamic>;
|
|
// List<StatusModel> statusModelList = [];
|
|
// for (var status in usersMap['status']) {
|
|
// statusModelList.add(StatusModel.fromJson(status));
|
|
// print('statusModelList==${statusModelList}');
|
|
// }
|
|
|
|
// openPercentage = double.tryParse(statusModelList[1].value.toString())!;
|
|
// curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
|
|
// blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
|
|
// add(UpdateCurtainEvent());
|
|
// });
|
|
// } catch (_) {}
|
|
// }
|
|
|
|
_updateCurtain(UpdateCurtainEvent event, Emitter<CurtainState> emit) {
|
|
curtainWidth = 270 - (openPercentage / 100) * curtainOpeningSpace;
|
|
blindHeight = 310 - (openPercentage / 100) * blindOpeningSpace;
|
|
emit(CurtainsOpening(
|
|
curtainWidth: curtainWidth,
|
|
blindHeight: blindHeight,
|
|
openPercentage: openPercentage,
|
|
));
|
|
}
|
|
|
|
List<GroupCurtainModel> groupList = [];
|
|
bool allSwitchesOn = true;
|
|
List<DeviceModel> devicesList = [];
|
|
CurtainModel deviceStatus = CurtainModel(control: 'stop', percent: 0);
|
|
void _fetchWizardStatus(
|
|
InitialWizardEvent event, Emitter<CurtainState> emit) async {
|
|
emit(LoadingInitialState());
|
|
|
|
try {
|
|
devicesList = [];
|
|
groupList = [];
|
|
allSwitchesOn = true;
|
|
devicesList = await DevicesAPI.getDeviceByGroupName(
|
|
HomeCubit.getInstance().selectedSpace?.id ?? '', 'CUR');
|
|
|
|
for (int i = 0; i < devicesList.length; i++) {
|
|
var response =
|
|
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
|
|
List<StatusModel> statusModelList = [];
|
|
for (var status in response['status']) {
|
|
statusModelList.add(StatusModel.fromJson(status));
|
|
}
|
|
deviceStatus = CurtainModel.fromJson(statusModelList);
|
|
groupList.add(GroupCurtainModel(
|
|
deviceId: devicesList[i].uuid ?? '',
|
|
deviceName: devicesList[i].name ?? '',
|
|
firstSwitch: deviceStatus.control,
|
|
percentControl: deviceStatus.percent));
|
|
}
|
|
|
|
if (groupList.isNotEmpty) {
|
|
groupList.firstWhere((element) {
|
|
if (element.percentControl > 1) {
|
|
allSwitchesOn = true;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
emit(
|
|
UpdateGroupState(curtainList: groupList, allSwitches: allSwitchesOn));
|
|
} catch (e) {
|
|
emit(FailedState());
|
|
return;
|
|
}
|
|
}
|
|
|
|
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
|
|
Emitter<CurtainState> emit) async {
|
|
emit(LoadingNewSate(curtainModel: deviceStatus));
|
|
try {
|
|
bool allSwitchesValue = true;
|
|
|
|
// Update the firstSwitch value in the groupList based on the deviceId
|
|
groupList.forEach((element) {
|
|
if (element.deviceId == event.deviceId) {
|
|
element.percentControl =
|
|
event.value; // Set the new value from the event
|
|
}
|
|
if (element.percentControl > 1) {
|
|
allSwitchesValue = true; // Check if any switch is not 'open'
|
|
}
|
|
});
|
|
|
|
final response = await DevicesAPI.deviceBatchController(
|
|
code: 'percent_control',
|
|
devicesUuid: [event.deviceId],
|
|
value: event.value, // Use the value from the event
|
|
);
|
|
|
|
emit(UpdateGroupState(
|
|
curtainList: groupList, allSwitches: allSwitchesValue));
|
|
|
|
if (response['success']) {
|
|
// Optionally add an initial event if needed.
|
|
}
|
|
} catch (_) {
|
|
// Handle the error if needed.
|
|
}
|
|
}
|
|
|
|
void _groupAllOn(GroupAllOnEvent event, Emitter<CurtainState> emit) async {
|
|
emit(LoadingNewSate(curtainModel: deviceStatus));
|
|
try {
|
|
for (int i = 0; i < groupList.length; i++) {
|
|
groupList[i].percentControl = 100;
|
|
}
|
|
|
|
emit(UpdateGroupState(curtainList: groupList, allSwitches: true));
|
|
|
|
List<String> allDeviceIds =
|
|
groupList.map((device) => device.deviceId).toList();
|
|
|
|
final response2 = await DevicesAPI.deviceBatchController(
|
|
code: 'percent_control',
|
|
devicesUuid: allDeviceIds,
|
|
value: 100,
|
|
);
|
|
|
|
if (response2['failedResults'].toString() != '[]') {
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
}
|
|
} catch (_) {
|
|
emit(FailedState());
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
// Optionally add an initial event if needed.
|
|
}
|
|
}
|
|
|
|
void _groupAllOff(GroupAllOffEvent event, Emitter<CurtainState> emit) async {
|
|
emit(LoadingNewSate(curtainModel: deviceStatus));
|
|
try {
|
|
for (int i = 0; i < groupList.length; i++) {
|
|
groupList[i].percentControl = 0;
|
|
}
|
|
|
|
emit(UpdateGroupState(curtainList: groupList, allSwitches: false));
|
|
|
|
List<String> allDeviceIds =
|
|
groupList.map((device) => device.deviceId).toList();
|
|
|
|
final response2 = await DevicesAPI.deviceBatchController(
|
|
code: 'percent_control',
|
|
devicesUuid: allDeviceIds,
|
|
value: 0,
|
|
);
|
|
|
|
if (response2['failedResults'].toString() != '[]') {
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
}
|
|
} catch (_) {
|
|
emit(FailedState());
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
}
|
|
}
|
|
}
|