Merged with dev

This commit is contained in:
Abdullah Alassaf
2025-04-06 01:17:30 +03:00
13 changed files with 481 additions and 319 deletions
@@ -2,14 +2,17 @@ import 'package:flutter/foundation.dart';
class FactoryResetModel {
final List<String> devicesUuid;
final String operationType;
FactoryResetModel({
required this.devicesUuid,
this.operationType = "RESET",
});
factory FactoryResetModel.fromJson(Map<String, dynamic> json) {
return FactoryResetModel(
devicesUuid: List<String>.from(json['devicesUuid']),
operationType: "RESET",
);
}
@@ -12,77 +12,95 @@ class DeviceSearchFilters extends StatefulWidget {
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
}
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout {
final TextEditingController communityController = TextEditingController();
final TextEditingController unitNameController = TextEditingController();
final TextEditingController productNameController = TextEditingController();
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
with HelperResponsiveLayout {
late final TextEditingController _unitNameController;
late final TextEditingController _productNameController;
@override
void initState() {
_unitNameController = TextEditingController();
_productNameController = TextEditingController();
super.initState();
}
@override
void dispose() {
_unitNameController.dispose();
_productNameController.dispose();
super.dispose();
}
List<Widget> get _widgets => [
_buildSearchField(
"Space Name",
_unitNameController,
200,
),
_buildSearchField(
"Device Name / Product Name",
_productNameController,
300,
),
_buildSearchResetButtons(),
];
@override
Widget build(BuildContext context) {
return isExtraLargeScreenSize(context)
? Row(
children: [
_buildSearchField("Community", communityController, 200),
const SizedBox(width: 20),
_buildSearchField("Space Name", unitNameController, 200),
const SizedBox(width: 20),
_buildSearchField("Device Name / Product Name", productNameController, 300),
const SizedBox(width: 20),
_buildSearchResetButtons(),
],
)
: Wrap(
spacing: 20,
runSpacing: 10,
children: [
_buildSearchField(
"Community",
communityController,
200,
),
_buildSearchField("Space Name", unitNameController, 200),
_buildSearchField(
"Device Name / Product Name",
productNameController,
300,
),
_buildSearchResetButtons(),
],
);
if (isExtraLargeScreenSize(context)) {
return Row(
children: _widgets.map(
(e) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: e,
);
},
).toList(),
);
}
return Wrap(
spacing: 20,
runSpacing: 10,
children: _widgets,
);
}
Widget _buildSearchField(String title, TextEditingController controller, double width) {
return Container(
child: StatefulTextField(
title: title,
width: width,
elevation: 2,
controller: controller,
onSubmitted: () {
context.read<DeviceManagementBloc>().add(SearchDevices(
productName: productNameController.text,
unitName: unitNameController.text,
community: communityController.text,
searchField: true));
},
onChanged: (p0) {},
),
Widget _buildSearchField(
String title,
TextEditingController controller,
double width,
) {
return StatefulTextField(
title: title,
width: width,
elevation: 2,
controller: controller,
onSubmitted: () {
final searchDevicesEvent = SearchDevices(
productName: _productNameController.text,
unitName: _unitNameController.text,
searchField: true,
);
context.read<DeviceManagementBloc>().add(searchDevicesEvent);
},
onChanged: (p0) {},
);
}
Widget _buildSearchResetButtons() {
return SearchResetButtons(
onSearch: () {
context.read<DeviceManagementBloc>().add(SearchDevices(
community: communityController.text,
unitName: unitNameController.text,
productName: productNameController.text,
searchField: true));
},
onSearch: () => context.read<DeviceManagementBloc>().add(
SearchDevices(
unitName: _unitNameController.text,
productName: _productNameController.text,
searchField: true,
),
),
onReset: () {
communityController.clear();
unitNameController.clear();
productNameController.clear();
_unitNameController.clear();
_productNameController.clear();
context.read<DeviceManagementBloc>()
..add(ResetFilters())
..add(FetchDevices(context));
@@ -1,16 +1,16 @@
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';
import 'package:syncrow_web/utils/style.dart';
class CommunityDropdown extends StatelessWidget {
final String? selectedValue;
final Function(String?) onChanged;
final TextEditingController _searchController = TextEditingController();
const CommunityDropdown({
CommunityDropdown({
Key? key,
required this.selectedValue,
required this.onChanged,
@@ -34,58 +34,119 @@ class CommunityDropdown extends StatelessWidget {
const SizedBox(height: 8),
BlocBuilder<SpaceTreeBloc, SpaceTreeState>(
builder: (context, state) {
List<CommunityModel> communities =
state.searchQuery.isNotEmpty ? state.filteredCommunity : state.communityList;
return SizedBox(
child: DropdownButtonFormField<String>(
dropdownColor: ColorsManager.whiteColors,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
child: DropdownButton2<String>(
underline: SizedBox(),
value: selectedValue,
items: communities.map((community) {
items: state.communityList.map((community) {
return DropdownMenuItem<String>(
value: community.uuid,
child: Text(' ${community.name}'),
child: Text(
' ${community.name}',
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
);
}).toList(),
onChanged: onChanged,
icon: const SizedBox.shrink(),
borderRadius: const BorderRadius.all(Radius.circular(10)),
style: TextStyle(color: Colors.black),
hint: Padding(
padding: EdgeInsets.only(left: 10),
child: Text(
"Please Select",
" Please Select",
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.textGray,
),
),
),
decoration: inputTextFormDeco().copyWith(
contentPadding: EdgeInsets.zero,
suffixIcon: Container(
padding: EdgeInsets.zero,
width: 70,
height: 45,
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: const BorderRadius.only(
bottomRight: Radius.circular(10),
topRight: Radius.circular(10),
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,
),
),
border: Border.all(
color: ColorsManager.textGray,
width: 1.0,
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,
),
),
),
),
child: const Center(
child: 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),
),
),
),
),
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,
),
),
);
));
},
),
],
@@ -62,28 +62,34 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
mainAxisSize: MainAxisSize.min,
children: [
const Divider(),
CommunityDropdown(
selectedValue: _selectedCommunity,
onChanged: (String? newValue) {
setState(() {
_selectedCommunity = newValue;
_selectedSpace = null;
});
if (newValue != null) {
_fetchSpaces(newValue);
}
},
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);
}
},
),
),
const SizedBox(height: 16),
SpaceDropdown(
hintMessage: spaceHint,
spaces: spaces,
selectedValue: _selectedSpace,
onChanged: (String? newValue) {
setState(() {
_selectedSpace = newValue;
});
},
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(
@@ -96,7 +102,6 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
),
child: TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
@@ -139,6 +144,7 @@ class _CreateNewRoutinesDialogState extends State<CreateNewRoutinesDialog> {
),
],
),
SizedBox(height: 10),
],
),
);
@@ -1,7 +1,8 @@
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/style.dart';
class SpaceDropdown extends StatelessWidget {
final List<SpaceModel> spaces;
@@ -33,62 +34,108 @@ class SpaceDropdown extends StatelessWidget {
),
),
const SizedBox(height: 8),
DropdownButtonFormField<String>(
value: selectedValue,
items: spaces.map((space) {
return DropdownMenuItem<String>(
value: space.uuid,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
' ${space.name}',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
fontSize: 12,
color: ColorsManager.blackColor,
),
),
Text(
' ${space.lastThreeParents}',
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
fontSize: 12,
),
),
],
));
}).toList(),
onChanged: onChanged,
icon: const SizedBox.shrink(),
borderRadius: const BorderRadius.all(Radius.circular(10)),
hint: Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
hintMessage,
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.textGray,
),
SizedBox(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
),
decoration: inputTextFormDeco().copyWith(
contentPadding: EdgeInsets.zero,
suffixIcon: Container(
width: 70,
height: 45,
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: const BorderRadius.only(
bottomRight: Radius.circular(10),
topRight: Radius.circular(10),
),
border: Border.all(
color: ColorsManager.textGray,
width: 1.0,
child: DropdownButton2<String>(
underline: const SizedBox(),
value: selectedValue,
items: spaces.map((space) {
return DropdownMenuItem<String>(
value: space.uuid,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
' ${space.name}',
style:
Theme.of(context).textTheme.bodyMedium!.copyWith(
fontSize: 12,
color: ColorsManager.blackColor,
),
),
Text(
' ${space.lastThreeParents}',
style:
Theme.of(context).textTheme.bodyMedium!.copyWith(
fontSize: 12,
),
),
],
),
);
}).toList(),
onChanged: onChanged,
style: TextStyle(color: Colors.black),
hint: Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
hintMessage,
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.textGray,
),
),
),
child: const Icon(
Icons.keyboard_arrow_down,
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: Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
selectedValue != null
? spaces
.firstWhere((e) => e.uuid == selectedValue)
.name
: hintMessage,
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[200],
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),
),
),
menuItemStyleData: const MenuItemStyleData(
height: 60,
),
),
),
@@ -33,8 +33,6 @@ class _RoutinesViewState extends State<RoutinesView> {
communityID: communityId, spaceID: spaceId));
await Future.delayed(const Duration(seconds: 1));
routineBloc.add(const CreateNewRoutineViewEvent(createRoutineView: true));
await Future.delayed(const Duration(milliseconds:500));
_bloc.add(const ResetSelectedEvent());
}
@override
@@ -301,11 +301,18 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
SpaceTemplateModel? spaceModel, List<SubspaceModel>? subspaces, List<Tag>? tags) {
setState(() {
// Set the first space in the center or use passed position
Offset centerPosition = position ?? ConnectionHelper.getCenterPosition(screenSize);
Offset newPosition;
if (parentIndex != null) {
newPosition =
getBalancedChildPosition(spaces[parentIndex]); // Ensure balanced position
} else {
newPosition = position ?? ConnectionHelper.getCenterPosition(screenSize);
}
SpaceModel newSpace = SpaceModel(
name: name,
icon: icon,
position: centerPosition,
position: newPosition,
isPrivate: false,
children: [],
status: SpaceStatus.newSpace,
@@ -425,7 +432,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
Connection(
startSpace: parent,
endSpace: child,
direction: child.incomingConnection?.direction ?? "down",
direction: "down",
),
);
@@ -522,6 +529,38 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
);
}
Offset getBalancedChildPosition(SpaceModel parent) {
int totalSiblings = parent.children.length + 1;
double totalWidth = (totalSiblings - 1) * 250; // Horizontal spacing
double startX = parent.position.dx - (totalWidth / 2);
Offset position = Offset(startX + (parent.children.length * 250), parent.position.dy + 180);
// Check for overlaps & adjust
while (spaces.any((s) => (s.position - position).distance < 250)) {
position = Offset(position.dx + 250, position.dy);
}
return position;
}
void realignTree() {
void updatePositions(SpaceModel node, double x, double y) {
node.position = Offset(x, y);
int numChildren = node.children.length;
double childStartX = x - ((numChildren - 1) * 250) / 2;
for (int i = 0; i < numChildren; i++) {
updatePositions(node.children[i], childStartX + (i * 250), y + 180);
}
}
if (spaces.isNotEmpty) {
updatePositions(spaces.first, spaces.first.position.dx, spaces.first.position.dy);
}
}
void _onDuplicate(BuildContext parentContext) {
final screenWidth = MediaQuery.of(context).size.width;
@@ -604,29 +643,57 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
void _duplicateSpace(SpaceModel space) {
final Map<SpaceModel, SpaceModel> originalToDuplicate = {};
const double horizontalGap = 200.0;
const double verticalGap = 100.0;
double horizontalGap = 250.0; // Increased spacing
double verticalGap = 180.0; // Adjusted for better visualization
SpaceModel duplicateRecursive(
SpaceModel original, Offset parentPosition, SpaceModel? duplicatedParent) {
Offset newPosition = Offset(parentPosition.dx + horizontalGap, original.position.dy);
print("🟢 Duplicating: ${space.name}");
while (spaces.any((s) =>
(s.position - newPosition).distance < horizontalGap && s.status != SpaceStatus.deleted)) {
newPosition += Offset(horizontalGap, 0);
/// **Find a new position ensuring no overlap**
Offset getBalancedChildPosition(SpaceModel parent) {
int totalSiblings = parent.children.length + 1;
double totalWidth = (totalSiblings - 1) * horizontalGap;
double startX = parent.position.dx - (totalWidth / 2);
Offset position = Offset(
startX + (parent.children.length * horizontalGap), parent.position.dy + verticalGap);
// **Check for overlaps & adjust**
while (spaces.any((s) => (s.position - position).distance < horizontalGap)) {
position = Offset(position.dx + horizontalGap, position.dy);
}
print("🔹 New position for ${parent.name}: (${position.dx}, ${position.dy})");
return position;
}
/// **Realign the entire tree after duplication**
void realignTree() {
void updatePositions(SpaceModel node, double x, double y) {
node.position = Offset(x, y);
print("✅ Adjusted ${node.name} to (${x}, ${y})");
int numChildren = node.children.length;
double childStartX = x - ((numChildren - 1) * horizontalGap) / 2;
for (int i = 0; i < numChildren; i++) {
updatePositions(node.children[i], childStartX + (i * horizontalGap), y + verticalGap);
}
}
if (spaces.isNotEmpty) {
print("🔄 Realigning tree...");
updatePositions(spaces.first, spaces.first.position.dx, spaces.first.position.dy);
}
}
/// **Recursive duplication logic**
SpaceModel duplicateRecursive(SpaceModel original, SpaceModel? duplicatedParent) {
Offset newPosition = duplicatedParent == null
? Offset(original.position.dx + horizontalGap, original.position.dy)
: getBalancedChildPosition(duplicatedParent);
final duplicatedName = SpaceHelper.generateUniqueSpaceName(original.name, spaces);
final List<SubspaceModel>? duplicatedSubspaces;
final List<Tag>? duplicatedTags;
if (original.spaceModel != null) {
duplicatedTags = [];
duplicatedSubspaces = [];
} else {
duplicatedTags = original.tags;
duplicatedSubspaces = original.subspaces;
}
print(
"🟡 Duplicating ${original.name} → ${duplicatedName} at (${newPosition.dx}, ${newPosition.dy})");
final duplicated = SpaceModel(
name: duplicatedName,
@@ -637,12 +704,10 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
status: SpaceStatus.newSpace,
parent: duplicatedParent,
spaceModel: original.spaceModel,
subspaces: duplicatedSubspaces,
tags: duplicatedTags,
subspaces: original.subspaces,
tags: original.tags,
);
originalToDuplicate[original] = duplicated;
setState(() {
spaces.add(duplicated);
_updateNodePosition(duplicated, duplicated.position);
@@ -651,60 +716,42 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
final newConnection = Connection(
startSpace: duplicatedParent,
endSpace: duplicated,
direction: original.incomingConnection?.direction ?? 'down',
direction: "down",
);
connections.add(newConnection);
duplicated.incomingConnection = newConnection;
duplicatedParent.addOutgoingConnection(newConnection);
duplicatedParent.children.add(duplicated);
print("🔗 Created connection: ${duplicatedParent.name} → ${duplicated.name}");
}
if (original.parent != null && duplicatedParent == null) {
final originalParent = original.parent!;
final duplicatedParent = originalToDuplicate[originalParent] ?? originalParent;
final parentConnection = Connection(
startSpace: duplicatedParent,
endSpace: duplicated,
direction: original.incomingConnection?.direction ?? "down",
);
connections.add(parentConnection);
duplicated.incomingConnection = parentConnection;
duplicatedParent.addOutgoingConnection(parentConnection);
}
// **Recalculate the whole tree to avoid overlaps**
realignTree();
});
final childrenWithDownDirection = original.children
.where((child) =>
child.incomingConnection?.direction == "down" && child.status != SpaceStatus.deleted)
.toList();
Offset childStartPosition = childrenWithDownDirection.length == 1
? duplicated.position
: newPosition + Offset(0, verticalGap);
for (final child in original.children) {
final isDownDirection = child.incomingConnection?.direction == "down" ?? false;
if (isDownDirection && childrenWithDownDirection.length == 1) {
childStartPosition = duplicated.position + Offset(0, verticalGap);
} else if (!isDownDirection) {
childStartPosition = duplicated.position + Offset(horizontalGap, 0);
}
final duplicatedChild = duplicateRecursive(child, childStartPosition, duplicated);
duplicated.children.add(duplicatedChild);
childStartPosition += Offset(0, verticalGap);
// Recursively duplicate children
for (var child in original.children) {
duplicateRecursive(child, duplicated);
}
return duplicated;
}
/// **Handle root duplication**
if (space.parent == null) {
duplicateRecursive(space, space.position, null);
print("🟠 Duplicating root node: ${space.name}");
SpaceModel duplicatedRoot = duplicateRecursive(space, null);
setState(() {
spaces.add(duplicatedRoot);
realignTree();
});
print("✅ Root duplication successful: ${duplicatedRoot.name}");
} else {
final duplicatedParent = originalToDuplicate[space.parent!] ?? space.parent!;
duplicateRecursive(space, space.position, duplicatedParent);
duplicateRecursive(space, space.parent);
}
print("🟢 Finished duplication process for: ${space.name}");
}
}
@@ -47,18 +47,6 @@ class SpaceCardWidget extends StatelessWidget {
children: [
buildSpaceContainer(index), // Build the space container
if (isHovered) ...[
PlusButtonWidget(
index: index,
direction: 'left',
offset: const Offset(-21, 20),
onButtonTap: onButtonTap,
),
PlusButtonWidget(
index: index,
direction: 'right',
offset: const Offset(140, 20),
onButtonTap: onButtonTap,
),
PlusButtonWidget(
index: index,
direction: 'down',
@@ -2,8 +2,7 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_m
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
class SpaceHelper {
static SpaceModel? findSpaceByUuid(
String? uuid, List<CommunityModel> communities) {
static SpaceModel? findSpaceByUuid(String? uuid, List<CommunityModel> communities) {
for (var community in communities) {
for (var space in community.spaces) {
if (space.uuid == uuid) return space;
@@ -12,8 +11,7 @@ class SpaceHelper {
return null;
}
static SpaceModel? findSpaceByInternalId(
String? internalId, List<SpaceModel> spaces) {
static SpaceModel? findSpaceByInternalId(String? internalId, List<SpaceModel> spaces) {
if (internalId != null) {
for (var space in spaces) {
if (space.internalId == internalId) return space;
@@ -23,8 +21,7 @@ class SpaceHelper {
return null;
}
static String generateUniqueSpaceName(
String originalName, List<SpaceModel> spaces) {
static String generateUniqueSpaceName(String originalName, List<SpaceModel> spaces) {
final baseName = originalName.replaceAll(RegExp(r'\(\d+\)$'), '').trim();
int maxNumber = 0;
@@ -54,13 +51,10 @@ class SpaceHelper {
return space == selectedSpace ||
selectedSpace.parent?.internalId == space.internalId ||
selectedSpace.children
?.any((child) => child.internalId == space.internalId) ==
true;
selectedSpace.children?.any((child) => child.internalId == space.internalId) == true;
}
static bool isNameConflict(
String value, SpaceModel? parentSpace, SpaceModel? editSpace) {
static bool isNameConflict(String value, SpaceModel? parentSpace, SpaceModel? editSpace) {
final siblings = parentSpace?.children
.where((child) => child.internalId != editSpace?.internalId)
.toList() ??
@@ -71,19 +65,17 @@ class SpaceHelper {
.toList() ??
[];
final editSiblingConflict =
editSiblings.any((child) => child.name == value);
final editSiblingConflict = editSiblings.any((child) => child.name == value);
final siblingConflict = siblings.any((child) => child.name == value);
final parentConflict = parentSpace?.name == value &&
parentSpace?.internalId != editSpace?.internalId;
final parentConflict =
parentSpace?.name == value && parentSpace?.internalId != editSpace?.internalId;
final parentOfEditSpaceConflict = editSpace?.parent?.name == value &&
editSpace?.parent?.internalId != editSpace?.internalId;
final parentOfEditSpaceConflict =
editSpace?.parent?.name == value && editSpace?.parent?.internalId != editSpace?.internalId;
final childConflict =
editSpace?.children.any((child) => child.name == value) ?? false;
final childConflict = editSpace?.children.any((child) => child.name == value) ?? false;
return siblingConflict ||
parentConflict ||
@@ -194,9 +194,10 @@ class VisitorPasswordBloc
emit(DeviceLoaded());
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
data = await AccessMangApi().fetchDevices(projectUuid);
data = await AccessMangApi().fetchDoorLockDeviceList(projectUuid);
emit(TableLoaded(data));
} catch (e) {
print("error: $e");
emit(FailedState(e.toString()));
}
}