From 788fb75a687b7618f755c3fb2ad60ed54d2af15e Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Mon, 27 Jan 2025 18:12:57 +0400 Subject: [PATCH 1/4] fixed UI alignment --- .../widgets/dialogs/create_space_dialog.dart | 89 ++++++++++--------- 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/lib/pages/spaces_management/all_spaces/widgets/dialogs/create_space_dialog.dart b/lib/pages/spaces_management/all_spaces/widgets/dialogs/create_space_dialog.dart index 2b8d4aaf..715e8b55 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/dialogs/create_space_dialog.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/dialogs/create_space_dialog.dart @@ -149,50 +149,53 @@ class CreateSpaceDialogState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - TextField( - controller: nameController, - onChanged: (value) { - enteredName = value.trim(); - setState(() { - isNameFieldExist = false; - isOkButtonEnabled = false; - isNameFieldInvalid = value.isEmpty; + SizedBox( + width: screenWidth * 0.25, + child: TextField( + controller: nameController, + onChanged: (value) { + enteredName = value.trim(); + setState(() { + isNameFieldExist = false; + isOkButtonEnabled = false; + isNameFieldInvalid = value.isEmpty; - if (!isNameFieldInvalid) { - if (_isNameConflict(value)) { - isNameFieldExist = true; - isOkButtonEnabled = false; - } else { - isNameFieldExist = false; - isOkButtonEnabled = true; + if (!isNameFieldInvalid) { + if (_isNameConflict(value)) { + isNameFieldExist = true; + isOkButtonEnabled = false; + } else { + isNameFieldExist = false; + isOkButtonEnabled = true; + } } - } - }); - }, - style: const TextStyle(color: Colors.black), - decoration: InputDecoration( - hintText: 'Please enter the name', - hintStyle: const TextStyle( - fontSize: 14, - color: ColorsManager.lightGrayColor, - fontWeight: FontWeight.w400, - ), - filled: true, - fillColor: ColorsManager.boxColor, - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - borderSide: BorderSide( - color: isNameFieldInvalid || isNameFieldExist - ? ColorsManager.red - : ColorsManager.boxColor, - width: 1.5, + }); + }, + style: const TextStyle(color: Colors.black), + decoration: InputDecoration( + hintText: 'Please enter the name', + hintStyle: const TextStyle( + fontSize: 14, + color: ColorsManager.lightGrayColor, + fontWeight: FontWeight.w400, ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - borderSide: const BorderSide( - color: ColorsManager.boxColor, - width: 1.5, + filled: true, + fillColor: ColorsManager.boxColor, + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide( + color: isNameFieldInvalid || isNameFieldExist + ? ColorsManager.red + : ColorsManager.boxColor, + width: 1.5, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide( + color: ColorsManager.boxColor, + width: 1.5, + ), ), ), ), @@ -222,6 +225,9 @@ class CreateSpaceDialogState extends State { const SizedBox(height: 10), selectedSpaceModel == null ? TextButton( + style: TextButton.styleFrom( + padding: EdgeInsets.zero, + ), onPressed: () { _showLinkSpaceModelDialog(context); }, @@ -309,6 +315,7 @@ class CreateSpaceDialogState extends State { subspaces == null ? TextButton( style: TextButton.styleFrom( + padding: EdgeInsets.zero, overlayColor: ColorsManager.transparentColor, ), onPressed: () async { From e61cfd7e49091dab328825320f5873491ab41efb Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Tue, 28 Jan 2025 10:48:14 +0400 Subject: [PATCH 2/4] added option to update subspace --- .../widgets/dialogs/create_space_dialog.dart | 19 ++- .../dialog/create_space_model_dialog.dart | 1 - .../widgets/subspace_model_create_widget.dart | 61 +++++++-- .../widgets/subspace_name_label_widget.dart | 121 +++++++++++++++--- 4 files changed, 170 insertions(+), 32 deletions(-) diff --git a/lib/pages/spaces_management/all_spaces/widgets/dialogs/create_space_dialog.dart b/lib/pages/spaces_management/all_spaces/widgets/dialogs/create_space_dialog.dart index 715e8b55..50d73fff 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/dialogs/create_space_dialog.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/dialogs/create_space_dialog.dart @@ -344,10 +344,21 @@ class CreateSpaceDialogState extends State { runSpacing: 8.0, children: [ if (subspaces != null) - ...subspaces!.map( - (subspace) => SubspaceNameDisplayWidget( - text: subspace.subspaceName, - )), + ...subspaces!.map((subspace) => + SubspaceNameDisplayWidget( + validateName: (updatedName) { + return !subspaces!.any((s) => + s != subspace && + s.subspaceName == updatedName); + }, + text: subspace.subspaceName, + onNameChanged: (updatedName) { + setState(() { + subspace.subspaceName = + updatedName; + }); + }, + )), EditChip( onTap: () async { _showSubSpaceDialog(context, enteredName, 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 a825e868..e172231e 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 @@ -123,7 +123,6 @@ class CreateSpaceModelDialog extends StatelessWidget { ), const SizedBox(height: 16), SubspaceModelCreate( - context, subspaces: state.space.subspaceModels ?? [], onSpaceModelUpdate: (updatedSubspaces) { context diff --git a/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart b/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart index 8dc981da..5fddfe6e 100644 --- a/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart +++ b/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart @@ -6,20 +6,36 @@ import 'package:syncrow_web/pages/spaces_management/create_subspace_model/views/ 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 { +class SubspaceModelCreate extends StatefulWidget { final List subspaces; final void Function(List newSubspaces)? onSpaceModelUpdate; - const SubspaceModelCreate(BuildContext context, - {Key? key, required this.subspaces, this.onSpaceModelUpdate}) - : super(key: key); + const SubspaceModelCreate({ + Key? key, + required this.subspaces, + this.onSpaceModelUpdate, + }) : super(key: key); + + @override + _SubspaceModelCreateState createState() => _SubspaceModelCreateState(); +} + +class _SubspaceModelCreateState extends State { + late List _subspaces; + String? errorSubspaceId; + + @override + void initState() { + super.initState(); + _subspaces = List.from(widget.subspaces); + } @override Widget build(BuildContext context) { final screenWidth = MediaQuery.of(context).size.width; return Container( - child: subspaces.isEmpty + child: _subspaces.isEmpty ? TextButton( style: TextButton.styleFrom( overlayColor: ColorsManager.transparentColor, @@ -41,16 +57,33 @@ class SubspaceModelCreate extends StatelessWidget { borderRadius: BorderRadius.circular(15), border: Border.all( color: ColorsManager.textFieldGreyColor, - width: 3.0, // Border width + width: 3.0, ), ), child: Wrap( spacing: 8.0, runSpacing: 8.0, children: [ - ...subspaces.map((subspace) => SubspaceNameDisplayWidget( - text: subspace.subspaceName, - )), + ..._subspaces.map((subspace) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SubspaceNameDisplayWidget( + text: subspace.subspaceName, + validateName: (updatedName) { + return !_subspaces.any((s) => + s != subspace && + s.subspaceName == updatedName); + }, + onNameChanged: (updatedName) { + setState(() { + subspace.subspaceName = updatedName; + }); + }, + ), + ], + ); + }), EditChip( onTap: () async { await _openDialog(context, 'Edit Sub-space'); @@ -71,9 +104,15 @@ class SubspaceModelCreate extends StatelessWidget { return CreateSubSpaceModelDialog( isEdit: true, dialogTitle: dialogTitle, - existingSubSpaces: subspaces, + existingSubSpaces: _subspaces, onUpdate: (subspaceModels) { - onSpaceModelUpdate!(subspaceModels); + setState(() { + _subspaces = subspaceModels; + errorSubspaceId = null; + }); + if (widget.onSpaceModelUpdate != null) { + widget.onSpaceModelUpdate!(subspaceModels); + } }, ); }, diff --git a/lib/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart b/lib/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart index a2920b89..2ecbf0b1 100644 --- a/lib/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart +++ b/lib/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart @@ -1,13 +1,15 @@ import 'package:flutter/material.dart'; import 'package:syncrow_web/utils/color_manager.dart'; -class SubspaceNameDisplayWidget extends StatelessWidget { +class SubspaceNameDisplayWidget extends StatefulWidget { final String text; final TextStyle? textStyle; final Color backgroundColor; final Color borderColor; final EdgeInsetsGeometry padding; final BorderRadiusGeometry borderRadius; + final void Function(String updatedName) onNameChanged; + final bool Function(String updatedName) validateName; const SubspaceNameDisplayWidget({ Key? key, @@ -17,25 +19,112 @@ class SubspaceNameDisplayWidget extends StatelessWidget { this.borderColor = ColorsManager.transparentColor, this.padding = const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), this.borderRadius = const BorderRadius.all(Radius.circular(10)), + required this.onNameChanged, + required this.validateName, }) : super(key: key); + @override + _SubspaceNameDisplayWidgetState createState() => + _SubspaceNameDisplayWidgetState(); +} + +class _SubspaceNameDisplayWidgetState extends State { + bool isEditing = false; + late TextEditingController _controller; + late FocusNode _focusNode; + late String previousName; + String? errorText; + + @override + void initState() { + super.initState(); + _controller = TextEditingController(text: widget.text); + _focusNode = FocusNode(); + previousName = widget.text; + } + + @override + void dispose() { + _controller.dispose(); + _focusNode.dispose(); + super.dispose(); + } + + void _handleValidationAndSave() { + final updatedName = _controller.text; + if (widget.validateName(updatedName)) { + setState(() { + errorText = null; + isEditing = false; + previousName = updatedName; + widget.onNameChanged(updatedName); + }); + } else { + setState(() { + errorText = 'Subspace name already exists.'; + }); + } + } + @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: ColorsManager.spaceColor), - ), + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + GestureDetector( + onTap: () { + setState(() { + isEditing = true; + _focusNode.requestFocus(); + }); + }, + child: Container( + padding: widget.padding, + decoration: BoxDecoration( + color: widget.backgroundColor, + borderRadius: widget.borderRadius, + border: Border.all(color: widget.borderColor), + ), + child: isEditing + ? TextField( + controller: _controller, + focusNode: _focusNode, + style: widget.textStyle ?? + Theme.of(context) + .textTheme + .bodySmall + ?.copyWith(color: ColorsManager.spaceColor), + autofocus: true, + decoration: const InputDecoration( + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(horizontal: 8.0), + ), + onSubmitted: (value) { + _handleValidationAndSave(); + }, + ) + : Text( + widget.text, + style: widget.textStyle ?? + Theme.of(context) + .textTheme + .bodySmall + ?.copyWith(color: ColorsManager.spaceColor), + ), + ), + ), + if (errorText != null) + Padding( + padding: const EdgeInsets.only(top: 4.0), + child: Text( + errorText!, + style: const TextStyle( + color: ColorsManager.warningRed, + fontSize: 12, + ), + ), + ), + ], ); } } From 4b7f4d42791476c34978ca4131da349031b800a9 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Tue, 28 Jan 2025 11:39:34 +0400 Subject: [PATCH 3/4] fixed calculating products on add another device --- .../assign_tag_models/views/assign_tag_models_dialog.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart b/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart index 31dba875..90843aa2 100644 --- a/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart +++ b/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart @@ -15,6 +15,7 @@ import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.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/pages/spaces_management/helper/tag_helper.dart'; class AssignTagModelsDialog extends StatelessWidget { final List? products; @@ -258,7 +259,6 @@ class AssignTagModelsDialog extends StatelessWidget { final processedTags = result['updatedTags'] as List; final processedSubspaces = result['subspaces']; - if (context.mounted) { Navigator.of(context).pop(); @@ -270,8 +270,10 @@ class AssignTagModelsDialog extends StatelessWidget { products: products, subspaces: subspaces, isCreate: false, - initialSelectedProducts: - addedProducts, + initialSelectedProducts: TagHelper + .createInitialSelectedProducts( + processedTags, + processedSubspaces), allTags: allTags, spaceName: spaceName, otherSpaceModels: otherSpaceModels, From 9091af26617beb5402d487c1df1a0a13058fb5be Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Tue, 28 Jan 2025 13:27:05 +0400 Subject: [PATCH 4/4] fixed text style --- lib/common/edit_chip.dart | 2 +- .../dialog/create_space_model_dialog.dart | 25 +++++++++++++------ .../widgets/subspace_name_label_widget.dart | 8 +++--- .../widgets/tag_chips_display_widget.dart | 11 +++++--- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/lib/common/edit_chip.dart b/lib/common/edit_chip.dart index 7607834d..1643b414 100644 --- a/lib/common/edit_chip.dart +++ b/lib/common/edit_chip.dart @@ -26,7 +26,7 @@ class EditChip extends StatelessWidget { child: Chip( label: Text( label, - style: TextStyle(color: labelColor), + style: Theme.of(context).textTheme.bodySmall!.copyWith(color: labelColor) ), backgroundColor: backgroundColor, shape: RoundedRectangleBorder( 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 e172231e..2fb2a5b0 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 @@ -102,14 +102,19 @@ class CreateSpaceModelDialog extends StatelessWidget { name: value, allModels: otherSpaceModels ?? [])); }, - style: const TextStyle(color: ColorsManager.blackColor), + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(color: ColorsManager.blackColor), decoration: InputDecoration( filled: true, fillColor: ColorsManager.textFieldGreyColor, hintText: 'Please enter the name', errorText: state.errorMessage, - hintStyle: const TextStyle( - color: ColorsManager.lightGrayColor), + hintStyle: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(color: ColorsManager.lightGrayColor), border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide.none, @@ -159,7 +164,9 @@ class CreateSpaceModelDialog extends StatelessWidget { const SizedBox(width: 10), Expanded( child: DefaultButton( - onPressed: (state.errorMessage == null) + onPressed: ((state.errorMessage != null && + state.errorMessage != '') || + !isNameValid) ? () { final updatedSpaceTemplate = updatedSpaceModel.copyWith( @@ -237,8 +244,9 @@ class CreateSpaceModelDialog extends StatelessWidget { : null, backgroundColor: ColorsManager.secondaryColor, borderRadius: 10, - foregroundColor: (state.errorMessage != null && - state.errorMessage != '') + foregroundColor: ((state.errorMessage != null && + state.errorMessage != '') || + !isNameValid) ? ColorsManager.whiteColorsWithOpacity : ColorsManager.whiteColors, child: const Text('OK'), @@ -252,7 +260,10 @@ class CreateSpaceModelDialog extends StatelessWidget { } else if (state is CreateSpaceModelError) { return Text( 'Error: ${state.message}', - style: const TextStyle(color: ColorsManager.warningRed), + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: ColorsManager.warningRed), ); } diff --git a/lib/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart b/lib/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart index 2ecbf0b1..63edcf8f 100644 --- a/lib/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart +++ b/lib/pages/spaces_management/space_model/widgets/subspace_name_label_widget.dart @@ -118,10 +118,10 @@ class _SubspaceNameDisplayWidgetState extends State { padding: const EdgeInsets.only(top: 4.0), child: Text( errorText!, - style: const TextStyle( - color: ColorsManager.warningRed, - fontSize: 12, - ), + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: ColorsManager.warningRed), ), ), ], diff --git a/lib/pages/spaces_management/space_model/widgets/tag_chips_display_widget.dart b/lib/pages/spaces_management/space_model/widgets/tag_chips_display_widget.dart index 11c7ca5b..a07f9b29 100644 --- a/lib/pages/spaces_management/space_model/widgets/tag_chips_display_widget.dart +++ b/lib/pages/spaces_management/space_model/widgets/tag_chips_display_widget.dart @@ -73,9 +73,12 @@ class TagChipDisplay extends StatelessWidget { ), label: Text( 'x${entry.value}', // Show count - style: const TextStyle( - color: ColorsManager.spaceColor, - ), + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + color: + ColorsManager.spaceColor), ), backgroundColor: ColorsManager.whiteColors, shape: RoundedRectangleBorder( @@ -89,7 +92,7 @@ class TagChipDisplay extends StatelessWidget { EditChip(onTap: () async { // Use the Navigator's context for showDialog Navigator.of(context).pop(); - + await showDialog( barrierDismissible: false, context: context,