now batch is working

This commit is contained in:
Rafeek-Khoudare
2025-06-27 16:26:39 +03:00
parent f43826a824
commit 396ce3dad8
12 changed files with 294 additions and 158 deletions

View File

@ -45,7 +45,8 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
) async {
emit(AcsLoadingState());
try {
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
final status =
await DevicesManagementApi().getDeviceStatus(event.deviceId);
deviceStatus = AcStatusModel.fromJson(event.deviceId, status.status);
if (deviceStatus.countdown1 != 0) {
final totalMinutes = deviceStatus.countdown1 * 6;
@ -82,10 +83,12 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
List<Status> statusList = [];
usersMap['status'].forEach((element) {
statusList.add(Status(code: element['code'], value: element['value']));
statusList
.add(Status(code: element['code'], value: element['value']));
});
deviceStatus = AcStatusModel.fromJson(usersMap['productUuid'], statusList);
deviceStatus =
AcStatusModel.fromJson(usersMap['productUuid'], statusList);
if (!isClosed) {
add(AcStatusUpdated(deviceStatus));
}
@ -129,8 +132,10 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
) async {
emit(AcsLoadingState());
try {
final status = await DevicesManagementApi().getBatchStatus(event.devicesIds);
deviceStatus = AcStatusModel.fromJson(event.devicesIds.first, status.status);
final status =
await DevicesManagementApi().getBatchStatus(event.devicesIds);
deviceStatus =
AcStatusModel.fromJson(event.devicesIds.first, status.status);
emit(ACStatusLoaded(status: deviceStatus));
} catch (e) {
emit(AcsFailedState(error: e.toString()));

View File

@ -213,7 +213,7 @@ mixin RouteControlsBasedCode {
case 'CUR_2':
return CurtainModuleBatchView(
devicesIds: devices
.where((e) => e.productType == 'AC')
.where((e) => e.productType == 'CUR_2')
.map((e) => e.uuid!)
.toList(),
);

View File

@ -1,45 +0,0 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:syncrow_web/pages/device_managment/curtain_module/models/curtain_module_model.dart';
import 'package:syncrow_web/services/control_device_service.dart';
import 'package:syncrow_web/services/devices_mang_api.dart';
part 'curtain_module_batch_event.dart';
part 'curtain_module_batch_state.dart';
class CurtainModuleBatchBloc
extends Bloc<CurtainModuleBatchEvent, CurtainModuleBatchState> {
final ControlDeviceService controlDeviceService;
StreamSubscription<DatabaseEvent>? _firebaseSubscription;
CurtainModuleBatchBloc(this.controlDeviceService)
: super(CurtainModuleBatchInitial()) {
on<CutrainModuleFetchBatchStatusEvent>(_onFetchAcBatchStatus);
}
Future<void> _onFetchAcBatchStatus(
CutrainModuleFetchBatchStatusEvent event,
Emitter<CurtainModuleBatchState> emit,
) async {
emit(CurtainModuleBatchLoadingState());
try {
final status =
await DevicesManagementApi().getBatchStatus(event.devicesIds);
status.status.forEach(
(element) => print(
'this is code ${element.code} - this is value ${element.value}'),
);
emit(
CurtainModuleBatchLoadedState(
curtainModuleStatusModel: CurtainModuleStatusModel.fromJson({}),
),
);
} catch (e) {
emit(CurtainModuleBatchFailedState(error: e.toString()));
}
}
}

View File

@ -1,19 +0,0 @@
part of 'curtain_module_batch_bloc.dart';
sealed class CurtainModuleBatchEvent extends Equatable {
const CurtainModuleBatchEvent();
@override
List<Object> get props => [];
}
class CutrainModuleFetchBatchStatusEvent extends CurtainModuleBatchEvent {
final List<String> devicesIds;
const CutrainModuleFetchBatchStatusEvent({
required this.devicesIds,
});
@override
List<Object> get props => [devicesIds];
}

View File

@ -1,28 +0,0 @@
part of 'curtain_module_batch_bloc.dart';
sealed class CurtainModuleBatchState extends Equatable {
const CurtainModuleBatchState();
@override
List<Object> get props => [];
}
final class CurtainModuleBatchInitial extends CurtainModuleBatchState {}
final class CurtainModuleBatchLoadingState extends CurtainModuleBatchState {}
final class CurtainModuleBatchLoadedState extends CurtainModuleBatchState {
final CurtainModuleStatusModel curtainModuleStatusModel;
const CurtainModuleBatchLoadedState({
required this.curtainModuleStatusModel,
});
}
final class CurtainModuleBatchFailedState extends CurtainModuleBatchState {
final String error;
const CurtainModuleBatchFailedState({required this.error});
@override
List<Object> get props => [error];
}

View File

@ -3,7 +3,9 @@ import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
import 'package:syncrow_web/pages/device_managment/curtain_module/models/curtain_module_model.dart';
import 'package:syncrow_web/services/batch_control_devices_service.dart';
import 'package:syncrow_web/services/control_device_service.dart';
import 'package:syncrow_web/services/devices_mang_api.dart';
@ -12,9 +14,13 @@ part 'curtain_module_state.dart';
class CurtainModuleBloc extends Bloc<CurtainModuleEvent, CurtainModuleState> {
final ControlDeviceService controlDeviceService;
final BatchControlDevicesService batchControlDevicesService;
StreamSubscription<DatabaseEvent>? _firebaseSubscription;
CurtainModuleBloc(this.controlDeviceService) : super(CurtainModuleInitial()) {
CurtainModuleBloc({
required this.controlDeviceService,
required this.batchControlDevicesService,
}) : super(CurtainModuleInitial()) {
on<FetchCurtainModuleStatusEvent>(_onFetchCurtainModuleStatusEvent);
on<SendCurtainPercentToApiEvent>(_onSendCurtainPercentToApiEvent);
on<OpenCurtainEvent>(_onOpenCurtainEvent);
@ -26,6 +32,13 @@ class CurtainModuleBloc extends Bloc<CurtainModuleEvent, CurtainModuleState> {
on<ChangeControlBackEvent>(_onChangeControlBackEvent);
on<ChangeControlBackModeEvent>(_onChangeControlBackModeEvent);
on<ChangeCurtainModuleStatusEvent>(_onChangeCurtainModuleStatusEvent);
//batch
on<CurtainModuleFetchBatchStatusEvent>(_onFetchCurtainModuleBatchStatus);
on<SendCurtainBatchPercentToApiEvent>(_onSendCurtainBatchPercentToApiEvent);
on<OpenCurtainBatchEvent>(_onOpenCurtainBatchEvent);
on<CloseCurtainBatchEvent>(_onCloseCurtainBatchEvent);
on<StopCurtainBatchEvent>(_onStopCurtainBatchEvent);
on<CurtainModuleFactoryReset>(_onFactoryReset);
}
Future<void> _onFetchCurtainModuleStatusEvent(
@ -224,6 +237,109 @@ class CurtainModuleBloc extends Bloc<CurtainModuleEvent, CurtainModuleState> {
}
}
FutureOr<void> _onFetchCurtainModuleBatchStatus(
CurtainModuleFetchBatchStatusEvent event,
Emitter<CurtainModuleState> emit,
) async {
emit(CurtainModuleLoading());
try {
final status =
await DevicesManagementApi().getBatchStatus(event.devicesIds);
final result = Map.fromEntries(
status.status.map((element) => MapEntry(element.code, element.value)),
);
emit(CurtainModuleStatusLoaded(
curtainModuleStatus: CurtainModuleStatusModel.fromJson(result),
));
} catch (e) {
emit(CurtainModuleError(message: e.toString()));
}
}
Future<void> _onSendCurtainBatchPercentToApiEvent(
SendCurtainBatchPercentToApiEvent event,
Emitter<CurtainModuleState> emit,
) async {
try {
await batchControlDevicesService.batchControlDevices(
uuids: event.devicesId,
code: event.status.code,
value: event.status.value,
);
} catch (e) {
emit(CurtainModuleError(message: 'Failed to send control command: $e'));
}
}
Future<void> _onOpenCurtainBatchEvent(
OpenCurtainBatchEvent event,
Emitter<CurtainModuleState> emit,
) async {
try {
await batchControlDevicesService.batchControlDevices(
uuids: event.devicesId,
code: 'control',
value: 'open',
);
} catch (e) {
emit(CurtainModuleError(message: 'Failed to open curtain: $e'));
}
}
Future<void> _onCloseCurtainBatchEvent(
CloseCurtainBatchEvent event,
Emitter<CurtainModuleState> emit,
) async {
try {
await batchControlDevicesService.batchControlDevices(
uuids: event.devicesId,
code: 'control',
value: 'close',
);
} catch (e) {
emit(CurtainModuleError(message: 'Failed to close curtain: $e'));
}
}
Future<void> _onStopCurtainBatchEvent(
StopCurtainBatchEvent event,
Emitter<CurtainModuleState> emit,
) async {
try {
await batchControlDevicesService.batchControlDevices(
uuids: event.devicesId,
code: 'control',
value: 'stop',
);
} catch (e) {
emit(CurtainModuleError(message: 'Failed to stop curtain: $e'));
}
}
Future<void> _onFactoryReset(
CurtainModuleFactoryReset event,
Emitter<CurtainModuleState> emit,
) async {
emit(CurtainModuleLoading());
try {
final response = await DevicesManagementApi().factoryReset(
event.factoryReset,
event.deviceId,
);
if (!response) {
emit(const CurtainModuleError(message: 'Failed'));
} else {
add(
FetchCurtainModuleStatusEvent(deviceId: event.deviceId),
);
}
} catch (e) {
emit(CurtainModuleError(message: e.toString()));
}
}
@override
Future<void> close() async {
await _firebaseSubscription?.cancel();

View File

@ -130,3 +130,64 @@ class ChangeCurtainModuleStatusEvent extends CurtainModuleEvent {
@override
List<Object> get props => [deviceId, status];
}
///batch
class CurtainModuleFetchBatchStatusEvent extends CurtainModuleEvent {
final List<String> devicesIds;
const CurtainModuleFetchBatchStatusEvent(this.devicesIds);
@override
List<Object> get props => [devicesIds];
}
class SendCurtainBatchPercentToApiEvent extends CurtainModuleEvent {
final List<String> devicesId;
final Status status;
const SendCurtainBatchPercentToApiEvent({
required this.devicesId,
required this.status,
});
@override
List<Object> get props => [devicesId, status];
}
class OpenCurtainBatchEvent extends CurtainModuleEvent {
final List<String> devicesId;
const OpenCurtainBatchEvent({required this.devicesId});
@override
List<Object> get props => [devicesId];
}
class CloseCurtainBatchEvent extends CurtainModuleEvent {
final List<String> devicesId;
const CloseCurtainBatchEvent({required this.devicesId});
@override
List<Object> get props => [devicesId];
}
class StopCurtainBatchEvent extends CurtainModuleEvent {
final List<String> devicesId;
const StopCurtainBatchEvent({required this.devicesId});
@override
List<Object> get props => [devicesId];
}
class CurtainModuleFactoryReset extends CurtainModuleEvent {
final String deviceId;
final FactoryResetModel factoryReset;
const CurtainModuleFactoryReset(
{required this.deviceId, required this.factoryReset});
@override
List<Object> get props => [deviceId, factoryReset];
}

View File

@ -1,8 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/device_managment/curtain_module/bloc/batch/curtain_module_batch_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
import 'package:syncrow_web/pages/device_managment/curtain_module/bloc/curtain_module_bloc.dart';
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/curtain_movment_widget.dart';
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
import 'package:syncrow_web/pages/device_managment/shared/icon_name_status_container.dart';
import 'package:syncrow_web/services/batch_control_devices_service.dart';
import 'package:syncrow_web/services/control_device_service.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
@ -17,8 +20,10 @@ class CurtainModuleBatchView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => CurtainModuleBatchBloc(RemoteControlDeviceService())
..add(CutrainModuleFetchBatchStatusEvent(devicesIds: devicesIds)),
create: (context) => CurtainModuleBloc(
controlDeviceService: RemoteControlDeviceService(),
batchControlDevicesService: RemoteBatchControlDevicesService())
..add(CurtainModuleFetchBatchStatusEvent(devicesIds)),
child: _buildStatusControls(context),
);
}
@ -30,37 +35,41 @@ class CurtainModuleBatchView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ControlCurtainMovementWidget(
deviceId: devicesIds.first,
devicesId: devicesIds,
),
const SizedBox(
height: 10,
),
SizedBox(
height: 120,
width: 350,
// width: 350,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: IconNameStatusContainer(
isFullIcon: false,
name: 'Factory Reset',
icon: Assets.factoryReset,
onTap: () {},
status: false,
textColor: ColorsManager.blackColor,
),
),
Expanded(
child: IconNameStatusContainer(
isFullIcon: false,
name: 'Firmware Update',
icon: Assets.firmware,
onTap: () {},
status: false,
textColor: ColorsManager.blackColor,
// Expanded(
// child:
FactoryResetWidget(
callFactoryReset: () {
context.read<CurtainModuleBloc>().add(
CurtainModuleFactoryReset(
deviceId: devicesIds.first,
factoryReset:
FactoryResetModel(devicesUuid: devicesIds),
),
);
},
),
// ),
// Expanded(
// child: IconNameStatusContainer(
// isFullIcon: false,
// name: 'Firmware Update',
// icon: Assets.firmware,
// onTap: () {},
// status: false,
// textColor: ColorsManager.blackColor,
// ),
// )
],
),
),

View File

@ -4,6 +4,7 @@ import 'package:syncrow_web/pages/device_managment/curtain_module/bloc/curtain_m
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/curtain_movment_widget.dart';
import 'package:syncrow_web/pages/device_managment/curtain_module/widgets/prefrences_dialog.dart';
import 'package:syncrow_web/pages/device_managment/shared/icon_name_status_container.dart';
import 'package:syncrow_web/services/batch_control_devices_service.dart';
import 'package:syncrow_web/services/control_device_service.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
@ -19,7 +20,9 @@ class CurtainModuleItems extends StatelessWidget with HelperResponsiveLayout {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => CurtainModuleBloc(RemoteControlDeviceService())
create: (context) => CurtainModuleBloc(
controlDeviceService: RemoteControlDeviceService(),
batchControlDevicesService: RemoteBatchControlDevicesService())
..add(FetchCurtainModuleStatusEvent(deviceId: deviceId)),
child: _buildStatusControls(context),
);
@ -32,7 +35,7 @@ class CurtainModuleItems extends StatelessWidget with HelperResponsiveLayout {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ControlCurtainMovementWidget(
deviceId: deviceId,
devicesId: [deviceId],
),
const SizedBox(
height: 10,
@ -70,7 +73,9 @@ class CurtainModuleItems extends StatelessWidget with HelperResponsiveLayout {
icon: Assets.preferences,
onTap: () => showDialog(
context: context,
builder: (_) => CurtainModulePrefrencesDialog(
builder: (_) => BlocProvider.value(
value: context.read<CurtainModuleBloc>(),
child: CurtainModulePrefrencesDialog(
curtainModuleBloc:
context.watch<CurtainModuleBloc>(),
deviceId: deviceId,
@ -78,6 +83,7 @@ class CurtainModuleItems extends StatelessWidget with HelperResponsiveLayout {
state.curtainModuleStatus,
),
),
),
status: false,
textColor: ColorsManager.blackColor,
);

View File

@ -9,10 +9,10 @@ import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
class ControlCurtainMovementWidget extends StatelessWidget {
final String deviceId;
final List<String> devicesId;
const ControlCurtainMovementWidget({
super.key,
required this.deviceId,
required this.devicesId,
});
@override
@ -26,9 +26,15 @@ class ControlCurtainMovementWidget extends StatelessWidget {
CurtainActionWidget(
icon: Assets.openCurtain,
onTap: () {
if (devicesId.length == 1) {
context.read<CurtainModuleBloc>().add(
OpenCurtainEvent(deviceId: deviceId),
OpenCurtainEvent(deviceId: devicesId.first),
);
} else {
context.read<CurtainModuleBloc>().add(
OpenCurtainBatchEvent(devicesId: devicesId),
);
}
},
),
const SizedBox(
@ -37,9 +43,15 @@ class ControlCurtainMovementWidget extends StatelessWidget {
CurtainActionWidget(
icon: Assets.pauseCurtain,
onTap: () {
if (devicesId.length == 1) {
context.read<CurtainModuleBloc>().add(
StopCurtainEvent(deviceId: deviceId),
StopCurtainEvent(deviceId: devicesId.first),
);
} else {
context.read<CurtainModuleBloc>().add(
StopCurtainBatchEvent(devicesId: devicesId),
);
}
},
),
const SizedBox(
@ -48,9 +60,15 @@ class ControlCurtainMovementWidget extends StatelessWidget {
CurtainActionWidget(
icon: Assets.closeCurtain,
onTap: () {
if (devicesId.length == 1) {
context.read<CurtainModuleBloc>().add(
CloseCurtainEvent(deviceId: deviceId),
CloseCurtainEvent(deviceId: devicesId.first),
);
} else {
context.read<CurtainModuleBloc>().add(
CloseCurtainBatchEvent(devicesId: devicesId),
);
}
},
),
BlocBuilder<CurtainModuleBloc, CurtainModuleState>(
@ -84,7 +102,7 @@ class ControlCurtainMovementWidget extends StatelessWidget {
} else if (state is CurtainModuleStatusLoaded) {
return CurtainSliderWidget(
status: state.curtainModuleStatus,
deviceId: deviceId,
devicesId: devicesId,
);
} else {
return const Center(
@ -108,12 +126,12 @@ class ControlCurtainMovementWidget extends StatelessWidget {
class CurtainSliderWidget extends StatefulWidget {
final CurtainModuleStatusModel status;
final String deviceId;
final List<String> devicesId;
const CurtainSliderWidget({
super.key,
required this.status,
required this.deviceId,
required this.devicesId,
});
@override
@ -167,16 +185,27 @@ class _CurtainSliderWidgetState extends State<CurtainSliderWidget> {
onChangeEnd: (value) {
final int targetPercent = (value * 100).round();
// Dispatch API call
if (widget.devicesId.length == 1) {
context.read<CurtainModuleBloc>().add(
SendCurtainPercentToApiEvent(
deviceId: widget.deviceId,
deviceId: widget.devicesId.first,
status: Status(
code: 'percent_control',
value: targetPercent,
),
),
);
} else {
context.read<CurtainModuleBloc>().add(
SendCurtainBatchPercentToApiEvent(
devicesId: widget.devicesId,
status: Status(
code: 'percent_control',
value: targetPercent,
),
),
);
}
// Revert back to Firebase-synced stream
setState(() {

View File

@ -4,7 +4,8 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
class DeviceBatchControlDialog extends StatelessWidget with RouteControlsBasedCode {
class DeviceBatchControlDialog extends StatelessWidget
with RouteControlsBasedCode {
final List<AllDevicesModel> devices;
const DeviceBatchControlDialog({super.key, required this.devices});
@ -18,7 +19,7 @@ class DeviceBatchControlDialog extends StatelessWidget with RouteControlsBasedCo
borderRadius: BorderRadius.circular(20),
),
child: SizedBox(
width: devices.length < 2 ? 500 : 800,
width: devices.length < 2 ? 600 : 800,
// height: context.screenHeight * 0.7,
child: SingleChildScrollView(
child: Padding(

View File

@ -11,7 +11,8 @@ abstract interface class BatchControlDevicesService {
});
}
final class RemoteBatchControlDevicesService implements BatchControlDevicesService {
final class RemoteBatchControlDevicesService
implements BatchControlDevicesService {
@override
Future<bool> batchControlDevices({
required List<String> uuids,