updated tag issue for subspace

This commit is contained in:
hannathkadher
2025-01-23 00:02:28 +04:00
parent 830725254f
commit 65d00c923a
19 changed files with 408 additions and 349 deletions

39
lib/common/edit_chip.dart Normal file
View File

@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class EditChip extends StatelessWidget {
final String label;
final VoidCallback onTap;
final Color labelColor;
final Color backgroundColor;
final Color borderColor;
final double borderRadius;
const EditChip({
Key? key,
this.label = 'Edit',
required this.onTap,
this.labelColor = ColorsManager.spaceColor,
this.backgroundColor = ColorsManager.whiteColors,
this.borderColor = ColorsManager.spaceColor,
this.borderRadius = 16.0,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Chip(
label: Text(
label,
style: TextStyle(color: labelColor),
),
backgroundColor: backgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadius),
side: BorderSide(color: borderColor),
),
),
);
}
}

View File

@ -0,0 +1,26 @@
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
import 'package:uuid/uuid.dart';
abstract class BaseTag {
String? uuid;
String? tag;
final ProductModel? product;
String internalId;
String? location;
BaseTag({
this.uuid,
required this.tag,
this.product,
String? internalId,
this.location,
}) : internalId = internalId ?? const Uuid().v4();
Map<String, dynamic> toJson();
BaseTag copyWith({
String? tag,
ProductModel? product,
String? location,
String? internalId,
});
}

View File

@ -1,22 +1,23 @@
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/base_tag.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_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/tag_body_model.dart';
import 'package:uuid/uuid.dart';
class Tag {
String? uuid;
String? tag;
final ProductModel? product;
String internalId;
String? location;
Tag(
{this.uuid,
required this.tag,
this.product,
String? internalId,
this.location})
: internalId = internalId ?? const Uuid().v4();
class Tag extends BaseTag {
Tag({
String? uuid,
required String? tag,
ProductModel? product,
String? internalId,
String? location,
}) : super(
uuid: uuid,
tag: tag,
product: product,
internalId: internalId,
location: location,
);
factory Tag.fromJson(Map<String, dynamic> json) {
final String internalId = json['internalId'] ?? const Uuid().v4();
@ -31,15 +32,19 @@ class Tag {
);
}
@override
Tag copyWith({
String? tag,
ProductModel? product,
String? location,
String? internalId,
}) {
return Tag(
uuid: uuid,
tag: tag ?? this.tag,
product: product ?? this.product,
location: location ?? this.location,
internalId: internalId ?? this.internalId,
);
}
@ -60,7 +65,7 @@ extension TagModelExtensions on Tag {
..productUuid = product?.uuid;
}
CreateTagBodyModel toCreateTagBodyModel() {
CreateTagBodyModel toCreateTagBodyModel() {
return CreateTagBodyModel()
..tag = tag ?? ''
..productUuid = product?.uuid;

View File

@ -344,6 +344,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
builder: (BuildContext context) {
return CreateSpaceDialog(
products: widget.products,
spaceModels: widget.spaceModels,
name: space.name,
icon: space.icon,
editSpace: space,

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/common/edit_chip.dart';
import 'package:syncrow_web/pages/common/buttons/cancel_button.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/spaces_management/add_device_type/views/add_device_type_widget.dart';
@ -10,15 +11,23 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_mo
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/dialogs/icon_selection_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/create_subspace/views/create_subspace_model_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart';
import 'package:syncrow_web/pages/spaces_management/link_space_model/view/link_space_model_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/button_content_widget.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/constants/space_icon_const.dart';
class CreateSpaceDialog extends StatefulWidget {
final Function(String, String, List<SelectedProduct> selectedProducts,
SpaceTemplateModel? spaceModel, List<SubspaceModel>? subspaces, List<Tag>? tags) onCreateSpace;
final Function(
String,
String,
List<SelectedProduct> selectedProducts,
SpaceTemplateModel? spaceModel,
List<SubspaceModel>? subspaces,
List<Tag>? tags) onCreateSpace;
final List<ProductModel>? products;
final String? name;
final String? icon;
@ -211,42 +220,13 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
),
const SizedBox(height: 10),
selectedSpaceModel == null
? DefaultButton(
? TextButton(
onPressed: () {
_showLinkSpaceModelDialog(context);
},
backgroundColor: ColorsManager.textFieldGreyColor,
foregroundColor: Colors.black,
borderColor: ColorsManager.neutralGray,
borderRadius: 16.0,
padding: 10.0, // Reduced padding for smaller size
child: Align(
alignment: Alignment.centerLeft,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(left: 6.0),
child: SvgPicture.asset(
Assets.link,
width: screenWidth *
0.015, // Adjust icon size
height: screenWidth * 0.015,
),
),
const SizedBox(width: 3),
Flexible(
child: Text(
'Link a space model',
overflow: TextOverflow
.ellipsis, // Prevent overflow
style: Theme.of(context)
.textTheme
.bodyMedium,
),
),
],
),
child: const ButtonContentWidget(
svgAssets: Assets.link,
label: 'Link a space model',
),
)
: Container(
@ -307,7 +287,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0),
padding: EdgeInsets.symmetric(horizontal: 6.0),
child: Text(
'OR',
style: TextStyle(
@ -326,47 +306,21 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
),
const SizedBox(height: 25),
subspaces == null
? DefaultButton(
onPressed: () {
? TextButton(
style: TextButton.styleFrom(
overlayColor: ColorsManager.transparentColor,
),
onPressed: () async {
_showSubSpaceDialog(context, enteredName, [],
false, widget.products, subspaces);
},
backgroundColor: ColorsManager.textFieldGreyColor,
foregroundColor: Colors.black,
borderColor: ColorsManager.neutralGray,
borderRadius: 16.0,
padding: 10.0, // Reduced padding for smaller size
child: Align(
alignment: Alignment.centerLeft,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(left: 6.0),
child: SvgPicture.asset(
Assets.addIcon,
width: screenWidth *
0.015, // Adjust icon size
height: screenWidth * 0.015,
),
),
const SizedBox(width: 3),
Flexible(
child: Text(
'Create sub space',
overflow: TextOverflow
.ellipsis, // Prevent overflow
style: Theme.of(context)
.textTheme
.bodyMedium,
),
),
],
),
child: const ButtonContentWidget(
icon: Icons.add,
label: 'Create Sub Space',
),
)
: SizedBox(
width: screenWidth * 0.35,
width: screenWidth * 0.25,
child: Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
@ -383,49 +337,15 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
children: [
if (subspaces != null)
...subspaces!.map(
(subspace) => Chip(
label: Text(
subspace.subspaceName,
style: const TextStyle(
color: ColorsManager
.spaceColor), // Text color
),
backgroundColor: ColorsManager
.whiteColors, // Chip background color
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
16), // Rounded chip
side: const BorderSide(
color: ColorsManager
.spaceColor), // Border color
),
),
),
GestureDetector(
(subspace) => SubspaceNameDisplayWidget(
text: subspace.subspaceName,
)),
EditChip(
onTap: () async {
_showSubSpaceDialog(
context,
enteredName,
[],
false,
widget.products,
subspaces);
_showSubSpaceDialog(context, enteredName,
[], true, widget.products, subspaces);
},
child: Chip(
label: const Text(
'Edit',
style: TextStyle(
color: ColorsManager.spaceColor),
),
backgroundColor:
ColorsManager.whiteColors,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: const BorderSide(
color: ColorsManager.spaceColor),
),
),
),
)
],
),
),
@ -452,7 +372,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
runSpacing: 8.0,
children: [
// Combine tags from spaceModel and subspaces
..._groupTags([
...TagHelper.groupTags([
...?tags,
...?subspaces?.expand(
(subspace) => subspace.tags ?? [])
@ -484,70 +404,31 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
),
),
),
GestureDetector(
onTap: () async {
_showTagCreateDialog(context, enteredName,
widget.products);
// Edit action
},
child: Chip(
label: const Text(
'Edit',
style: TextStyle(
color: ColorsManager.spaceColor),
),
backgroundColor:
ColorsManager.whiteColors,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: const BorderSide(
color: ColorsManager.spaceColor),
),
),
),
EditChip(onTap: () async {
_showTagCreateDialog(
context,
enteredName,
widget.products,
);
// Edit action
})
],
),
),
)
: DefaultButton(
: TextButton(
onPressed: () {
_showTagCreateDialog(
context, enteredName, widget.products);
},
backgroundColor: ColorsManager.textFieldGreyColor,
foregroundColor: Colors.black,
borderColor: ColorsManager.neutralGray,
borderRadius: 16.0,
padding: 10.0, // Reduced padding for smaller size
child: Align(
alignment: Alignment.centerLeft,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(left: 6.0),
child: SvgPicture.asset(
Assets.addIcon,
width: screenWidth *
0.015, // Adjust icon size
height: screenWidth * 0.015,
),
),
const SizedBox(width: 3),
Flexible(
child: Text(
'Add devices',
overflow: TextOverflow
.ellipsis, // Prevent overflow
style: Theme.of(context)
.textTheme
.bodyMedium,
),
),
],
),
style: TextButton.styleFrom(
padding: EdgeInsets.zero,
),
)
child: const ButtonContentWidget(
icon: Icons.add,
label: 'Add Devices',
))
],
),
),
@ -579,8 +460,13 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
? enteredName
: (widget.name ?? '');
if (newName.isNotEmpty) {
widget.onCreateSpace(newName, selectedIcon,
selectedProducts, selectedSpaceModel,subspaces,tags);
widget.onCreateSpace(
newName,
selectedIcon,
selectedProducts,
selectedSpaceModel,
subspaces,
tags);
Navigator.of(context).pop();
}
}
@ -655,7 +541,7 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
builder: (BuildContext context) {
return CreateSubSpaceDialog(
spaceName: name,
dialogTitle: 'Create Sub-space',
dialogTitle: isEdit ? 'Edit Sub-space' : 'Create Sub-space',
spaceTags: spaceTags,
isEdit: isEdit,
products: products,

View File

@ -29,6 +29,7 @@ class AssignTagModelsDialog extends StatelessWidget {
final String title;
final BuildContext? pageContext;
final List<String>? otherSpaceModels;
final List<SpaceTemplateModel>? allSpaceModels;
const AssignTagModelsDialog(
{Key? key,
@ -42,7 +43,8 @@ class AssignTagModelsDialog extends StatelessWidget {
required this.title,
this.pageContext,
this.otherSpaceModels,
this.spaceModel})
this.spaceModel,
this.allSpaceModels})
: super(key: key);
@override
@ -212,8 +214,8 @@ class AssignTagModelsDialog extends StatelessWidget {
width: double.infinity,
child: DialogDropdown(
items: locations,
selectedValue:
tag.location ?? 'Main Space',
selectedValue: tag.location ??
'Main Space',
onSelected: (value) {
context
.read<
@ -250,8 +252,7 @@ class AssignTagModelsDialog extends StatelessWidget {
label: 'Add New Device',
onPressed: () async {
for (var tag in state.tags) {
if (tag.location == null ||
subspaces == null) {
if (tag.location == null) {
continue;
}
@ -352,6 +353,7 @@ class AssignTagModelsDialog extends StatelessWidget {
builder: (BuildContext dialogContext) {
return CreateSpaceModelDialog(
products: products,
allSpaceModels: allSpaceModels,
allTags: allTags,
pageContext: pageContext,
otherSpaceModels: otherSpaceModels,

View File

@ -6,18 +6,23 @@ import 'subspace_event.dart';
import 'subspace_state.dart';
class SubSpaceBloc extends Bloc<SubSpaceEvent, SubSpaceState> {
SubSpaceBloc() : super(SubSpaceState([], [], '')) {
SubSpaceBloc() : super(SubSpaceState([], [], '',{})) {
on<AddSubSpace>((event, emit) {
final existingNames =
state.subSpaces.map((e) => e.subspaceName).toSet();
final existingNames = state.subSpaces.map((e) => e.subspaceName).toSet();
if (existingNames.contains(event.subSpace.subspaceName.toLowerCase())) {
final updatedDuplicates = Set<String>.from(state.duplicates)
..add(event.subSpace.subspaceName.toLowerCase());
final updatedSubSpaces = List<SubspaceModel>.from(state.subSpaces)
..add(event.subSpace);
emit(SubSpaceState(
state.subSpaces,
updatedSubSpaces,
state.updatedSubSpaceModels,
'Subspace name already exists.',
'*Duplicated sub-space name',
updatedDuplicates,
));
} else {
// Add subspace if no duplicate exists
final updatedSubSpaces = List<SubspaceModel>.from(state.subSpaces)
..add(event.subSpace);
@ -25,6 +30,8 @@ class SubSpaceBloc extends Bloc<SubSpaceEvent, SubSpaceState> {
updatedSubSpaces,
state.updatedSubSpaceModels,
'',
state.duplicates,
// Clear error message
));
}
});
@ -38,6 +45,16 @@ class SubSpaceBloc extends Bloc<SubSpaceEvent, SubSpaceState> {
state.updatedSubSpaceModels,
);
final nameOccurrences = <String, int>{};
for (final subSpace in updatedSubSpaces) {
final lowerName = subSpace.subspaceName.toLowerCase();
nameOccurrences[lowerName] = (nameOccurrences[lowerName] ?? 0) + 1;
}
final updatedDuplicates = nameOccurrences.entries
.where((entry) => entry.value > 1)
.map((entry) => entry.key)
.toSet();
if (event.subSpace.uuid?.isNotEmpty ?? false) {
updatedSubspaceModels.add(UpdateSubspaceModel(
action: Action.delete,
@ -45,13 +62,36 @@ class SubSpaceBloc extends Bloc<SubSpaceEvent, SubSpaceState> {
));
}
emit(SubSpaceState(
updatedSubSpaces,
updatedSubspaceModels,
'', // Clear error message
));
emit(SubSpaceState(updatedSubSpaces, updatedSubspaceModels, '',
updatedDuplicates // Clear error message
));
});
// Handle UpdateSubSpace Event
on<UpdateSubSpace>((event, emit) {
final updatedSubSpaces = state.subSpaces.map((subSpace) {
if (subSpace.uuid == event.updatedSubSpace.uuid) {
return event.updatedSubSpace;
}
return subSpace;
}).toList();
final updatedSubspaceModels = List<UpdateSubspaceModel>.from(
state.updatedSubSpaceModels,
);
updatedSubspaceModels.add(UpdateSubspaceModel(
action: Action.update,
uuid: event.updatedSubSpace.uuid!,
));
emit(SubSpaceState(
updatedSubSpaces,
updatedSubspaceModels,
'',
state.duplicates,
));
});
}
}

View File

@ -4,23 +4,26 @@ class SubSpaceState {
final List<SubspaceModel> subSpaces;
final List<UpdateSubspaceModel> updatedSubSpaceModels;
final String errorMessage;
final Set<String> duplicates;
SubSpaceState(
this.subSpaces,
this.updatedSubSpaceModels,
this.errorMessage,
this.duplicates,
);
SubSpaceState copyWith({
List<SubspaceModel>? subSpaces,
List<UpdateSubspaceModel>? updatedSubSpaceModels,
String? errorMessage,
Set<String>? duplicates,
}) {
return SubSpaceState(
subSpaces ?? this.subSpaces,
updatedSubSpaceModels ?? this.updatedSubSpaceModels,
errorMessage ?? this.errorMessage,
duplicates ?? this.duplicates,
);
}
}

View File

@ -81,41 +81,64 @@ class CreateSubSpaceDialog extends StatelessWidget {
spacing: 8.0,
runSpacing: 8.0,
children: [
...state.subSpaces.map(
(subSpace) => Chip(
label: Text(
subSpace.subspaceName,
style: const TextStyle(
color: ColorsManager.spaceColor),
),
backgroundColor: ColorsManager.whiteColors,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: const BorderSide(
color: ColorsManager.transparentColor,
width: 0,
),
),
deleteIcon: Container(
width: 24,
height: 24,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: ColorsManager.lightGrayColor,
width: 1.5,
...state.subSpaces.asMap().entries.map(
(entry) {
final index = entry.key;
final subSpace = entry.value;
final lowerName =
subSpace.subspaceName.toLowerCase();
final duplicateIndices = state.subSpaces
.asMap()
.entries
.where((e) =>
e.value.subspaceName.toLowerCase() ==
lowerName)
.map((e) => e.key)
.toList();
final isDuplicate =
duplicateIndices.length > 1 &&
duplicateIndices.indexOf(index) != 0;
return Chip(
label: Text(
subSpace.subspaceName,
style: const TextStyle(
color: ColorsManager.spaceColor,
),
),
child: const Icon(
Icons.close,
size: 16,
color: ColorsManager.lightGrayColor,
backgroundColor: ColorsManager.whiteColors,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: BorderSide(
color: isDuplicate
? ColorsManager.red
: ColorsManager.transparentColor,
width: 0,
),
),
),
onDeleted: () => context
.read<SubSpaceBloc>()
.add(RemoveSubSpace(subSpace)),
),
deleteIcon: Container(
width: 24,
height: 24,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: ColorsManager.lightGrayColor,
width: 1.5,
),
),
child: const Icon(
Icons.close,
size: 16,
color: ColorsManager.lightGrayColor,
),
),
onDeleted: () => context
.read<SubSpaceBloc>()
.add(RemoveSubSpace(subSpace)),
);
},
),
SizedBox(
width: 200,
@ -142,27 +165,29 @@ class CreateSubSpaceDialog extends StatelessWidget {
color: ColorsManager.blackColor),
),
),
if (state.errorMessage.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
state.errorMessage,
style: const TextStyle(
color: ColorsManager.warningRed,
fontSize: 12,
),
),
),
],
),
),
if (state.errorMessage.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
state.errorMessage,
style: const TextStyle(
color: ColorsManager.warningRed,
fontSize: 12,
),
),
),
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: CancelButton(
label: 'Cancel',
onPressed: () async {},
onPressed: () async {
Navigator.of(context).pop();
},
),
),
const SizedBox(width: 10),

View File

@ -1,3 +1,4 @@
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/base_tag.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/space_model/models/subspace_template_model.dart';
@ -33,7 +34,7 @@ class TagHelper {
return initialTags;
}
static Map<ProductModel, int> groupTags(List<TagModel> tags) {
static Map<ProductModel, int> groupTags(List<BaseTag> tags) {
final Map<ProductModel, int> groupedTags = {};
for (var tag in tags) {
if (tag.product != null) {

View File

@ -301,7 +301,7 @@ class CreateSpaceModelBloc
if (newTags != null || prevTags != null) {
// Case 1: Tags deleted
if (prevTags != null && newTags != null) {
for (var prevTag in prevTags!) {
for (var prevTag in prevTags) {
final existsInNew =
newTags!.any((newTag) => newTag.uuid == prevTag.uuid);
if (!existsInNew) {

View File

@ -1,22 +1,22 @@
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/base_tag.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart';
import 'package:uuid/uuid.dart';
class TagModel {
String? uuid;
String? tag;
final ProductModel? product;
String internalId;
String? location;
TagModel(
{this.uuid,
required this.tag,
this.product,
String? internalId,
this.location})
: internalId = internalId ?? const Uuid().v4();
class TagModel extends BaseTag {
TagModel({
String? uuid,
required String? tag,
ProductModel? product,
String? internalId,
String? location,
}) : super(
uuid: uuid,
tag: tag,
product: product,
internalId: internalId,
location: location,
);
factory TagModel.fromJson(Map<String, dynamic> json) {
final String internalId = json['internalId'] ?? const Uuid().v4();
@ -30,16 +30,19 @@ class TagModel {
);
}
@override
TagModel copyWith(
{String? tag,
ProductModel? product,
String? uuid,
String? location,
String? internalId}) {
String? internalId}) {
return TagModel(
tag: tag ?? this.tag,
product: product ?? this.product,
location: location ?? this.location,
internalId: internalId ?? this.internalId,
uuid:uuid?? this.uuid
);
}

View File

@ -63,7 +63,8 @@ class SpaceModelPage extends StatelessWidget {
}
// Render existing space model
final model = spaceModels[index];
final otherModel = List<String>.from(allSpaceModelNames);
final otherModel =
List<String>.from(allSpaceModelNames);
otherModel.remove(model.modelName);
return GestureDetector(
onTap: () {
@ -76,6 +77,7 @@ class SpaceModelPage extends StatelessWidget {
spaceModel: model,
otherSpaceModels: otherModel,
pageContext: context,
allSpaceModels: spaceModels,
);
},
);

View File

@ -1,15 +1,15 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class ButtonContentWidget extends StatelessWidget {
final IconData icon;
final IconData? icon;
final String label;
final String? svgAssets;
const ButtonContentWidget({
Key? key,
required this.icon,
required this.label,
}) : super(key: key);
const ButtonContentWidget(
{Key? key, this.icon, required this.label, this.svgAssets})
: super(key: key);
@override
Widget build(BuildContext context) {
@ -30,10 +30,20 @@ class ButtonContentWidget extends StatelessWidget {
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 16.0),
child: Row(
children: [
Icon(
icon,
color: ColorsManager.spaceColor,
),
if (icon != null)
Icon(
icon,
color: ColorsManager.spaceColor,
),
if (svgAssets != null)
Padding(
padding: const EdgeInsets.only(left: 6.0),
child: SvgPicture.asset(
svgAssets!,
width: screenWidth * 0.015, // Adjust icon size
height: screenWidth * 0.015,
),
),
const SizedBox(width: 10),
Expanded(
child: Text(

View File

@ -22,6 +22,7 @@ class CreateSpaceModelDialog extends StatelessWidget {
final SpaceTemplateModel? spaceModel;
final BuildContext? pageContext;
final List<String>? otherSpaceModels;
final List<SpaceTemplateModel>? allSpaceModels;
const CreateSpaceModelDialog(
{Key? key,
@ -29,7 +30,8 @@ class CreateSpaceModelDialog extends StatelessWidget {
this.allTags,
this.spaceModel,
this.pageContext,
this.otherSpaceModels})
this.otherSpaceModels,
this.allSpaceModels})
: super(key: key);
@override
@ -138,6 +140,7 @@ class CreateSpaceModelDialog extends StatelessWidget {
spaceNameController: spaceNameController,
pageContext: pageContext,
otherSpaceModels: otherSpaceModels,
allSpaceModels: allSpaceModels,
),
const SizedBox(height: 20),
SizedBox(
@ -147,7 +150,8 @@ class CreateSpaceModelDialog extends StatelessWidget {
Expanded(
child: CancelButton(
label: 'Cancel',
onPressed: () => Navigator.of(context).pop(),
onPressed: (){
Navigator.of(context).pop();},
),
),
const SizedBox(width: 10),

View File

@ -1,7 +1,9 @@
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/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';
import 'package:syncrow_web/utils/color_manager.dart';
class SubspaceModelCreate extends StatelessWidget {
@ -46,39 +48,13 @@ class SubspaceModelCreate extends StatelessWidget {
spacing: 8.0,
runSpacing: 8.0,
children: [
...subspaces.map((subspace) => Container(
padding: const EdgeInsets.symmetric(
horizontal: 8.0, vertical: 4.0),
decoration: BoxDecoration(
color: ColorsManager.whiteColors,
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: ColorsManager.transparentColor),
),
child: Text(
subspace.subspaceName,
style: Theme.of(context)
.textTheme
.bodySmall
?.copyWith(color: ColorsManager.spaceColor),
),
...subspaces.map((subspace) => SubspaceNameDisplayWidget(
text: subspace.subspaceName,
)),
GestureDetector(
EditChip(
onTap: () async {
await _openDialog(context, 'Edit Sub-space');
},
child: Chip(
label: const Text(
'Edit',
style: TextStyle(color: ColorsManager.spaceColor),
),
backgroundColor: ColorsManager.whiteColors,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side:
const BorderSide(color: ColorsManager.spaceColor),
),
),
),
],
),

View File

@ -0,0 +1,40 @@
import 'package:flutter/material.dart';
class SubspaceNameDisplayWidget extends StatelessWidget {
final String text;
final TextStyle? textStyle;
final Color backgroundColor;
final Color borderColor;
final EdgeInsetsGeometry padding;
final BorderRadiusGeometry borderRadius;
const SubspaceNameDisplayWidget({
Key? key,
required this.text,
this.textStyle,
this.backgroundColor = Colors.white,
this.borderColor = Colors.transparent,
this.padding = const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
this.borderRadius = const BorderRadius.all(Radius.circular(10)),
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: padding,
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: borderRadius,
border: Border.all(color: borderColor),
),
child: Text(
text,
style: textStyle ??
Theme.of(context)
.textTheme
.bodySmall
?.copyWith(color: Colors.black),
),
);
}
}

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_web/common/edit_chip.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/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';
@ -18,6 +19,7 @@ class TagChipDisplay extends StatelessWidget {
final TextEditingController spaceNameController;
final BuildContext? pageContext;
final List<String>? otherSpaceModels;
final List<SpaceTemplateModel>? allSpaceModels;
const TagChipDisplay(BuildContext context,
{Key? key,
@ -28,7 +30,8 @@ class TagChipDisplay extends StatelessWidget {
required this.allTags,
required this.spaceNameController,
this.pageContext,
this.otherSpaceModels})
this.otherSpaceModels,
this.allSpaceModels})
: super(key: key);
@override
@ -83,45 +86,31 @@ class TagChipDisplay extends StatelessWidget {
),
),
),
GestureDetector(
onTap: () async {
// Use the Navigator's context for showDialog
final navigatorContext =
Navigator.of(context).overlay?.context;
EditChip(onTap: () async {
// Use the Navigator's context for showDialog
Navigator.of(context).pop();
if (navigatorContext != null) {
await showDialog<bool>(
barrierDismissible: false,
context: navigatorContext,
builder: (context) => AssignTagModelsDialog(
products: products,
await showDialog<bool>(
barrierDismissible: false,
context: context,
builder: (context) => AssignTagModelsDialog(
products: products,
allSpaceModels: allSpaceModels,
subspaces: subspaces,
pageContext: pageContext,
allTags: allTags,
spaceModel: spaceModel,
otherSpaceModels: otherSpaceModels,
initialTags: TagHelper.generateInitialTags(
subspaces: subspaces,
pageContext: pageContext,
allTags: allTags,
spaceModel: spaceModel,
initialTags: TagHelper.generateInitialTags(
subspaces: subspaces,
spaceTagModels: spaceModel?.tags ?? []),
title: 'Edit Device',
addedProducts:
TagHelper.createInitialSelectedProducts(
spaceModel?.tags ?? [], subspaces),
spaceName: spaceModel?.modelName ?? '',
));
}
},
child: Chip(
label: const Text(
'Edit',
style: TextStyle(color: ColorsManager.spaceColor),
),
backgroundColor: ColorsManager.whiteColors,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: const BorderSide(color: ColorsManager.spaceColor),
),
),
),
spaceTagModels: spaceModel?.tags ?? []),
title: 'Edit Device',
addedProducts:
TagHelper.createInitialSelectedProducts(
spaceModel?.tags ?? [], subspaces),
spaceName: spaceModel?.modelName ?? '',
));
})
],
),
),
@ -141,6 +130,7 @@ class TagChipDisplay extends StatelessWidget {
pageContext: pageContext,
isCreate: true,
spaceModel: spaceModel,
otherSpaceModels: otherSpaceModels,
),
);
},

View File

@ -26,6 +26,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
final List<String>? otherSpaceModels;
final BuildContext? pageContext;
final SpaceTemplateModel? spaceModel;
final List<SpaceTemplateModel>? allSpaceModels;
const AddDeviceTypeModelWidget(
{super.key,
@ -38,7 +39,8 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
required this.isCreate,
this.pageContext,
this.otherSpaceModels,
this.spaceModel});
this.spaceModel,
this.allSpaceModels});
@override
Widget build(BuildContext context) {
@ -106,6 +108,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
context: context,
builder: (BuildContext dialogContext) {
return CreateSpaceModelDialog(
allSpaceModels: allSpaceModels,
products: products,
allTags: allTags,
pageContext: pageContext,
@ -175,11 +178,12 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
context: context,
builder: (context) => AssignTagModelsDialog(
products: products,
allSpaceModels: allSpaceModels,
subspaces: subspaces,
addedProducts: state.selectedProducts,
allTags: allTags,
spaceName: spaceName,
initialTags: state.initialTag,
initialTags: initialTags,
otherSpaceModels: otherSpaceModels,
title: dialogTitle,
spaceModel: spaceModel,
@ -216,13 +220,15 @@ class AddDeviceTypeModelWidget extends StatelessWidget {
if (subspace.tags != null) {
initialTags.addAll(
subspace.tags!.map(
(tag) => tag.copyWith(location: subspace.subspaceName),
(tag) => tag.copyWith(
location: subspace.subspaceName,
tag: tag.tag,
internalId: tag.internalId),
),
);
}
}
}
return initialTags;
}
}