addign tag model

This commit is contained in:
hannathkadher
2025-01-05 23:22:30 +04:00
parent 0fda5457ae
commit a31eb27c92
13 changed files with 190 additions and 102 deletions

View File

@ -28,16 +28,36 @@ class AssignTagModelsDialog extends StatefulWidget {
class AssignTagModelsDialogState extends State<AssignTagModelsDialog> { class AssignTagModelsDialogState extends State<AssignTagModelsDialog> {
late List<TagModel> tags; late List<TagModel> tags;
late List<SelectedProduct> selectedProducts; late List<SelectedProduct> selectedProducts;
late List<String> locations;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
print(widget.addedProducts);
print(widget.subspaces);
if (widget.products != null) { // Initialize tags from widget.initialTags or create new ones if it's empty
print(widget.products); tags = widget.initialTags?.isNotEmpty == true
tags = []; ? widget.initialTags!
} : widget.addedProducts
.expand((selectedProduct) => List.generate(
selectedProduct.count, // Generate `count` number of tags
(index) => TagModel(
tag: '', // Initialize each tag with a default value
product: selectedProduct.product,
location: 'None', // Default location
),
))
.toList();
// Initialize selected products
selectedProducts = widget.addedProducts; selectedProducts = widget.addedProducts;
// Initialize locations from subspaces or empty list if null
locations = widget.subspaces != null
? widget.subspaces!.map((subspace) => subspace.subspaceName).toList()
: [];
locations.add("None");
} }
@override @override
@ -47,51 +67,121 @@ class AssignTagModelsDialogState extends State<AssignTagModelsDialog> {
backgroundColor: ColorsManager.whiteColors, backgroundColor: ColorsManager.whiteColors,
content: SingleChildScrollView( content: SingleChildScrollView(
child: Container( child: Container(
width: MediaQuery.of(context).size.width * 0.9, width: MediaQuery.of(context).size.width * 0.4,
child: DataTable( decoration: BoxDecoration(
columns: const [ border: Border.all(color: ColorsManager.dataHeaderGrey, width: 1),
DataColumn(label: Text('#')), borderRadius: BorderRadius.circular(20),
DataColumn(label: Text('Device')), ),
DataColumn(label: Text('Tag')), child: Theme(
DataColumn(label: Text('Location')), data: Theme.of(context).copyWith(
], dataTableTheme: DataTableThemeData(
rows: selectedProducts.asMap().entries.map((entry) { headingRowColor:
final index = entry.key + 1; MaterialStateProperty.all(ColorsManager.dataHeaderGrey),
final selectedProduct = entry.value; headingTextStyle: const TextStyle(
return DataRow(cells: [ color: ColorsManager.blackColor,
DataCell(Text(index.toString())), fontWeight: FontWeight.bold,
DataCell(Text(selectedProduct.productName ?? 'Unknown')),
DataCell(
DropdownButton<String>(
value:
'Tag 1', // Static text that matches an item in the list
onChanged: (value) {
// Handle value change if needed
},
items: List.generate(10, (index) {
final tag = 'Tag ${index + 1}';
return DropdownMenuItem(value: tag, child: Text(tag));
}),
),
), ),
DataCell( ),
DropdownButton<String>( ),
value: widget.subspaces?.isNotEmpty == true child: DataTable(
? widget.subspaces!.first.subspaceName border: TableBorder.all(
: null, color: ColorsManager.dataHeaderGrey,
onChanged: (value) { width: 1,
// Handle value changes here borderRadius: BorderRadius.circular(20),
}, ),
items: widget.subspaces! columns: const [
.map((subspace) => DropdownMenuItem( DataColumn(label: Text('#')),
value: subspace.subspaceName, DataColumn(label: Text('Device')),
child: Text(subspace.subspaceName), DataColumn(label: Text('Tag')),
)) DataColumn(label: Text('Location')),
.toList(), ],
), rows: tags.asMap().entries.map((entry) {
), final index = entry.key + 1;
]); final tag = entry.value;
}).toList(),
return DataRow(
cells: [
DataCell(
Center(
child: Text(index.toString()),
),
),
DataCell(
Center(
child: Text(tag.product?.catName ?? 'Unknown'),
),
),
DataCell(
Center(
child: DropdownButton<String>(
value: tag.tag!.isNotEmpty ? tag.tag : null,
onChanged: (value) {
setState(() {
tag.tag = value ?? ''; // Update tag value
});
},
items: [
const DropdownMenuItem(
value: null,
child: Text('None'),
),
...List.generate(10, (index) {
final tagName = 'Tag ${index + 1}';
return DropdownMenuItem(
value: tagName,
child: Text(tagName),
);
}),
],
),
),
),
DataCell(
Center(
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
alignment: AlignmentDirectional.centerEnd,
value: locations.contains(tag.location)
? tag.location
: null, // Validate value
onChanged: (value) {
setState(() {
tag.location =
value ?? 'None'; // Update location
});
},
dropdownColor: Colors.white,
icon: const Icon(
Icons.arrow_drop_down,
color: Colors.black,
),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.black,
),
isExpanded: true,
items: locations
.map((location) => DropdownMenuItem(
value: location,
child: Text(
location,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Colors.grey,
),
),
))
.toList(),
),
),
),
),
],
);
}).toList(),
),
), ),
), ),
), ),

View File

@ -329,7 +329,6 @@ class SpaceManagementBloc
Emitter<SpaceManagementState> emit, Emitter<SpaceManagementState> emit,
) { ) {
final communities = List<CommunityModel>.from(previousState.communities); final communities = List<CommunityModel>.from(previousState.communities);
for (var community in communities) { for (var community in communities) {
if (community.uuid == communityUuid) { if (community.uuid == communityUuid) {
@ -367,26 +366,26 @@ class SpaceManagementBloc
try { try {
if (space.uuid != null && space.uuid!.isNotEmpty) { if (space.uuid != null && space.uuid!.isNotEmpty) {
final response = await _api.updateSpace( final response = await _api.updateSpace(
communityId: communityUuid, communityId: communityUuid,
spaceId: space.uuid!, spaceId: space.uuid!,
name: space.name, name: space.name,
parentId: space.parent?.uuid, parentId: space.parent?.uuid,
isPrivate: space.isPrivate, isPrivate: space.isPrivate,
position: space.position, position: space.position,
icon: space.icon, icon: space.icon,
direction: space.incomingConnection?.direction, direction: space.incomingConnection?.direction,
products: space.selectedProducts); );
} else { } else {
// Call create if the space does not have a UUID // Call create if the space does not have a UUID
final response = await _api.createSpace( final response = await _api.createSpace(
communityId: communityUuid, communityId: communityUuid,
name: space.name, name: space.name,
parentId: space.parent?.uuid, parentId: space.parent?.uuid,
isPrivate: space.isPrivate, isPrivate: space.isPrivate,
position: space.position, position: space.position,
icon: space.icon, icon: space.icon,
direction: space.incomingConnection?.direction, direction: space.incomingConnection?.direction,
products: space.selectedProducts); );
space.uuid = response?.uuid; space.uuid = response?.uuid;
} }
} catch (e) { } catch (e) {
@ -426,7 +425,7 @@ class SpaceManagementBloc
emit(SpaceManagementLoading()); emit(SpaceManagementLoading());
try { try {
List<CommunityModel> communities = await _api.fetchCommunities(); List<CommunityModel> communities = await _api.fetchCommunities();
List<CommunityModel> updatedCommunities = await Future.wait( List<CommunityModel> updatedCommunities = await Future.wait(
communities.map((community) async { communities.map((community) async {
List<SpaceModel> spaces = List<SpaceModel> spaces =

View File

@ -1,9 +1,12 @@
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
class SelectedProduct { class SelectedProduct {
final String productId; final String productId;
int count; int count;
final String productName; final String productName;
final ProductModel? product;
SelectedProduct({required this.productId, required this.count, required this.productName}); SelectedProduct({required this.productId, required this.count, required this.productName, this.product});
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {

View File

@ -20,7 +20,6 @@ class SpaceModel {
Offset position; Offset position;
bool isHovered; bool isHovered;
SpaceStatus status; SpaceStatus status;
List<SelectedProduct> selectedProducts;
String internalId; String internalId;
List<Connection> outgoingConnections = []; // Connections from this space List<Connection> outgoingConnections = []; // Connections from this space
@ -41,7 +40,6 @@ class SpaceModel {
this.isHovered = false, this.isHovered = false,
this.incomingConnection, this.incomingConnection,
this.status = SpaceStatus.unchanged, this.status = SpaceStatus.unchanged,
this.selectedProducts = const [],
}) : internalId = internalId ?? const Uuid().v4(); }) : internalId = internalId ?? const Uuid().v4();
factory SpaceModel.fromJson(Map<String, dynamic> json, factory SpaceModel.fromJson(Map<String, dynamic> json,
@ -85,15 +83,6 @@ class SpaceModel {
icon: json['icon'] ?? Assets.location, icon: json['icon'] ?? Assets.location,
position: Offset(json['x'] ?? 0, json['y'] ?? 0), position: Offset(json['x'] ?? 0, json['y'] ?? 0),
isHovered: false, isHovered: false,
selectedProducts: json['spaceProducts'] != null
? (json['spaceProducts'] as List).map((product) {
return SelectedProduct(
productId: product['product']['uuid'],
count: product['productCount'],
productName: '',
);
}).toList()
: [],
); );
if (json['incomingConnections'] != null && if (json['incomingConnections'] != null &&

View File

@ -114,7 +114,7 @@ class _AddDeviceWidgetState extends State<AddDeviceWidget> {
Widget _buildDeviceTypeTile(ProductModel product, Size size) { Widget _buildDeviceTypeTile(ProductModel product, Size size) {
final selectedProduct = productCounts.firstWhere( final selectedProduct = productCounts.firstWhere(
(p) => p.productId == product.uuid, (p) => p.productId == product.uuid,
orElse: () => SelectedProduct(productId: product.uuid, count: 0, productName: product.catName), orElse: () => SelectedProduct(productId: product.uuid, count: 0, productName: product.catName, product: product),
); );
return SizedBox( return SizedBox(
@ -143,7 +143,7 @@ class _AddDeviceWidgetState extends State<AddDeviceWidget> {
if (newCount > 0) { if (newCount > 0) {
if (!productCounts.contains(selectedProduct)) { if (!productCounts.contains(selectedProduct)) {
productCounts productCounts
.add(SelectedProduct(productId: product.uuid, count: newCount, productName: product.catName)); .add(SelectedProduct(productId: product.uuid, count: newCount, productName: product.catName, product: product));
} else { } else {
selectedProduct.count = newCount; selectedProduct.count = newCount;
} }

View File

@ -299,7 +299,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
isPrivate: false, isPrivate: false,
children: [], children: [],
status: SpaceStatus.newSpace, status: SpaceStatus.newSpace,
selectedProducts: selectedProducts); );
if (parentIndex != null && direction != null) { if (parentIndex != null && direction != null) {
SpaceModel parentSpace = spaces[parentIndex]; SpaceModel parentSpace = spaces[parentIndex];
@ -335,14 +335,12 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
icon: space.icon, icon: space.icon,
editSpace: space, editSpace: space,
isEdit: true, isEdit: true,
selectedProducts: space.selectedProducts,
onCreateSpace: (String name, String icon, onCreateSpace: (String name, String icon,
List<SelectedProduct> selectedProducts) { List<SelectedProduct> selectedProducts) {
setState(() { setState(() {
// Update the space's properties // Update the space's properties
space.name = name; space.name = name;
space.icon = icon; space.icon = icon;
space.selectedProducts = selectedProducts;
if (space.status != SpaceStatus.newSpace) { if (space.status != SpaceStatus.newSpace) {
space.status = SpaceStatus.modified; // Mark as modified space.status = SpaceStatus.modified; // Mark as modified

View File

@ -2,7 +2,7 @@ import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model
class SubspaceTemplateModel { class SubspaceTemplateModel {
final String? uuid; final String? uuid;
final String subspaceName; String subspaceName;
final bool disabled; final bool disabled;
final List<TagModel>? tags; final List<TagModel>? tags;

View File

@ -1,18 +1,21 @@
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/space_model/models/subspace_template_model.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
class TagModel { class TagModel {
String? uuid; String? uuid;
String tag; String? tag;
final ProductModel? product; final ProductModel? product;
String internalId; String internalId;
String? location;
TagModel({ TagModel(
this.uuid, {this.uuid,
required this.tag, required this.tag,
this.product, this.product,
String? internalId, String? internalId,
}) : internalId = internalId ?? const Uuid().v4(); this.location})
: internalId = internalId ?? const Uuid().v4();
factory TagModel.fromJson(Map<String, dynamic> json) { factory TagModel.fromJson(Map<String, dynamic> json) {
final String internalId = json['internalId'] ?? const Uuid().v4(); final String internalId = json['internalId'] ?? const Uuid().v4();

View File

@ -13,19 +13,19 @@ class AddDeviceTypeModelBloc
UpdateProductCountEvent event, Emitter<List<SelectedProduct>> emit) { UpdateProductCountEvent event, Emitter<List<SelectedProduct>> emit) {
final existingProduct = state.firstWhere( final existingProduct = state.firstWhere(
(p) => p.productId == event.productId, (p) => p.productId == event.productId,
orElse: () => SelectedProduct(productId: event.productId, count: 0,productName: event.productName ), orElse: () => SelectedProduct(productId: event.productId, count: 0,productName: event.productName,product: event.product ),
); );
if (event.count > 0) { if (event.count > 0) {
if (!state.contains(existingProduct)) { if (!state.contains(existingProduct)) {
emit([ emit([
...state, ...state,
SelectedProduct(productId: event.productId, count: event.count, productName: event.productName) SelectedProduct(productId: event.productId, count: event.count, productName: event.productName, product: event.product)
]); ]);
} else { } else {
final updatedList = state.map((p) { final updatedList = state.map((p) {
if (p.productId == event.productId) { if (p.productId == event.productId) {
return SelectedProduct(productId: p.productId, count: event.count, productName: p.productName); return SelectedProduct(productId: p.productId, count: event.count, productName: p.productName,product: p.product);
} }
return p; return p;
}).toList(); }).toList();

View File

@ -1,4 +1,5 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart';
abstract class AddDeviceTypeModelEvent extends Equatable { abstract class AddDeviceTypeModelEvent extends Equatable {
@override @override
@ -9,8 +10,9 @@ class UpdateProductCountEvent extends AddDeviceTypeModelEvent {
final String productId; final String productId;
final int count; final int count;
final String productName; final String productName;
final ProductModel product;
UpdateProductCountEvent({required this.productId, required this.count, required this.productName}); UpdateProductCountEvent({required this.productId, required this.count, required this.productName, required this.product});
@override @override
List<Object> get props => [productId, count]; List<Object> get props => [productId, count];

View File

@ -24,7 +24,11 @@ class DeviceTypeTileWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final selectedProduct = productCounts.firstWhere( final selectedProduct = productCounts.firstWhere(
(p) => p.productId == product.uuid, (p) => p.productId == product.uuid,
orElse: () => SelectedProduct(productId: product.uuid, count: 0, productName: product.catName), orElse: () => SelectedProduct(
productId: product.uuid,
count: 0,
productName: product.catName,
product: product),
); );
return Card( return Card(
@ -48,7 +52,10 @@ class DeviceTypeTileWidget extends StatelessWidget {
onCountChanged: (newCount) { onCountChanged: (newCount) {
context.read<AddDeviceTypeModelBloc>().add( context.read<AddDeviceTypeModelBloc>().add(
UpdateProductCountEvent( UpdateProductCountEvent(
productId: product.uuid, count: newCount,productName: product.catName), productId: product.uuid,
count: newCount,
productName: product.catName,
product: product),
); );
}, },
), ),

View File

@ -167,7 +167,6 @@ class CommunitySpaceManagementApi {
bool isPrivate = false, bool isPrivate = false,
required Offset position, required Offset position,
String? icon, String? icon,
required List<SelectedProduct> products,
}) async { }) async {
try { try {
final body = { final body = {
@ -177,7 +176,6 @@ class CommunitySpaceManagementApi {
'y': position.dy, 'y': position.dy,
'direction': direction, 'direction': direction,
'icon': icon, 'icon': icon,
'products': products.map((product) => product.toJson()).toList(),
}; };
if (parentId != null) { if (parentId != null) {
body['parentUuid'] = parentId; body['parentUuid'] = parentId;
@ -207,7 +205,6 @@ class CommunitySpaceManagementApi {
String? direction, String? direction,
bool isPrivate = false, bool isPrivate = false,
required Offset position, required Offset position,
required List<SelectedProduct> products,
}) async { }) async {
try { try {
final body = { final body = {
@ -217,7 +214,6 @@ class CommunitySpaceManagementApi {
'y': position.dy, 'y': position.dy,
'direction': direction, 'direction': direction,
'icon': icon, 'icon': icon,
'products': products.map((product) => product.toJson()).toList(),
}; };
if (parentId != null) { if (parentId != null) {
body['parentUuid'] = parentId; body['parentUuid'] = parentId;

View File

@ -56,5 +56,6 @@ abstract class ColorsManager {
static const Color CircleImageBackground = Color(0xFFF4F4F4); static const Color CircleImageBackground = Color(0xFFF4F4F4);
static const Color softGray = Color(0xFFD5D5D5); static const Color softGray = Color(0xFFD5D5D5);
static const Color semiTransparentBlack = Color(0x19000000); static const Color semiTransparentBlack = Color(0x19000000);
static const Color dataHeaderGrey = Color(0x33999999);
} }
//background: #background: #5D5D5D; //background: #background: #5D5D5D;