diff --git a/lib/pages/spaces_management/assign_tag/views/assign_tag_dialog.dart b/lib/pages/spaces_management/assign_tag/views/assign_tag_dialog.dart index cb1f7b46..dd56c0bb 100644 --- a/lib/pages/spaces_management/assign_tag/views/assign_tag_dialog.dart +++ b/lib/pages/spaces_management/assign_tag/views/assign_tag_dialog.dart @@ -237,7 +237,8 @@ class AssignTagDialog extends StatelessWidget { final processedTags = result['updatedTags'] as List; - final processedSubspaces = result['subspaces']; + final processedSubspaces = List.from( + result['subspaces'] as List); Navigator.of(context).pop(); @@ -276,7 +277,8 @@ class AssignTagDialog extends StatelessWidget { final processedTags = result['updatedTags'] as List; final processedSubspaces = - result['subspaces'] as List; + List.from( + result['subspaces'] as List); onSave?.call(processedTags, processedSubspaces); Navigator.of(context).pop(); } @@ -301,105 +303,31 @@ class AssignTagDialog extends StatelessWidget { List getAvailableTags( List allTags, List currentTags, Tag currentTag) { - return allTags - .where((tagValue) => !currentTags - .where((e) => e != currentTag) // Exclude the current row - .map((e) => e.tag) - .contains(tagValue)) - .toList(); + List availableTagsForTagModel = TagHelper.getAvailableTags( + allTags: allTags, + currentTags: currentTags, + currentTag: currentTag, + getTag: (tag) => tag.tag ?? '', + ); + return availableTagsForTagModel; } Map processTags( List updatedTags, List? subspaces) { - final modifiedTags = List.from(updatedTags); - final modifiedSubspaces = List.from(subspaces ?? []); - - if (subspaces != null) { - for (var subspace in subspaces) { - subspace.tags?.removeWhere( - (tag) => !modifiedTags - .any((updatedTag) => updatedTag.internalId == tag.internalId), - ); - } - } - for (var tag in modifiedTags.toList()) { - if (modifiedSubspaces.isEmpty) continue; - - final prevIndice = checkTagExistInSubspace(tag, modifiedSubspaces); - - if ((tag.location == 'Main Space' || tag.location == null) && - (prevIndice == null || - modifiedSubspaces[prevIndice].subspaceName == 'Main Space')) { - continue; - } - - if ((tag.location == 'Main Space' || tag.location == null) && - prevIndice != null) { - modifiedSubspaces[prevIndice] - .tags - ?.removeWhere((t) => t.internalId == tag.internalId); - continue; - } - - if ((tag.location != 'Main Space' && tag.location != null) && - prevIndice == null) { - final newIndex = modifiedSubspaces - .indexWhere((subspace) => subspace.subspaceName == tag.location); - if (newIndex != -1) { - if (modifiedSubspaces[newIndex] - .tags - ?.any((t) => t.internalId == tag.internalId) != - true) { - tag.location = modifiedSubspaces[newIndex].subspaceName; - modifiedSubspaces[newIndex].tags?.add(tag); - } - } - modifiedTags.removeWhere((t) => t.internalId == tag.internalId); - continue; - } - - if ((tag.location != 'Main Space' && tag.location != null) && - tag.location != modifiedSubspaces[prevIndice!].subspaceName) { - modifiedSubspaces[prevIndice] - .tags - ?.removeWhere((t) => t.internalId == tag.internalId); - final newIndex = modifiedSubspaces - .indexWhere((subspace) => subspace.subspaceName == tag.location); - if (newIndex != -1) { - if (modifiedSubspaces[newIndex] - .tags - ?.any((t) => t.internalId == tag.internalId) != - true) { - tag.location = modifiedSubspaces[newIndex].subspaceName; - modifiedSubspaces[newIndex].tags?.add(tag); - } - } - - modifiedTags.removeWhere((t) => t.internalId == tag.internalId); - continue; - } - - if ((tag.location != 'Main Space' && tag.location != null) && - tag.location == modifiedSubspaces[prevIndice!].subspaceName) { - modifiedTags.removeWhere((t) => t.internalId == tag.internalId); - continue; - } - - if ((tag.location == 'Main Space' || tag.location == null) && - prevIndice != null) { - modifiedSubspaces[prevIndice] - .tags - ?.removeWhere((t) => t.internalId == tag.internalId); - } - } - - return { - 'updatedTags': modifiedTags, - 'subspaces': modifiedSubspaces, - }; + return TagHelper.updateTags( + updatedTags: updatedTags, + subspaces: subspaces, + getInternalId: (tag) => tag.internalId, + getLocation: (tag) => tag.location, + setLocation: (tag, location) => tag.location = location, + getSubspaceName: (subspace) => subspace.subspaceName, + getSubspaceTags: (subspace) => subspace.tags, + setSubspaceTags: (subspace, tags) => subspace.tags = tags, + checkTagExistInSubspace: checkTagExistInSubspace, + ); } - int? checkTagExistInSubspace(Tag tag, List? subspaces) { + int? checkTagExistInSubspace(Tag tag, List? subspaces) { if (subspaces == null) return null; for (int i = 0; i < subspaces.length; i++) { final subspace = subspaces[i]; diff --git a/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart b/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart index 9696723a..5fdaf937 100644 --- a/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart +++ b/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart @@ -133,8 +133,9 @@ class AssignTagModelsDialog extends StatelessWidget { : List.generate(state.tags.length, (index) { final tag = state.tags[index]; final controller = controllers[index]; - final availableTags = getAvailableTags( - allTags ?? [], state.tags, tag); + final availableTags = + TagHelper.getAvailableTagModels( + allTags ?? [], state.tags, tag); return DataRow( cells: [ @@ -254,11 +255,15 @@ class AssignTagModelsDialog extends StatelessWidget { final updatedTags = List.from(state.tags); final result = - processTags(updatedTags, subspaces); + TagHelper.updateSubspaceTagModels( + updatedTags, subspaces); final processedTags = result['updatedTags'] as List; - final processedSubspaces = result['subspaces']; + final processedSubspaces = + List.from( + result['subspaces'] as List); + if (context.mounted) { Navigator.of(context).pop(); @@ -305,14 +310,17 @@ class AssignTagModelsDialog extends StatelessWidget { ? () async { final updatedTags = List.from(state.tags); + final result = - processTags(updatedTags, subspaces); + TagHelper.updateSubspaceTagModels( + updatedTags, subspaces); final processedTags = result['updatedTags'] as List; final processedSubspaces = - result['subspaces'] - as List; + List.from( + result['subspaces'] + as List); Navigator.of(context) .popUntil((route) => route.isFirst); @@ -356,120 +364,4 @@ class AssignTagModelsDialog extends StatelessWidget { ), )); } - - List getAvailableTags( - List allTags, List currentTags, TagModel currentTag) { - return allTags - .where((tagValue) => !currentTags - .where((e) => e != currentTag) // Exclude the current row - .map((e) => e.tag) - .contains(tagValue)) - .toList(); - } - - int? checkTagExistInSubspace( - TagModel tag, List? subspaces) { - if (subspaces == null) return null; - for (int i = 0; i < subspaces.length; i++) { - final subspace = subspaces[i]; - if (subspace.tags == null) continue; - for (var t in subspace.tags!) { - if (tag.internalId == t.internalId) { - return i; - } - } - } - return null; - } - - Map processTags( - List updatedTags, List? subspaces) { - final modifiedTags = List.from(updatedTags); - final modifiedSubspaces = List.from(subspaces ?? []); - - if (subspaces != null) { - for (var subspace in subspaces) { - subspace.tags?.removeWhere( - (tag) => !modifiedTags - .any((updatedTag) => updatedTag.internalId == tag.internalId), - ); - } - } - - for (var tag in modifiedTags.toList()) { - if (modifiedSubspaces.isEmpty) continue; - - final prevIndice = checkTagExistInSubspace(tag, modifiedSubspaces); - - if ((tag.location == 'Main Space' || tag.location == null) && - (prevIndice == null || - modifiedSubspaces[prevIndice].subspaceName == 'Main Space')) { - continue; - } - - if ((tag.location == 'Main Space' || tag.location == null) && - prevIndice != null) { - modifiedSubspaces[prevIndice] - .tags - ?.removeWhere((t) => t.internalId == tag.internalId); - continue; - } - - if ((tag.location != 'Main Space' && tag.location != null) && - prevIndice == null) { - final newIndex = modifiedSubspaces - .indexWhere((subspace) => subspace.subspaceName == tag.location); - if (newIndex != -1) { - if (modifiedSubspaces[newIndex] - .tags - ?.any((t) => t.internalId == tag.internalId) != - true) { - tag.location = modifiedSubspaces[newIndex].subspaceName; - modifiedSubspaces[newIndex].tags?.add(tag); - } - } - modifiedTags.removeWhere((t) => t.internalId == tag.internalId); - continue; - } - - if ((tag.location != 'Main Space' && tag.location != null) && - tag.location != modifiedSubspaces[prevIndice!].subspaceName) { - modifiedSubspaces[prevIndice] - .tags - ?.removeWhere((t) => t.internalId == tag.internalId); - final newIndex = modifiedSubspaces - .indexWhere((subspace) => subspace.subspaceName == tag.location); - if (newIndex != -1) { - if (modifiedSubspaces[newIndex] - .tags - ?.any((t) => t.internalId == tag.internalId) != - true) { - tag.location = modifiedSubspaces[newIndex].subspaceName; - modifiedSubspaces[newIndex].tags?.add(tag); - } - } - - modifiedTags.removeWhere((t) => t.internalId == tag.internalId); - continue; - } - - if ((tag.location != 'Main Space' && tag.location != null) && - tag.location == modifiedSubspaces[prevIndice!].subspaceName) { - modifiedTags.removeWhere((t) => t.internalId == tag.internalId); - continue; - } - - if ((tag.location == 'Main Space' || tag.location == null) && - prevIndice != null) { - modifiedSubspaces[prevIndice] - .tags - ?.removeWhere((t) => t.internalId == tag.internalId); - } - } - - return { - 'updatedTags': modifiedTags, - 'subspaces': modifiedSubspaces, - }; - } } diff --git a/lib/pages/spaces_management/helper/tag_helper.dart b/lib/pages/spaces_management/helper/tag_helper.dart index 041f005f..c50e6ba8 100644 --- a/lib/pages/spaces_management/helper/tag_helper.dart +++ b/lib/pages/spaces_management/helper/tag_helper.dart @@ -7,6 +7,138 @@ import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_ import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart'; class TagHelper { + static Map updateTags({ + required List updatedTags, + required List? subspaces, + required String Function(T) getInternalId, + required String? Function(T) getLocation, + required void Function(T, String) setLocation, + required String Function(dynamic) getSubspaceName, + required List? Function(dynamic) getSubspaceTags, + required void Function(dynamic, List?) setSubspaceTags, + required int? Function(T, List) checkTagExistInSubspace, + }) { + final modifiedTags = List.from(updatedTags); + final modifiedSubspaces = List.from(subspaces ?? []); + + if (subspaces != null) { + for (var subspace in subspaces) { + getSubspaceTags(subspace)?.removeWhere( + (tag) => !modifiedTags.any( + (updatedTag) => getInternalId(updatedTag) == getInternalId(tag)), + ); + } + } + + for (var tag in modifiedTags.toList()) { + if (modifiedSubspaces.isEmpty) continue; + + final prevIndice = checkTagExistInSubspace(tag, modifiedSubspaces); + final tagLocation = getLocation(tag); + + if ((tagLocation == 'Main Space' || tagLocation == null) && + (prevIndice == null || + getSubspaceName(modifiedSubspaces[prevIndice]) == 'Main Space')) { + continue; + } + + if ((tagLocation == 'Main Space' || tagLocation == null) && + prevIndice != null) { + getSubspaceTags(modifiedSubspaces[prevIndice]) + ?.removeWhere((t) => getInternalId(t) == getInternalId(tag)); + continue; + } + + if ((tagLocation != 'Main Space' && tagLocation != null) && + prevIndice == null) { + final newIndex = modifiedSubspaces + .indexWhere((subspace) => getSubspaceName(subspace) == tagLocation); + + if (newIndex != -1) { + if (getSubspaceTags(modifiedSubspaces[newIndex]) + ?.any((t) => getInternalId(t) == getInternalId(tag)) != + true) { + setLocation(tag, getSubspaceName(modifiedSubspaces[newIndex])); + final subspaceTags = + getSubspaceTags(modifiedSubspaces[newIndex]) ?? []; + subspaceTags.add(tag); + setSubspaceTags(modifiedSubspaces[newIndex], subspaceTags); + } + } + + modifiedTags.removeWhere((t) => getInternalId(t) == getInternalId(tag)); + continue; + } + + if ((tagLocation != 'Main Space' && tagLocation != null) && + tagLocation != getSubspaceName(modifiedSubspaces[prevIndice!])) { + getSubspaceTags(modifiedSubspaces[prevIndice]) + ?.removeWhere((t) => getInternalId(t) == getInternalId(tag)); + + final newIndex = modifiedSubspaces + .indexWhere((subspace) => getSubspaceName(subspace) == tagLocation); + + if (newIndex != -1) { + if (getSubspaceTags(modifiedSubspaces[newIndex]) + ?.any((t) => getInternalId(t) == getInternalId(tag)) != + true) { + setLocation(tag, getSubspaceName(modifiedSubspaces[newIndex])); + final subspaceTags = + getSubspaceTags(modifiedSubspaces[newIndex]) ?? []; + subspaceTags.add(tag); + setSubspaceTags(modifiedSubspaces[newIndex], subspaceTags); + } + } + + modifiedTags.removeWhere((t) => getInternalId(t) == getInternalId(tag)); + continue; + } + + if ((tagLocation != 'Main Space' && tagLocation != null) && + tagLocation == getSubspaceName(modifiedSubspaces[prevIndice!])) { + modifiedTags.removeWhere((t) => getInternalId(t) == getInternalId(tag)); + continue; + } + + if ((tagLocation == 'Main Space' || tagLocation == null) && + prevIndice != null) { + getSubspaceTags(modifiedSubspaces[prevIndice]) + ?.removeWhere((t) => getInternalId(t) == getInternalId(tag)); + } + } + + return { + 'updatedTags': modifiedTags, + 'subspaces': modifiedSubspaces, + }; + } + + static List getAvailableTags({ + required List allTags, + required List currentTags, + required T currentTag, + required String? Function(T) getTag, // Allow nullable return type + }) { + return allTags + .where((tagValue) => !currentTags + .where((e) => e != currentTag) // Exclude the current row + .map((e) => getTag(e) ?? '') // Handle null values gracefully + .contains(tagValue)) + .toList(); + } + + static List getAvailableTagModels( + List allTags, List currentTags, TagModel currentTag) { + List availableTagsForTagModel = + TagHelper.getAvailableTags( + allTags: allTags, + currentTags: currentTags, + currentTag: currentTag, + getTag: (tag) => tag.tag ?? '', + ); + return availableTagsForTagModel; + } + static List generateInitialTags({ List? spaceTagModels, List? subspaces, @@ -36,7 +168,7 @@ class TagHelper { return initialTags; } - static List generateInitialForTags({ + static List generateInitialForTags({ List? spaceTags, List? subspaces, }) { @@ -145,4 +277,35 @@ class TagHelper { )) .toList(); } + + static int? checkTagExistInSubspaceModels(TagModel tag, List? subspaces) { + if (subspaces == null) return null; + + for (int i = 0; i < subspaces.length; i++) { + final subspace = subspaces[i] as SubspaceTemplateModel; // Explicit cast + if (subspace.tags == null) continue; + for (var t in subspace.tags!) { + if (tag.internalId == t.internalId) { + return i; + } + } + } + return null; + } + + static Map updateSubspaceTagModels( + List updatedTags, List? subspaces) { + return TagHelper.updateTags( + updatedTags: updatedTags, + subspaces: subspaces, + getInternalId: (tag) => tag.internalId, + getLocation: (tag) => tag.location, + setLocation: (tag, location) => tag.location = location, + getSubspaceName: (subspace) => subspace.subspaceName, + getSubspaceTags: (subspace) => subspace.tags, + setSubspaceTags: (subspace, tags) => subspace.tags = tags, + checkTagExistInSubspace: checkTagExistInSubspaceModels, + ); + } + } diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart index 212400b9..28b548b0 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart @@ -129,10 +129,16 @@ class CreateSpaceModelDialog extends StatelessWidget { const SizedBox(height: 16), SubspaceModelCreate( subspaces: state.space.subspaceModels ?? [], - onSpaceModelUpdate: (updatedSubspaces) { + tags: state.space.tags ?? [], + onSpaceModelUpdate: (updatedSubspaces,updatedTags) { context .read() .add(AddSubspacesToSpaceTemplate(updatedSubspaces)); + if(updatedTags!=null){ + context + .read() + .add(AddTagsToSpaceTemplate(updatedTags)); + } }, ), const SizedBox(height: 10), diff --git a/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart b/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart index 3e13f9c5..d8e27bec 100644 --- a/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart +++ b/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:syncrow_web/common/edit_chip.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/button_content_widget.dart'; import 'package:syncrow_web/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart'; @@ -8,13 +9,16 @@ import 'package:syncrow_web/utils/color_manager.dart'; class SubspaceModelCreate extends StatefulWidget { final List subspaces; - final void Function(List newSubspaces)? + final void Function( + List newSubspaces, List? tags)? onSpaceModelUpdate; + final List tags; const SubspaceModelCreate({ Key? key, required this.subspaces, this.onSpaceModelUpdate, + required this.tags, }) : super(key: key); @override @@ -24,11 +28,13 @@ class SubspaceModelCreate extends StatefulWidget { class _SubspaceModelCreateState extends State { late List _subspaces; String? errorSubspaceId; + late List _tags; @override void initState() { super.initState(); _subspaces = List.from(widget.subspaces); + _tags = List.from(widget.tags); } @override @@ -105,14 +111,26 @@ class _SubspaceModelCreateState extends State { isEdit: true, dialogTitle: dialogTitle, existingSubSpaces: _subspaces, - onUpdate: (subspaceModels) { + final updatedIds = subspaceModels.map((s) => s.internalId).toSet(); + final deletedSubspaces = _subspaces + .where((s) => !updatedIds.contains(s.internalId)) + .toList(); + + final List tagsToAppendToSpace = []; + + for (var s in deletedSubspaces) { + if (s.tags != null) { + tagsToAppendToSpace.addAll(s.tags!); + } + } + setState(() { _subspaces = subspaceModels; - errorSubspaceId = null; + _tags.addAll(tagsToAppendToSpace); }); if (widget.onSpaceModelUpdate != null) { - widget.onSpaceModelUpdate!(subspaceModels); + widget.onSpaceModelUpdate!(subspaceModels, _tags); } }, ); diff --git a/lib/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart b/lib/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart index 63edcf8f..6a6aec44 100644 --- a/lib/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart +++ b/lib/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart @@ -52,6 +52,13 @@ class _SubspaceNameDisplayWidgetState extends State { void _handleValidationAndSave() { final updatedName = _controller.text; + + if (updatedName.isEmpty) { + setState(() { + errorText = 'Subspace name cannot be empty.'; + }); + return; + } if (widget.validateName(updatedName)) { setState(() { errorText = null;