mirror of
https://github.com/SyncrowIOT/web.git
synced 2026-10-26 17:17:56 +00:00
Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34d4d892d9 | ||
|
|
3193fd26fe | ||
|
|
43802a9fad | ||
|
|
6e0b1775f0 | ||
|
|
233fb2ee2c | ||
|
|
b26928b3d5 | ||
|
|
6fc35a7b9a | ||
|
|
756457927c | ||
|
|
17a582ab99 | ||
|
|
09fb604acc | ||
|
|
2068df173d | ||
|
|
bfc2a381d2 | ||
|
|
c03b8f290c | ||
|
|
2c684a9495 |
+1
-2
@@ -24,11 +24,10 @@ 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
|
||||||
|
|||||||
+17
-15
@@ -75,7 +75,7 @@ class FlushMountedPresenceSensorBatchControlView 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,
|
||||||
@@ -92,7 +92,7 @@ class FlushMountedPresenceSensorBatchControlView 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,
|
||||||
@@ -109,7 +109,7 @@ class FlushMountedPresenceSensorBatchControlView 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,
|
||||||
@@ -117,7 +117,7 @@ class FlushMountedPresenceSensorBatchControlView extends StatelessWidget
|
|||||||
action: (int value) => context.read<FlushMountedPresenceSensorBloc>().add(
|
action: (int value) => context.read<FlushMountedPresenceSensorBloc>().add(
|
||||||
FlushMountedPresenceSensorBatchControlEvent(
|
FlushMountedPresenceSensorBatchControlEvent(
|
||||||
deviceIds: devicesIds,
|
deviceIds: devicesIds,
|
||||||
code: FlushMountedPresenceSensorModel.codePresenceDelay,
|
code: FlushMountedPresenceSensorModel.codeSensiReduce,
|
||||||
value: value,
|
value: value,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -137,19 +137,21 @@ class FlushMountedPresenceSensorBatchControlView extends StatelessWidget
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
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,
|
||||||
FlushMountedPresenceSensorBatchControlEvent(
|
action: (double value) =>
|
||||||
deviceIds: devicesIds,
|
context.read<FlushMountedPresenceSensorBloc>().add(
|
||||||
code: FlushMountedPresenceSensorModel.codeSensiReduce,
|
FlushMountedPresenceSensorBatchControlEvent(
|
||||||
value: value,
|
deviceIds: devicesIds,
|
||||||
),
|
code: FlushMountedPresenceSensorModel.codePresenceDelay,
|
||||||
),
|
value: (value * 10).toInt(),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
PresenceUpdateData(
|
PresenceUpdateData(
|
||||||
value: ((model.noneDelay / 10).toDouble()),
|
value: ((model.noneDelay / 10).toDouble()),
|
||||||
|
|||||||
+19
-17
@@ -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;
|
||||||
|
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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: 800),
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ final class DebouncedControlDeviceService implements ControlDeviceService {
|
|||||||
|
|
||||||
DebouncedControlDeviceService({
|
DebouncedControlDeviceService({
|
||||||
required this.decoratee,
|
required this.decoratee,
|
||||||
this.debounceDuration = const Duration(milliseconds: 800),
|
this.debounceDuration = const Duration(milliseconds: 1500),
|
||||||
});
|
});
|
||||||
|
|
||||||
final _pendingRequests = <(String deviceUuid, Status status)>[];
|
final _pendingRequests = <(String deviceUuid, Status status)>[];
|
||||||
@@ -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