Compare commits

..

12 Commits

Author SHA1 Message Date
6c691d4b3c displays ceiling sensor in routine 2025-04-09 12:46:43 +03:00
550acc4953 Merge pull request #137 from SyncrowIOT/fix-remove-option-from-then-dialog-routins
add dialogType to devices and add parameter in showSwitchFunctionsDialog
2025-04-09 12:18:33 +03:00
fd6b737556 Refactor one_gang_switch_dialog.dart to use one_gang_switch instead of ac in function names and variables 2025-04-09 12:17:26 +03:00
d08ab8caac add dialogType to devices and add parameter in showSwitchFunctionsDialog 2025-04-09 10:09:56 +03:00
c2476b9719 Merge pull request #132 from SyncrowIOT/fix_routine_popup_and_wall_sensor_bugs
Fix routine popup and wall sensor bugs
2025-04-07 16:43:48 +03:00
a56f4e488e Refactor routine_view_card.dart to adjust the size of the CircularProgressIndicator
Fix routine popup
Update wall_presence_sensor.dart to handle null selectedOperationName
2025-04-07 16:42:44 +03:00
6bd9fb7e4e Refactor routine_view_card.dart to adjust the size o 2025-04-07 16:22:21 +03:00
d264409d29 - Refactor the WpsFunctions class in wps_functions.dart to use 'cm' instead of 'temp' for the description of operational values.
- Update the WallPresenceSensor class in wall_presence_sensor.dart to use the selected operation name
2025-04-07 14:27:36 +03:00
ca44f3bf55 fix routine popup 2025-04-07 12:53:12 +03:00
9949a0a0bf Merge pull request #131 from SyncrowIOT/SP-1281-FE-Save-Display-Configured-Sensor-as-a-Card
save presence state and edit selected value
2025-04-07 09:30:38 +03:00
8dc4081a89 save presence state and edit selected value 2025-04-06 16:38:34 +03:00
52498f4e6b Merge pull request #130 from SyncrowIOT/routine_ui_issue
Refactor SVG icons and update asset paths and fix RoutinesView issues
2025-04-06 16:33:49 +03:00
20 changed files with 696 additions and 549 deletions

View File

@ -247,12 +247,18 @@ SOS
switch (productType) {
case 'AC':
return [
SwitchFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
ModeFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
TempSetFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
CurrentTempFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
LevelFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
ChildLockFunction(deviceId: uuid ?? '', deviceName: name ?? ''),
SwitchFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
ModeFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
TempSetFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
CurrentTempFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
LevelFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
ChildLockFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
];
case '1G':
@ -275,44 +281,42 @@ SOS
case '3G':
return [
ThreeGangSwitch1Function(
deviceId: uuid ?? '', deviceName: name ?? ''),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
ThreeGangSwitch2Function(
deviceId: uuid ?? '', deviceName: name ?? ''),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
ThreeGangSwitch3Function(
deviceId: uuid ?? '', deviceName: name ?? ''),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
ThreeGangCountdown1Function(
deviceId: uuid ?? '', deviceName: name ?? ''),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
ThreeGangCountdown2Function(
deviceId: uuid ?? '', deviceName: name ?? ''),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
ThreeGangCountdown3Function(
deviceId: uuid ?? '', deviceName: name ?? ''),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
];
case 'WPS':
return [
//IF Functions
PresenceStateFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
CurrentDistanceFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
IlluminanceValueFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
PresenceTimeFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
//THEN Functions
FarDetectionFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
MotionSensitivityFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
MotionLessSensitivityFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
IndicatorFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'BOTH'),
NoOneTimeFunction(
deviceId: uuid ?? '', deviceName: name ?? '', type: 'IF'),
deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN'),
// FarDetectionSliderFunction(
// deviceId: uuid ?? '', deviceName: name ?? '', type: 'THEN')
];
default:
return [];

View File

@ -2,6 +2,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_event.dart';
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_state.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
import 'package:syncrow_web/services/space_mana_api.dart';
@ -10,11 +11,12 @@ class CreateRoutineBloc extends Bloc<CreateRoutineEvent, CreateRoutineState> {
on<SpaceOnlyWithDevicesEvent>(_fetchSpaceOnlyWithDevices);
on<SaveCommunityIdAndSpaceIdEvent>(saveSpaceIdCommunityId);
on<ResetSelectedEvent>(resetSelected);
on<FetchCommunityEvent>(_fetchCommunity);
}
String selectedSpaceId = '';
String selectedCommunityId = '';
List<CommunityModel> communities = [];
List<SpaceModel> spacesOnlyWithDevices = [];
Future<void> _fetchSpaceOnlyWithDevices(
@ -30,7 +32,7 @@ class CreateRoutineBloc extends Bloc<CreateRoutineEvent, CreateRoutineState> {
emit(SpaceWithDeviceLoadedState(spacesOnlyWithDevices));
} catch (e) {
emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
emit(SpaceTreeErrorState('Error loading spaces: $e'));
}
}
@ -48,4 +50,18 @@ class CreateRoutineBloc extends Bloc<CreateRoutineEvent, CreateRoutineState> {
selectedCommunityId = '';
emit(const ResetSelectedState());
}
Future<void> _fetchCommunity(
FetchCommunityEvent event, Emitter<CreateRoutineState> emit) async {
emit(const CommunitiesLoadingState());
try {
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
communities =
await CommunitySpaceManagementApi().fetchCommunities(projectUuid);
emit(const CommunityLoadedState());
} catch (e) {
emit(SpaceTreeErrorState('Error loading communities $e'));
}
}
}

View File

@ -41,3 +41,11 @@ class ResetSelectedEvent extends CreateRoutineEvent {
@override
List<Object> get props => [];
}
class FetchCommunityEvent extends CreateRoutineEvent {
const FetchCommunityEvent();
@override
List<Object> get props => [];
}

View File

@ -44,3 +44,10 @@ class ResetSelectedState extends CreateRoutineState {
const ResetSelectedState();
}
class CommunityLoadedState extends CreateRoutineState {
const CommunityLoadedState();
}
class CommunitiesLoadingState extends CreateRoutineState {
const CommunitiesLoadingState();
}

View File

@ -1,12 +1,11 @@
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class CommunityDropdown extends StatelessWidget {
final String? selectedValue;
final List<CommunityModel> communities;
final Function(String?) onChanged;
final TextEditingController _searchController = TextEditingController();
@ -14,6 +13,7 @@ class CommunityDropdown extends StatelessWidget {
Key? key,
required this.selectedValue,
required this.onChanged,
required this.communities,
}) : super(key: key);
@override
@ -32,123 +32,123 @@ class CommunityDropdown extends StatelessWidget {
),
),
const SizedBox(height: 8),
BlocBuilder<SpaceTreeBloc, SpaceTreeState>(
builder: (context, state) {
return SizedBox(
child: Container(
SizedBox(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
child: DropdownButton2<String>(
underline: const SizedBox(),
value: selectedValue,
items: communities.map((community) {
return DropdownMenuItem<String>(
value: community.uuid,
child: Text(
' ${community.name}',
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
);
}).toList(),
onChanged: onChanged,
style: const TextStyle(color: Colors.black),
hint: Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
" Please Select",
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.textGray,
),
),
),
customButton: Container(
height: 45,
decoration: BoxDecoration(
border: Border.all(color: ColorsManager.textGray, width: 1.0),
borderRadius: BorderRadius.circular(10),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 5,
child: Text(
selectedValue != null
? " ${communities.firstWhere((element) => element.uuid == selectedValue).name}"
: ' Please Select',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: selectedValue != null
? Colors.black
: ColorsManager.textGray,
),
overflow: TextOverflow.ellipsis,
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: const BorderRadius.only(
topRight: Radius.circular(10),
bottomRight: Radius.circular(10),
),
),
height: 45,
child: const Icon(
Icons.keyboard_arrow_down,
color: ColorsManager.textGray,
),
),
),
],
),
),
dropdownStyleData: DropdownStyleData(
maxHeight: MediaQuery.of(context).size.height * 0.4,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
child: DropdownButton2<String>(
underline: SizedBox(),
value: selectedValue,
items: state.communityList.map((community) {
return DropdownMenuItem<String>(
value: community.uuid,
child: Text(
' ${community.name}',
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
dropdownSearchData: DropdownSearchData(
searchController: _searchController,
searchInnerWidgetHeight: 50,
searchInnerWidget: Container(
height: 50,
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: TextFormField(
style: const TextStyle(color: Colors.black),
controller: _searchController,
decoration: InputDecoration(
isDense: true,
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 12,
),
);
}).toList(),
onChanged: onChanged,
style: TextStyle(color: Colors.black),
hint: Padding(
padding: EdgeInsets.only(left: 10),
child: Text(
" Please Select",
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.textGray,
),
),
),
customButton: Container(
height: 45,
decoration: BoxDecoration(
border: Border.all(color: ColorsManager.textGray, width: 1.0),
borderRadius: BorderRadius.circular(10),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 5,
child: Text(
selectedValue != null
? " ${state.communityList.firstWhere((element) => element.uuid == selectedValue).name}"
: ' Please Select',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color:
selectedValue != null ? Colors.black : ColorsManager.textGray,
),
overflow: TextOverflow.ellipsis,
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: const BorderRadius.only(
topRight: Radius.circular(10),
bottomRight: Radius.circular(10),
),
),
height: 45,
child: const Icon(
Icons.keyboard_arrow_down,
color: ColorsManager.textGray,
),
),
),
],
),
),
dropdownStyleData: DropdownStyleData(
maxHeight: MediaQuery.of(context).size.height * 0.4,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
),
dropdownSearchData: DropdownSearchData(
searchController: _searchController,
searchInnerWidgetHeight: 50,
searchInnerWidget: Container(
height: 50,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: TextFormField(
style: const TextStyle(color: Colors.black),
controller: _searchController,
decoration: InputDecoration(
isDense: true,
contentPadding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 12,
),
hintText: 'Search for community...',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
hintText: 'Search for community...',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
searchMatchFn: (item, searchValue) {
final communityName = (item.child as Text).data?.toLowerCase() ?? '';
return communityName.contains(searchValue.toLowerCase().trim());
},
),
onMenuStateChange: (isOpen) {
if (!isOpen) {
_searchController.clear();
}
},
menuItemStyleData: const MenuItemStyleData(
height: 40,
),
),
));
},
),
searchMatchFn: (item, searchValue) {
final communityName =
(item.child as Text).data?.toLowerCase() ?? '';
return communityName
.contains(searchValue.toLowerCase().trim());
},
),
onMenuStateChange: (isOpen) {
if (!isOpen) {
_searchController.clear();
}
},
menuItemStyleData: const MenuItemStyleData(
height: 40,
),
),
))
],
),
);

View File

@ -5,11 +5,10 @@ import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routi
import 'package:syncrow_web/pages/routines/bloc/create_routine_bloc/create_routine_bloc.dart';
import 'package:syncrow_web/pages/routines/create_new_routines/commu_dropdown.dart';
import 'package:syncrow_web/pages/routines/create_new_routines/space_dropdown.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class CreateNewRoutinesDialog extends StatefulWidget {
const CreateNewRoutinesDialog({Key? key}) : super(key: key);
const CreateNewRoutinesDialog({super.key});
@override
State<CreateNewRoutinesDialog> createState() =>
@ -19,136 +18,160 @@ class CreateNewRoutinesDialog extends StatefulWidget {
class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
String? _selectedCommunity;
String? _selectedSpace;
void _fetchSpaces(String communityId) {
context
.read<CreateRoutineBloc>()
.add(SpaceOnlyWithDevicesEvent(communityId));
}
@override
Widget build(BuildContext context) {
return BlocBuilder<CreateRoutineBloc, CreateRoutineState>(
builder: (context, state) {
final _bloc = BlocProvider.of<CreateRoutineBloc>(context);
final spaces = _bloc.spacesOnlyWithDevices;
final isLoading = state is SpaceWithDeviceLoadingState;
return BlocProvider(
create: (BuildContext context) =>
CreateRoutineBloc()..add(const FetchCommunityEvent()),
child: BlocBuilder<CreateRoutineBloc, CreateRoutineState>(
builder: (context, state) {
final _bloc = BlocProvider.of<CreateRoutineBloc>(context);
final spaces = _bloc.spacesOnlyWithDevices;
final isLoadingCommunities = state is CommunitiesLoadingState;
final isLoadingSpaces = state is SpaceWithDeviceLoadingState;
String spaceHint = 'Select a community first';
if (_selectedCommunity != null) {
if (isLoadingSpaces) {
spaceHint = 'Loading spaces...';
} else if (spaces.isEmpty) {
spaceHint = 'No spaces available';
} else {
spaceHint = 'Select Space';
}
}
String spaceHint = 'Select a community first';
if (_selectedCommunity != null) {
if (isLoading) {
spaceHint = 'Loading spaces...';
} else if (spaces.isEmpty) {
spaceHint = 'No spaces available';
} else {
spaceHint = 'Select Space';
}
}
return AlertDialog(
backgroundColor: Colors.white,
insetPadding: EdgeInsets.zero,
contentPadding: EdgeInsets.zero,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
title: Text(
'Create New Routines',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: ColorsManager.primaryColor,
),
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Divider(),
Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: CommunityDropdown(
selectedValue: _selectedCommunity,
onChanged: (String? newValue) {
setState(() {
_selectedCommunity = newValue;
_selectedSpace = null;
});
if (newValue != null) {
_fetchSpaces(newValue);
}
},
),
return AlertDialog(
backgroundColor: Colors.white,
insetPadding: EdgeInsets.zero,
contentPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
title: Text(
'Create New Routines',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: ColorsManager.primaryColor,
),
),
const SizedBox(height: 5),
Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: SpaceDropdown(
hintMessage: spaceHint,
spaces: spaces,
selectedValue: _selectedSpace,
onChanged: (String? newValue) {
setState(() {
_selectedSpace = newValue;
});
},
),
),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
content: Stack(
children: [
Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
),
child: TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
'Cancel',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
fontWeight: FontWeight.w400,
fontSize: 14,
color: ColorsManager.blackColor,
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
const Divider(),
Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: CommunityDropdown(
communities: _bloc.communities,
selectedValue: _selectedCommunity,
onChanged: (String? newValue) {
setState(() {
_selectedCommunity = newValue;
_selectedSpace = null;
});
if (newValue != null) {
_bloc.add(SpaceOnlyWithDevicesEvent(newValue));
}
},
),
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
),
child: TextButton(
onPressed:
_selectedCommunity != null && _selectedSpace != null
? () {
Navigator.of(context).pop({
'community': _selectedCommunity,
'space': _selectedSpace,
});
}
: null,
child: Text(
'Next',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
fontWeight: FontWeight.w400,
fontSize: 14,
color: _selectedCommunity != null &&
const SizedBox(height: 5),
Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: SpaceDropdown(
hintMessage: spaceHint,
spaces: spaces,
selectedValue: _selectedSpace,
onChanged: (String? newValue) {
setState(() {
_selectedSpace = newValue;
});
},
),
),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
),
child: TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
'Cancel',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
fontWeight: FontWeight.w400,
fontSize: 14,
color: ColorsManager.blackColor,
),
),
),
),
Padding(
padding: const EdgeInsets.only(
left: 20,
right: 20,
),
child: TextButton(
onPressed: _selectedCommunity != null &&
_selectedSpace != null
? ColorsManager.blueColor
: Colors.blue.shade100,
? () {
Navigator.of(context).pop({
'community': _selectedCommunity,
'space': _selectedSpace,
});
}
: null,
child: Text(
'Next',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(
fontWeight: FontWeight.w400,
fontSize: 14,
color: _selectedCommunity != null &&
_selectedSpace != null
? ColorsManager.blueColor
: Colors.blue.shade100,
),
),
),
),
],
),
const SizedBox(height: 10),
],
),
if (isLoadingCommunities)
const SizedBox(
height: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Center(
child: CircularProgressIndicator(
color: ColorsManager.primaryColor,
),
),
],
),
),
),
],
),
SizedBox(height: 10),
],
),
);
},
);
);
},
));
}
}

View File

@ -1,11 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/ac_dialog.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/one_gang_switch_dialog.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/three_gang_switch_dialog.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/two_gang_switch_dialog.dart';
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/wall_sensor/wall_presence_sensor.dart';
class DeviceDialogHelper {
@ -49,45 +49,46 @@ class DeviceDialogHelper {
final deviceSelectedFunctions =
routineBloc.state.selectedFunctions[data['uniqueCustomId']] ?? [];
if (removeComparetors && data['productType'] != 'WPS') {
//remove the current temp function in the 'if container'
functions.removeAt(3);
}
switch (productType) {
case 'AC':
return ACHelper.showACFunctionsDialog(
context,
functions,
data['device'],
deviceSelectedFunctions,
data['uniqueCustomId'],
removeComparetors);
context: context,
functions: functions,
device: data['device'],
deviceSelectedFunctions: deviceSelectedFunctions,
uniqueCustomId: data['uniqueCustomId'],
removeComparetors: removeComparetors,
dialogType: dialogType,
);
case '1G':
return OneGangSwitchHelper.showSwitchFunctionsDialog(
context,
functions,
data['device'],
deviceSelectedFunctions,
data['uniqueCustomId'],
removeComparetors);
dialogType: dialogType,
context: context,
functions: functions,
device: data['device'],
deviceSelectedFunctions: deviceSelectedFunctions,
uniqueCustomId: data['uniqueCustomId'],
removeComparetors: removeComparetors);
case '2G':
return TwoGangSwitchHelper.showSwitchFunctionsDialog(
context,
functions,
data['device'],
deviceSelectedFunctions,
data['uniqueCustomId'],
removeComparetors);
dialogType: dialogType,
context: context,
functions: functions,
device: data['device'],
deviceSelectedFunctions: deviceSelectedFunctions,
uniqueCustomId: data['uniqueCustomId'],
removeComparetors: removeComparetors);
case '3G':
return ThreeGangSwitchHelper.showSwitchFunctionsDialog(
context,
functions,
data['device'],
deviceSelectedFunctions,
data['uniqueCustomId'],
removeComparetors);
dialogType: dialogType,
context: context,
functions: functions,
device: data['device'],
deviceSelectedFunctions: deviceSelectedFunctions,
uniqueCustomId: data['uniqueCustomId'],
removeComparetors: removeComparetors);
case 'WPS':
return WallPresenceSensor.showWPSFunctionsDialog(
dialogType: dialogType,

View File

@ -5,23 +5,28 @@ import 'package:syncrow_web/utils/constants/app_enum.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
abstract class ACFunction extends DeviceFunction<AcStatusModel> {
final String type;
ACFunction({
required super.deviceId,
required super.deviceName,
required super.code,
required super.operationName,
required super.icon,
required this.type,
});
List<ACOperationalValue> getOperationalValues();
}
class SwitchFunction extends ACFunction {
SwitchFunction({required super.deviceId, required super.deviceName})
SwitchFunction(
{required super.deviceId, required super.deviceName, required type})
: super(
code: 'switch',
operationName: 'Power',
icon: Assets.assetsAcPower,
type: type,
);
@override
@ -40,11 +45,13 @@ class SwitchFunction extends ACFunction {
}
class ModeFunction extends ACFunction {
ModeFunction({required super.deviceId, required super.deviceName})
ModeFunction(
{required super.deviceId, required super.deviceName, required type})
: super(
code: 'mode',
operationName: 'Mode',
icon: Assets.assetsFreezing,
type: type,
);
@override
@ -72,7 +79,8 @@ class TempSetFunction extends ACFunction {
final int max;
final int step;
TempSetFunction({required super.deviceId, required super.deviceName})
TempSetFunction(
{required super.deviceId, required super.deviceName, required type})
: min = 160,
max = 300,
step = 1,
@ -80,6 +88,7 @@ class TempSetFunction extends ACFunction {
code: 'temp_set',
operationName: 'Set Temperature',
icon: Assets.assetsTempreture,
type: type,
);
@override
@ -97,8 +106,10 @@ class TempSetFunction extends ACFunction {
}
class LevelFunction extends ACFunction {
LevelFunction({required super.deviceId, required super.deviceName})
LevelFunction(
{required super.deviceId, required super.deviceName, required type})
: super(
type: type,
code: 'level',
operationName: 'Fan Speed',
icon: Assets.assetsFanSpeed,
@ -130,8 +141,10 @@ class LevelFunction extends ACFunction {
}
class ChildLockFunction extends ACFunction {
ChildLockFunction({required super.deviceId, required super.deviceName})
ChildLockFunction(
{required super.deviceId, required super.deviceName, required type})
: super(
type: type,
code: 'child_lock',
operationName: 'Child Lock',
icon: Assets.assetsChildLock,
@ -157,11 +170,13 @@ class CurrentTempFunction extends ACFunction {
final int max;
final int step;
CurrentTempFunction({required super.deviceId, required super.deviceName})
CurrentTempFunction(
{required super.deviceId, required super.deviceName, required type})
: min = -100,
max = 990,
step = 1,
super(
type: type,
code: 'temp_current',
operationName: 'Current Temperature',
icon: Assets.currentTemp,

View File

@ -3,7 +3,7 @@ import 'package:syncrow_web/pages/routines/models/gang_switches/switch_operation
import 'package:syncrow_web/utils/constants/assets.dart';
class ThreeGangSwitch1Function extends BaseSwitchFunction {
ThreeGangSwitch1Function({required super.deviceId, required super.deviceName})
ThreeGangSwitch1Function({required super.deviceId, required super.deviceName ,required type})
: super(
code: 'switch_1',
operationName: 'Light 1 Switch',
@ -26,7 +26,7 @@ class ThreeGangSwitch1Function extends BaseSwitchFunction {
}
class ThreeGangCountdown1Function extends BaseSwitchFunction {
ThreeGangCountdown1Function({required super.deviceId, required super.deviceName})
ThreeGangCountdown1Function({required super.deviceId, required super.deviceName ,required type})
: super(
code: 'countdown_1',
operationName: 'Light 1 Countdown',
@ -47,7 +47,7 @@ class ThreeGangCountdown1Function extends BaseSwitchFunction {
}
class ThreeGangSwitch2Function extends BaseSwitchFunction {
ThreeGangSwitch2Function({required super.deviceId, required super.deviceName})
ThreeGangSwitch2Function({required super.deviceId, required super.deviceName, required type})
: super(
code: 'switch_2',
operationName: 'Light 2 Switch',
@ -70,7 +70,7 @@ class ThreeGangSwitch2Function extends BaseSwitchFunction {
}
class ThreeGangCountdown2Function extends BaseSwitchFunction {
ThreeGangCountdown2Function({required super.deviceId, required super.deviceName})
ThreeGangCountdown2Function({required super.deviceId, required super.deviceName ,required type})
: super(
code: 'countdown_2',
operationName: 'Light 2 Countdown',
@ -91,7 +91,7 @@ class ThreeGangCountdown2Function extends BaseSwitchFunction {
}
class ThreeGangSwitch3Function extends BaseSwitchFunction {
ThreeGangSwitch3Function({required super.deviceId, required super.deviceName})
ThreeGangSwitch3Function({required super.deviceId, required super.deviceName ,required type})
: super(
code: 'switch_3',
operationName: 'Light 3 Switch',
@ -114,7 +114,7 @@ class ThreeGangSwitch3Function extends BaseSwitchFunction {
}
class ThreeGangCountdown3Function extends BaseSwitchFunction {
ThreeGangCountdown3Function({required super.deviceId, required super.deviceName})
ThreeGangCountdown3Function({required super.deviceId, required super.deviceName ,required type})
: super(
code: 'countdown_3',
operationName: 'Light 3 Countdown',

View File

@ -1,5 +1,3 @@
import 'package:syncrow_web/pages/device_managment/wall_sensor/model/wall_sensor_model.dart';
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
import 'package:syncrow_web/pages/routines/models/wps/wps_operational_value.dart';
@ -195,7 +193,7 @@ class NoOneTimeFunction extends WpsFunctions {
WpsOperationalValue(
icon: icon,
description: 'Custom $unit',
value: null,
value: null,
)
];
}
@ -216,12 +214,12 @@ class PresenceStateFunction extends WpsFunctions {
WpsOperationalValue(
icon: Assets.assetsAcPower,
description: "None",
value: true,
value: 'none',
),
WpsOperationalValue(
icon: Assets.presenceStateIcon,
description: "Presence",
value: false,
value: 'presence',
),
];
}
@ -238,7 +236,7 @@ class CurrentDistanceFunction extends WpsFunctions {
step = 1,
super(
type: type,
code: 'current_distance',
code: 'dis_current',
operationName: 'Current Distance',
icon: Assets.currentDistanceIcon,
);
@ -246,11 +244,12 @@ class CurrentDistanceFunction extends WpsFunctions {
@override
List<WpsOperationalValue> getOperationalValues() {
List<WpsOperationalValue> values = [];
for (int temp = min; temp <= max; temp += step) {
for (int cm = min; cm <= max; cm += step) {
values.add(WpsOperationalValue(
icon: Assets.assetsTempreture,
description: "${temp}CM",
value: temp,
description: "${cm}CM",
value: cm,
));
}
return values;

View File

@ -71,7 +71,8 @@ class IfContainer extends StatelessWidget {
'1G',
'2G',
'3G',
'WPS'
'WPS',
'CPS',
].contains(
state.ifItems[index]['productType'])) {
context.read<RoutineBloc>().add(
@ -105,9 +106,7 @@ class IfContainer extends StatelessWidget {
);
},
onAcceptWithDetails: (data) async {
print('data.data=${data.data}');
final uniqueCustomId = const Uuid().v4();
final mutableData = Map<String, dynamic>.from(data.data);
mutableData['uniqueCustomId'] = uniqueCustomId;
@ -131,7 +130,7 @@ class IfContainer extends StatelessWidget {
context
.read<RoutineBloc>()
.add(AddToIfContainer(mutableData, false));
} else if (!['AC', '1G', '2G', '3G', 'WPS']
} else if (!['AC', '1G', '2G', '3G', 'WPS', 'CPS']
.contains(mutableData['productType'])) {
context
.read<RoutineBloc>()

View File

@ -31,165 +31,185 @@ class _FetchRoutineScenesState extends State<FetchRoutineScenesAutomation>
? const Center(
child: CircularProgressIndicator(),
)
: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Scenes (Tab to Run)",
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
if (state.scenes.isEmpty)
Expanded(
child: Text(
: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
"Scenes (Tab to Run)",
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
if (state.scenes.isEmpty)
Text(
"No scenes found",
style: context.textTheme.bodyMedium?.copyWith(
color: ColorsManager.grayColor,
),
),
),
if (state.scenes.isNotEmpty)
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: isSmallScreenSize(context) ? 190 : 200,
maxWidth: MediaQuery.sizeOf(context).width * 0.8),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: state.scenes.length,
itemBuilder: (context, index) {
final scene = state.scenes[index];
final isLoading =
state.loadingSceneId == scene.id;
if (state.scenes.isNotEmpty)
SizedBox(
height: 200,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: state.scenes.length,
itemBuilder: (context, index) {
final scene = state.scenes[index];
final isLoading =
state.loadingSceneId == scene.id;
return Padding(
padding: EdgeInsets.only(
right: isSmallScreenSize(context) ? 4.0 : 8.0,
),
child: RoutineViewCard(
isLoading: isLoading,
sceneOnTap: () {
context.read<RoutineBloc>().add(
SceneTrigger(
sceneId: scene.id,
name: scene.name));
},
status: state.scenes[index].status,
communityId:
state.scenes[index].communityId ?? '',
spaceId: state.scenes[index].spaceId,
sceneId: state.scenes[index].sceneTuyaId!,
automationId: state.scenes[index].id,
cardType: 'scenes',
spaceName: state.scenes[index].spaceName,
onTap: () {
BlocProvider.of<RoutineBloc>(context).add(
const CreateNewRoutineViewEvent(
createRoutineView: true),
);
context.read<RoutineBloc>().add(
GetSceneDetails(
sceneId: state.scenes[index].id,
isTabToRun: true,
isUpdate: true,
),
);
},
textString: state.scenes[index].name,
icon: state.scenes[index].icon ??
Assets.logoHorizontal,
isFromScenes: true,
iconInBytes: state.scenes[index].iconInBytes,
),
);
}),
return Padding(
padding: EdgeInsets.only(
right:
isSmallScreenSize(context) ? 4.0 : 8.0,
),
child: Column(
children: [
RoutineViewCard(
isLoading: isLoading,
sceneOnTap: () {
context.read<RoutineBloc>().add(
SceneTrigger(
sceneId: scene.id,
name: scene.name));
},
status: state.scenes[index].status,
communityId:
state.scenes[index].communityId ??
'',
spaceId: state.scenes[index].spaceId,
sceneId:
state.scenes[index].sceneTuyaId!,
automationId: state.scenes[index].id,
cardType: 'scenes',
spaceName:
state.scenes[index].spaceName,
onTap: () {
BlocProvider.of<RoutineBloc>(context)
.add(
const CreateNewRoutineViewEvent(
createRoutineView: true),
);
context.read<RoutineBloc>().add(
GetSceneDetails(
sceneId:
state.scenes[index].id,
isTabToRun: true,
isUpdate: true,
),
);
},
textString: state.scenes[index].name,
icon: state.scenes[index].icon ??
Assets.logoHorizontal,
isFromScenes: true,
iconInBytes:
state.scenes[index].iconInBytes,
),
],
),
);
}),
),
const SizedBox(height: 10),
Text(
"Automations",
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
Text(
"Automations",
style: Theme.of(context).textTheme.titleLarge?.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 3),
if (state.automations.isEmpty)
Expanded(
child: Text(
const SizedBox(height: 3),
if (state.automations.isEmpty)
Text(
"No automations found",
style: context.textTheme.bodyMedium?.copyWith(
color: ColorsManager.grayColor,
),
),
),
if (state.automations.isNotEmpty)
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: isSmallScreenSize(context) ? 190 : 195,
),
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: state.automations.length,
itemBuilder: (context, index) {
final isLoading = state.automations!
.contains(state.automations[index].id);
if (state.automations.isNotEmpty)
SizedBox(
height: 200,
return Padding(
padding: EdgeInsets.only(
right: isSmallScreenSize(context) ? 4.0 : 8.0,
),
child: RoutineViewCard(
isLoading: isLoading,
onChanged: (v) {
// BlocProvider.of<RoutineBloc>(context)
context.read<RoutineBloc>().add(
UpdateAutomationStatus(
automationId:
state.automations[index].id,
automationStatusUpdate:
AutomationStatusUpdate(
spaceUuid: state
.automations[index]
.spaceId,
isEnable: v),
communityId: state
.automations[index].communityId,
),
);
},
status: state.automations[index].status,
communityId: '',
spaceId: state.automations[index].spaceId,
sceneId: '',
automationId: state.automations[index].id,
cardType: 'automations',
spaceName: state.scenes[index].spaceName,
onTap: () {
BlocProvider.of<RoutineBloc>(context).add(
const CreateNewRoutineViewEvent(
createRoutineView: true),
);
context.read<RoutineBloc>().add(
GetAutomationDetails(
automationId:
state.automations[index].id,
isAutomation: true,
isUpdate: true),
);
},
textString: state.automations[index].name,
icon: state.automations[index].icon ??
Assets.automation,
),
);
}),
),
],
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: state.automations.length,
itemBuilder: (context, index) {
final isLoading = state.automations!
.contains(state.automations[index].id);
return Column(
children: [
Padding(
padding: EdgeInsets.only(
right: isSmallScreenSize(context)
? 4.0
: 8.0,
),
child: RoutineViewCard(
isLoading: isLoading,
onChanged: (v) {
context.read<RoutineBloc>().add(
UpdateAutomationStatus(
automationId: state
.automations[index].id,
automationStatusUpdate:
AutomationStatusUpdate(
spaceUuid: state
.automations[
index]
.spaceId,
isEnable: v),
communityId: state
.automations[index]
.communityId,
),
);
},
status: state.automations[index].status,
communityId: '',
spaceId:
state.automations[index].spaceId,
sceneId: '',
automationId:
state.automations[index].id,
cardType: 'automations',
spaceName:
state.scenes[index].spaceName,
onTap: () {
BlocProvider.of<RoutineBloc>(context)
.add(
const CreateNewRoutineViewEvent(
createRoutineView: true),
);
context.read<RoutineBloc>().add(
GetAutomationDetails(
automationId: state
.automations[index].id,
isAutomation: true,
isUpdate: true),
);
},
textString:
state.automations[index].name,
icon: state.automations[index].icon ??
Assets.automation,
),
),
],
);
}),
),
],
),
),
);
},

View File

@ -177,6 +177,8 @@ class _RoutineViewCardState extends State<RoutineViewCard> {
: (widget.icon is String &&
widget.icon.endsWith('.svg'))
? SvgPicture.asset(
height: iconSize,
width: iconSize,
widget.icon,
fit: BoxFit.contain,
)

View File

@ -38,7 +38,8 @@ class _RoutineDevicesState extends State<RoutineDevices> {
device.productType == '1G' ||
device.productType == '2G' ||
device.productType == '3G' ||
device.productType == 'WPS')
device.productType == 'WPS' ||
device.productType == 'CPS')
.toList();
return Wrap(

View File

@ -13,29 +13,38 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
class ACHelper {
static Future<Map<String, dynamic>?> showACFunctionsDialog(
BuildContext context,
List<DeviceFunction> functions,
AllDevicesModel? device,
List<DeviceFunctionData>? deviceSelectedFunctions,
String uniqueCustomId,
bool? removeComparetors,
) async {
List<ACFunction> acFunctions = functions.whereType<ACFunction>().toList();
static Future<Map<String, dynamic>?> showACFunctionsDialog({
required BuildContext context,
required List<DeviceFunction> functions,
required AllDevicesModel? device,
required List<DeviceFunctionData>? deviceSelectedFunctions,
required String uniqueCustomId,
required bool? removeComparetors,
required String dialogType,
}) async {
List<ACFunction> acFunctions =
functions.whereType<ACFunction>().where((function) {
if (dialogType == 'THEN') {
return function.type == 'THEN' || function.type == 'BOTH';
}
return function.type == 'IF' || function.type == 'BOTH';
}).toList();
// List<ACFunction> acFunctions = functions.whereType<ACFunction>().toList();
return showDialog<Map<String, dynamic>?>(
context: context,
builder: (BuildContext context) {
return BlocProvider(
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
create: (_) => FunctionBloc()
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
child: AlertDialog(
contentPadding: EdgeInsets.zero,
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
builder: (context, state) {
final selectedFunction = state.selectedFunction;
final selectedOperationName = state.selectedOperationName;
final selectedFunctionData =
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
final selectedFunctionData = state.addedFunctions
.firstWhere((f) => f.functionCode == selectedFunction,
orElse: () => DeviceFunctionData(
entityId: '',
functionCode: selectedFunction ?? '',
@ -65,8 +74,10 @@ class ACHelper {
child: _buildFunctionsList(
context: context,
acFunctions: acFunctions,
onFunctionSelected: (functionCode, operationName) =>
context.read<FunctionBloc>().add(SelectFunction(
onFunctionSelected:
(functionCode, operationName) => context
.read<FunctionBloc>()
.add(SelectFunction(
functionCode: functionCode,
operationName: operationName,
)),
@ -194,7 +205,8 @@ class ACHelper {
);
}
final selectedFn = acFunctions.firstWhere((f) => f.code == selectedFunction);
final selectedFn =
acFunctions.firstWhere((f) => f.code == selectedFunction);
final values = selectedFn.getOperationalValues();
return _buildOperationalValuesList(
@ -290,7 +302,8 @@ class ACHelper {
minHeight: 40.0,
minWidth: 40.0,
),
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
isSelected:
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
children: conditions.map((c) => Text(c)).toList(),
);
}
@ -384,9 +397,13 @@ class ACHelper {
style: context.textTheme.bodyMedium,
),
trailing: Icon(
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
isSelected
? Icons.radio_button_checked
: Icons.radio_button_unchecked,
size: 24,
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
color: isSelected
? ColorsManager.primaryColorWithOpacity
: ColorsManager.textGray,
),
onTap: () {
if (!isSelected) {
@ -398,7 +415,8 @@ class ACHelper {
operationName: operationName,
value: value.value,
condition: selectedFunctionData?.condition,
valueDescription: selectedFunctionData?.valueDescription,
valueDescription:
selectedFunctionData?.valueDescription,
),
),
);

View File

@ -5,8 +5,10 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routines/helper/duration_format_helper.dart';
import 'package:syncrow_web/pages/routines/models/ac/ac_function.dart';
import 'package:syncrow_web/pages/routines/models/device_functions.dart';
import 'package:syncrow_web/pages/routines/models/gang_switches/base_switch_function.dart';
import 'package:syncrow_web/pages/routines/models/gang_switches/one_gang_switch/one_gang_switch.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_header.dart';
@ -14,29 +16,32 @@ import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
class OneGangSwitchHelper {
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog(
BuildContext context,
List<DeviceFunction> functions,
AllDevicesModel? device,
List<DeviceFunctionData>? deviceSelectedFunctions,
String uniqueCustomId,
bool removeComparetors,
) async {
List<BaseSwitchFunction> acFunctions = functions.whereType<BaseSwitchFunction>().toList();
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog({
required String dialogType,
required BuildContext context,
required List<DeviceFunction> functions,
required AllDevicesModel? device,
required List<DeviceFunctionData>? deviceSelectedFunctions,
required String uniqueCustomId,
required bool removeComparetors,
}) async {
List<BaseSwitchFunction> oneGangFunctions =
functions.whereType<BaseSwitchFunction>().toList();
return showDialog<Map<String, dynamic>?>(
context: context,
builder: (BuildContext context) {
return BlocProvider(
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
create: (_) => FunctionBloc()
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
child: AlertDialog(
contentPadding: EdgeInsets.zero,
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
builder: (context, state) {
final selectedFunction = state.selectedFunction;
final selectedOperationName = state.selectedOperationName;
final selectedFunctionData =
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
final selectedFunctionData = state.addedFunctions
.firstWhere((f) => f.functionCode == selectedFunction,
orElse: () => DeviceFunctionData(
entityId: '',
functionCode: selectedFunction ?? '',
@ -61,12 +66,12 @@ class OneGangSwitchHelper {
// Left side: Function list
Expanded(
child: ListView.separated(
itemCount: acFunctions.length,
itemCount: oneGangFunctions.length,
separatorBuilder: (_, __) => const Divider(
color: ColorsManager.dividerColor,
),
itemBuilder: (context, index) {
final function = acFunctions[index];
final function = oneGangFunctions[index];
return ListTile(
leading: SvgPicture.asset(
function.icon,
@ -83,9 +88,12 @@ class OneGangSwitchHelper {
color: ColorsManager.textGray,
),
onTap: () {
context.read<FunctionBloc>().add(SelectFunction(
context
.read<FunctionBloc>()
.add(SelectFunction(
functionCode: function.code,
operationName: function.operationName,
operationName:
function.operationName,
));
},
);
@ -99,7 +107,7 @@ class OneGangSwitchHelper {
context: context,
selectedFunction: selectedFunction,
selectedFunctionData: selectedFunctionData,
acFunctions: acFunctions,
acFunctions: oneGangFunctions,
device: device,
operationName: selectedOperationName ?? '',
removeComparetors: removeComparetors,
@ -174,8 +182,14 @@ class OneGangSwitchHelper {
removeComparetors: removeComparetors,
);
}
final selectedFn = acFunctions.firstWhere(
(f) => f.code == selectedFunction,
orElse: () => OneGangSwitchFunction(
deviceId: '',
deviceName: '',
),
);
final selectedFn = acFunctions.firstWhere((f) => f.code == selectedFunction);
final values = selectedFn.getOperationalValues();
return _buildOperationalValuesList(
@ -212,11 +226,11 @@ class OneGangSwitchHelper {
selectedFunctionData,
),
const SizedBox(height: 20),
_buildCountDownDisplay(
context, initialValue, device, operationName, selectedFunctionData, selectCode),
_buildCountDownDisplay(context, initialValue, device, operationName,
selectedFunctionData, selectCode),
const SizedBox(height: 20),
_buildCountDownSlider(
context, initialValue, device, operationName, selectedFunctionData, selectCode),
_buildCountDownSlider(context, initialValue, device, operationName,
selectedFunctionData, selectCode),
],
);
}
@ -257,7 +271,8 @@ class OneGangSwitchHelper {
minHeight: 40.0,
minWidth: 40.0,
),
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
isSelected:
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
children: conditions.map((c) => Text(c)).toList(),
);
}
@ -305,7 +320,8 @@ class OneGangSwitchHelper {
value: (initialValue ?? 0).toDouble(),
min: operationalValues.minValue?.toDouble() ?? 0.0,
max: operationalValues.maxValue?.toDouble() ?? 0.0,
divisions: (((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
divisions: (((operationalValues.maxValue ?? 0) -
(operationalValues.minValue ?? 0)) /
(operationalValues.stepValue ?? 1))
.round(),
onChanged: (value) {
@ -357,9 +373,13 @@ class OneGangSwitchHelper {
style: context.textTheme.bodyMedium,
),
trailing: Icon(
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
isSelected
? Icons.radio_button_checked
: Icons.radio_button_unchecked,
size: 24,
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
color: isSelected
? ColorsManager.primaryColorWithOpacity
: ColorsManager.textGray,
),
onTap: () {
if (!isSelected) {
@ -371,7 +391,8 @@ class OneGangSwitchHelper {
operationName: operationName,
value: value.value,
condition: selectedFunctionData?.condition,
valueDescription: selectedFunctionData?.valueDescription,
valueDescription:
selectedFunctionData?.valueDescription,
),
),
);

View File

@ -14,14 +14,15 @@ import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
class ThreeGangSwitchHelper {
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog(
BuildContext context,
List<DeviceFunction> functions,
AllDevicesModel? device,
List<DeviceFunctionData>? deviceSelectedFunctions,
String uniqueCustomId,
bool removeComparetors,
) async {
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog({
required BuildContext context,
required List<DeviceFunction> functions,
required AllDevicesModel? device,
required List<DeviceFunctionData>? deviceSelectedFunctions,
required String uniqueCustomId,
required String dialogType,
required bool removeComparetors,
}) async {
List<BaseSwitchFunction> switchFunctions =
functions.whereType<BaseSwitchFunction>().toList();

View File

@ -14,29 +14,32 @@ import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
class TwoGangSwitchHelper {
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog(
BuildContext context,
List<DeviceFunction> functions,
AllDevicesModel? device,
List<DeviceFunctionData>? deviceSelectedFunctions,
String uniqueCustomId,
bool removeComparetors,
) async {
List<BaseSwitchFunction> switchFunctions = functions.whereType<BaseSwitchFunction>().toList();
static Future<Map<String, dynamic>?> showSwitchFunctionsDialog({
required BuildContext context,
required List<DeviceFunction> functions,
required AllDevicesModel? device,
required List<DeviceFunctionData>? deviceSelectedFunctions,
required String uniqueCustomId,
required bool removeComparetors,
required String dialogType,
}) async {
List<BaseSwitchFunction> switchFunctions =
functions.whereType<BaseSwitchFunction>().toList();
return showDialog<Map<String, dynamic>?>(
context: context,
builder: (BuildContext context) {
return BlocProvider(
create: (_) => FunctionBloc()..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
create: (_) => FunctionBloc()
..add(InitializeFunctions(deviceSelectedFunctions ?? [])),
child: AlertDialog(
contentPadding: EdgeInsets.zero,
content: BlocBuilder<FunctionBloc, FunctionBlocState>(
builder: (context, state) {
final selectedFunction = state.selectedFunction;
final selectedOperationName = state.selectedOperationName;
final selectedFunctionData =
state.addedFunctions.firstWhere((f) => f.functionCode == selectedFunction,
final selectedFunctionData = state.addedFunctions
.firstWhere((f) => f.functionCode == selectedFunction,
orElse: () => DeviceFunctionData(
entityId: '',
functionCode: selectedFunction ?? '',
@ -83,9 +86,12 @@ class TwoGangSwitchHelper {
color: ColorsManager.textGray,
),
onTap: () {
context.read<FunctionBloc>().add(SelectFunction(
context
.read<FunctionBloc>()
.add(SelectFunction(
functionCode: function.code,
operationName: function.operationName,
operationName:
function.operationName,
));
},
);
@ -161,7 +167,8 @@ class TwoGangSwitchHelper {
required String operationName,
required bool removeComparetors,
}) {
if (selectedFunction == 'countdown_1' || selectedFunction == 'countdown_2') {
if (selectedFunction == 'countdown_1' ||
selectedFunction == 'countdown_2') {
final initialValue = selectedFunctionData?.value ?? 200;
return _buildTemperatureSelector(
context: context,
@ -175,7 +182,8 @@ class TwoGangSwitchHelper {
);
}
final selectedFn = switchFunctions.firstWhere((f) => f.code == selectedFunction);
final selectedFn =
switchFunctions.firstWhere((f) => f.code == selectedFunction);
final values = selectedFn.getOperationalValues();
return _buildOperationalValuesList(
@ -212,11 +220,11 @@ class TwoGangSwitchHelper {
selectedFunctionData,
),
const SizedBox(height: 20),
_buildCountDownDisplay(
context, initialValue, device, operationName, selectedFunctionData, selectCode),
_buildCountDownDisplay(context, initialValue, device, operationName,
selectedFunctionData, selectCode),
const SizedBox(height: 20),
_buildCountDownSlider(
context, initialValue, device, operationName, selectedFunctionData, selectCode),
_buildCountDownSlider(context, initialValue, device, operationName,
selectedFunctionData, selectCode),
],
);
}
@ -257,7 +265,8 @@ class TwoGangSwitchHelper {
minHeight: 40.0,
minWidth: 40.0,
),
isSelected: conditions.map((c) => c == (currentCondition ?? "==")).toList(),
isSelected:
conditions.map((c) => c == (currentCondition ?? "==")).toList(),
children: conditions.map((c) => Text(c)).toList(),
);
}
@ -305,7 +314,8 @@ class TwoGangSwitchHelper {
value: (initialValue ?? 0).toDouble(),
min: operationalValues.minValue?.toDouble() ?? 0.0,
max: operationalValues.maxValue?.toDouble() ?? 0.0,
divisions: (((operationalValues.maxValue ?? 0) - (operationalValues.minValue ?? 0)) /
divisions: (((operationalValues.maxValue ?? 0) -
(operationalValues.minValue ?? 0)) /
(operationalValues.stepValue ?? 1))
.round(),
onChanged: (value) {
@ -357,9 +367,13 @@ class TwoGangSwitchHelper {
style: context.textTheme.bodyMedium,
),
trailing: Icon(
isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked,
isSelected
? Icons.radio_button_checked
: Icons.radio_button_unchecked,
size: 24,
color: isSelected ? ColorsManager.primaryColorWithOpacity : ColorsManager.textGray,
color: isSelected
? ColorsManager.primaryColorWithOpacity
: ColorsManager.textGray,
),
onTap: () {
if (!isSelected) {
@ -371,7 +385,8 @@ class TwoGangSwitchHelper {
operationName: operationName,
value: value.value,
condition: selectedFunctionData?.condition,
valueDescription: selectedFunctionData?.valueDescription,
valueDescription:
selectedFunctionData?.valueDescription,
),
),
);

View File

@ -13,7 +13,6 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/routines/bloc/functions_bloc/functions_bloc_bloc.dart';
class WallPresenceSensor extends StatefulWidget {
final List<DeviceFunction> functions;
final AllDevicesModel? device;
@ -171,7 +170,7 @@ class _WallPresenceSensorState extends State<WallPresenceSensor> {
orElse: () => DeviceFunctionData(
entityId: '',
functionCode: selectedFunction,
operationName: '',
operationName: state.selectedOperationName ?? '',
value: null,
),
);
@ -251,11 +250,8 @@ class _ValueSelector extends StatelessWidget {
);
}
bool _isSliderFunction(String function) => [
'current_distance',
'presence_time',
'illuminance_value'
].contains(function);
bool _isSliderFunction(String function) =>
['dis_current', 'presence_time', 'illuminance_value'].contains(function);
}
class _SliderValueSelector extends StatelessWidget {
@ -382,7 +378,7 @@ class _ValueDisplay extends StatelessWidget {
switch (functionCode) {
case 'presence_time':
return '$intValue Min';
case 'current_distance':
case 'dis_current':
return '$intValue CM';
case 'illuminance_value':
return '$intValue Lux';
@ -421,7 +417,7 @@ class _FunctionSlider extends StatelessWidget {
switch (functionCode) {
case 'presence_time':
return (0, 65535);
case 'current_distance':
case 'dis_current':
return (1, 600);
case 'illuminance_value':
return (0, 10000);

View File

@ -3,10 +3,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/automation_dialog.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/delay_dialog.dart';
import 'package:syncrow_web/pages/routines/helper/dialog_helper/device_dialog_helper.dart';
import 'package:syncrow_web/pages/routines/widgets/dragable_card.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/automation_dialog.dart';
import 'package:syncrow_web/pages/routines/widgets/routine_dialogs/delay_dialog.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:uuid/uuid.dart';
@ -113,7 +113,8 @@ class ThenContainer extends StatelessWidget {
'1G',
'2G',
'3G',
'WPS'
'WPS',
'CPS',
].contains(state.thenItems[index]
['productType'])) {
context.read<RoutineBloc>().add(
@ -229,7 +230,7 @@ class ThenContainer extends StatelessWidget {
dialogType: "THEN");
if (result != null) {
context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
} else if (!['AC', '1G', '2G', '3G', 'WPS']
} else if (!['AC', '1G', '2G', '3G', 'WPS', 'CPS']
.contains(mutableData['productType'])) {
context.read<RoutineBloc>().add(AddToThenContainer(mutableData));
}