mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2025-07-16 01:56:19 +00:00
Merge pull request #19 from SyncrowIOT/configure_wall_presence_sensors
Configure_wall_presence_sensors
This commit is contained in:
@ -1,7 +1,9 @@
|
||||
import 'package:syncrow_app/utils/resource_manager/constants.dart';
|
||||
|
||||
class FunctionModel {
|
||||
String? code;
|
||||
String? type;
|
||||
String? values;
|
||||
FunctionType? type;
|
||||
ValueModel? values;
|
||||
|
||||
FunctionModel({
|
||||
required this.code,
|
||||
@ -25,3 +27,41 @@ class FunctionModel {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//"values": "{\"unit\":\"\",\"min\":1,\"max\":10,\"scale\":0,\"step\":1}",
|
||||
|
||||
class ValueModel {
|
||||
String? unit;
|
||||
int? min;
|
||||
int? max;
|
||||
int? scale;
|
||||
int? step;
|
||||
|
||||
ValueModel({
|
||||
required this.unit,
|
||||
required this.min,
|
||||
required this.max,
|
||||
required this.scale,
|
||||
required this.step,
|
||||
});
|
||||
|
||||
factory ValueModel.fromJson(Map<String, dynamic> json) {
|
||||
return ValueModel(
|
||||
unit: json['unit'],
|
||||
min: json['min'],
|
||||
max: json['max'],
|
||||
scale: json['scale'],
|
||||
step: json['step'],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'unit': unit,
|
||||
'min': min,
|
||||
'max': max,
|
||||
'scale': scale,
|
||||
'step': step,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,349 +0,0 @@
|
||||
part of "wall_sensor_interface.dart";
|
||||
|
||||
class ParametersList extends StatelessWidget {
|
||||
const ParametersList({
|
||||
super.key,
|
||||
required this.wallSensor,
|
||||
});
|
||||
|
||||
final DeviceModel wallSensor;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Expanded(
|
||||
flex: 7,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: List.generate(
|
||||
wallSensorButtons.length,
|
||||
(index) {
|
||||
if (index == 3) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 12, horizontal: 15),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
showParameterDialog(
|
||||
context,
|
||||
'Motion Detection Sensitivity',
|
||||
wallSensor,
|
||||
5,
|
||||
0,
|
||||
10,
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const BodySmall(
|
||||
text: 'Motion\nDetectionn\nSensitivity',
|
||||
textAlign: TextAlign.center),
|
||||
BodyLarge(
|
||||
text: '5',
|
||||
style: context.bodyLarge
|
||||
.copyWith(fontWeight: FontsManager.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Container(
|
||||
width: 1,
|
||||
height: 45,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const BodySmall(
|
||||
text: 'Motionless\nDetection\nSensitivity',
|
||||
textAlign: TextAlign.center),
|
||||
BodyLarge(
|
||||
text: '5',
|
||||
style: context.bodyLarge.copyWith(
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Container(
|
||||
width: 1,
|
||||
height: 45,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
),
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const BodySmall(
|
||||
text: 'Far\nDetection',
|
||||
textAlign: TextAlign.center),
|
||||
BodyLarge(
|
||||
text: '600cm',
|
||||
style: context.bodyLarge.copyWith(
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
listItem(wallSensorButtons[index], context, wallSensor)
|
||||
],
|
||||
);
|
||||
}
|
||||
return listItem(wallSensorButtons[index], context, wallSensor);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final List<Map<String, Object?>> wallSensorButtons = const [
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsTime,
|
||||
'title': 'Presence Time',
|
||||
'value': 0,
|
||||
'unit': 'min',
|
||||
'page': null,
|
||||
},
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsDistance,
|
||||
'title': 'Current Distance',
|
||||
'value': 279,
|
||||
'unit': 'cm',
|
||||
'dialog': null,
|
||||
},
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsIlluminanceValue,
|
||||
'title': 'Illuminance Value',
|
||||
'value': 0,
|
||||
'unit': 'Lux',
|
||||
'page': null,
|
||||
},
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsEmpty,
|
||||
'title': 'Nobody Time',
|
||||
'value': 10,
|
||||
'unit': 'sec',
|
||||
'dialog': null,
|
||||
},
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsIndicator,
|
||||
'title': 'Indicator',
|
||||
'page': null,
|
||||
},
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsRecord,
|
||||
'title': 'Presence Record',
|
||||
'page': null,
|
||||
},
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsIlluminanceRecord,
|
||||
'title': 'Illuminance Record',
|
||||
'page': null,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
Widget listItem(
|
||||
Map<String, Object?> wallSensorButton,
|
||||
BuildContext context,
|
||||
DeviceModel wallSensor,
|
||||
) {
|
||||
return DefaultContainer(
|
||||
margin: const EdgeInsets.only(bottom: 5),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20),
|
||||
onTap: () {
|
||||
if (wallSensorButton['page'] != null) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => wallSensorButton['page'] as Widget,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
wallSensorButton['icon'] as String,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 25,
|
||||
),
|
||||
BodyMedium(text: wallSensorButton['title'] as String),
|
||||
if (wallSensorButton['value'] != null) const Spacer(),
|
||||
if (wallSensorButton['value'] != null)
|
||||
BodyMedium(
|
||||
text: '${wallSensorButton['value']}${wallSensorButton['unit']}',
|
||||
style: context.bodyMedium.copyWith(color: ColorsManager.greyColor),
|
||||
),
|
||||
if (wallSensorButton['value'] != null)
|
||||
if (wallSensorButton['title'] == 'Indicator')
|
||||
Expanded(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Transform.scale(
|
||||
scale: .8,
|
||||
child: CupertinoSwitch(
|
||||
value: false,
|
||||
onChanged: (value) {},
|
||||
applyTheme: true,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
// CustomSwitch(device: wallSensor),
|
||||
if (wallSensorButton['title'] == 'Nobody Time')
|
||||
const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 15,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
showParameterDialog(
|
||||
BuildContext context,
|
||||
String title,
|
||||
DeviceModel wallSensor,
|
||||
int value,
|
||||
int min,
|
||||
int max,
|
||||
) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => Dialog(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
BodyMedium(
|
||||
text: title,
|
||||
style: context.bodyMedium.copyWith(
|
||||
color: ColorsManager.primaryColorWithOpacity,
|
||||
fontWeight: FontsManager.extraBold,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 15,
|
||||
horizontal: 50,
|
||||
),
|
||||
child: Container(
|
||||
height: 1,
|
||||
width: double.infinity,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10,
|
||||
),
|
||||
child: TitleMedium(
|
||||
text: value.toString(),
|
||||
style: context.titleMedium.copyWith(
|
||||
color: Colors.black,
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// Icon(Icons.minus),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
value--;
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.remove,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
Slider(
|
||||
value: value.toDouble(),
|
||||
onChanged: (value) {
|
||||
// value = value;
|
||||
},
|
||||
min: 0,
|
||||
max: 10,
|
||||
label: value.toString(),
|
||||
inactiveColor: ColorsManager.greyColor,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
value++;
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.add,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
height: 1,
|
||||
width: double.infinity,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: BodyMedium(
|
||||
text: 'Cancel',
|
||||
style: context.bodyMedium
|
||||
.copyWith(color: ColorsManager.greyColor),
|
||||
),
|
||||
)),
|
||||
Container(
|
||||
height: 50,
|
||||
width: 1,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: BodyMedium(
|
||||
text: 'Confirm',
|
||||
style: context.bodyMedium.copyWith(
|
||||
color: ColorsManager.primaryColorWithOpacity),
|
||||
),
|
||||
)),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
@ -10,16 +8,23 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dar
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/context_extension.dart';
|
||||
import 'package:syncrow_app/utils/helpers/misc_string_helpers.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/constants.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
|
||||
|
||||
import 'wall_sensor_interface.dart';
|
||||
|
||||
class CeilingSensorInterface extends StatelessWidget {
|
||||
const CeilingSensorInterface({super.key, required this.ceilingSensor});
|
||||
|
||||
final DeviceModel ceilingSensor;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String state = ceilingSensor.status
|
||||
.firstWhere((element) => element.code == "presence_state")
|
||||
.value
|
||||
.toString();
|
||||
return AnnotatedRegion(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
|
||||
@ -58,13 +63,71 @@ class CeilingSensorInterface extends StatelessWidget {
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.presenceSensorAssetsPresenceSensorMotion,
|
||||
width: 100,
|
||||
height: 100,
|
||||
InkWell(
|
||||
onTap: () {
|
||||
if ((ceilingSensor.isOnline ?? false) == false) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text(
|
||||
'Device is offline',
|
||||
),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
String controlCode = 'sensitivity';
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => ParameterControlDialog(
|
||||
title: 'Sensitivity',
|
||||
sensor: ceilingSensor,
|
||||
controlCode: controlCode,
|
||||
value: ceilingSensor.status
|
||||
.firstWhere(
|
||||
(element) => element.code == controlCode)
|
||||
.value as int,
|
||||
min: ceilingSensor.functions
|
||||
.firstWhere((element) =>
|
||||
element.code == controlCode)
|
||||
.values
|
||||
?.min ??
|
||||
0,
|
||||
max: ceilingSensor.functions
|
||||
.firstWhere((element) =>
|
||||
element.code == controlCode)
|
||||
.values
|
||||
?.max ??
|
||||
0,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: SvgPicture.asset(
|
||||
state == 'presence'
|
||||
? Assets.presenceSensorAssetsPresence
|
||||
: Assets.presenceSensorAssetsPresenceSensorMotion,
|
||||
width: 100,
|
||||
height: 100,
|
||||
// colorFilter: ColorFilter.mode(
|
||||
// (ceilingSensor.isOnline ?? false)
|
||||
// ? ColorsManager.primaryColor
|
||||
// : Colors.grey.withOpacity(0.9),
|
||||
// BlendMode.srcIn,
|
||||
// ),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
BodyMedium(
|
||||
text: 'Motion',
|
||||
text: StringHelpers.toTitleCase(state),
|
||||
// (ceilingSensor.isOnline ?? false)
|
||||
// ? StringHelpers.toTitleCase(ceilingSensor.status
|
||||
// .firstWhere((element) =>
|
||||
// element.code == 'presence_state')
|
||||
// .value
|
||||
// .toString())
|
||||
// : "Offline",
|
||||
style: context.bodyMedium.copyWith(
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
|
@ -0,0 +1,173 @@
|
||||
part of 'wall_sensor_interface.dart';
|
||||
|
||||
class ParameterControlDialog extends StatefulWidget {
|
||||
final String title;
|
||||
final DeviceModel sensor;
|
||||
final int value;
|
||||
final int min;
|
||||
final int max;
|
||||
final String controlCode;
|
||||
|
||||
const ParameterControlDialog({
|
||||
super.key,
|
||||
required this.title,
|
||||
required this.sensor,
|
||||
required this.value,
|
||||
required this.min,
|
||||
required this.max,
|
||||
required this.controlCode,
|
||||
});
|
||||
|
||||
@override
|
||||
ParameterControlDialogState createState() => ParameterControlDialogState();
|
||||
}
|
||||
|
||||
class ParameterControlDialogState extends State<ParameterControlDialog> {
|
||||
late int _value;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_value = widget.value;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
BodyMedium(
|
||||
text: widget.title,
|
||||
style: context.bodyMedium.copyWith(
|
||||
color: ColorsManager.primaryColorWithOpacity,
|
||||
fontWeight: FontsManager.extraBold,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 15,
|
||||
horizontal: 50,
|
||||
),
|
||||
child: Container(
|
||||
height: 1,
|
||||
width: double.infinity,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10,
|
||||
),
|
||||
child: TitleMedium(
|
||||
text: _value.toString(),
|
||||
style: context.titleMedium.copyWith(
|
||||
color: Colors.black,
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_value = (_value - 1).clamp(widget.min, widget.max);
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.remove,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
Slider(
|
||||
value: _value.toDouble(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_value = value.toInt();
|
||||
});
|
||||
},
|
||||
min: widget.min.toDouble(),
|
||||
max: widget.max.toDouble(),
|
||||
label: _value.toString(),
|
||||
inactiveColor: ColorsManager.greyColor,
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_value = (_value + 1).clamp(widget.min, widget.max);
|
||||
});
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.add,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(
|
||||
height: 1,
|
||||
width: double.infinity,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Center(
|
||||
child: BodyMedium(
|
||||
text: 'Cancel',
|
||||
style: context.bodyMedium
|
||||
.copyWith(color: ColorsManager.greyColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 50,
|
||||
width: 1,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.pop(context, _value);
|
||||
if (widget.sensor.isOnline == null) {
|
||||
return;
|
||||
}
|
||||
if (!widget.sensor.isOnline!) {
|
||||
debugPrint('Device is offline');
|
||||
return;
|
||||
}
|
||||
|
||||
DevicesCubit.getInstance().deviceControl(
|
||||
DeviceControlModel(
|
||||
deviceId: widget.sensor.id,
|
||||
code: widget.controlCode,
|
||||
value: widget.value),
|
||||
widget.sensor.id ?? '');
|
||||
},
|
||||
child: Center(
|
||||
child: BodyMedium(
|
||||
text: 'Confirm',
|
||||
style: context.bodyMedium.copyWith(
|
||||
color: ColorsManager.primaryColorWithOpacity),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,358 @@
|
||||
part of "wall_sensor_interface.dart";
|
||||
|
||||
class ParametersList extends StatelessWidget {
|
||||
const ParametersList({
|
||||
super.key,
|
||||
required this.wallSensor,
|
||||
});
|
||||
|
||||
final DeviceModel wallSensor;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Expanded(
|
||||
flex: 7,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: List.generate(
|
||||
wallSensorButtons.length,
|
||||
(index) {
|
||||
if (index == 3) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
DefaultContainer(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 12, horizontal: 15),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
if ((wallSensor.isOnline ?? false) == false) {
|
||||
return;
|
||||
}
|
||||
String controlCode = 'motion_sensitivity_value';
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => ParameterControlDialog(
|
||||
title: 'Motion Detection Sensitivity',
|
||||
sensor: wallSensor,
|
||||
controlCode: controlCode,
|
||||
value: wallSensor.status
|
||||
.firstWhere((element) =>
|
||||
element.code == controlCode)
|
||||
.value as int,
|
||||
min: wallSensor.functions
|
||||
.firstWhere((element) =>
|
||||
element.code == controlCode)
|
||||
.values
|
||||
?.min ??
|
||||
0,
|
||||
max: wallSensor.functions
|
||||
.firstWhere((element) =>
|
||||
element.code == controlCode)
|
||||
.values
|
||||
?.max ??
|
||||
0,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const BodySmall(
|
||||
text: 'Motion\nDetection\nSensitivity',
|
||||
textAlign: TextAlign.center),
|
||||
BodyLarge(
|
||||
text: wallSensor.status
|
||||
.firstWhere((element) =>
|
||||
element.code ==
|
||||
'motion_sensitivity_value')
|
||||
.value
|
||||
.toString(),
|
||||
style: context.bodyLarge
|
||||
.copyWith(fontWeight: FontsManager.bold),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Container(
|
||||
width: 1,
|
||||
height: 45,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
if ((wallSensor.isOnline ?? false) == false) {
|
||||
return;
|
||||
}
|
||||
String controlCode = 'motionless_sensitivity';
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => ParameterControlDialog(
|
||||
title: 'Motionless Detection Sensitivity',
|
||||
sensor: wallSensor,
|
||||
controlCode: controlCode,
|
||||
value: wallSensor.status
|
||||
.firstWhere((element) =>
|
||||
element.code == controlCode)
|
||||
.value as int,
|
||||
min: wallSensor.functions
|
||||
.firstWhere((element) =>
|
||||
element.code == controlCode)
|
||||
.values
|
||||
?.min ??
|
||||
0,
|
||||
max: wallSensor.functions
|
||||
.firstWhere((element) =>
|
||||
element.code == controlCode)
|
||||
.values
|
||||
?.max ??
|
||||
0,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const BodySmall(
|
||||
text: 'Motionless\nDetection\nSensitivity',
|
||||
textAlign: TextAlign.center),
|
||||
BodyLarge(
|
||||
text: wallSensor.status
|
||||
.firstWhere((element) =>
|
||||
element.code ==
|
||||
'motionless_sensitivity')
|
||||
.value
|
||||
.toString(),
|
||||
style: context.bodyLarge.copyWith(
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Container(
|
||||
width: 1,
|
||||
height: 45,
|
||||
color: ColorsManager.greyColor,
|
||||
),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
if ((wallSensor.isOnline ?? false) == false) {
|
||||
return;
|
||||
}
|
||||
String controlCode = 'far_detection';
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => ParameterControlDialog(
|
||||
title: 'Far Detection',
|
||||
sensor: wallSensor,
|
||||
controlCode: controlCode,
|
||||
value: wallSensor.status
|
||||
.firstWhere((element) =>
|
||||
element.code == controlCode)
|
||||
.value as int,
|
||||
min: wallSensor.functions
|
||||
.firstWhere((element) =>
|
||||
element.code == controlCode)
|
||||
.values
|
||||
?.min ??
|
||||
0,
|
||||
max: wallSensor.functions
|
||||
.firstWhere((element) =>
|
||||
element.code == controlCode)
|
||||
.values
|
||||
?.max ??
|
||||
0,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const BodySmall(
|
||||
text: 'Far\nDetection',
|
||||
textAlign: TextAlign.center),
|
||||
BodyLarge(
|
||||
text:
|
||||
'${wallSensor.status.firstWhere((element) => element.code == 'far_detection').value.toString()}${wallSensor.functions.firstWhere((element) => element.code == 'far_detection').values?.unit ?? ''}',
|
||||
style: context.bodyLarge.copyWith(
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
listItem(wallSensorButtons[index], context, wallSensor)
|
||||
],
|
||||
);
|
||||
}
|
||||
return listItem(wallSensorButtons[index], context, wallSensor);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
//{"result":{"productId":"awarhusb","productType":"WPS","status":[{"code":"presence_state","value":"none"},{"code":"far_detection","value":75},{"code":"presence_time","value":0},{"code":"motion_sensitivity_value","value":5},{"code":"motionless_sensitivity","value":5},{"code":"dis_current","value":214},{"code":"illuminance_value","value":231},{"code":"indicator","value":true}]},"success":true}
|
||||
final List<Map<String, Object?>> wallSensorButtons = const [
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsTime,
|
||||
'title': 'Presence Time',
|
||||
'code': 'presence_time',
|
||||
},
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsDistance,
|
||||
'title': 'Current Distance',
|
||||
'code': 'dis_current',
|
||||
},
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsIlluminanceValue,
|
||||
'title': 'Illuminance Value',
|
||||
'code': 'illuminance_value',
|
||||
},
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsEmpty,
|
||||
'title': 'Nobody Time',
|
||||
'code': null,
|
||||
//TODO: Implement the nobody time
|
||||
},
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsIndicator,
|
||||
'title': 'Indicator',
|
||||
'code': 'indicator',
|
||||
},
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsRecord,
|
||||
'title': 'Presence Record',
|
||||
'code': null
|
||||
},
|
||||
{
|
||||
'icon': Assets.presenceSensorAssetsIlluminanceRecord,
|
||||
'title': 'Illuminance Record',
|
||||
'code': null
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
Widget listItem(
|
||||
Map<String, Object?> wallSensorButton,
|
||||
BuildContext context,
|
||||
DeviceModel wallSensor,
|
||||
) {
|
||||
String? unit;
|
||||
dynamic value;
|
||||
if (wallSensorButton['code'] != null) {
|
||||
if (wallSensor.status
|
||||
.any((element) => element.code == wallSensorButton['code'] as String)) {
|
||||
unit = unitsMap[wallSensorButton['code'] as String];
|
||||
value = wallSensor.status
|
||||
.firstWhere(
|
||||
(element) => element.code == wallSensorButton['code'] as String)
|
||||
.value;
|
||||
}
|
||||
}
|
||||
return DefaultContainer(
|
||||
margin: const EdgeInsets.only(bottom: 5),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 20),
|
||||
onTap: () {
|
||||
if (wallSensorButton['page'] != null) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => wallSensorButton['page'] as Widget,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
wallSensorButton['icon'] as String,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 25,
|
||||
),
|
||||
BodyMedium(
|
||||
text: wallSensorButton['title'] as String,
|
||||
),
|
||||
if (wallSensorButton['code'] != null) const Spacer(),
|
||||
if (wallSensorButton['code'] != null)
|
||||
if (wallSensorButton['title'] != 'Indicator')
|
||||
BodyMedium(
|
||||
text: '${value ?? 'N/A'}${unit ?? ''}',
|
||||
style:
|
||||
context.bodyMedium.copyWith(color: ColorsManager.greyColor),
|
||||
),
|
||||
if (wallSensorButton['title'] == 'Indicator')
|
||||
Expanded(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Transform.scale(
|
||||
scale: .8,
|
||||
child: CupertinoSwitch(
|
||||
value: value ?? false,
|
||||
onChanged: (value) {
|
||||
if (wallSensor.isOnline ?? false) {
|
||||
DevicesCubit.getInstance().deviceControl(
|
||||
DeviceControlModel(
|
||||
deviceId: wallSensor.id,
|
||||
code: 'indicator',
|
||||
value: value,
|
||||
),
|
||||
wallSensor.id ?? '');
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Device is offline'),
|
||||
backgroundColor: Colors.red,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
applyTheme: true,
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (wallSensorButton['title'] == 'Nobody Time')
|
||||
const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
color: ColorsManager.greyColor,
|
||||
size: 15,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, String> unitsMap = {
|
||||
'presence_time': 's',
|
||||
'dis_current': 'cm',
|
||||
'illuminance_value': 'lux',
|
||||
'far_detection': 'cm',
|
||||
'motion_sensitivity_value': '',
|
||||
'motionless_sensitivity': '',
|
||||
};
|
@ -1,17 +1,23 @@
|
||||
part of "wall_sensor_interface.dart";
|
||||
|
||||
class PresenceIndicator extends StatelessWidget {
|
||||
const PresenceIndicator({super.key});
|
||||
|
||||
const PresenceIndicator({super.key, required this.wallSensor});
|
||||
final DeviceModel wallSensor;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String state = wallSensor.status
|
||||
.firstWhere((element) => element.code == "presence_state")
|
||||
.value
|
||||
.toString();
|
||||
return Expanded(
|
||||
flex: 6,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.presenceSensorAssetsPresence,
|
||||
state == 'presence'
|
||||
? Assets.presenceSensorAssetsPresence
|
||||
: Assets.presenceSensorAssetsPresenceSensorMotion,
|
||||
width: 100,
|
||||
height: 100,
|
||||
),
|
||||
@ -19,7 +25,7 @@ class PresenceIndicator extends StatelessWidget {
|
||||
height: 10,
|
||||
),
|
||||
BodyMedium(
|
||||
text: 'Presence',
|
||||
text: StringHelpers.toTitleCase(state),
|
||||
style: context.bodyMedium.copyWith(fontWeight: FontsManager.bold),
|
||||
),
|
||||
],
|
@ -2,6 +2,8 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||
@ -10,12 +12,14 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/context_extension.dart';
|
||||
import 'package:syncrow_app/utils/helpers/misc_string_helpers.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/constants.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
|
||||
|
||||
part "parameters_list.dart";
|
||||
part "presence_indicator.dart";
|
||||
part "parameter_control_dialog.dart";
|
||||
|
||||
class WallMountedInterface extends StatelessWidget {
|
||||
const WallMountedInterface({super.key, required this.wallSensor});
|
||||
@ -56,7 +60,9 @@ class WallMountedInterface extends StatelessWidget {
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
const PresenceIndicator(),
|
||||
PresenceIndicator(
|
||||
wallSensor: wallSensor,
|
||||
),
|
||||
ParametersList(wallSensor: wallSensor),
|
||||
],
|
||||
),
|
@ -12,7 +12,7 @@ import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_interface.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface.dart';
|
||||
|
||||
import 'package:syncrow_app/features/devices/view/widgets/presence_sensor/wall_sensor_interface.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/presence_sensors/wall_sensor_interface.dart';
|
||||
|
||||
import 'package:syncrow_app/features/devices/view/widgets/presence_sensors/ceiling_sensor_interface.dart';
|
||||
|
||||
|
@ -35,7 +35,10 @@ class WizartSwitches extends StatelessWidget {
|
||||
onTap: () {
|
||||
// DevicesCubit.getInstance().selectCategory(index);
|
||||
//Navigate to the chosen category view without animation
|
||||
|
||||
if (DevicesCubit.getInstance().chosenCategoryView ==
|
||||
null) {
|
||||
return;
|
||||
}
|
||||
Navigator.push(context,
|
||||
CustomPageRoute(builder: (context) {
|
||||
return DevicesCubit.getInstance()
|
||||
|
@ -61,4 +61,11 @@ class StringHelpers {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static String toTitleCase(String text) {
|
||||
return text
|
||||
.split(' ')
|
||||
.map((word) => word[0].toUpperCase() + word.substring(1))
|
||||
.join(' ');
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,15 @@ enum DeviceType {
|
||||
// DL awu7anehyu5q1iu8
|
||||
// WPS awarhusb
|
||||
// 3G 1a6vgvyi
|
||||
enum FunctionType { Boolean, Enum, Integer, Raw, String }
|
||||
|
||||
Map<String, FunctionType> functionTypesMap = {
|
||||
"Boolean": FunctionType.Boolean,
|
||||
"Enum": FunctionType.Enum,
|
||||
"Integer": FunctionType.Integer,
|
||||
"Raw": FunctionType.Raw,
|
||||
"String": FunctionType.String,
|
||||
};
|
||||
Map<String, DeviceType> devicesTypesMap = {
|
||||
"wzdcrqh0": DeviceType.AC,
|
||||
"wp8ticoo2bhumwgb": DeviceType.Gateway,
|
||||
@ -61,75 +69,127 @@ Map<String, DeviceType> devicesTypesMap = {
|
||||
};
|
||||
Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
|
||||
DeviceType.AC: [
|
||||
FunctionModel(code: 'switch', type: 'Boolean', values: '{}'),
|
||||
FunctionModel(
|
||||
code: 'mode', type: 'Enum', values: '{"range":["cold","hot","wind"]}'),
|
||||
code: 'switch',
|
||||
type: functionTypesMap['Boolean'],
|
||||
values: ValueModel.fromJson({})),
|
||||
FunctionModel(
|
||||
code: 'mode',
|
||||
type: functionTypesMap['Enum'],
|
||||
values: ValueModel.fromJson({
|
||||
"range": ["cold", "hot", "wind"]
|
||||
})),
|
||||
FunctionModel(
|
||||
code: 'temp_set',
|
||||
type: 'Integer',
|
||||
values: '{"unit":"℃","min":200,"max":300,"scale":1,"step":5}'),
|
||||
type: functionTypesMap['Integer'],
|
||||
values: ValueModel.fromJson(
|
||||
{"unit": "℃", "min": 200, "max": 300, "scale": 1, "step": 5})),
|
||||
FunctionModel(
|
||||
code: 'level',
|
||||
type: 'Enum',
|
||||
values: '{"range":["low","middle","high","auto"]}'),
|
||||
FunctionModel(code: 'child_lock', type: 'Boolean', values: '{}'),
|
||||
type: functionTypesMap['Enum'],
|
||||
values: ValueModel.fromJson({
|
||||
"range": ["low", "middle", "high", "auto"]
|
||||
})),
|
||||
FunctionModel(
|
||||
code: 'child_lock',
|
||||
type: functionTypesMap['Boolean'],
|
||||
values: ValueModel.fromJson({})),
|
||||
],
|
||||
DeviceType.Gateway: [
|
||||
FunctionModel(code: 'switch_alarm_sound', type: 'Boolean', values: '{}'),
|
||||
FunctionModel(
|
||||
code: 'switch_alarm_sound',
|
||||
type: functionTypesMap['Boolean'],
|
||||
values: ValueModel.fromJson({})),
|
||||
FunctionModel(
|
||||
code: 'master_state',
|
||||
type: 'Enum',
|
||||
values: '{"range":["normal","alarm"]}'),
|
||||
FunctionModel(code: 'factory_reset', type: 'Boolean', values: '{}'),
|
||||
type: functionTypesMap['Enum'],
|
||||
values: ValueModel.fromJson({
|
||||
"range": ["normal", "alarm"]
|
||||
})),
|
||||
FunctionModel(
|
||||
code: 'alarm_active', type: 'String', values: '{"maxlen":255}'),
|
||||
code: 'factory_reset',
|
||||
type: functionTypesMap['Boolean'],
|
||||
values: ValueModel.fromJson({})),
|
||||
FunctionModel(
|
||||
code: 'alarm_active',
|
||||
type: functionTypesMap['String'],
|
||||
values: ValueModel.fromJson({"maxlen": 255})),
|
||||
],
|
||||
DeviceType.CeilingSensor: [
|
||||
FunctionModel(
|
||||
code: 'sensitivity',
|
||||
type: 'Integer',
|
||||
values: '{"unit":"","min":1,"max":10,"scale":0,"step":1}'),
|
||||
type: functionTypesMap['Integer'],
|
||||
values: ValueModel.fromJson(
|
||||
{"unit": "", "min": 1, "max": 10, "scale": 0, "step": 1})),
|
||||
],
|
||||
DeviceType.DoorLock: [
|
||||
FunctionModel(code: 'remote_no_pd_setkey', type: 'Raw', values: '{}'),
|
||||
FunctionModel(code: 'remote_no_dp_key', type: 'Raw', values: '{}'),
|
||||
FunctionModel(code: 'normal_open_switch', type: 'Boolean', values: '{}'),
|
||||
FunctionModel(
|
||||
code: 'remote_no_pd_setkey',
|
||||
type: functionTypesMap['Raw'],
|
||||
values: ValueModel.fromJson({})),
|
||||
FunctionModel(
|
||||
code: 'remote_no_dp_key',
|
||||
type: functionTypesMap['Raw'],
|
||||
values: ValueModel.fromJson({})),
|
||||
FunctionModel(
|
||||
code: 'normal_open_switch',
|
||||
type: functionTypesMap['Boolean'],
|
||||
values: ValueModel.fromJson({})),
|
||||
],
|
||||
DeviceType.WallSensor: [
|
||||
FunctionModel(
|
||||
code: 'far_detection',
|
||||
type: 'Integer',
|
||||
values: '{"unit":"cm","min":75,"max":600,"scale":0,"step":75}'),
|
||||
type: functionTypesMap['Integer'],
|
||||
values: ValueModel.fromJson(
|
||||
{"unit": "cm", "min": 75, "max": 600, "scale": 0, "step": 75})),
|
||||
FunctionModel(
|
||||
code: 'presence_time',
|
||||
type: 'Integer',
|
||||
values: '{"unit":"Min","min":0,"max":65535,"scale":0,"step":1}'),
|
||||
type: functionTypesMap['Integer'],
|
||||
values: ValueModel.fromJson(
|
||||
{"unit": "Min", "min": 0, "max": 65535, "scale": 0, "step": 1})),
|
||||
FunctionModel(
|
||||
code: 'motion_sensitivity_value',
|
||||
type: 'Integer',
|
||||
values: '{"unit":"","min":1,"max":5,"scale":0,"step":1}'),
|
||||
type: functionTypesMap['Integer'],
|
||||
values: ValueModel.fromJson(
|
||||
{"unit": "", "min": 1, "max": 5, "scale": 0, "step": 1})),
|
||||
FunctionModel(
|
||||
code: 'motionless_sensitivity',
|
||||
type: 'Integer',
|
||||
values: '{"unit":"","min":1,"max":5,"scale":0,"step":1}'),
|
||||
FunctionModel(code: 'indicator', type: 'Boolean', values: '{}'),
|
||||
type: functionTypesMap['Integer'],
|
||||
values: ValueModel.fromJson(
|
||||
{"unit": "", "min": 1, "max": 5, "scale": 0, "step": 1})),
|
||||
FunctionModel(
|
||||
code: 'indicator',
|
||||
type: functionTypesMap['Boolean'],
|
||||
values: ValueModel.fromJson({})),
|
||||
],
|
||||
DeviceType.ThreeGang: [
|
||||
FunctionModel(code: 'switch_1', type: 'Boolean', values: '{}'),
|
||||
FunctionModel(code: 'switch_2', type: 'Boolean', values: '{}'),
|
||||
FunctionModel(code: 'switch_3', type: 'Boolean', values: '{}'),
|
||||
FunctionModel(
|
||||
code: 'switch_1',
|
||||
type: functionTypesMap['Boolean'],
|
||||
values: ValueModel.fromJson({})),
|
||||
FunctionModel(
|
||||
code: 'switch_2',
|
||||
type: functionTypesMap['Boolean'],
|
||||
values: ValueModel.fromJson({})),
|
||||
FunctionModel(
|
||||
code: 'switch_3',
|
||||
type: functionTypesMap['Boolean'],
|
||||
values: ValueModel.fromJson({})),
|
||||
FunctionModel(
|
||||
code: 'countdown_1',
|
||||
type: 'Integer',
|
||||
values: '{"unit":"s","min":0,"max":43200,"scale":0,"step":1}'),
|
||||
type: functionTypesMap['Integer'],
|
||||
values: ValueModel.fromJson(
|
||||
{"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})),
|
||||
FunctionModel(
|
||||
code: 'countdown_2',
|
||||
type: 'Integer',
|
||||
values: '{"unit":"s","min":0,"max":43200,"scale":0,"step":1}'),
|
||||
type: functionTypesMap['Integer'],
|
||||
values: ValueModel.fromJson(
|
||||
{"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})),
|
||||
FunctionModel(
|
||||
code: 'countdown_3',
|
||||
type: 'Integer',
|
||||
values: '{"unit":"s","min":0,"max":43200,"scale":0,"step":1}'),
|
||||
type: functionTypesMap['Integer'],
|
||||
values: ValueModel.fromJson(
|
||||
{"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})),
|
||||
],
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user