diff --git a/lib/pages/spaces_management/all_spaces/assign_tag_models/views/assign_tag_models_dialog.dart b/lib/pages/spaces_management/all_spaces/assign_tag_models/views/assign_tag_models_dialog.dart index 885f483b..b04e1c35 100644 --- a/lib/pages/spaces_management/all_spaces/assign_tag_models/views/assign_tag_models_dialog.dart +++ b/lib/pages/spaces_management/all_spaces/assign_tag_models/views/assign_tag_models_dialog.dart @@ -11,15 +11,17 @@ class AssignTagModelsDialog extends StatefulWidget { final List? initialTags; final ValueChanged>? onTagsAssigned; final List addedProducts; + final List? allTags; - const AssignTagModelsDialog({ - Key? key, - required this.products, - required this.subspaces, - required this.addedProducts, - this.initialTags, - this.onTagsAssigned, - }) : super(key: key); + const AssignTagModelsDialog( + {Key? key, + required this.products, + required this.subspaces, + required this.addedProducts, + this.initialTags, + this.onTagsAssigned, + this.allTags}) + : super(key: key); @override AssignTagModelsDialogState createState() => AssignTagModelsDialogState(); @@ -29,12 +31,15 @@ class AssignTagModelsDialogState extends State { late List tags; late List selectedProducts; late List locations; + late List otherTags; + late List controllers; + Set usedTags = {}; + String? errorMessage; + bool isSaveEnabled = true; @override void initState() { super.initState(); - print(widget.addedProducts); - print(widget.subspaces); // Initialize tags from widget.initialTags or create new ones if it's empty tags = widget.initialTags?.isNotEmpty == true @@ -58,6 +63,39 @@ class AssignTagModelsDialogState extends State { ? widget.subspaces!.map((subspace) => subspace.subspaceName).toList() : []; locations.add("None"); + + otherTags = widget.allTags != null ? widget.allTags! : []; + + controllers = List.generate( + tags.length, + (index) => TextEditingController(text: tags[index].tag), + ); + + for (final tag in tags) { + if (tag.tag != null && tag.tag!.isNotEmpty) { + usedTags.add(tag.tag!); + } + } + + _validateTags(); + } + + void _validateTags() { + // Disable save if any tag is empty + final hasEmptyTag = + tags.any((tag) => tag.tag == null || tag.tag!.trim().isEmpty); + setState(() { + isSaveEnabled = !hasEmptyTag; + }); + } + + @override + void dispose() { + // Dispose of controllers + for (final controller in controllers) { + controller.dispose(); + } + super.dispose(); } @override @@ -66,123 +104,160 @@ class AssignTagModelsDialogState extends State { title: const Text('Assign Tags'), backgroundColor: ColorsManager.whiteColors, content: SingleChildScrollView( - child: Container( - width: MediaQuery.of(context).size.width * 0.4, - decoration: BoxDecoration( - border: Border.all(color: ColorsManager.dataHeaderGrey, width: 1), - borderRadius: BorderRadius.circular(20), - ), - child: Theme( - data: Theme.of(context).copyWith( - dataTableTheme: DataTableThemeData( - headingRowColor: - MaterialStateProperty.all(ColorsManager.dataHeaderGrey), - headingTextStyle: const TextStyle( - color: ColorsManager.blackColor, - fontWeight: FontWeight.bold, - ), - ), - ), - child: DataTable( - border: TableBorder.all( - color: ColorsManager.dataHeaderGrey, - width: 1, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: MediaQuery.of(context).size.width * 0.4, + decoration: BoxDecoration( + border: + Border.all(color: ColorsManager.dataHeaderGrey, width: 1), borderRadius: BorderRadius.circular(20), ), - columns: const [ - DataColumn(label: Text('#')), - DataColumn(label: Text('Device')), - DataColumn(label: Text('Tag')), - DataColumn(label: Text('Location')), - ], - rows: tags.asMap().entries.map((entry) { - final index = entry.key + 1; - final tag = entry.value; + child: DataTable( + border: TableBorder.all( + color: ColorsManager.dataHeaderGrey, + width: 1, + borderRadius: BorderRadius.circular(20), + ), + columns: const [ + DataColumn(label: Text('#')), + DataColumn(label: Text('Device')), + DataColumn(label: Text('Tag')), + DataColumn(label: Text('Location')), + ], + rows: List.generate(tags.length, (index) { + final tag = tags[index]; + final controller = controllers[index]; - return DataRow( - cells: [ - DataCell( - Center( - child: Text(index.toString()), - ), - ), - DataCell( - Center( - child: Text(tag.product?.catName ?? 'Unknown'), - ), - ), - DataCell( - Center( - child: DropdownButton( - value: tag.tag!.isNotEmpty ? tag.tag : null, - onChanged: (value) { - setState(() { - tag.tag = value ?? ''; // Update tag value - }); - }, - items: [ - const DropdownMenuItem( - value: null, - child: Text('None'), + return DataRow( + cells: [ + DataCell(Center(child: Text(index.toString()))), + DataCell( + Center(child: Text(tag.product?.name ?? 'Unknown'))), + DataCell( + Row( + children: [ + Expanded( + child: TextFormField( + controller: controller, + decoration: const InputDecoration( + hintText: 'Enter Tag', + border: InputBorder.none, + hintStyle: TextStyle( + color: Colors.grey, + fontSize: 14, + ), + ), + style: const TextStyle( + color: Colors.black, + fontSize: 14, + ), + onChanged: (value) { + setState(() { + tag.tag = value.trim(); + _validateTags(); + }); + }, + ), + ), + PopupMenuButton( + icon: const Icon(Icons.arrow_drop_down, + color: Colors.black), + onSelected: (value) { + setState(() { + if (tag.tag != null && tag.tag!.isNotEmpty) { + usedTags.remove(tag.tag!); + } + controller.text = value; + tag.tag = value; + + if (tag.tag != null && tag.tag!.isNotEmpty) { + usedTags.add(tag.tag!); + } + _validateTags(); // Validate after selection + }); + }, + color: Colors.white, + itemBuilder: (context) { + return widget.allTags! + .where((tagValue) => + !usedTags.contains(tagValue)) + .map((tagValue) { + return PopupMenuItem( + value: tagValue, + child: Text( + tagValue, + style: const TextStyle( + color: Color(0xFF5D5D5D), + fontSize: 14, + ), + ), + ); + }).toList(); + }, ), - ...List.generate(10, (index) { - final tagName = 'Tag ${index + 1}'; - return DropdownMenuItem( - value: tagName, - child: Text(tagName), - ); - }), ], ), ), - ), - DataCell( - Center( - child: DropdownButtonHideUnderline( - child: DropdownButton( - 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, + DataCell( + Center( + child: DropdownButtonHideUnderline( + child: DropdownButton( + alignment: AlignmentDirectional.center, + value: locations.contains(tag.location) + ? tag.location + : null, + onChanged: (value) { + setState(() { + tag.location = value ?? 'None'; + }); + }, + dropdownColor: ColorsManager.whiteColors, + icon: const Icon(Icons.arrow_drop_down, + color: Colors.black), + style: const TextStyle( + fontSize: 10, + 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: Color(0xFF5D5D5D), + ), ), - ), - )) - .toList(), + )) + .toList(), + ), ), ), ), - ), - ], - ); - }).toList(), + ], + ); + }), + ), ), - ), + if (errorMessage != null) + Container( + width: MediaQuery.of(context).size.width * 0.4, + padding: const EdgeInsets.only(top: 8.0, left: 12.0), + child: Text( + errorMessage!, + style: const TextStyle( + color: Colors.red, + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + ), + ], ), ), actions: [ @@ -198,15 +273,19 @@ class AssignTagModelsDialogState extends State { ), ), ElevatedButton( - onPressed: () { - Navigator.of(context).pop(); - if (widget.onTagsAssigned != null) { - widget.onTagsAssigned!(tags); - } - }, + onPressed: isSaveEnabled + ? () { + Navigator.of(context).pop(); + if (widget.onTagsAssigned != null) { + widget.onTagsAssigned!(tags); + } + } + : null, // Disable the button if validation fails child: const Text('Save'), style: ElevatedButton.styleFrom( - backgroundColor: ColorsManager.secondaryColor, + backgroundColor: isSaveEnabled + ? ColorsManager.secondaryColor + : Colors.grey, // Change button color when disabled foregroundColor: ColorsManager.whiteColors, ), ), diff --git a/lib/pages/spaces_management/space_model/models/space_template_model.dart b/lib/pages/spaces_management/space_model/models/space_template_model.dart index 51804178..2fa99d2b 100644 --- a/lib/pages/spaces_management/space_model/models/space_template_model.dart +++ b/lib/pages/spaces_management/space_model/models/space_template_model.dart @@ -61,7 +61,6 @@ class SpaceTemplateModel { } } - class UpdateSubspaceTemplateModel { final String uuid; final Action action; @@ -133,3 +132,28 @@ class UpdateTagModel { }; } } + +extension SpaceTemplateExtensions on SpaceTemplateModel { + List listAllTagValues() { + final List tagValues = []; + + if (tags != null) { + tagValues.addAll( + tags!.map((tag) => tag.tag ?? '').where((tag) => tag.isNotEmpty)); + } + + if (subspaceModels != null) { + for (final subspace in subspaceModels!) { + if (subspace.tags != null) { + tagValues.addAll( + subspace.tags! + .map((tag) => tag.tag ?? '') + .where((tag) => tag.isNotEmpty), + ); + } + } + } + + return tagValues; + } +} diff --git a/lib/pages/spaces_management/space_model/view/space_model_page.dart b/lib/pages/spaces_management/space_model/view/space_model_page.dart index 3c601e47..553f3be2 100644 --- a/lib/pages/spaces_management/space_model/view/space_model_page.dart +++ b/lib/pages/spaces_management/space_model/view/space_model_page.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart'; -import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_bloc.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/dialog/create_space_model_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/space_model_card_widget.dart'; @@ -16,6 +14,7 @@ class SpaceModelPage extends StatelessWidget { @override Widget build(BuildContext context) { + final allTagValues = getAllTagValues(); return Scaffold( backgroundColor: ColorsManager.whiteColors, body: Padding( @@ -24,11 +23,11 @@ class SpaceModelPage extends StatelessWidget { //clipBehavior: Clip.none, shrinkWrap: false, physics: const AlwaysScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, crossAxisSpacing: 13.0, mainAxisSpacing: 13.0, - childAspectRatio: 3.5, + childAspectRatio: calculateChildAspectRatio(context), ), itemCount: spaceModels.length + 1, itemBuilder: (context, index) { @@ -38,7 +37,7 @@ class SpaceModelPage extends StatelessWidget { showDialog( context: context, builder: (BuildContext context) { - return CreateSpaceModelDialog(products: products); + return CreateSpaceModelDialog(products: products,allTags: allTagValues,); }, ); }, @@ -91,4 +90,31 @@ class SpaceModelPage extends StatelessWidget { ), ); } + + double calculateChildAspectRatio(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; + + // Adjust the aspect ratio based on the screen width + if (screenWidth > 1600) { + return 4.0; // For large screens + } + if (screenWidth > 1200) { + return 3.2; // For large screens + } else if (screenWidth > 800) { + return 3.0; // For medium screens + } else { + return 2.0; // For small screens + } + } + + List getAllTagValues() { + final List allTags = []; + + for (final spaceModel in spaceModels) { + if (spaceModel.tags != null) { + allTags.addAll(spaceModel.listAllTagValues()); + } + } + return allTags; + } } 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 c70e3c56..fce0522a 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 @@ -16,8 +16,9 @@ import '../../models/subspace_template_model.dart'; class CreateSpaceModelDialog extends StatelessWidget { final List? products; + final List? allTags; - const CreateSpaceModelDialog({Key? key, this.products}) : super(key: key); + const CreateSpaceModelDialog({Key? key, this.products, this.allTags}) : super(key: key); @override Widget build(BuildContext context) { @@ -79,6 +80,7 @@ class CreateSpaceModelDialog extends StatelessWidget { builder: (context) => AddDeviceTypeModelWidget( products: products, subspaces: subspaces, + allTags: allTags, ), ); if (result == true) { diff --git a/lib/pages/spaces_management/space_model/widgets/space_model_card_widget.dart b/lib/pages/spaces_management/space_model/widgets/space_model_card_widget.dart index 92d5735d..208b0893 100644 --- a/lib/pages/spaces_management/space_model/widgets/space_model_card_widget.dart +++ b/lib/pages/spaces_management/space_model/widgets/space_model_card_widget.dart @@ -69,7 +69,8 @@ class SpaceModelCardWidget extends StatelessWidget { spacing: 3.0, runSpacing: 3.0, children: [ - for (var subspace in model.subspaceModels!.take(3)) + for (var subspace in model.subspaceModels! + .take(calculateTakeCount(context))) SubspaceChipWidget(subspace: subspace.subspaceName), ], ), @@ -126,4 +127,16 @@ class SpaceModelCardWidget extends StatelessWidget { ), ); } + + int calculateTakeCount(BuildContext context) { + double screenWidth = MediaQuery.of(context).size.width; + // Adjust the count based on the screen width + if (screenWidth > 1500) { + return 3; // For large screens + } else if (screenWidth > 1200) { + return 2; + } else { + return 1; // For smaller screens + } + } } diff --git a/lib/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart b/lib/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart index 7c9204ef..3f74ebb8 100644 --- a/lib/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart +++ b/lib/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart @@ -15,13 +15,15 @@ class AddDeviceTypeModelWidget extends StatelessWidget { final ValueChanged>? onProductsSelected; final List? initialSelectedProducts; final List? subspaces; + final List? allTags; const AddDeviceTypeModelWidget( {super.key, this.products, this.initialSelectedProducts, this.onProductsSelected, - this.subspaces}); + this.subspaces, + this.allTags}); @override Widget build(BuildContext context) { @@ -80,6 +82,7 @@ class AddDeviceTypeModelWidget extends StatelessWidget { products: products, subspaces: subspaces, addedProducts: currentState, + allTags: allTags, ), ); }