mirror of
https://github.com/SyncrowIOT/web.git
synced 2026-10-26 19:07:55 +00:00
Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34d4d892d9 | ||
|
|
3193fd26fe | ||
|
|
43802a9fad | ||
|
|
6e0b1775f0 | ||
|
|
233fb2ee2c | ||
|
|
b26928b3d5 | ||
|
|
6fc35a7b9a | ||
|
|
756457927c | ||
|
|
17a582ab99 | ||
|
|
09fb604acc | ||
|
|
2068df173d | ||
|
|
bfc2a381d2 | ||
|
|
778257644d | ||
|
|
c8e540e938 | ||
|
|
ba20998067 | ||
|
|
75b0b24543 | ||
|
|
c03b8f290c | ||
|
|
2c684a9495 | ||
|
|
fbc45b465f | ||
|
|
c9c939c59f | ||
|
|
d1bb7b129f |
@@ -60,7 +60,15 @@ class _CurrentTempState extends State<CurrentTemp> {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(CurrentTemp oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (oldWidget.tempSet != widget.tempSet) {
|
||||||
|
setState(() {
|
||||||
|
_adjustedValue = _initialAdjustedValue(widget.tempSet);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_debounce?.cancel();
|
_debounce?.cancel();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import 'package:syncrow_web/pages/device_managment/curtain/view/curtain_batch_st
|
|||||||
import 'package:syncrow_web/pages/device_managment/curtain/view/curtain_status_view.dart';
|
import 'package:syncrow_web/pages/device_managment/curtain/view/curtain_status_view.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/door_lock/view/door_lock_batch_control_view.dart';
|
import 'package:syncrow_web/pages/device_managment/door_lock/view/door_lock_batch_control_view.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/door_lock/view/door_lock_control_view.dart';
|
import 'package:syncrow_web/pages/device_managment/door_lock/view/door_lock_control_view.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/flush_mounted_presence_sensor/views/flush_mounted_presence_sensor_batch_control_view.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/flush_mounted_presence_sensor/views/flush_mounted_presence_sensor_control_view.dart';
|
import 'package:syncrow_web/pages/device_managment/flush_mounted_presence_sensor/views/flush_mounted_presence_sensor_control_view.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/garage_door/view/garage_door_batch_control_view.dart';
|
import 'package:syncrow_web/pages/device_managment/garage_door/view/garage_door_batch_control_view.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/garage_door/view/garage_door_control_view.dart';
|
import 'package:syncrow_web/pages/device_managment/garage_door/view/garage_door_control_view.dart';
|
||||||
@@ -198,6 +199,10 @@ mixin RouteControlsBasedCode {
|
|||||||
return SOSBatchControlView(
|
return SOSBatchControlView(
|
||||||
deviceIds: devices.where((e) => (e.productType == 'SOS')).map((e) => e.uuid!).toList(),
|
deviceIds: devices.where((e) => (e.productType == 'SOS')).map((e) => e.uuid!).toList(),
|
||||||
);
|
);
|
||||||
|
case 'NCPS':
|
||||||
|
return FlushMountedPresenceSensorBatchControlView(
|
||||||
|
devicesIds: devices.where((e) => (e.productType == 'NCPS')).map((e) => e.uuid!).toList(),
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ import 'package:syncrow_web/pages/device_managment/shared/table/report_table.dar
|
|||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
class CeilingSensorControlsView extends StatelessWidget with HelperResponsiveLayout {
|
class CeilingSensorControlsView extends StatelessWidget
|
||||||
|
with HelperResponsiveLayout {
|
||||||
const CeilingSensorControlsView({super.key, required this.device});
|
const CeilingSensorControlsView({super.key, required this.device});
|
||||||
|
|
||||||
final AllDevicesModel device;
|
final AllDevicesModel device;
|
||||||
@@ -31,29 +32,35 @@ class CeilingSensorControlsView extends StatelessWidget with HelperResponsiveLay
|
|||||||
..add(CeilingInitialEvent(device.uuid ?? '')),
|
..add(CeilingInitialEvent(device.uuid ?? '')),
|
||||||
child: BlocBuilder<CeilingSensorBloc, CeilingSensorState>(
|
child: BlocBuilder<CeilingSensorBloc, CeilingSensorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state is CeilingLoadingInitialState || state is CeilingReportsLoadingState) {
|
if (state is CeilingLoadingInitialState ||
|
||||||
|
state is CeilingReportsLoadingState) {
|
||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
} else if (state is CeilingUpdateState) {
|
} else if (state is CeilingUpdateState) {
|
||||||
return _buildGridView(
|
return _buildGridView(context, state.ceilingSensorModel,
|
||||||
context, state.ceilingSensorModel, isExtraLarge, isLarge, isMedium);
|
isExtraLarge, isLarge, isMedium);
|
||||||
} else if (state is CeilingReportsState) {
|
} else if (state is CeilingReportsState) {
|
||||||
return ReportsTable(
|
return ReportsTable(
|
||||||
report: state.deviceReport,
|
report: state.deviceReport,
|
||||||
onRowTap: (index) {},
|
onRowTap: (index) {},
|
||||||
onClose: () {
|
onClose: () {
|
||||||
context.read<CeilingSensorBloc>().add(BackToCeilingGridViewEvent());
|
context
|
||||||
|
.read<CeilingSensorBloc>()
|
||||||
|
.add(BackToCeilingGridViewEvent());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else if (state is ShowCeilingDescriptionState) {
|
} else if (state is ShowCeilingDescriptionState) {
|
||||||
return DescriptionView(
|
return DescriptionView(
|
||||||
description: state.description,
|
description: state.description,
|
||||||
onClose: () {
|
onClose: () {
|
||||||
context.read<CeilingSensorBloc>().add(BackToCeilingGridViewEvent());
|
context
|
||||||
|
.read<CeilingSensorBloc>()
|
||||||
|
.add(BackToCeilingGridViewEvent());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else if (state is CeilingReportsFailedState) {
|
} else if (state is CeilingReportsFailedState) {
|
||||||
final model = context.read<CeilingSensorBloc>().deviceStatus;
|
final model = context.read<CeilingSensorBloc>().deviceStatus;
|
||||||
return _buildGridView(context, model, isExtraLarge, isLarge, isMedium);
|
return _buildGridView(
|
||||||
|
context, model, isExtraLarge, isLarge, isMedium);
|
||||||
}
|
}
|
||||||
return const Center(child: Text('Error fetching status'));
|
return const Center(child: Text('Error fetching status'));
|
||||||
},
|
},
|
||||||
@@ -61,8 +68,8 @@ class CeilingSensorControlsView extends StatelessWidget with HelperResponsiveLay
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildGridView(BuildContext context, CeilingSensorModel model, bool isExtraLarge,
|
Widget _buildGridView(BuildContext context, CeilingSensorModel model,
|
||||||
bool isLarge, bool isMedium) {
|
bool isExtraLarge, bool isLarge, bool isMedium) {
|
||||||
return GridView(
|
return GridView(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 50),
|
padding: const EdgeInsets.symmetric(horizontal: 50),
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
@@ -143,8 +150,8 @@ class CeilingSensorControlsView extends StatelessWidget with HelperResponsiveLay
|
|||||||
),
|
),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.read<CeilingSensorBloc>().add(
|
context.read<CeilingSensorBloc>().add(GetCeilingDeviceReportsEvent(
|
||||||
GetCeilingDeviceReportsEvent(code: 'presence_state', deviceUuid: device.uuid!));
|
code: 'presence_state', deviceUuid: device.uuid!));
|
||||||
},
|
},
|
||||||
child: const PresenceStaticWidget(
|
child: const PresenceStaticWidget(
|
||||||
icon: Assets.illuminanceRecordIcon,
|
icon: Assets.illuminanceRecordIcon,
|
||||||
@@ -153,9 +160,8 @@ class CeilingSensorControlsView extends StatelessWidget with HelperResponsiveLay
|
|||||||
),
|
),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context
|
context.read<CeilingSensorBloc>().add(GetCeilingDeviceReportsEvent(
|
||||||
.read<CeilingSensorBloc>()
|
code: '', deviceUuid: device.uuid!));
|
||||||
.add(GetCeilingDeviceReportsEvent(code: '', deviceUuid: device.uuid!));
|
|
||||||
},
|
},
|
||||||
child: const PresenceStaticWidget(
|
child: const PresenceStaticWidget(
|
||||||
icon: Assets.helpDescriptionIcon,
|
icon: Assets.helpDescriptionIcon,
|
||||||
|
|||||||
+34
-21
@@ -49,6 +49,9 @@ class FlushMountedPresenceSensorBloc
|
|||||||
on<FlushMountedPresenceSensorFactoryResetEvent>(
|
on<FlushMountedPresenceSensorFactoryResetEvent>(
|
||||||
_onFlushMountedPresenceSensorFactoryResetEvent,
|
_onFlushMountedPresenceSensorFactoryResetEvent,
|
||||||
);
|
);
|
||||||
|
on<FlushMountedPresenceSensorStatusUpdatedEvent>(
|
||||||
|
_onFlushMountedPresenceSensorStatusUpdatedEvent,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onFlushMountedPresenceSensorFetchStatusEvent(
|
void _onFlushMountedPresenceSensorFetchStatusEvent(
|
||||||
@@ -60,7 +63,7 @@ class FlushMountedPresenceSensorBloc
|
|||||||
final response = await DevicesManagementApi().getDeviceStatus(deviceId);
|
final response = await DevicesManagementApi().getDeviceStatus(deviceId);
|
||||||
deviceStatus = FlushMountedPresenceSensorModel.fromJson(response.status);
|
deviceStatus = FlushMountedPresenceSensorModel.fromJson(response.status);
|
||||||
emit(FlushMountedPresenceSensorUpdateState(model: deviceStatus));
|
emit(FlushMountedPresenceSensorUpdateState(model: deviceStatus));
|
||||||
_listenToChanges(emit, deviceId);
|
_listenToChanges(deviceId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(FlushMountedPresenceSensorFailedState(error: e.toString()));
|
emit(FlushMountedPresenceSensorFailedState(error: e.toString()));
|
||||||
return;
|
return;
|
||||||
@@ -81,31 +84,33 @@ class FlushMountedPresenceSensorBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _listenToChanges(
|
void _listenToChanges(String deviceId) {
|
||||||
Emitter<FlushMountedPresenceSensorState> emit,
|
try {
|
||||||
String deviceId,
|
final ref = FirebaseDatabase.instance.ref(
|
||||||
) async {
|
'device-status/$deviceId',
|
||||||
final ref = FirebaseDatabase.instance.ref(
|
);
|
||||||
'device-status/$deviceId',
|
|
||||||
);
|
ref.onValue.listen((event) {
|
||||||
|
final eventsMap = event.snapshot.value as Map<dynamic, dynamic>;
|
||||||
|
|
||||||
await ref.onValue.listen(
|
|
||||||
(DatabaseEvent event) async {
|
|
||||||
Map<dynamic, dynamic> usersMap =
|
|
||||||
event.snapshot.value as Map<dynamic, dynamic>;
|
|
||||||
List<Status> statusList = [];
|
List<Status> statusList = [];
|
||||||
|
eventsMap['status'].forEach((element) {
|
||||||
(usersMap['status'] as List<dynamic>?)?.forEach((element) {
|
statusList.add(
|
||||||
statusList.add(Status(code: element['code'], value: element['value']));
|
Status(code: element['code'], value: element['value']),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
deviceStatus = FlushMountedPresenceSensorModel.fromJson(statusList);
|
deviceStatus = FlushMountedPresenceSensorModel.fromJson(statusList);
|
||||||
if (!emit.isDone) {
|
if (!isClosed) {
|
||||||
emit(FlushMountedPresenceSensorLoadingNewSate(model: deviceStatus));
|
add(FlushMountedPresenceSensorStatusUpdatedEvent(deviceStatus));
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
onError: (error) => log(error.toString(), name: 'FirebaseDatabaseError'),
|
} catch (_) {
|
||||||
).asFuture();
|
log(
|
||||||
|
'Error listening to changes',
|
||||||
|
name: 'FlushMountedPresenceSensorBloc._listenToChanges',
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onFlushMountedPresenceSensorChangeValueEvent(
|
void _onFlushMountedPresenceSensorChangeValueEvent(
|
||||||
@@ -234,4 +239,12 @@ class FlushMountedPresenceSensorBloc
|
|||||||
emit(FlushMountedPresenceSensorFailedState(error: e.toString()));
|
emit(FlushMountedPresenceSensorFailedState(error: e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onFlushMountedPresenceSensorStatusUpdatedEvent(
|
||||||
|
FlushMountedPresenceSensorStatusUpdatedEvent event,
|
||||||
|
Emitter<FlushMountedPresenceSensorState> emit,
|
||||||
|
) {
|
||||||
|
deviceStatus = event.model;
|
||||||
|
emit(FlushMountedPresenceSensorUpdateState(model: deviceStatus));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-2
@@ -10,15 +10,24 @@ sealed class FlushMountedPresenceSensorEvent extends Equatable {
|
|||||||
class FlushMountedPresenceSensorFetchStatusEvent
|
class FlushMountedPresenceSensorFetchStatusEvent
|
||||||
extends FlushMountedPresenceSensorEvent {}
|
extends FlushMountedPresenceSensorEvent {}
|
||||||
|
|
||||||
|
class FlushMountedPresenceSensorStatusUpdatedEvent
|
||||||
|
extends FlushMountedPresenceSensorEvent {
|
||||||
|
const FlushMountedPresenceSensorStatusUpdatedEvent(this.model);
|
||||||
|
|
||||||
|
final FlushMountedPresenceSensorModel model;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [model];
|
||||||
|
}
|
||||||
|
|
||||||
class FlushMountedPresenceSensorChangeValueEvent
|
class FlushMountedPresenceSensorChangeValueEvent
|
||||||
extends FlushMountedPresenceSensorEvent {
|
extends FlushMountedPresenceSensorEvent {
|
||||||
final int value;
|
final int value;
|
||||||
final String code;
|
final String code;
|
||||||
final bool isBatchControl;
|
|
||||||
const FlushMountedPresenceSensorChangeValueEvent({
|
const FlushMountedPresenceSensorChangeValueEvent({
|
||||||
required this.value,
|
required this.value,
|
||||||
required this.code,
|
required this.code,
|
||||||
this.isBatchControl = false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
+1
-1
@@ -16,6 +16,6 @@ abstract final class FlushMountedPresenceSensorBlocFactory {
|
|||||||
batchControlDevicesService: DebouncedBatchControlDevicesService(
|
batchControlDevicesService: DebouncedBatchControlDevicesService(
|
||||||
decoratee: RemoteBatchControlDevicesService(),
|
decoratee: RemoteBatchControlDevicesService(),
|
||||||
),
|
),
|
||||||
)..add(FlushMountedPresenceSensorFetchStatusEvent());
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-22
@@ -22,7 +22,7 @@ class FlushMountedPresenceSensorBatchControlView extends StatelessWidget
|
|||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => FlushMountedPresenceSensorBlocFactory.create(
|
create: (context) => FlushMountedPresenceSensorBlocFactory.create(
|
||||||
deviceId: devicesIds.first,
|
deviceId: devicesIds.first,
|
||||||
),
|
)..add(FlushMountedPresenceSensorFetchBatchStatusEvent(devicesIds)),
|
||||||
child: BlocBuilder<FlushMountedPresenceSensorBloc,
|
child: BlocBuilder<FlushMountedPresenceSensorBloc,
|
||||||
FlushMountedPresenceSensorState>(
|
FlushMountedPresenceSensorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
@@ -67,14 +67,15 @@ class FlushMountedPresenceSensorBatchControlView extends StatelessWidget
|
|||||||
maxValue: 9,
|
maxValue: 9,
|
||||||
steps: 1,
|
steps: 1,
|
||||||
action: (int value) => context.read<FlushMountedPresenceSensorBloc>().add(
|
action: (int value) => context.read<FlushMountedPresenceSensorBloc>().add(
|
||||||
FlushMountedPresenceSensorChangeValueEvent(
|
FlushMountedPresenceSensorBatchControlEvent(
|
||||||
|
deviceIds: devicesIds,
|
||||||
code: FlushMountedPresenceSensorModel.codeSensitivity,
|
code: FlushMountedPresenceSensorModel.codeSensitivity,
|
||||||
value: value,
|
value: value,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PresenceUpdateData(
|
PresenceUpdateData(
|
||||||
value: (model.nearDetection / 100).toDouble(),
|
value: (model.nearDetection / 100).clamp(0.0, double.infinity),
|
||||||
title: 'Nearest Detect Dist:',
|
title: 'Nearest Detect Dist:',
|
||||||
description: 'm',
|
description: 'm',
|
||||||
minValue: 0.0,
|
minValue: 0.0,
|
||||||
@@ -83,14 +84,15 @@ class FlushMountedPresenceSensorBatchControlView extends StatelessWidget
|
|||||||
valuesPercision: 1,
|
valuesPercision: 1,
|
||||||
action: (double value) =>
|
action: (double value) =>
|
||||||
context.read<FlushMountedPresenceSensorBloc>().add(
|
context.read<FlushMountedPresenceSensorBloc>().add(
|
||||||
FlushMountedPresenceSensorChangeValueEvent(
|
FlushMountedPresenceSensorBatchControlEvent(
|
||||||
|
deviceIds: devicesIds,
|
||||||
code: FlushMountedPresenceSensorModel.codeNearDetection,
|
code: FlushMountedPresenceSensorModel.codeNearDetection,
|
||||||
value: (value * 100).toInt(),
|
value: (value * 100).toInt(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PresenceUpdateData(
|
PresenceUpdateData(
|
||||||
value: (model.farDetection / 100).toDouble(),
|
value: (model.farDetection / 100).clamp(0.0, double.infinity),
|
||||||
title: 'Max Detect Dist:',
|
title: 'Max Detect Dist:',
|
||||||
description: 'm',
|
description: 'm',
|
||||||
minValue: 0.0,
|
minValue: 0.0,
|
||||||
@@ -99,51 +101,57 @@ class FlushMountedPresenceSensorBatchControlView extends StatelessWidget
|
|||||||
valuesPercision: 1,
|
valuesPercision: 1,
|
||||||
action: (double value) =>
|
action: (double value) =>
|
||||||
context.read<FlushMountedPresenceSensorBloc>().add(
|
context.read<FlushMountedPresenceSensorBloc>().add(
|
||||||
FlushMountedPresenceSensorChangeValueEvent(
|
FlushMountedPresenceSensorBatchControlEvent(
|
||||||
|
deviceIds: devicesIds,
|
||||||
code: FlushMountedPresenceSensorModel.codeFarDetection,
|
code: FlushMountedPresenceSensorModel.codeFarDetection,
|
||||||
value: (value * 100).toInt(),
|
value: (value * 100).toInt(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PresenceUpdateData(
|
PresenceUpdateData(
|
||||||
value: model.presenceDelay.toDouble(),
|
value: model.sensiReduce.toDouble(),
|
||||||
title: 'Trigger Level:',
|
title: 'Trigger Level:',
|
||||||
minValue: 0,
|
minValue: 0,
|
||||||
maxValue: 3,
|
maxValue: 3,
|
||||||
steps: 1,
|
steps: 1,
|
||||||
action: (int value) => context.read<FlushMountedPresenceSensorBloc>().add(
|
action: (int value) => context.read<FlushMountedPresenceSensorBloc>().add(
|
||||||
FlushMountedPresenceSensorChangeValueEvent(
|
FlushMountedPresenceSensorBatchControlEvent(
|
||||||
code: FlushMountedPresenceSensorModel.codePresenceDelay,
|
deviceIds: devicesIds,
|
||||||
|
code: FlushMountedPresenceSensorModel.codeSensiReduce,
|
||||||
value: value,
|
value: value,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PresenceUpdateData(
|
PresenceUpdateData(
|
||||||
value: (model.occurDistReduce.toDouble()),
|
value: model.occurDistReduce.toDouble(),
|
||||||
title: 'Indent Level:',
|
title: 'Indent Level:',
|
||||||
minValue: 0,
|
minValue: 0,
|
||||||
maxValue: 3,
|
maxValue: 3,
|
||||||
steps: 1,
|
steps: 1,
|
||||||
action: (int value) => context.read<FlushMountedPresenceSensorBloc>().add(
|
action: (int value) => context.read<FlushMountedPresenceSensorBloc>().add(
|
||||||
FlushMountedPresenceSensorChangeValueEvent(
|
FlushMountedPresenceSensorBatchControlEvent(
|
||||||
|
deviceIds: devicesIds,
|
||||||
code: FlushMountedPresenceSensorModel.codeOccurDistReduce,
|
code: FlushMountedPresenceSensorModel.codeOccurDistReduce,
|
||||||
value: value,
|
value: value,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PresenceUpdateData(
|
PresenceUpdateData(
|
||||||
value: (model.sensiReduce.toDouble()),
|
value: (model.presenceDelay / 10).toDouble(),
|
||||||
title: 'Target Confirm Time:',
|
title: 'Target Confirm Time:',
|
||||||
description: 's',
|
description: 's',
|
||||||
minValue: 0,
|
minValue: 0.0,
|
||||||
maxValue: 3,
|
maxValue: 0.5,
|
||||||
steps: 1,
|
steps: 0.1,
|
||||||
action: (int value) => context.read<FlushMountedPresenceSensorBloc>().add(
|
valuesPercision: 1,
|
||||||
FlushMountedPresenceSensorChangeValueEvent(
|
action: (double value) =>
|
||||||
code: FlushMountedPresenceSensorModel.codeSensiReduce,
|
context.read<FlushMountedPresenceSensorBloc>().add(
|
||||||
value: value,
|
FlushMountedPresenceSensorBatchControlEvent(
|
||||||
),
|
deviceIds: devicesIds,
|
||||||
),
|
code: FlushMountedPresenceSensorModel.codePresenceDelay,
|
||||||
|
value: (value * 10).toInt(),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
PresenceUpdateData(
|
PresenceUpdateData(
|
||||||
value: ((model.noneDelay / 10).toDouble()),
|
value: ((model.noneDelay / 10).toDouble()),
|
||||||
@@ -154,7 +162,8 @@ class FlushMountedPresenceSensorBatchControlView extends StatelessWidget
|
|||||||
steps: 1,
|
steps: 1,
|
||||||
action: (double value) =>
|
action: (double value) =>
|
||||||
context.read<FlushMountedPresenceSensorBloc>().add(
|
context.read<FlushMountedPresenceSensorBloc>().add(
|
||||||
FlushMountedPresenceSensorChangeValueEvent(
|
FlushMountedPresenceSensorBatchControlEvent(
|
||||||
|
deviceIds: devicesIds,
|
||||||
code: FlushMountedPresenceSensorModel.codeNoneDelay,
|
code: FlushMountedPresenceSensorModel.codeNoneDelay,
|
||||||
value: (value * 10).round(),
|
value: (value * 10).round(),
|
||||||
),
|
),
|
||||||
|
|||||||
+20
-18
@@ -15,7 +15,7 @@ import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_la
|
|||||||
|
|
||||||
class FlushMountedPresenceSensorControlView extends StatelessWidget
|
class FlushMountedPresenceSensorControlView extends StatelessWidget
|
||||||
with HelperResponsiveLayout {
|
with HelperResponsiveLayout {
|
||||||
const FlushMountedPresenceSensorControlView({super.key, required this.device});
|
const FlushMountedPresenceSensorControlView({required this.device, super.key});
|
||||||
|
|
||||||
final AllDevicesModel device;
|
final AllDevicesModel device;
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ class FlushMountedPresenceSensorControlView extends StatelessWidget
|
|||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => FlushMountedPresenceSensorBlocFactory.create(
|
create: (context) => FlushMountedPresenceSensorBlocFactory.create(
|
||||||
deviceId: device.uuid ?? '-1',
|
deviceId: device.uuid ?? '-1',
|
||||||
),
|
)..add(FlushMountedPresenceSensorFetchStatusEvent()),
|
||||||
child: BlocBuilder<FlushMountedPresenceSensorBloc,
|
child: BlocBuilder<FlushMountedPresenceSensorBloc,
|
||||||
FlushMountedPresenceSensorState>(
|
FlushMountedPresenceSensorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
@@ -113,7 +113,7 @@ class FlushMountedPresenceSensorControlView extends StatelessWidget
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
PresenceUpdateData(
|
PresenceUpdateData(
|
||||||
value: (model.nearDetection / 100).toDouble(),
|
value: (model.nearDetection / 100).clamp(0.0, double.infinity),
|
||||||
title: 'Nearest Detect Dist:',
|
title: 'Nearest Detect Dist:',
|
||||||
description: 'm',
|
description: 'm',
|
||||||
minValue: 0.0,
|
minValue: 0.0,
|
||||||
@@ -129,7 +129,7 @@ class FlushMountedPresenceSensorControlView extends StatelessWidget
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
PresenceUpdateData(
|
PresenceUpdateData(
|
||||||
value: (model.farDetection / 100).toDouble(),
|
value: (model.farDetection / 100).clamp(0.0, double.infinity),
|
||||||
title: 'Max Detect Dist:',
|
title: 'Max Detect Dist:',
|
||||||
description: 'm',
|
description: 'm',
|
||||||
minValue: 0.0,
|
minValue: 0.0,
|
||||||
@@ -145,20 +145,20 @@ class FlushMountedPresenceSensorControlView extends StatelessWidget
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
PresenceUpdateData(
|
PresenceUpdateData(
|
||||||
value: (model.presenceDelay.toDouble()),
|
value: model.sensiReduce.toDouble(),
|
||||||
title: 'Trigger Level:',
|
title: 'Trigger Level:',
|
||||||
minValue: 0,
|
minValue: 0,
|
||||||
maxValue: 3,
|
maxValue: 3,
|
||||||
steps: 1,
|
steps: 1,
|
||||||
action: (int value) => context.read<FlushMountedPresenceSensorBloc>().add(
|
action: (int value) => context.read<FlushMountedPresenceSensorBloc>().add(
|
||||||
FlushMountedPresenceSensorChangeValueEvent(
|
FlushMountedPresenceSensorChangeValueEvent(
|
||||||
code: FlushMountedPresenceSensorModel.codePresenceDelay,
|
code: FlushMountedPresenceSensorModel.codeSensiReduce,
|
||||||
value: value,
|
value: value,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PresenceUpdateData(
|
PresenceUpdateData(
|
||||||
value: (model.occurDistReduce.toDouble()),
|
value: model.occurDistReduce.toDouble(),
|
||||||
title: 'Indent Level:',
|
title: 'Indent Level:',
|
||||||
minValue: 0,
|
minValue: 0,
|
||||||
maxValue: 3,
|
maxValue: 3,
|
||||||
@@ -171,21 +171,23 @@ class FlushMountedPresenceSensorControlView extends StatelessWidget
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
PresenceUpdateData(
|
PresenceUpdateData(
|
||||||
value: (model.sensiReduce.toDouble()),
|
value: (model.presenceDelay / 10).toDouble(),
|
||||||
|
valuesPercision: 1,
|
||||||
title: 'Target Confirm Time:',
|
title: 'Target Confirm Time:',
|
||||||
description: 's',
|
description: 's',
|
||||||
minValue: 0,
|
minValue: 0.0,
|
||||||
maxValue: 3,
|
maxValue: 0.5,
|
||||||
steps: 1,
|
steps: 0.1,
|
||||||
action: (int value) => context.read<FlushMountedPresenceSensorBloc>().add(
|
action: (double value) =>
|
||||||
FlushMountedPresenceSensorChangeValueEvent(
|
context.read<FlushMountedPresenceSensorBloc>().add(
|
||||||
code: FlushMountedPresenceSensorModel.codeSensiReduce,
|
FlushMountedPresenceSensorChangeValueEvent(
|
||||||
value: value,
|
code: FlushMountedPresenceSensorModel.codePresenceDelay,
|
||||||
),
|
value: (value * 10).toInt(),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
PresenceUpdateData(
|
PresenceUpdateData(
|
||||||
value: ((model.noneDelay / 10).toDouble()),
|
value: (model.noneDelay / 10).toDouble(),
|
||||||
description: 's',
|
description: 's',
|
||||||
title: 'Disappe Delay:',
|
title: 'Disappe Delay:',
|
||||||
minValue: 20,
|
minValue: 20,
|
||||||
|
|||||||
@@ -84,6 +84,16 @@ class _PresenceUpdateDataState extends State<PresenceNoBodyTime> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(PresenceNoBodyTime oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (oldWidget.value != widget.value) {
|
||||||
|
setState(() {
|
||||||
|
_currentValue = widget.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DeviceControlsContainer(
|
return DeviceControlsContainer(
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
on<ShowDescriptionEvent>(_showDescription);
|
on<ShowDescriptionEvent>(_showDescription);
|
||||||
on<BackToGridViewEvent>(_backToGridView);
|
on<BackToGridViewEvent>(_backToGridView);
|
||||||
on<WallSensorFactoryResetEvent>(_onFactoryReset);
|
on<WallSensorFactoryResetEvent>(_onFactoryReset);
|
||||||
|
on<WallSensorRealtimeUpdateEvent>(_onRealtimeUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _fetchWallSensorStatus(
|
void _fetchWallSensorStatus(
|
||||||
@@ -30,7 +31,7 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
var response = await DevicesManagementApi().getDeviceStatus(deviceId);
|
var response = await DevicesManagementApi().getDeviceStatus(deviceId);
|
||||||
deviceStatus = WallSensorModel.fromJson(response.status);
|
deviceStatus = WallSensorModel.fromJson(response.status);
|
||||||
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
||||||
_listenToChanges(emit, deviceId);
|
_listenToChanges(deviceId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(WallSensorFailedState(error: e.toString()));
|
emit(WallSensorFailedState(error: e.toString()));
|
||||||
return;
|
return;
|
||||||
@@ -52,28 +53,27 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_listenToChanges(Emitter<WallSensorState> emit, deviceId) {
|
void _listenToChanges(String deviceId) {
|
||||||
try {
|
DatabaseReference ref =
|
||||||
DatabaseReference ref =
|
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
FirebaseDatabase.instance.ref('device-status/$deviceId');
|
ref.onValue.listen((DatabaseEvent event) {
|
||||||
Stream<DatabaseEvent> stream = ref.onValue;
|
final data = event.snapshot.value as Map<dynamic, dynamic>?;
|
||||||
|
if (data == null) return;
|
||||||
|
|
||||||
stream.listen((DatabaseEvent event) {
|
final statusList = (data['status'] as List?)
|
||||||
Map<dynamic, dynamic> usersMap =
|
?.map((e) => Status(code: e['code'], value: e['value']))
|
||||||
event.snapshot.value as Map<dynamic, dynamic>;
|
.toList();
|
||||||
List<Status> statusList = [];
|
|
||||||
|
|
||||||
usersMap['status'].forEach((element) {
|
if (statusList != null) {
|
||||||
statusList
|
final updatedDeviceStatus = WallSensorModel.fromJson(statusList);
|
||||||
.add(Status(code: element['code'], value: element['value']));
|
if (!isClosed) {
|
||||||
});
|
add(WallSensorRealtimeUpdateEvent(updatedDeviceStatus));
|
||||||
|
}
|
||||||
deviceStatus = WallSensorModel.fromJson(statusList);
|
}
|
||||||
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
});
|
||||||
});
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _changeValue(
|
void _changeValue(
|
||||||
WallSensorChangeValueEvent event, Emitter<WallSensorState> emit) async {
|
WallSensorChangeValueEvent event, Emitter<WallSensorState> emit) async {
|
||||||
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
emit(WallSensorLoadingNewSate(wallSensorModel: deviceStatus));
|
||||||
@@ -195,4 +195,12 @@ class WallSensorBloc extends Bloc<WallSensorEvent, WallSensorState> {
|
|||||||
emit(WallSensorFailedState(error: e.toString()));
|
emit(WallSensorFailedState(error: e.toString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onRealtimeUpdate(
|
||||||
|
WallSensorRealtimeUpdateEvent event,
|
||||||
|
Emitter<WallSensorState> emit,
|
||||||
|
) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(WallSensorUpdateState(wallSensorModel: deviceStatus));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.dart';
|
||||||
|
|
||||||
abstract class WallSensorEvent extends Equatable {
|
abstract class WallSensorEvent extends Equatable {
|
||||||
const WallSensorEvent();
|
const WallSensorEvent();
|
||||||
@@ -70,3 +71,8 @@ class WallSensorFactoryResetEvent extends WallSensorEvent {
|
|||||||
required this.factoryReset,
|
required this.factoryReset,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class WallSensorRealtimeUpdateEvent extends WallSensorEvent {
|
||||||
|
final WallSensorModel deviceStatus;
|
||||||
|
const WallSensorRealtimeUpdateEvent(this.deviceStatus);
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import 'package:syncrow_web/pages/routines/models/ac/ac_operational_value.dart';
|
|||||||
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
@@ -74,11 +75,26 @@ class ACHelper {
|
|||||||
child: _buildFunctionsList(
|
child: _buildFunctionsList(
|
||||||
context: context,
|
context: context,
|
||||||
acFunctions: acFunctions,
|
acFunctions: acFunctions,
|
||||||
onFunctionSelected: (functionCode, operationName) =>
|
device: device,
|
||||||
context.read<FunctionBloc>().add(SelectFunction(
|
onFunctionSelected: (functionCode, operationName) {
|
||||||
functionCode: functionCode,
|
RoutineTapFunctionHelper.onTapFunction(
|
||||||
operationName: operationName,
|
context,
|
||||||
)),
|
functionCode: functionCode,
|
||||||
|
functionOperationName: operationName,
|
||||||
|
functionValueDescription:
|
||||||
|
selectedFunctionData.valueDescription,
|
||||||
|
deviceUuid: device?.uuid,
|
||||||
|
codesToAddIntoFunctionsWithDefaultValue: [
|
||||||
|
'temp_set',
|
||||||
|
'temp_current',
|
||||||
|
],
|
||||||
|
defaultValue: functionCode == 'temp_set'
|
||||||
|
? 200
|
||||||
|
: functionCode == 'temp_current'
|
||||||
|
? -100
|
||||||
|
: 0,
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Value selector
|
// Value selector
|
||||||
@@ -137,6 +153,7 @@ class ACHelper {
|
|||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required List<ACFunction> acFunctions,
|
required List<ACFunction> acFunctions,
|
||||||
required Function(String, String) onFunctionSelected,
|
required Function(String, String) onFunctionSelected,
|
||||||
|
required AllDevicesModel? device,
|
||||||
}) {
|
}) {
|
||||||
return ListView.separated(
|
return ListView.separated(
|
||||||
shrinkWrap: false,
|
shrinkWrap: false,
|
||||||
|
|||||||
+6
-1
@@ -131,7 +131,12 @@ class _CeilingSensorDialogState extends State<CeilingSensorDialog> {
|
|||||||
return Row(
|
return Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
CpsFunctionsList(cpsFunctions: _cpsFunctions),
|
CpsFunctionsList(
|
||||||
|
cpsFunctions: _cpsFunctions,
|
||||||
|
device: widget.device,
|
||||||
|
selectedFunctionData: selectedFunctionData,
|
||||||
|
dialogType: widget.dialogType,
|
||||||
|
),
|
||||||
if (state.selectedFunction != null)
|
if (state.selectedFunction != null)
|
||||||
Expanded(
|
Expanded(
|
||||||
child: isToggleFunction
|
child: isToggleFunction
|
||||||
|
|||||||
@@ -1,14 +1,24 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/routines/models/ceiling_presence_sensor_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/ceiling_presence_sensor_functions.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialog_function_list_tile.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialog_function_list_tile.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class CpsFunctionsList extends StatelessWidget {
|
class CpsFunctionsList extends StatelessWidget {
|
||||||
const CpsFunctionsList({required this.cpsFunctions, super.key});
|
const CpsFunctionsList({
|
||||||
|
required this.cpsFunctions,
|
||||||
|
required this.device,
|
||||||
|
required this.selectedFunctionData,
|
||||||
|
required this.dialogType,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
final List<CpsFunctions> cpsFunctions;
|
final List<CpsFunctions> cpsFunctions;
|
||||||
|
final AllDevicesModel? device;
|
||||||
|
final DeviceFunctionData? selectedFunctionData;
|
||||||
|
final String dialogType;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -26,12 +36,27 @@ class CpsFunctionsList extends StatelessWidget {
|
|||||||
return RoutineDialogFunctionListTile(
|
return RoutineDialogFunctionListTile(
|
||||||
iconPath: function.icon,
|
iconPath: function.icon,
|
||||||
operationName: function.operationName,
|
operationName: function.operationName,
|
||||||
onTap: () => context.read<FunctionBloc>().add(
|
onTap: () => RoutineTapFunctionHelper.onTapFunction(
|
||||||
SelectFunction(
|
context,
|
||||||
functionCode: function.code,
|
functionCode: function.code,
|
||||||
operationName: function.operationName,
|
functionOperationName: function.operationName,
|
||||||
),
|
functionValueDescription: selectedFunctionData?.valueDescription,
|
||||||
),
|
deviceUuid: device?.uuid,
|
||||||
|
codesToAddIntoFunctionsWithDefaultValue: [
|
||||||
|
'static_max_dis',
|
||||||
|
'presence_reference',
|
||||||
|
'moving_reference',
|
||||||
|
'perceptual_boundary',
|
||||||
|
'moving_boundary',
|
||||||
|
'moving_rigger_time',
|
||||||
|
'moving_static_time',
|
||||||
|
'none_body_time',
|
||||||
|
'moving_max_dis',
|
||||||
|
'moving_range',
|
||||||
|
'presence_range',
|
||||||
|
if (dialogType == "IF") 'sensitivity',
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
||||||
|
|
||||||
|
abstract final class RoutineTapFunctionHelper {
|
||||||
|
const RoutineTapFunctionHelper._();
|
||||||
|
|
||||||
|
static void onTapFunction(
|
||||||
|
BuildContext context, {
|
||||||
|
required String functionCode,
|
||||||
|
required String functionOperationName,
|
||||||
|
required String? functionValueDescription,
|
||||||
|
required String? deviceUuid,
|
||||||
|
required List<String> codesToAddIntoFunctionsWithDefaultValue,
|
||||||
|
int defaultValue = 0,
|
||||||
|
}) {
|
||||||
|
final functionsBloc = context.read<FunctionBloc>();
|
||||||
|
functionsBloc.add(
|
||||||
|
SelectFunction(
|
||||||
|
functionCode: functionCode,
|
||||||
|
operationName: functionOperationName,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final addedFunctions = functionsBloc.state.addedFunctions;
|
||||||
|
final isFunctionAlreadyAdded = addedFunctions.any(
|
||||||
|
(e) => e.functionCode == functionCode,
|
||||||
|
);
|
||||||
|
final shouldAddFunction =
|
||||||
|
codesToAddIntoFunctionsWithDefaultValue.contains(functionCode);
|
||||||
|
if (!isFunctionAlreadyAdded && shouldAddFunction) {
|
||||||
|
context.read<FunctionBloc>().add(
|
||||||
|
AddFunction(
|
||||||
|
functionData: DeviceFunctionData(
|
||||||
|
entityId: deviceUuid ?? '',
|
||||||
|
functionCode: functionCode,
|
||||||
|
operationName: functionOperationName,
|
||||||
|
value: defaultValue,
|
||||||
|
condition: '==',
|
||||||
|
valueDescription: functionValueDescription,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import 'package:syncrow_web/pages/routines/models/gang_switches/one_gang_switch/
|
|||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
@@ -24,21 +25,23 @@ class OneGangSwitchHelper {
|
|||||||
required String uniqueCustomId,
|
required String uniqueCustomId,
|
||||||
required bool removeComparetors,
|
required bool removeComparetors,
|
||||||
}) async {
|
}) async {
|
||||||
List<BaseSwitchFunction> oneGangFunctions = functions.whereType<BaseSwitchFunction>().toList();
|
List<BaseSwitchFunction> oneGangFunctions =
|
||||||
|
functions.whereType<BaseSwitchFunction>().toList();
|
||||||
|
|
||||||
return showDialog<Map<String, dynamic>?>(
|
return showDialog<Map<String, dynamic>?>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
create: (_) => FunctionBloc()
|
||||||
|
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
|
||||||
child: AlertDialog(
|
child: AlertDialog(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final selectedFunction = state.selectedFunction;
|
final selectedFunction = state.selectedFunction;
|
||||||
final selectedOperationName = state.selectedOperationName;
|
final selectedOperationName = state.selectedOperationName;
|
||||||
final selectedFunctionData =
|
final selectedFunctionData = state.addedFunctions
|
||||||
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
|
.firstWhere((f) => f.functionCode == selectedFunction,
|
||||||
orElse: () => DeviceFunctionData(
|
orElse: () => DeviceFunctionData(
|
||||||
entityId: '',
|
entityId: '',
|
||||||
functionCode: selectedFunction ?? '',
|
functionCode: selectedFunction ?? '',
|
||||||
@@ -84,12 +87,19 @@ class OneGangSwitchHelper {
|
|||||||
size: 16,
|
size: 16,
|
||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () =>
|
||||||
context.read<FunctionBloc>().add(SelectFunction(
|
RoutineTapFunctionHelper.onTapFunction(
|
||||||
functionCode: function.code,
|
context,
|
||||||
operationName: function.operationName,
|
functionCode: function.code,
|
||||||
));
|
functionOperationName:
|
||||||
},
|
function.operationName,
|
||||||
|
functionValueDescription:
|
||||||
|
selectedFunctionData.valueDescription,
|
||||||
|
deviceUuid: device?.uuid,
|
||||||
|
codesToAddIntoFunctionsWithDefaultValue: [
|
||||||
|
'countdown_1',
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -220,11 +230,11 @@ class OneGangSwitchHelper {
|
|||||||
selectedFunctionData,
|
selectedFunctionData,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownDisplay(
|
_buildCountDownDisplay(context, initialValue, device, operationName,
|
||||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
selectedFunctionData, selectCode),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
_buildCountDownSlider(
|
_buildCountDownSlider(context, initialValue, device, operationName,
|
||||||
context, initialValue, device, operationName, selectedFunctionData, selectCode),
|
selectedFunctionData, selectCode),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -314,9 +324,10 @@ class OneGangSwitchHelper {
|
|||||||
value: (initialValue ?? 0).toDouble(),
|
value: (initialValue ?? 0).toDouble(),
|
||||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||||
divisions: (((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
divisions:
|
||||||
(operationalValues.stepValue ?? 1))
|
(((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
||||||
.round(),
|
(operationalValues.stepValue ?? 1))
|
||||||
|
.round(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
context.read<FunctionBloc>().add(
|
context.read<FunctionBloc>().add(
|
||||||
AddFunction(
|
AddFunction(
|
||||||
@@ -368,7 +379,9 @@ class OneGangSwitchHelper {
|
|||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
|
color: isSelected
|
||||||
|
? ColorsManager.primaryColorWithOpacity
|
||||||
|
: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (!isSelected) {
|
if (!isSelected) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_func
|
|||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
@@ -85,15 +86,21 @@ class ThreeGangSwitchHelper {
|
|||||||
size: 16,
|
size: 16,
|
||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () =>
|
||||||
context
|
RoutineTapFunctionHelper.onTapFunction(
|
||||||
.read<FunctionBloc>()
|
context,
|
||||||
.add(SelectFunction(
|
functionCode: function.code,
|
||||||
functionCode: function.code,
|
functionOperationName:
|
||||||
operationName:
|
function.operationName,
|
||||||
function.operationName,
|
functionValueDescription:
|
||||||
));
|
selectedFunctionData.valueDescription,
|
||||||
},
|
deviceUuid: device?.uuid,
|
||||||
|
codesToAddIntoFunctionsWithDefaultValue: [
|
||||||
|
'countdown_1',
|
||||||
|
'countdown_2',
|
||||||
|
'countdown_3',
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -183,8 +190,7 @@ class ThreeGangSwitchHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedFn =
|
final selectedFn = switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
|
||||||
final values = selectedFn.getOperationalValues();
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
return _buildOperationalValuesList(
|
return _buildOperationalValuesList(
|
||||||
@@ -266,8 +272,7 @@ class ThreeGangSwitchHelper {
|
|||||||
minHeight: 40.0,
|
minHeight: 40.0,
|
||||||
minWidth: 40.0,
|
minWidth: 40.0,
|
||||||
),
|
),
|
||||||
isSelected:
|
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||||
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
children: conditions.map((c) => Text(c)).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -316,10 +321,10 @@ class ThreeGangSwitchHelper {
|
|||||||
value: (initialValue ?? 0).toDouble(),
|
value: (initialValue ?? 0).toDouble(),
|
||||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||||
divisions: (((operationalValues.maxValue ?? 0) -
|
divisions:
|
||||||
(operationalValues.minValue ?? 0)) /
|
(((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
||||||
(operationalValues.stepValue ?? 1))
|
(operationalValues.stepValue ?? 1))
|
||||||
.round(),
|
.round(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
context.read<FunctionBloc>().add(
|
context.read<FunctionBloc>().add(
|
||||||
AddFunction(
|
AddFunction(
|
||||||
@@ -369,9 +374,7 @@ class ThreeGangSwitchHelper {
|
|||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected
|
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
||||||
? Icons.radio_button_checked
|
|
||||||
: Icons.radio_button_unchecked,
|
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected
|
color: isSelected
|
||||||
? ColorsManager.primaryColorWithOpacity
|
? ColorsManager.primaryColorWithOpacity
|
||||||
@@ -387,8 +390,7 @@ class ThreeGangSwitchHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value.value,
|
value: value.value,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription:
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
selectedFunctionData?.valueDescription,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_func
|
|||||||
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operational_value.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
@@ -85,15 +86,20 @@ class TwoGangSwitchHelper {
|
|||||||
size: 16,
|
size: 16,
|
||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () =>
|
||||||
context
|
RoutineTapFunctionHelper.onTapFunction(
|
||||||
.read<FunctionBloc>()
|
context,
|
||||||
.add(SelectFunction(
|
functionCode: function.code,
|
||||||
functionCode: function.code,
|
functionOperationName:
|
||||||
operationName:
|
function.operationName,
|
||||||
function.operationName,
|
functionValueDescription:
|
||||||
));
|
selectedFunctionData.valueDescription,
|
||||||
},
|
deviceUuid: device?.uuid,
|
||||||
|
codesToAddIntoFunctionsWithDefaultValue: [
|
||||||
|
'countdown_1',
|
||||||
|
'countdown_2',
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -167,8 +173,7 @@ class TwoGangSwitchHelper {
|
|||||||
required String operationName,
|
required String operationName,
|
||||||
required bool removeComparetors,
|
required bool removeComparetors,
|
||||||
}) {
|
}) {
|
||||||
if (selectedFunction == 'countdown_1' ||
|
if (selectedFunction == 'countdown_1' || selectedFunction == 'countdown_2') {
|
||||||
selectedFunction == 'countdown_2') {
|
|
||||||
final initialValue = selectedFunctionData?.value ?? 0;
|
final initialValue = selectedFunctionData?.value ?? 0;
|
||||||
return _buildTemperatureSelector(
|
return _buildTemperatureSelector(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -182,8 +187,7 @@ class TwoGangSwitchHelper {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final selectedFn =
|
final selectedFn = switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
||||||
switchFunctions.firstWhere((f) => f.code == selectedFunction);
|
|
||||||
final values = selectedFn.getOperationalValues();
|
final values = selectedFn.getOperationalValues();
|
||||||
|
|
||||||
return _buildOperationalValuesList(
|
return _buildOperationalValuesList(
|
||||||
@@ -265,8 +269,7 @@ class TwoGangSwitchHelper {
|
|||||||
minHeight: 40.0,
|
minHeight: 40.0,
|
||||||
minWidth: 40.0,
|
minWidth: 40.0,
|
||||||
),
|
),
|
||||||
isSelected:
|
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
||||||
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
|
|
||||||
children: conditions.map((c) => Text(c)).toList(),
|
children: conditions.map((c) => Text(c)).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -315,10 +318,10 @@ class TwoGangSwitchHelper {
|
|||||||
value: (initialValue ?? 0).toDouble(),
|
value: (initialValue ?? 0).toDouble(),
|
||||||
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
min: operationalValues.minValue?.toDouble() ?? 0.0,
|
||||||
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
max: operationalValues.maxValue?.toDouble() ?? 0.0,
|
||||||
divisions: (((operationalValues.maxValue ?? 0) -
|
divisions:
|
||||||
(operationalValues.minValue ?? 0)) /
|
(((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
|
||||||
(operationalValues.stepValue ?? 1))
|
(operationalValues.stepValue ?? 1))
|
||||||
.round(),
|
.round(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
context.read<FunctionBloc>().add(
|
context.read<FunctionBloc>().add(
|
||||||
AddFunction(
|
AddFunction(
|
||||||
@@ -368,9 +371,7 @@ class TwoGangSwitchHelper {
|
|||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
),
|
),
|
||||||
trailing: Icon(
|
trailing: Icon(
|
||||||
isSelected
|
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
|
||||||
? Icons.radio_button_checked
|
|
||||||
: Icons.radio_button_unchecked,
|
|
||||||
size: 24,
|
size: 24,
|
||||||
color: isSelected
|
color: isSelected
|
||||||
? ColorsManager.primaryColorWithOpacity
|
? ColorsManager.primaryColorWithOpacity
|
||||||
@@ -386,8 +387,7 @@ class TwoGangSwitchHelper {
|
|||||||
operationName: operationName,
|
operationName: operationName,
|
||||||
value: value.value,
|
value: value.value,
|
||||||
condition: selectedFunctionData?.condition,
|
condition: selectedFunctionData?.condition,
|
||||||
valueDescription:
|
valueDescription: selectedFunctionData?.valueDescription,
|
||||||
selectedFunctionData?.valueDescription,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import 'package:syncrow_web/pages/routines/models/device_functions.dart';
|
|||||||
import 'package:syncrow_web/pages/routines/models/wps/wps_functions.dart';
|
import 'package:syncrow_web/pages/routines/models/wps/wps_functions.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_footer.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
import 'package:syncrow_web/pages/routines/widgets/dialog_header.dart';
|
||||||
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/helpers/routine_tap_function_helper.dart';
|
||||||
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/wall_sensor/wps_value_selector_widget.dart';
|
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/wall_sensor/wps_value_selector_widget.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
@@ -111,13 +112,23 @@ class _WallPresenceSensorState extends State<WallPresenceSensor> {
|
|||||||
return Row(
|
return Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
_buildFunctionList(context),
|
_buildFunctionList(context, state),
|
||||||
if (state.selectedFunction != null) _buildValueSelector(context, state),
|
if (state.selectedFunction != null) _buildValueSelector(context, state),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildFunctionList(BuildContext context) {
|
Widget _buildFunctionList(BuildContext context, FunctionBlocState state) {
|
||||||
|
final selectedFunction = state.selectedFunction;
|
||||||
|
final selectedFunctionData = state.addedFunctions.firstWhere(
|
||||||
|
(f) => f.functionCode == selectedFunction,
|
||||||
|
orElse: () => DeviceFunctionData(
|
||||||
|
entityId: '',
|
||||||
|
functionCode: selectedFunction ?? '',
|
||||||
|
operationName: '',
|
||||||
|
value: null,
|
||||||
|
),
|
||||||
|
);
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 360,
|
width: 360,
|
||||||
child: ListView.separated(
|
child: ListView.separated(
|
||||||
@@ -149,12 +160,18 @@ class _WallPresenceSensorState extends State<WallPresenceSensor> {
|
|||||||
size: 16,
|
size: 16,
|
||||||
color: ColorsManager.textGray,
|
color: ColorsManager.textGray,
|
||||||
),
|
),
|
||||||
onTap: () => context.read<FunctionBloc>().add(
|
onTap: () => RoutineTapFunctionHelper.onTapFunction(
|
||||||
SelectFunction(
|
context,
|
||||||
functionCode: function.code,
|
functionCode: function.code,
|
||||||
operationName: function.operationName,
|
functionOperationName: function.operationName,
|
||||||
),
|
functionValueDescription: selectedFunctionData.valueDescription,
|
||||||
),
|
deviceUuid: widget.device?.uuid,
|
||||||
|
codesToAddIntoFunctionsWithDefaultValue: [
|
||||||
|
'dis_current',
|
||||||
|
'presence_time',
|
||||||
|
'illuminance_value',
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:syncrow_web/common/widgets/empty_search_result_widget.dart';
|
import 'package:syncrow_web/common/widgets/empty_search_result_widget.dart';
|
||||||
import 'package:syncrow_web/common/widgets/search_bar.dart';
|
import 'package:syncrow_web/common/widgets/search_bar.dart';
|
||||||
import 'package:syncrow_web/common/widgets/sidebar_communities_list.dart';
|
import 'package:syncrow_web/common/widgets/sidebar_communities_list.dart';
|
||||||
|
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
|
||||||
@@ -15,6 +16,8 @@ import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/cent
|
|||||||
import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_event.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
|
import '../../../space_tree/bloc/space_tree_event.dart';
|
||||||
|
|
||||||
class SidebarWidget extends StatefulWidget {
|
class SidebarWidget extends StatefulWidget {
|
||||||
final List<CommunityModel> communities;
|
final List<CommunityModel> communities;
|
||||||
final String? selectedSpaceUuid;
|
final String? selectedSpaceUuid;
|
||||||
@@ -40,13 +43,31 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_selectedId = widget.selectedSpaceUuid;
|
|
||||||
_scrollController = ScrollController();
|
_scrollController = ScrollController();
|
||||||
|
_scrollController.addListener(_onScroll);
|
||||||
|
_selectedId = widget.selectedSpaceUuid;
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onScroll() {
|
||||||
|
if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 100) {
|
||||||
|
// Trigger pagination event
|
||||||
|
final bloc = context.read<SpaceTreeBloc>();
|
||||||
|
if (!bloc.state.paginationIsLoading && bloc.state.paginationModel?.hasNext == true) {
|
||||||
|
bloc.add(
|
||||||
|
PaginationEvent(
|
||||||
|
bloc.state.paginationModel!,
|
||||||
|
bloc.state.communityList,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
_scrollController.removeListener(_onScroll);
|
||||||
|
|
||||||
_scrollController.dispose();
|
_scrollController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
@@ -59,38 +80,6 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
|||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<CommunityModel> _filteredCommunities() {
|
|
||||||
if (_searchQuery.isEmpty) {
|
|
||||||
_selectedSpaceUuid = null;
|
|
||||||
return widget.communities;
|
|
||||||
}
|
|
||||||
|
|
||||||
return widget.communities.where((community) {
|
|
||||||
final containsQueryInCommunity =
|
|
||||||
community.name.toLowerCase().contains(_searchQuery.toLowerCase());
|
|
||||||
final containsQueryInSpaces = community.spaces.any((space) =>
|
|
||||||
_containsQuery(space: space, query: _searchQuery.toLowerCase()));
|
|
||||||
|
|
||||||
return containsQueryInCommunity || containsQueryInSpaces;
|
|
||||||
}).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _containsQuery({
|
|
||||||
required SpaceModel space,
|
|
||||||
required String query,
|
|
||||||
}) {
|
|
||||||
final matchesSpace = space.name.toLowerCase().contains(query);
|
|
||||||
final matchesChildren = space.children.any(
|
|
||||||
(child) => _containsQuery(space: child, query: query),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (matchesSpace || matchesChildren) {
|
|
||||||
_selectedSpaceUuid = space.uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
return matchesSpace || matchesChildren;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _isSpaceOrChildSelected(SpaceModel space) {
|
bool _isSpaceOrChildSelected(SpaceModel space) {
|
||||||
final isSpaceSelected = _selectedSpaceUuid == space.uuid;
|
final isSpaceSelected = _selectedSpaceUuid == space.uuid;
|
||||||
final anySubSpaceIsSelected = space.children.any(_isSpaceOrChildSelected);
|
final anySubSpaceIsSelected = space.children.any(_isSpaceOrChildSelected);
|
||||||
@@ -101,7 +90,10 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final filteredCommunities = _filteredCommunities();
|
final spaceTreeState = context.watch<SpaceTreeBloc>().state;
|
||||||
|
final filteredCommunities = spaceTreeState.isSearching
|
||||||
|
? spaceTreeState.filteredCommunity
|
||||||
|
: spaceTreeState.communityList;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
width: _width,
|
width: _width,
|
||||||
@@ -112,7 +104,13 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
|||||||
children: [
|
children: [
|
||||||
SidebarHeader(onAddCommunity: _onAddCommunity),
|
SidebarHeader(onAddCommunity: _onAddCommunity),
|
||||||
CustomSearchBar(
|
CustomSearchBar(
|
||||||
onSearchChanged: (query) => setState(() => _searchQuery = query),
|
onSearchChanged: (query) {
|
||||||
|
setState(() {
|
||||||
|
_searchQuery = query;
|
||||||
|
});
|
||||||
|
|
||||||
|
context.read<SpaceTreeBloc>().add(SearchQueryEvent(query));
|
||||||
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -120,14 +118,18 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
|||||||
visible: filteredCommunities.isNotEmpty,
|
visible: filteredCommunities.isNotEmpty,
|
||||||
replacement: const EmptySearchResultWidget(),
|
replacement: const EmptySearchResultWidget(),
|
||||||
child: SidebarCommunitiesList(
|
child: SidebarCommunitiesList(
|
||||||
scrollController: _scrollController,
|
scrollController: _scrollController,
|
||||||
onScrollToEnd: () {},
|
onScrollToEnd: () {},
|
||||||
communities: filteredCommunities,
|
communities: filteredCommunities,
|
||||||
itemBuilder: (context, index) => _buildCommunityTile(
|
itemBuilder: (context, index) {
|
||||||
context,
|
if (index == filteredCommunities.length) {
|
||||||
filteredCommunities[index],
|
return const Padding(
|
||||||
),
|
padding: EdgeInsets.all(8.0),
|
||||||
),
|
child: Center(child: CircularProgressIndicator()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return _buildCommunityTile(context, filteredCommunities[index]);
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -205,9 +207,8 @@ class _SidebarWidgetState extends State<SidebarWidget> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onAddCommunity() => _selectedId?.isNotEmpty ?? true
|
void _onAddCommunity() =>
|
||||||
? _clearSelection()
|
_selectedId?.isNotEmpty ?? true ? _clearSelection() : _showCreateCommunityDialog();
|
||||||
: _showCreateCommunityDialog();
|
|
||||||
|
|
||||||
void _clearSelection() {
|
void _clearSelection() {
|
||||||
setState(() => _selectedId = '');
|
setState(() => _selectedId = '');
|
||||||
|
|||||||
@@ -46,14 +46,14 @@ final class DebouncedBatchControlDevicesService
|
|||||||
final BatchControlDevicesService decoratee;
|
final BatchControlDevicesService decoratee;
|
||||||
final Duration debounceDuration;
|
final Duration debounceDuration;
|
||||||
|
|
||||||
final _pendingRequests = <(List<String> uuids, String code, Object value)>[];
|
|
||||||
var _isProcessing = false;
|
|
||||||
|
|
||||||
DebouncedBatchControlDevicesService({
|
DebouncedBatchControlDevicesService({
|
||||||
required this.decoratee,
|
required this.decoratee,
|
||||||
this.debounceDuration = const Duration(milliseconds: 1500),
|
this.debounceDuration = const Duration(milliseconds: 1500),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final _pendingRequests = <(List<String> uuids, String code, Object value)>[];
|
||||||
|
var _isProcessing = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> batchControlDevices({
|
Future<bool> batchControlDevices({
|
||||||
required List<String> uuids,
|
required List<String> uuids,
|
||||||
@@ -68,16 +68,26 @@ final class DebouncedBatchControlDevicesService
|
|||||||
|
|
||||||
await Future.delayed(debounceDuration);
|
await Future.delayed(debounceDuration);
|
||||||
|
|
||||||
final lastRequest = _pendingRequests.last;
|
final groupedRequests =
|
||||||
|
<String, (List<String> uuids, String code, Object value)>{};
|
||||||
|
for (final request in _pendingRequests) {
|
||||||
|
final (_, requestCode, requestValue) = request;
|
||||||
|
groupedRequests[requestCode] = request;
|
||||||
|
}
|
||||||
_pendingRequests.clear();
|
_pendingRequests.clear();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final (lastRequestUuids, lastRequestCode, lastRequestValue) = lastRequest;
|
var allSuccessful = true;
|
||||||
return decoratee.batchControlDevices(
|
for (final request in groupedRequests.values) {
|
||||||
uuids: lastRequestUuids,
|
final (lastRequestUuids, lastRequestCode, lastRequestValue) = request;
|
||||||
code: lastRequestCode,
|
final success = await decoratee.batchControlDevices(
|
||||||
value: lastRequestValue,
|
uuids: lastRequestUuids,
|
||||||
);
|
code: lastRequestCode,
|
||||||
|
value: lastRequestValue,
|
||||||
|
);
|
||||||
|
if (!success) allSuccessful = false;
|
||||||
|
}
|
||||||
|
return allSuccessful;
|
||||||
} finally {
|
} finally {
|
||||||
_isProcessing = false;
|
_isProcessing = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,15 +59,24 @@ final class DebouncedControlDeviceService implements ControlDeviceService {
|
|||||||
|
|
||||||
await Future.delayed(debounceDuration);
|
await Future.delayed(debounceDuration);
|
||||||
|
|
||||||
final lastRequest = _pendingRequests.last;
|
final groupedRequests = <String, (String deviceUuid, Status status)>{};
|
||||||
|
for (final request in _pendingRequests) {
|
||||||
|
final (_, requestStatus) = request;
|
||||||
|
groupedRequests[requestStatus.code] = request;
|
||||||
|
}
|
||||||
_pendingRequests.clear();
|
_pendingRequests.clear();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final (lastRequestDeviceUuid, lastRequestStatus) = lastRequest;
|
var allSuccessful = true;
|
||||||
return decoratee.controlDevice(
|
for (final request in groupedRequests.values) {
|
||||||
deviceUuid: lastRequestDeviceUuid,
|
final (lastRequestDeviceUuid, lastRequestStatus) = request;
|
||||||
status: lastRequestStatus,
|
final success = await decoratee.controlDevice(
|
||||||
);
|
deviceUuid: lastRequestDeviceUuid,
|
||||||
|
status: lastRequestStatus,
|
||||||
|
);
|
||||||
|
if (!success) allSuccessful = false;
|
||||||
|
}
|
||||||
|
return allSuccessful;
|
||||||
} finally {
|
} finally {
|
||||||
_isProcessing = false;
|
_isProcessing = false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user