From 616adccfdda7fd8611a4a5e1c2eb36d896439644 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Tue, 15 Apr 2025 12:58:20 +0300 Subject: [PATCH 1/3] Applied the correct scenario of tapping add community icon button. --- .../widgets/sidebar_add_community_button.dart | 23 ++----------- .../all_spaces/widgets/sidebar_header.dart | 11 +++++-- .../all_spaces/widgets/sidebar_widget.dart | 32 ++++++++++++++++--- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/lib/pages/spaces_management/all_spaces/widgets/sidebar_add_community_button.dart b/lib/pages/spaces_management/all_spaces/widgets/sidebar_add_community_button.dart index 5c769d48..ae1eb2bf 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/sidebar_add_community_button.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/sidebar_add_community_button.dart @@ -1,19 +1,15 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart'; -import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart'; -import 'package:syncrow_web/pages/spaces_management/create_community/view/create_community_dialog.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; class SidebarAddCommunityButton extends StatelessWidget { const SidebarAddCommunityButton({ - required this.existingCommunityNames, + required this.onTap, super.key, }); - final List existingCommunityNames; + final void Function() onTap; @override Widget build(BuildContext context) { @@ -30,22 +26,9 @@ class SidebarAddCommunityButton extends StatelessWidget { ), ), ), - onPressed: () => _showCreateCommunityDialog(context), + onPressed: onTap, icon: SvgPicture.asset(Assets.addIcon), ), ); } - - void _showCreateCommunityDialog(BuildContext context) => showDialog( - context: context, - builder: (context) => CreateCommunityDialog( - isEditMode: false, - existingCommunityNames: existingCommunityNames, - onCreateCommunity: (name, description) { - context.read().add( - CreateCommunityEvent(name, description, context), - ); - }, - ), - ); } diff --git a/lib/pages/spaces_management/all_spaces/widgets/sidebar_header.dart b/lib/pages/spaces_management/all_spaces/widgets/sidebar_header.dart index 135be109..1706d51a 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/sidebar_header.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/sidebar_header.dart @@ -5,9 +5,12 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/style.dart'; class SidebarHeader extends StatelessWidget { - const SidebarHeader({required this.existingCommunityNames, super.key}); + const SidebarHeader({ + required this.onAddCommunity, + super.key, + }); - final List existingCommunityNames; + final void Function() onAddCommunity; @override Widget build(BuildContext context) { @@ -23,7 +26,9 @@ class SidebarHeader extends StatelessWidget { color: ColorsManager.blackColor, ), ), - SidebarAddCommunityButton(existingCommunityNames: existingCommunityNames), + SidebarAddCommunityButton( + onTap: onAddCommunity, + ), ], ), ); diff --git a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart index 35bb8ad2..b30a8c96 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart @@ -8,6 +8,7 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/community_tile.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/sidebar_header.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/space_tile_widget.dart'; +import 'package:syncrow_web/pages/spaces_management/create_community/view/create_community_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_event.dart'; import 'package:syncrow_web/utils/style.dart'; @@ -94,10 +95,7 @@ class _SidebarWidgetState extends State { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - SidebarHeader( - existingCommunityNames: - widget.communities.map((community) => community.name).toList(), - ), + SidebarHeader(onAddCommunity: _onAddCommunity), CustomSearchBar( onSearchChanged: (query) => setState(() => _searchQuery = query), ), @@ -179,4 +177,30 @@ class _SidebarWidgetState extends State { ), ); } + + void _onAddCommunity() => _selectedId?.isNotEmpty ?? true + ? _clearSelection() + : _showCreateCommunityDialog(); + + void _clearSelection() { + setState(() => _selectedId = ''); + context.read().add( + NewCommunityEvent(communities: widget.communities), + ); + } + + void _showCreateCommunityDialog() { + showDialog( + context: context, + builder: (context) => CreateCommunityDialog( + isEditMode: false, + existingCommunityNames: widget.communities.map((e) => e.name).toList(), + onCreateCommunity: (name, description) { + context.read().add( + CreateCommunityEvent(name, description, context), + ); + }, + ), + ); + } } From 7dcaa20da12ace15f71e1a9693a4bd9dc031f490 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Tue, 15 Apr 2025 13:06:30 +0300 Subject: [PATCH 2/3] Enhanced the code and look of `DialogFooter` buttons. --- lib/pages/routines/widgets/dialog_footer.dart | 62 +++++++++---------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/lib/pages/routines/widgets/dialog_footer.dart b/lib/pages/routines/widgets/dialog_footer.dart index 15db9732..e5a548f7 100644 --- a/lib/pages/routines/widgets/dialog_footer.dart +++ b/lib/pages/routines/widgets/dialog_footer.dart @@ -8,12 +8,12 @@ class DialogFooter extends StatelessWidget { final int? dialogWidth; const DialogFooter({ - Key? key, + super.key, required this.onCancel, required this.onConfirm, required this.isConfirmEnabled, this.dialogWidth, - }) : super(key: key); + }); @override Widget build(BuildContext context) { @@ -28,21 +28,19 @@ class DialogFooter extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - Expanded( - child: _buildFooterButton( - context, - 'Cancel', - onCancel, - ), + _buildFooterButton( + context: context, + text: 'Cancel', + onTap: onCancel, ), if (isConfirmEnabled) ...[ Container(width: 1, height: 50, color: ColorsManager.greyColor), - Expanded( - child: _buildFooterButton( - context, - 'Confirm', - onConfirm, - ), + _buildFooterButton( + context: context, + text: 'Confirm', + onTap: onConfirm, + textColor: + isConfirmEnabled ? ColorsManager.primaryColorWithOpacity : Colors.red, ), ], ], @@ -50,24 +48,24 @@ class DialogFooter extends StatelessWidget { ); } - Widget _buildFooterButton( - BuildContext context, - String text, - VoidCallback? onTap, - ) { - return GestureDetector( - onTap: onTap, - child: SizedBox( - height: 50, - child: Center( - child: Text( - text, - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: text == 'Confirm' - ? ColorsManager.primaryColorWithOpacity - : ColorsManager.textGray, - ), - ), + Widget _buildFooterButton({ + required BuildContext context, + required String text, + required VoidCallback? onTap, + Color? textColor, + }) { + return Expanded( + child: TextButton( + style: TextButton.styleFrom( + foregroundColor: ColorsManager.primaryColorWithOpacity, + disabledForegroundColor: ColorsManager.primaryColor, + ), + onPressed: onTap, + child: Text( + text, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: textColor ?? ColorsManager.textGray, + ), ), ), ); From 1bfab8cc768557c5da701f7d997b837beaf0bc68 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Tue, 15 Apr 2025 14:38:06 +0300 Subject: [PATCH 3/3] SP-1189-Fix tapping ok and nothing happening bug by taking the action out of the widget. --- .../widgets/loaded_space_widget.dart | 7 + .../all_spaces/widgets/sidebar_widget.dart | 8 +- .../views/create_subspace_model_dialog.dart | 231 ++++-------------- .../create_subspace_model_chips_box.dart | 64 +++++ .../create_subspace_model_footer_buttons.dart | 53 ++++ .../widgets/subspace_chip.dart | 58 +++++ .../widgets/subspaces_textfield.dart | 68 ++++++ 7 files changed, 297 insertions(+), 192 deletions(-) create mode 100644 lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_chips_box.dart create mode 100644 lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_footer_buttons.dart create mode 100644 lib/pages/spaces_management/create_subspace_model/widgets/subspace_chip.dart create mode 100644 lib/pages/spaces_management/create_subspace_model/widgets/subspaces_textfield.dart diff --git a/lib/pages/spaces_management/all_spaces/widgets/loaded_space_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/loaded_space_widget.dart index 66b2d6da..5ef9c79b 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/loaded_space_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/loaded_space_widget.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_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/space_model.dart'; @@ -107,6 +109,11 @@ class _LoadedSpaceViewState extends State { selectedSpaceUuid: widget.selectedSpace?.uuid ?? widget.selectedCommunity?.uuid ?? '', + onCreateCommunity: (name, description) { + context.read().add( + CreateCommunityEvent(name, description, context), + ); + }, ), CommunityStructureArea( selectedCommunity: widget.selectedCommunity, diff --git a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart index b30a8c96..3eb1c001 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart @@ -16,9 +16,11 @@ import 'package:syncrow_web/utils/style.dart'; class SidebarWidget extends StatefulWidget { final List communities; final String? selectedSpaceUuid; + final void Function(String name, String description) onCreateCommunity; const SidebarWidget({ required this.communities, + required this.onCreateCommunity, this.selectedSpaceUuid, super.key, }); @@ -195,11 +197,7 @@ class _SidebarWidgetState extends State { builder: (context) => CreateCommunityDialog( isEditMode: false, existingCommunityNames: widget.communities.map((e) => e.name).toList(), - onCreateCommunity: (name, description) { - context.read().add( - CreateCommunityEvent(name, description, context), - ); - }, + onCreateCommunity: widget.onCreateCommunity, ), ); } diff --git a/lib/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart b/lib/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart index 7a39891b..66acdf3d 100644 --- a/lib/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart +++ b/lib/pages/spaces_management/create_subspace_model/views/create_subspace_model_dialog.dart @@ -1,12 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.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/create_subspace_model/bloc/subspace_model_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_event.dart'; import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_state.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_chips_box.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_footer_buttons.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; class CreateSubSpaceModelDialog extends StatelessWidget { final bool isEdit; @@ -14,211 +15,67 @@ class CreateSubSpaceModelDialog extends StatelessWidget { final List? existingSubSpaces; final void Function(List newSubspaces)? onUpdate; - const CreateSubSpaceModelDialog( - {Key? key, - required this.isEdit, - required this.dialogTitle, - this.existingSubSpaces, - this.onUpdate}) - : super(key: key); + const CreateSubSpaceModelDialog({ + required this.isEdit, + required this.dialogTitle, + this.existingSubSpaces, + this.onUpdate, + super.key, + }); @override Widget build(BuildContext context) { final screenWidth = MediaQuery.of(context).size.width; - final textController = TextEditingController(); return Dialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), child: BlocProvider( - create: (_) { + create: (context) { final bloc = SubSpaceModelBloc(); if (existingSubSpaces != null) { - for (var subSpace in existingSubSpaces!) { + for (final subSpace in existingSubSpaces ?? []) { bloc.add(AddSubSpaceModel(subSpace)); } } return bloc; }, child: BlocBuilder( - builder: (context, state) { - return Container( - color: ColorsManager.whiteColors, - child: SizedBox( - width: screenWidth * 0.3, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - dialogTitle, - style: Theme.of(context) - .textTheme - .headlineLarge - ?.copyWith(color: ColorsManager.blackColor), - ), - const SizedBox(height: 16), - Container( - width: screenWidth * 0.35, - padding: const EdgeInsets.symmetric( - vertical: 10.0, horizontal: 16.0), - decoration: BoxDecoration( - color: ColorsManager.boxColor, - borderRadius: BorderRadius.circular(10), - ), - child: Wrap( - spacing: 8.0, - runSpacing: 8.0, - children: [ - ...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: Theme.of(context) - .textTheme - .bodySmall - ?.copyWith( - color: ColorsManager.spaceColor, - )), - backgroundColor: ColorsManager.whiteColors, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - side: BorderSide( - color: isDuplicate - ? ColorsManager.red - : ColorsManager.transparentColor, - width: 0, - ), - ), - 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() - .add(RemoveSubSpaceModel(subSpace)), - ); - }, - ), - SizedBox( - width: 200, - child: TextField( - controller: textController, - decoration: InputDecoration( - border: InputBorder.none, - hintText: state.subSpaces.isEmpty - ? 'Please enter the name' - : null, - hintStyle: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: ColorsManager - .lightGrayColor)), - onSubmitted: (value) { - if (value.trim().isNotEmpty) { - context.read().add( - AddSubSpaceModel( - SubspaceTemplateModel( - subspaceName: value.trim(), - disabled: false))); - textController.clear(); - } - }, - style: Theme.of(context) - .textTheme - .bodyMedium - ?.copyWith( - color: ColorsManager.blackColor)), - ), - ], - ), - ), - if (state.errorMessage.isNotEmpty) - Padding( - padding: const EdgeInsets.only(bottom: 16.0), - child: Text(state.errorMessage, - style: Theme.of(context) - .textTheme - .bodySmall - ?.copyWith( - color: ColorsManager.red, - )), - ), - const SizedBox(height: 16), - Row( - children: [ - Expanded( - child: CancelButton( - label: 'Cancel', - onPressed: () async { - Navigator.of(context).pop(); - }, - ), - ), - const SizedBox(width: 10), - Expanded( - child: DefaultButton( - onPressed: (state.errorMessage.isNotEmpty) - ? null - : () async { - final subSpaces = context - .read() - .state - .subSpaces; - Navigator.of(context).pop(); - if (onUpdate != null) { - onUpdate!(subSpaces); - } - }, - backgroundColor: ColorsManager.secondaryColor, - borderRadius: 10, - foregroundColor: state.errorMessage.isNotEmpty - ? ColorsManager.whiteColorsWithOpacity - : ColorsManager.whiteColors, - child: const Text('OK'), - ), - ), - ], - ), - ], + builder: (context, state) => Container( + color: ColorsManager.whiteColors, + width: screenWidth * 0.3, + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + dialogTitle, + style: context.textTheme.headlineLarge?.copyWith( + color: ColorsManager.blackColor, + ), + ), + const SizedBox(height: 16), + CreateSubspaceModelChipsBox(subSpaces: state.subSpaces), + if (state.errorMessage.isNotEmpty) + Padding( + padding: const EdgeInsets.only(bottom: 16), + child: Text( + state.errorMessage, + style: context.textTheme.bodySmall?.copyWith( + color: ColorsManager.red, + ), ), ), - )); - }, + const SizedBox(height: 16), + CreateSubspaceModelFooterButtons( + onUpdate: onUpdate, + errorMessage: state.errorMessage, + ), + ], + ), + ), ), ), ); diff --git a/lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_chips_box.dart b/lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_chips_box.dart new file mode 100644 index 00000000..a18fc8d8 --- /dev/null +++ b/lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_chips_box.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/subspace_chip.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/subspaces_textfield.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; + +class CreateSubspaceModelChipsBox extends StatelessWidget { + const CreateSubspaceModelChipsBox({ + required this.subSpaces, + super.key, + }); + + final List subSpaces; + + @override + Widget build(BuildContext context) { + final screenWidth = MediaQuery.of(context).size.width; + + return Container( + width: screenWidth * 0.35, + padding: const EdgeInsets.symmetric( + vertical: 10, + horizontal: 16, + ), + decoration: BoxDecoration( + color: ColorsManager.boxColor, + borderRadius: BorderRadius.circular(10), + ), + child: Wrap( + spacing: 8, + runSpacing: 8, + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + ...subSpaces.asMap().entries.map( + (entry) { + final index = entry.key; + final subSpace = entry.value; + + final lowerName = subSpace.subspaceName.toLowerCase(); + + final duplicateIndices = 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 SubspaceChip( + subSpace: subSpace, + isDuplicate: isDuplicate, + ); + }, + ), + SubspacesTextfield( + hintText: subSpaces.isEmpty ? 'Please enter the name' : null, + ), + ], + ), + ); + } +} diff --git a/lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_footer_buttons.dart b/lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_footer_buttons.dart new file mode 100644 index 00000000..a8dcf89c --- /dev/null +++ b/lib/pages/spaces_management/create_subspace_model/widgets/create_subspace_model_footer_buttons.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.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/create_subspace_model/bloc/subspace_model_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; + +class CreateSubspaceModelFooterButtons extends StatelessWidget { + const CreateSubspaceModelFooterButtons({ + required this.onUpdate, + required this.errorMessage, + super.key, + }); + + final void Function(List newSubspaces)? onUpdate; + final String errorMessage; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Expanded( + child: CancelButton( + label: 'Cancel', + onPressed: () => Navigator.of(context).pop(), + ), + ), + const SizedBox(width: 10), + Expanded( + child: DefaultButton( + onPressed: errorMessage.isEmpty + ? () { + Navigator.of(context).pop(); + if (onUpdate != null) { + final subSpaces = + context.read().state.subSpaces; + onUpdate!(subSpaces); + } + } + : null, + backgroundColor: ColorsManager.secondaryColor, + borderRadius: 10, + foregroundColor: errorMessage.isNotEmpty + ? ColorsManager.whiteColorsWithOpacity + : ColorsManager.whiteColors, + child: const Text('OK'), + ), + ), + ], + ); + } +} diff --git a/lib/pages/spaces_management/create_subspace_model/widgets/subspace_chip.dart b/lib/pages/spaces_management/create_subspace_model/widgets/subspace_chip.dart new file mode 100644 index 00000000..b54e0712 --- /dev/null +++ b/lib/pages/spaces_management/create_subspace_model/widgets/subspace_chip.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_event.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; + +class SubspaceChip extends StatelessWidget { + const SubspaceChip({ + required this.subSpace, + required this.isDuplicate, + super.key, + }); + + final SubspaceTemplateModel subSpace; + final bool isDuplicate; + + @override + Widget build(BuildContext context) { + return Chip( + label: Text( + subSpace.subspaceName, + style: context.textTheme.bodySmall?.copyWith( + color: isDuplicate ? ColorsManager.red : ColorsManager.spaceColor, + ), + ), + backgroundColor: ColorsManager.whiteColors, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + color: isDuplicate ? ColorsManager.red : ColorsManager.transparentColor, + width: 0, + ), + ), + deleteIcon: Container( + padding: const EdgeInsetsDirectional.all(1), + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: ColorsManager.lightGrayColor, + width: 1.5, + ), + ), + child: const FittedBox( + fit: BoxFit.scaleDown, + child: Icon( + Icons.close, + color: ColorsManager.lightGrayColor, + ), + ), + ), + onDeleted: () => context.read().add( + RemoveSubSpaceModel(subSpace), + ), + ); + } +} diff --git a/lib/pages/spaces_management/create_subspace_model/widgets/subspaces_textfield.dart b/lib/pages/spaces_management/create_subspace_model/widgets/subspaces_textfield.dart new file mode 100644 index 00000000..d654b960 --- /dev/null +++ b/lib/pages/spaces_management/create_subspace_model/widgets/subspaces_textfield.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/create_subspace_model/bloc/subspace_model_event.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; + +class SubspacesTextfield extends StatefulWidget { + const SubspacesTextfield({ + required this.hintText, + super.key, + }); + + final String? hintText; + + @override + State createState() => _SubspacesTextfieldState(); +} + +class _SubspacesTextfieldState extends State { + late final TextEditingController _controller; + @override + void initState() { + _controller = TextEditingController(); + super.initState(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return SizedBox( + width: 100, + child: TextField( + controller: _controller, + decoration: InputDecoration( + border: InputBorder.none, + hintText: widget.hintText, + hintStyle: context.textTheme.bodySmall?.copyWith( + color: ColorsManager.lightGrayColor, + ), + ), + onSubmitted: (value) { + final trimmedValue = value.trim(); + if (trimmedValue.isNotEmpty) { + context.read().add( + AddSubSpaceModel( + SubspaceTemplateModel( + subspaceName: trimmedValue, + disabled: false, + ), + ), + ); + _controller.clear(); + } + }, + style: context.textTheme.bodyMedium?.copyWith( + color: ColorsManager.blackColor, + ), + ), + ); + } +}