mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-11-27 02:34:56 +00:00
edit flow
This commit is contained in:
@ -3,8 +3,7 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
|
|||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_event.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_event.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_state.dart';
|
||||||
|
|
||||||
class AssignTagBloc
|
class AssignTagBloc extends Bloc<AssignTagEvent, AssignTagState> {
|
||||||
extends Bloc<AssignTagEvent, AssignTagState> {
|
|
||||||
AssignTagBloc() : super(AssignTagInitial()) {
|
AssignTagBloc() : super(AssignTagInitial()) {
|
||||||
on<InitializeTags>((event, emit) {
|
on<InitializeTags>((event, emit) {
|
||||||
final initialTags = event.initialTags ?? [];
|
final initialTags = event.initialTags ?? [];
|
||||||
@ -40,7 +39,7 @@ class AssignTagBloc
|
|||||||
(index) => Tag(
|
(index) => Tag(
|
||||||
tag: '',
|
tag: '',
|
||||||
product: selectedProduct.product,
|
product: selectedProduct.product,
|
||||||
location: 'None',
|
location: 'Main Space',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -55,8 +54,7 @@ class AssignTagBloc
|
|||||||
on<UpdateTagEvent>((event, emit) {
|
on<UpdateTagEvent>((event, emit) {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
|
|
||||||
if (currentState is AssignTagLoaded &&
|
if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
|
||||||
currentState.tags.isNotEmpty) {
|
|
||||||
final tags = List<Tag>.from(currentState.tags);
|
final tags = List<Tag>.from(currentState.tags);
|
||||||
tags[event.index].tag = event.tag;
|
tags[event.index].tag = event.tag;
|
||||||
emit(AssignTagLoaded(
|
emit(AssignTagLoaded(
|
||||||
@ -70,8 +68,7 @@ class AssignTagBloc
|
|||||||
on<UpdateLocation>((event, emit) {
|
on<UpdateLocation>((event, emit) {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
|
|
||||||
if (currentState is AssignTagLoaded &&
|
if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
|
||||||
currentState.tags.isNotEmpty) {
|
|
||||||
final tags = List<Tag>.from(currentState.tags);
|
final tags = List<Tag>.from(currentState.tags);
|
||||||
|
|
||||||
// Use copyWith for immutability
|
// Use copyWith for immutability
|
||||||
@ -88,8 +85,7 @@ class AssignTagBloc
|
|||||||
on<ValidateTags>((event, emit) {
|
on<ValidateTags>((event, emit) {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
|
|
||||||
if (currentState is AssignTagLoaded &&
|
if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
|
||||||
currentState.tags.isNotEmpty) {
|
|
||||||
final tags = List<Tag>.from(currentState.tags);
|
final tags = List<Tag>.from(currentState.tags);
|
||||||
|
|
||||||
emit(AssignTagLoaded(
|
emit(AssignTagLoaded(
|
||||||
@ -103,8 +99,7 @@ class AssignTagBloc
|
|||||||
on<DeleteTag>((event, emit) {
|
on<DeleteTag>((event, emit) {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
|
|
||||||
if (currentState is AssignTagLoaded &&
|
if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) {
|
||||||
currentState.tags.isNotEmpty) {
|
|
||||||
final updatedTags = List<Tag>.from(currentState.tags)
|
final updatedTags = List<Tag>.from(currentState.tags)
|
||||||
..remove(event.tagToDelete);
|
..remove(event.tagToDelete);
|
||||||
|
|
||||||
|
|||||||
@ -224,7 +224,7 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
DataCell(
|
DataCell(
|
||||||
DropdownButtonHideUnderline(
|
DropdownButtonHideUnderline(
|
||||||
child: DropdownButton<String>(
|
child: DropdownButton<String>(
|
||||||
value: tag.location ?? 'None',
|
value: tag.location ?? 'Main',
|
||||||
dropdownColor: ColorsManager
|
dropdownColor: ColorsManager
|
||||||
.whiteColors, // Dropdown background
|
.whiteColors, // Dropdown background
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@ -232,9 +232,9 @@ class AssignTagDialog extends StatelessWidget {
|
|||||||
.black), // Style for selected text
|
.black), // Style for selected text
|
||||||
items: [
|
items: [
|
||||||
const DropdownMenuItem<String>(
|
const DropdownMenuItem<String>(
|
||||||
value: 'None',
|
value: 'Main Space',
|
||||||
child: Text(
|
child: Text(
|
||||||
'None',
|
'Main Space',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: ColorsManager
|
color: ColorsManager
|
||||||
.textPrimaryColor),
|
.textPrimaryColor),
|
||||||
|
|||||||
@ -40,7 +40,7 @@ class AssignTagModelBloc
|
|||||||
(index) => TagModel(
|
(index) => TagModel(
|
||||||
tag: '',
|
tag: '',
|
||||||
product: selectedProduct.product,
|
product: selectedProduct.product,
|
||||||
location: 'None',
|
location: 'Main Space',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -123,6 +123,7 @@ class AssignTagModelBloc
|
|||||||
|
|
||||||
bool _validateTags(List<TagModel> tags) {
|
bool _validateTags(List<TagModel> tags) {
|
||||||
if (tags.isEmpty) {
|
if (tags.isEmpty) {
|
||||||
|
print("tags empty");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final uniqueTags = tags.map((tag) => tag.tag?.trim() ?? '').toSet();
|
final uniqueTags = tags.map((tag) => tag.tag?.trim() ?? '').toSet();
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assig
|
|||||||
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_state.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/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/models/tag_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
|
|
||||||
class AssignTagModelsDialog extends StatelessWidget {
|
class AssignTagModelsDialog extends StatelessWidget {
|
||||||
@ -40,8 +41,11 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final List<String> locations =
|
final List<String> locations = (subspaces ?? [])
|
||||||
(subspaces ?? []).map((subspace) => subspace.subspaceName).toList();
|
.map((subspace) => subspace.subspaceName)
|
||||||
|
.toList()
|
||||||
|
..add('Main Space');
|
||||||
|
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (_) => AssignTagModelBloc()
|
create: (_) => AssignTagModelBloc()
|
||||||
..add(InitializeTagModels(
|
..add(InitializeTagModels(
|
||||||
@ -173,7 +177,8 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
width: double
|
width: double
|
||||||
.infinity, // Ensure full width for dropdown
|
.infinity, // Ensure full width for dropdown
|
||||||
child: DialogTextfieldDropdown(
|
child: DialogTextfieldDropdown(
|
||||||
items: availableTags ?? [],
|
items: availableTags,
|
||||||
|
initialValue: tag.tag,
|
||||||
onSelected: (value) {
|
onSelected: (value) {
|
||||||
controller.text = value;
|
controller.text = value;
|
||||||
context
|
context
|
||||||
@ -223,26 +228,55 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: CancelButton(
|
child: Builder(
|
||||||
label: 'Add New Device',
|
builder: (buttonContext) => CancelButton(
|
||||||
onPressed: () async {
|
label: 'Add New Device',
|
||||||
Navigator.of(context).pop();
|
onPressed: () async {
|
||||||
final assignedTags = <TagModel>{};
|
Navigator.of(context).pop();
|
||||||
for (var tag in state.tags) {
|
|
||||||
if (tag.location == null || subspaces == null) {
|
for (var tag in state.tags) {
|
||||||
continue;
|
if (tag.location == null || subspaces == null) {
|
||||||
}
|
continue;
|
||||||
for (var subspace in subspaces!) {
|
|
||||||
if (tag.location == subspace.subspaceName) {
|
|
||||||
subspace.tags ??= [];
|
|
||||||
subspace.tags!.add(tag);
|
|
||||||
assignedTags.add(tag);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final previousTagSubspace =
|
||||||
|
checkTagExistInSubspace(tag, subspaces ?? []);
|
||||||
|
|
||||||
|
if (tag.location == 'Main Space') {
|
||||||
|
removeTagFromSubspace(tag, previousTagSubspace);
|
||||||
|
} else if (tag.location !=
|
||||||
|
previousTagSubspace?.subspaceName) {
|
||||||
|
removeTagFromSubspace(tag, previousTagSubspace);
|
||||||
|
moveToNewSubspace(tag, subspaces ?? []);
|
||||||
|
state.tags.removeWhere(
|
||||||
|
(t) => t.internalId == tag.internalId);
|
||||||
|
} else {
|
||||||
|
updateTagInSubspace(tag, previousTagSubspace);
|
||||||
|
state.tags.removeWhere(
|
||||||
|
(t) => t.internalId == tag.internalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
await showDialog<bool>(
|
||||||
|
barrierDismissible: false,
|
||||||
|
context:
|
||||||
|
Navigator.of(context, rootNavigator: true)
|
||||||
|
.context,
|
||||||
|
builder: (context) => AddDeviceTypeModelWidget(
|
||||||
|
products: products,
|
||||||
|
subspaces: subspaces,
|
||||||
|
isCreate: false,
|
||||||
|
initialSelectedProducts: addedProducts,
|
||||||
|
allTags: allTags,
|
||||||
|
spaceName: spaceName,
|
||||||
|
spaceTagModels: state.tags,
|
||||||
|
onUpdate: (tags, subspaces) {
|
||||||
|
onUpdate?.call(state.tags, subspaces);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
state.tags.removeWhere(assignedTags.contains);
|
),
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
@ -256,23 +290,38 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
onPressed: state.isSaveEnabled
|
onPressed: state.isSaveEnabled
|
||||||
? () async {
|
? () async {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
final assignedTags = <TagModel>{};
|
|
||||||
for (var tag in state.tags) {
|
for (var tag in state.tags) {
|
||||||
if (tag.location == null ||
|
if (tag.location == null ||
|
||||||
subspaces == null) {
|
subspaces == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (var subspace in subspaces!) {
|
|
||||||
if (tag.location == subspace.subspaceName) {
|
final previousTagSubspace =
|
||||||
subspace.tags ??= [];
|
checkTagExistInSubspace(
|
||||||
subspace.tags!.add(tag);
|
tag, subspaces ?? []);
|
||||||
assignedTags.add(tag);
|
|
||||||
break;
|
if (tag.location == 'Main Space') {
|
||||||
}
|
removeTagFromSubspace(
|
||||||
|
tag, previousTagSubspace);
|
||||||
|
} else if (tag.location !=
|
||||||
|
previousTagSubspace?.subspaceName) {
|
||||||
|
removeTagFromSubspace(
|
||||||
|
tag, previousTagSubspace);
|
||||||
|
moveToNewSubspace(tag, subspaces ?? []);
|
||||||
|
state.tags.removeWhere(
|
||||||
|
(t) => t.internalId == tag.internalId);
|
||||||
|
} else {
|
||||||
|
updateTagInSubspace(
|
||||||
|
tag, previousTagSubspace);
|
||||||
|
state.tags.removeWhere(
|
||||||
|
(t) => t.internalId == tag.internalId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.tags.removeWhere(assignedTags.contains);
|
print("tryinh yo save");
|
||||||
onUpdate!(state.tags,subspaces);
|
|
||||||
|
onUpdate?.call(state.tags, subspaces);
|
||||||
|
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
child: const Text('Save'),
|
child: const Text('Save'),
|
||||||
@ -302,4 +351,40 @@ class AssignTagModelsDialog extends StatelessWidget {
|
|||||||
.contains(tagValue))
|
.contains(tagValue))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void removeTagFromSubspace(TagModel tag, SubspaceTemplateModel? subspace) {
|
||||||
|
subspace?.tags?.removeWhere((t) => t.internalId == tag.internalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
SubspaceTemplateModel? checkTagExistInSubspace(
|
||||||
|
TagModel tag, List<SubspaceTemplateModel>? subspaces) {
|
||||||
|
if (subspaces == null) return null;
|
||||||
|
for (var subspace in subspaces) {
|
||||||
|
if (subspace.tags == null) return null;
|
||||||
|
for (var t in subspace.tags!) {
|
||||||
|
if (tag.internalId == t.internalId) return subspace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void moveToNewSubspace(TagModel tag, List<SubspaceTemplateModel> subspaces) {
|
||||||
|
final targetSubspace = subspaces
|
||||||
|
.firstWhere((subspace) => subspace.subspaceName == tag.location);
|
||||||
|
|
||||||
|
targetSubspace.tags ??= [];
|
||||||
|
if (targetSubspace.tags?.any((t) => t.internalId == tag.internalId) !=
|
||||||
|
true) {
|
||||||
|
targetSubspace.tags?.add(tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateTagInSubspace(TagModel tag, SubspaceTemplateModel? subspace) {
|
||||||
|
final currentTag = subspace?.tags?.firstWhere(
|
||||||
|
(t) => t.internalId == tag.internalId,
|
||||||
|
);
|
||||||
|
if (currentTag != null) {
|
||||||
|
currentTag.tag = tag.tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,15 +17,19 @@ class TagHelper {
|
|||||||
if (subspaces != null) {
|
if (subspaces != null) {
|
||||||
for (var subspace in subspaces) {
|
for (var subspace in subspaces) {
|
||||||
if (subspace.tags != null) {
|
if (subspace.tags != null) {
|
||||||
initialTags.addAll(
|
for (var existingTag in subspace.tags!) {
|
||||||
subspace.tags!.map(
|
initialTags.addAll(
|
||||||
(tag) => tag.copyWith(location: subspace.subspaceName),
|
subspace.tags!.map(
|
||||||
),
|
(tag) => tag.copyWith(
|
||||||
);
|
location: subspace.subspaceName,
|
||||||
|
internalId: existingTag.internalId,
|
||||||
|
tag: existingTag.tag),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return initialTags;
|
return initialTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_spac
|
|||||||
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_state.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_state.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.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/models/tag_model.dart';
|
||||||
import 'package:syncrow_web/services/space_model_mang_api.dart';
|
import 'package:syncrow_web/services/space_model_mang_api.dart';
|
||||||
|
|
||||||
@ -67,36 +68,102 @@ class CreateSpaceModelBloc
|
|||||||
_space = event.spaceTemplate;
|
_space = event.spaceTemplate;
|
||||||
emit(CreateSpaceModelLoaded(_space!));
|
emit(CreateSpaceModelLoaded(_space!));
|
||||||
});
|
});
|
||||||
|
|
||||||
on<AddSubspacesToSpaceTemplate>((event, emit) {
|
on<AddSubspacesToSpaceTemplate>((event, emit) {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
|
|
||||||
if (currentState is CreateSpaceModelLoaded) {
|
if (currentState is CreateSpaceModelLoaded) {
|
||||||
final updatedSpace = currentState.space.copyWith(
|
final eventSubspaceIds =
|
||||||
subspaceModels: [
|
event.subspaces.map((e) => e.internalId).toSet();
|
||||||
...(_space!.subspaceModels ?? []),
|
|
||||||
...event.subspaces,
|
// Update or retain subspaces
|
||||||
],
|
final updatedSubspaces = currentState.space.subspaceModels
|
||||||
);
|
?.where((subspace) =>
|
||||||
|
eventSubspaceIds.contains(subspace.internalId))
|
||||||
|
.map((subspace) {
|
||||||
|
final matchingEventSubspace = event.subspaces.firstWhere(
|
||||||
|
(e) => e.internalId == subspace.internalId,
|
||||||
|
orElse: () => subspace,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update the subspace's tags
|
||||||
|
final eventTagIds = matchingEventSubspace.tags
|
||||||
|
?.map((e) => e.internalId)
|
||||||
|
.toSet() ??
|
||||||
|
{};
|
||||||
|
|
||||||
|
final updatedTags = [
|
||||||
|
...?subspace.tags?.map<TagModel>((tag) {
|
||||||
|
final matchingTag =
|
||||||
|
matchingEventSubspace.tags?.firstWhere(
|
||||||
|
(e) => e.internalId == tag.internalId,
|
||||||
|
orElse: () => tag,
|
||||||
|
);
|
||||||
|
final isUpdated = matchingTag != tag;
|
||||||
|
return isUpdated
|
||||||
|
? tag.copyWith(tag: matchingTag?.tag)
|
||||||
|
: tag;
|
||||||
|
}) ??
|
||||||
|
<TagModel>[],
|
||||||
|
...?matchingEventSubspace.tags?.where(
|
||||||
|
(e) =>
|
||||||
|
subspace.tags
|
||||||
|
?.every((t) => t.internalId != e.internalId) ??
|
||||||
|
true,
|
||||||
|
) ??
|
||||||
|
<TagModel>[],
|
||||||
|
];
|
||||||
|
return subspace.copyWith(
|
||||||
|
subspaceName: matchingEventSubspace.subspaceName,
|
||||||
|
tags: updatedTags,
|
||||||
|
);
|
||||||
|
}).toList() ??
|
||||||
|
[];
|
||||||
|
|
||||||
|
// Add new subspaces
|
||||||
|
event.subspaces
|
||||||
|
.where((e) =>
|
||||||
|
updatedSubspaces.every((s) => s.internalId != e.internalId))
|
||||||
|
.forEach((newSubspace) {
|
||||||
|
updatedSubspaces.add(newSubspace);
|
||||||
|
});
|
||||||
|
|
||||||
|
final updatedSpace =
|
||||||
|
currentState.space.copyWith(subspaceModels: updatedSubspaces);
|
||||||
|
|
||||||
emit(CreateSpaceModelLoaded(updatedSpace));
|
emit(CreateSpaceModelLoaded(updatedSpace));
|
||||||
} else {
|
} else {
|
||||||
emit(CreateSpaceModelError("Space template not initialized"));
|
emit(CreateSpaceModelError("Space template not initialized"));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
on<AddTagsToSpaceTemplate>((event, emit) {
|
on<AddTagsToSpaceTemplate>((event, emit) {
|
||||||
final currentState = state;
|
final currentState = state;
|
||||||
|
|
||||||
if (currentState is CreateSpaceModelLoaded) {
|
if (currentState is CreateSpaceModelLoaded) {
|
||||||
final updatedTags = currentState.space.copyWith(
|
final eventTagIds = event.tags.map((e) => e.internalId).toSet();
|
||||||
tags: [
|
|
||||||
...(_space!.tags ?? []),
|
final updatedTags = currentState.space.tags
|
||||||
...event.tags,
|
?.where((tag) => eventTagIds.contains(tag.internalId))
|
||||||
],
|
.map((tag) {
|
||||||
);
|
final matchingEventTag = event.tags.firstWhere(
|
||||||
emit(CreateSpaceModelLoaded(updatedTags));
|
(e) => e.internalId == tag.internalId,
|
||||||
|
orElse: () => tag,
|
||||||
|
);
|
||||||
|
return matchingEventTag != tag
|
||||||
|
? tag.copyWith(tag: matchingEventTag.tag)
|
||||||
|
: tag;
|
||||||
|
}).toList() ??
|
||||||
|
[];
|
||||||
|
|
||||||
|
event.tags
|
||||||
|
.where(
|
||||||
|
(e) => updatedTags.every((t) => t.internalId != e.internalId))
|
||||||
|
.forEach((e) {
|
||||||
|
updatedTags.add(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
emit(CreateSpaceModelLoaded(
|
||||||
|
currentState.space.copyWith(tags: updatedTags)));
|
||||||
} else {
|
} else {
|
||||||
emit(CreateSpaceModelError("Space template not initialized"));
|
emit(CreateSpaceModelError("Space template not initialized"));
|
||||||
}
|
}
|
||||||
@ -106,7 +173,6 @@ class CreateSpaceModelBloc
|
|||||||
final currentState = state;
|
final currentState = state;
|
||||||
if (currentState is CreateSpaceModelLoaded) {
|
if (currentState is CreateSpaceModelLoaded) {
|
||||||
if (event.name.trim().isEmpty) {
|
if (event.name.trim().isEmpty) {
|
||||||
|
|
||||||
emit(CreateSpaceModelLoaded(
|
emit(CreateSpaceModelLoaded(
|
||||||
currentState.space,
|
currentState.space,
|
||||||
errorMessage: "Model name cannot be empty",
|
errorMessage: "Model name cannot be empty",
|
||||||
@ -114,7 +180,7 @@ class CreateSpaceModelBloc
|
|||||||
} else {
|
} else {
|
||||||
final updatedSpaceModel =
|
final updatedSpaceModel =
|
||||||
currentState.space.copyWith(modelName: event.name);
|
currentState.space.copyWith(modelName: event.name);
|
||||||
|
|
||||||
emit(CreateSpaceModelLoaded(updatedSpaceModel));
|
emit(CreateSpaceModelLoaded(updatedSpaceModel));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,22 +1,28 @@
|
|||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class SubspaceTemplateModel {
|
class SubspaceTemplateModel {
|
||||||
final String? uuid;
|
final String? uuid;
|
||||||
String subspaceName;
|
String subspaceName;
|
||||||
final bool disabled;
|
final bool disabled;
|
||||||
List<TagModel>? tags;
|
List<TagModel>? tags;
|
||||||
|
String internalId;
|
||||||
|
|
||||||
SubspaceTemplateModel({
|
SubspaceTemplateModel({
|
||||||
this.uuid,
|
this.uuid,
|
||||||
required this.subspaceName,
|
required this.subspaceName,
|
||||||
required this.disabled,
|
required this.disabled,
|
||||||
this.tags,
|
this.tags,
|
||||||
});
|
String? internalId,
|
||||||
|
}) : internalId = internalId ?? const Uuid().v4();
|
||||||
|
|
||||||
factory SubspaceTemplateModel.fromJson(Map<String, dynamic> json) {
|
factory SubspaceTemplateModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
final String internalId = json['internalId'] ?? const Uuid().v4();
|
||||||
|
|
||||||
return SubspaceTemplateModel(
|
return SubspaceTemplateModel(
|
||||||
uuid: json['uuid'] ?? '',
|
uuid: json['uuid'] ?? '',
|
||||||
subspaceName: json['subspaceName'] ?? '',
|
subspaceName: json['subspaceName'] ?? '',
|
||||||
|
internalId: internalId,
|
||||||
disabled: json['disabled'] ?? false,
|
disabled: json['disabled'] ?? false,
|
||||||
tags: (json['tags'] as List<dynamic>?)
|
tags: (json['tags'] as List<dynamic>?)
|
||||||
?.map((item) => TagModel.fromJson(item))
|
?.map((item) => TagModel.fromJson(item))
|
||||||
@ -33,4 +39,20 @@ class SubspaceTemplateModel {
|
|||||||
'tags': tags?.map((e) => e.toJson()).toList() ?? [],
|
'tags': tags?.map((e) => e.toJson()).toList() ?? [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SubspaceTemplateModel copyWith({
|
||||||
|
String? uuid,
|
||||||
|
String? subspaceName,
|
||||||
|
bool? disabled,
|
||||||
|
List<TagModel>? tags,
|
||||||
|
String? internalId,
|
||||||
|
}) {
|
||||||
|
return SubspaceTemplateModel(
|
||||||
|
uuid: uuid ?? this.uuid,
|
||||||
|
subspaceName: subspaceName ?? this.subspaceName,
|
||||||
|
disabled: disabled ?? this.disabled,
|
||||||
|
tags: tags ?? this.tags,
|
||||||
|
internalId: internalId ?? this.internalId,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,15 +30,16 @@ class TagModel {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TagModel copyWith({
|
TagModel copyWith(
|
||||||
String? tag,
|
{String? tag,
|
||||||
ProductModel? product,
|
ProductModel? product,
|
||||||
String? location,
|
String? location,
|
||||||
}) {
|
String? internalId}) {
|
||||||
return TagModel(
|
return TagModel(
|
||||||
tag: tag ?? this.tag,
|
tag: tag ?? this.tag,
|
||||||
product: product ?? this.product,
|
product: product ?? this.product,
|
||||||
location: location ?? this.location,
|
location: location ?? this.location,
|
||||||
|
internalId: internalId ?? this.internalId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,4 +59,4 @@ extension TagModelExtensions on TagModel {
|
|||||||
..tag = tag ?? ''
|
..tag = tag ?? ''
|
||||||
..productUuid = product?.uuid;
|
..productUuid = product?.uuid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,15 +44,15 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
|||||||
child: BlocProvider(
|
child: BlocProvider(
|
||||||
create: (_) {
|
create: (_) {
|
||||||
final bloc = CreateSpaceModelBloc(_spaceModelApi);
|
final bloc = CreateSpaceModelBloc(_spaceModelApi);
|
||||||
if (spaceModel != null) {
|
if (spaceModel != null) {
|
||||||
bloc.add(UpdateSpaceTemplate(spaceModel!));
|
bloc.add(UpdateSpaceTemplate(spaceModel!));
|
||||||
} else {
|
} else {
|
||||||
bloc.add(UpdateSpaceTemplate(SpaceTemplateModel(
|
bloc.add(UpdateSpaceTemplate(SpaceTemplateModel(
|
||||||
modelName: '',
|
modelName: '',
|
||||||
subspaceModels: const [],
|
subspaceModels: const [],
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
spaceNameController.addListener(() {
|
spaceNameController.addListener(() {
|
||||||
bloc.add(UpdateSpaceTemplateName(name: spaceNameController.text));
|
bloc.add(UpdateSpaceTemplateName(name: spaceNameController.text));
|
||||||
});
|
});
|
||||||
@ -72,7 +72,9 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
spaceModel?.uuid == null ? 'Create New Space Model': 'Edit Space Model',
|
spaceModel?.uuid == null
|
||||||
|
? 'Create New Space Model'
|
||||||
|
: 'Edit Space Model',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.headlineLarge
|
.headlineLarge
|
||||||
@ -127,16 +129,18 @@ class CreateSpaceModelDialog extends StatelessWidget {
|
|||||||
allTags: allTags,
|
allTags: allTags,
|
||||||
spaceNameController: spaceNameController,
|
spaceNameController: spaceNameController,
|
||||||
onLoad: (tags, subspaces) {
|
onLoad: (tags, subspaces) {
|
||||||
if(subspaces!=null){
|
if (context.read<CreateSpaceModelBloc>().state
|
||||||
context
|
is CreateSpaceModelLoaded) {
|
||||||
.read<CreateSpaceModelBloc>()
|
if (subspaces != null) {
|
||||||
.add(AddSubspacesToSpaceTemplate(subspaces));
|
|
||||||
}
|
|
||||||
if(tags!=null){
|
|
||||||
context
|
context
|
||||||
.read<CreateSpaceModelBloc>()
|
.read<CreateSpaceModelBloc>()
|
||||||
.add(AddTagsToSpaceTemplate(tags));
|
.add(AddSubspacesToSpaceTemplate(subspaces));
|
||||||
|
}
|
||||||
|
if (tags != null) {
|
||||||
|
context
|
||||||
|
.read<CreateSpaceModelBloc>()
|
||||||
|
.add(AddTagsToSpaceTemplate(tags));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart';
|
||||||
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
|
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.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/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/models/tag_model.dart';
|
||||||
@ -53,7 +54,7 @@ class TagChipDisplay extends StatelessWidget {
|
|||||||
runSpacing: 8.0,
|
runSpacing: 8.0,
|
||||||
children: [
|
children: [
|
||||||
// Combine tags from spaceModel and subspaces
|
// Combine tags from spaceModel and subspaces
|
||||||
..._groupTags([
|
...TagHelper.groupTags([
|
||||||
...?spaceModel?.tags,
|
...?spaceModel?.tags,
|
||||||
...?spaceModel?.subspaceModels
|
...?spaceModel?.subspaceModels
|
||||||
?.expand((subspace) => subspace.tags ?? [])
|
?.expand((subspace) => subspace.tags ?? [])
|
||||||
@ -84,24 +85,32 @@ class TagChipDisplay extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
Navigator.of(context).pop();
|
// Use the Navigator's context for showDialog
|
||||||
|
final navigatorContext =
|
||||||
|
Navigator.of(context).overlay?.context;
|
||||||
|
|
||||||
await showDialog<bool>(
|
if (navigatorContext != null) {
|
||||||
barrierDismissible: false,
|
await showDialog<bool>(
|
||||||
context: context,
|
barrierDismissible: false,
|
||||||
builder: (context) => AddDeviceTypeModelWidget(
|
context: navigatorContext,
|
||||||
isCreate: false,
|
builder: (context) => AssignTagModelsDialog(
|
||||||
products: products,
|
products: products,
|
||||||
subspaces: subspaces,
|
subspaces: subspaces,
|
||||||
allTags: allTags,
|
allTags: allTags,
|
||||||
spaceName: spaceNameController.text,
|
initialTags: TagHelper.generateInitialTags(
|
||||||
spaceTagModels: spaceModel?.tags,
|
subspaces: subspaces,
|
||||||
initialSelectedProducts:
|
spaceTagModels: spaceModel?.tags ?? []),
|
||||||
_createInitialSelectedProducts(
|
title: 'Edit Device',
|
||||||
spaceModel?.tags, spaceModel?.subspaceModels),
|
addedProducts:
|
||||||
),
|
TagHelper.createInitialSelectedProducts(
|
||||||
);
|
spaceModel?.tags ?? [], subspaces),
|
||||||
// Edit action
|
spaceName: spaceModel?.modelName ?? '',
|
||||||
|
onUpdate: (tags, subspaces){
|
||||||
|
print("here");
|
||||||
|
onLoad?.call(tags, subspaces);}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: Chip(
|
child: Chip(
|
||||||
label: const Text(
|
label: const Text(
|
||||||
@ -130,11 +139,7 @@ class TagChipDisplay extends StatelessWidget {
|
|||||||
allTags: allTags,
|
allTags: allTags,
|
||||||
spaceName: spaceNameController.text,
|
spaceName: spaceNameController.text,
|
||||||
isCreate: true,
|
isCreate: true,
|
||||||
onLoad: (tags, subspaces) {
|
onLoad: (tags, subspaces) => onLoad?.call(tags, subspaces),
|
||||||
if (onLoad != null) {
|
|
||||||
onLoad!(tags, subspaces);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -147,49 +152,4 @@ class TagChipDisplay extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<ProductModel, int> _groupTags(List<TagModel> tags) {
|
|
||||||
final Map<ProductModel, int> groupedTags = {};
|
|
||||||
for (var tag in tags) {
|
|
||||||
if (tag.product != null) {
|
|
||||||
groupedTags[tag.product!] = (groupedTags[tag.product!] ?? 0) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return groupedTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<SelectedProduct> _createInitialSelectedProducts(
|
|
||||||
List<TagModel>? tags, List<SubspaceTemplateModel>? subspaces) {
|
|
||||||
final Map<ProductModel, int> productCounts = {};
|
|
||||||
|
|
||||||
if (tags != null) {
|
|
||||||
for (var tag in tags) {
|
|
||||||
if (tag.product != null) {
|
|
||||||
productCounts[tag.product!] = (productCounts[tag.product!] ?? 0) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subspaces != null) {
|
|
||||||
for (var subspace in subspaces) {
|
|
||||||
if (subspace.tags != null) {
|
|
||||||
for (var tag in subspace.tags!) {
|
|
||||||
if (tag.product != null) {
|
|
||||||
productCounts[tag.product!] =
|
|
||||||
(productCounts[tag.product!] ?? 0) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return productCounts.entries
|
|
||||||
.map((entry) => SelectedProduct(
|
|
||||||
productId: entry.key.uuid,
|
|
||||||
count: entry.value,
|
|
||||||
productName: entry.key.name ?? 'Unnamed',
|
|
||||||
product: entry.key,
|
|
||||||
))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,6 +23,8 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
|
|||||||
final bool isCreate;
|
final bool isCreate;
|
||||||
final void Function(
|
final void Function(
|
||||||
List<TagModel>? tags, List<SubspaceTemplateModel>? subspaces)? onLoad;
|
List<TagModel>? tags, List<SubspaceTemplateModel>? subspaces)? onLoad;
|
||||||
|
final void Function(
|
||||||
|
List<TagModel>? tags, List<SubspaceTemplateModel>? subspaces)? onUpdate;
|
||||||
|
|
||||||
const AddDeviceTypeModelWidget({
|
const AddDeviceTypeModelWidget({
|
||||||
super.key,
|
super.key,
|
||||||
@ -34,10 +36,18 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
|
|||||||
required this.spaceName,
|
required this.spaceName,
|
||||||
required this.isCreate,
|
required this.isCreate,
|
||||||
this.onLoad,
|
this.onLoad,
|
||||||
|
this.onUpdate,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
|
if (spaceTagModels != null) {
|
||||||
|
for (var tag in spaceTagModels!) {
|
||||||
|
print(tag.tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final size = MediaQuery.of(context).size;
|
final size = MediaQuery.of(context).size;
|
||||||
final crossAxisCount = size.width > 1200
|
final crossAxisCount = size.width > 1200
|
||||||
? 8
|
? 8
|
||||||
@ -123,15 +133,12 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
|
|||||||
spaceTagModels: spaceTagModels,
|
spaceTagModels: spaceTagModels,
|
||||||
subspaces: subspaces,
|
subspaces: subspaces,
|
||||||
);
|
);
|
||||||
if (isCreate) {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
final dialogTitle = initialTags.isNotEmpty
|
final dialogTitle = initialTags.isNotEmpty
|
||||||
? 'Edit Device'
|
? 'Edit Device'
|
||||||
: 'Assign Tags';
|
: 'Assign Tags';
|
||||||
|
Navigator.of(context).pop();
|
||||||
await showDialog<bool>(
|
await showDialog<bool>(
|
||||||
barrierDismissible: false,
|
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AssignTagModelsDialog(
|
builder: (context) => AssignTagModelsDialog(
|
||||||
products: products,
|
products: products,
|
||||||
@ -142,9 +149,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
|
|||||||
initialTags: state.initialTag,
|
initialTags: state.initialTag,
|
||||||
title: dialogTitle,
|
title: dialogTitle,
|
||||||
onUpdate: (tags, subspaces) {
|
onUpdate: (tags, subspaces) {
|
||||||
if (onLoad != null) {
|
onLoad?.call(tags, subspaces);
|
||||||
onLoad!(tags, subspaces);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user