From 00a9cb11880fe5a7410b0cb1a00f5e861784ada3 Mon Sep 17 00:00:00 2001 From: mohammad Date: Mon, 10 Feb 2025 12:38:20 +0300 Subject: [PATCH 1/8] link_space model --- assets/icons/delete_space_link_icon.svg | 21 ++ assets/icons/space_link_icon.svg | 25 +++ .../add_user_dialog/view/build_tree_view.dart | 1 - .../models/space_template_model.dart | 3 + .../widgets/dialog/confirm_merge_dialog.dart | 84 ++++++++ .../dialog/confirm_overwrite_dialog.dart | 84 ++++++++ .../widgets/dialog/custom_loading_dialog.dart | 110 ++++++++++ .../link_space_model_spaces_dialog.dart | 190 ++++++++++++++++++ .../dialog/linking_attention_dialog.dart | 111 ++++++++++ .../widgets/dialog/overwrite_dialog.dart | 112 +++++++++++ .../widgets/space_model_card_widget.dart | 61 +++++- lib/services/space_mana_api.dart | 1 + lib/utils/color_manager.dart | 2 +- lib/utils/constants/assets.dart | 6 +- 14 files changed, 799 insertions(+), 12 deletions(-) create mode 100644 assets/icons/delete_space_link_icon.svg create mode 100644 assets/icons/space_link_icon.svg create mode 100644 lib/pages/spaces_management/space_model/widgets/dialog/confirm_merge_dialog.dart create mode 100644 lib/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart create mode 100644 lib/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart create mode 100644 lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart create mode 100644 lib/pages/spaces_management/space_model/widgets/dialog/linking_attention_dialog.dart create mode 100644 lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart diff --git a/assets/icons/delete_space_link_icon.svg b/assets/icons/delete_space_link_icon.svg new file mode 100644 index 00000000..a55d2e04 --- /dev/null +++ b/assets/icons/delete_space_link_icon.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/space_link_icon.svg b/assets/icons/space_link_icon.svg new file mode 100644 index 00000000..f10c57ad --- /dev/null +++ b/assets/icons/space_link_icon.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/pages/roles_and_permission/users_page/add_user_dialog/view/build_tree_view.dart b/lib/pages/roles_and_permission/users_page/add_user_dialog/view/build_tree_view.dart index b7fc1085..24ada87d 100644 --- a/lib/pages/roles_and_permission/users_page/add_user_dialog/view/build_tree_view.dart +++ b/lib/pages/roles_and_permission/users_page/add_user_dialog/view/build_tree_view.dart @@ -19,7 +19,6 @@ class TreeView extends StatelessWidget { @override Widget build(BuildContext context) { final _blocRole = BlocProvider.of(context); - debugPrint('TreeView constructed with userId = $userId'); return BlocProvider( create: (_) => UsersBloc(), // ..add(const LoadCommunityAndSpacesEvent()), 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 22378f1f..aca986bf 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 @@ -11,6 +11,7 @@ class SpaceTemplateModel extends Equatable { List? subspaceModels; final List? tags; String internalId; + DateTime? createdAt; @override List get props => [modelName, subspaceModels, tags]; @@ -21,6 +22,7 @@ class SpaceTemplateModel extends Equatable { required this.modelName, this.subspaceModels, this.tags, + this.createdAt, }) : internalId = internalId ?? const Uuid().v4(); factory SpaceTemplateModel.fromJson(Map json) { @@ -28,6 +30,7 @@ class SpaceTemplateModel extends Equatable { return SpaceTemplateModel( uuid: json['uuid'] ?? '', + createdAt: json['createdAt'] ?? '', internalId: internalId, modelName: json['modelName'] ?? '', subspaceModels: (json['subspaceModels'] as List?) diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/confirm_merge_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/confirm_merge_dialog.dart new file mode 100644 index 00000000..2a39d67b --- /dev/null +++ b/lib/pages/spaces_management/space_model/widgets/dialog/confirm_merge_dialog.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; + +class ConfirmMergeDialog extends StatelessWidget { + const ConfirmMergeDialog({super.key}); + + @override + Widget build(BuildContext context) { + return AlertDialog( + backgroundColor: ColorsManager.whiteColors, + title: Center( + child: Text( + 'Merge', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.w400, fontSize: 30), + )), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + 'Are you sure you want to merge?', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.w400, fontSize: 18), + ), + const SizedBox(height: 25), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + child: ElevatedButton( + onPressed: () { + Navigator.pop(context); + }, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 14), + backgroundColor: ColorsManager.boxColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 3, + ), + child: Text( + "Cancel", + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.w400, fontSize: 16), + ), + ), + ), + const SizedBox(width: 10), + Expanded( + child: ElevatedButton( + onPressed: () {}, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 14), + backgroundColor: ColorsManager.secondaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 3, + ), + child: Text( + "Ok", + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w400, + fontSize: 16, + color: ColorsManager.whiteColors, + ), + ), + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart new file mode 100644 index 00000000..7e7c5641 --- /dev/null +++ b/lib/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; + +class ConfirmOverwriteDialog extends StatelessWidget { + const ConfirmOverwriteDialog({super.key}); + + @override + Widget build(BuildContext context) { + return AlertDialog( + backgroundColor: ColorsManager.whiteColors, + title: Center( + child: Text( + 'Overwrite', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.w400, fontSize: 30), + )), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + 'Are you sure you want to overwrite?', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.w400, fontSize: 18), + ), + const SizedBox(height: 25), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + child: ElevatedButton( + onPressed: () { + Navigator.pop(context); + }, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 14), + backgroundColor: ColorsManager.boxColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 3, + ), + child: Text( + "Cancel", + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.w400, fontSize: 16), + ), + ), + ), + const SizedBox(width: 10), + Expanded( + child: ElevatedButton( + onPressed: () {}, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 14), + backgroundColor: ColorsManager.secondaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 3, + ), + child: Text( + "Ok", + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w400, + fontSize: 16, + color: ColorsManager.whiteColors, + ), + ), + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart new file mode 100644 index 00000000..2d50d93b --- /dev/null +++ b/lib/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart @@ -0,0 +1,110 @@ +import 'dart:math'; +import 'package:flutter/material.dart'; + +void showCustomLoadingDialog(BuildContext context) { + showDialog( + context: context, + barrierDismissible: false, // Prevent closing by tapping outside + builder: (BuildContext context) { + Future.delayed(Duration(seconds: 3), () { + Navigator.of(context).pop(); // Auto-close after 3 seconds + }); + + return Dialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), + elevation: 10, + backgroundColor: Colors.white, + child: Padding( + padding: EdgeInsets.symmetric(vertical: 30, horizontal: 50), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Custom loader + CustomLoadingIndicator(), + SizedBox(height: 20), + Text( + "Linking in progress", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.black87, + ), + ), + ], + ), + ), + ); + }, + ); +} + +class CustomLoadingIndicator extends StatefulWidget { + @override + _CustomLoadingIndicatorState createState() => _CustomLoadingIndicatorState(); +} + +class _CustomLoadingIndicatorState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + vsync: this, + duration: Duration(seconds: 1), // Rotation speed + )..repeat(); // Infinite animation + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return SizedBox( + width: 50, + height: 50, + child: AnimatedBuilder( + animation: _controller, + builder: (context, child) { + return Transform.rotate( + angle: _controller.value * 2 * pi, // Full rotation + child: CustomPaint( + painter: LoadingPainter(), + ), + ); + }, + ), + ); + } +} + +class LoadingPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final Paint paint = Paint() + ..strokeWidth = 5 + ..strokeCap = StrokeCap.round + ..style = PaintingStyle.stroke; + + final double radius = size.width / 2; + final Offset center = Offset(size.width / 2, size.height / 2); + + for (int i = 0; i < 12; i++) { + final double angle = (i * 30) * (pi / 180); + final double startX = center.dx + radius * cos(angle); + final double startY = center.dy + radius * sin(angle); + final double endX = center.dx + (radius - 8) * cos(angle); + final double endY = center.dy + (radius - 8) * sin(angle); + + paint.color = Colors.blue.withOpacity(i / 12); // Gradient effect + canvas.drawLine(Offset(startX, startY), Offset(endX, endY), paint); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) => true; +} diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart new file mode 100644 index 00000000..ff38152e --- /dev/null +++ b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart @@ -0,0 +1,190 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/view/build_tree_view.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; +import 'package:syncrow_web/utils/style.dart'; + +class LinkSpaceModelSpacesDialog extends StatelessWidget { + final SpaceTemplateModel spaceModel; + LinkSpaceModelSpacesDialog({super.key, required this.spaceModel}); + + TextEditingController searchController = TextEditingController(); + + @override + Widget build(BuildContext context) { + return AlertDialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), + backgroundColor: Colors.white, + contentPadding: const EdgeInsets.all(20), + content: SizedBox( + width: MediaQuery.of(context).size.width * 0.4, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Title + const Center( + child: Text( + "Link Space Model to Spaces", + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.blueAccent, + ), + ), + ), + const Divider(), + const SizedBox(height: 16), + + // Details Section + _buildDetailRow("Space model name:", spaceModel.modelName), + _buildDetailRow("Creation date and time:", spaceModel.modelName), + _buildDetailRow("Created by:", "Admin"), + const SizedBox(height: 12), + + // Link to Section + const Text( + "Link to:", + style: TextStyle(fontWeight: FontWeight.bold), + ), + const Text( + "Please select all the spaces where you would like to link the Routine.", + style: TextStyle(fontSize: 12, color: Colors.grey), + ), + + const SizedBox(height: 8), + + // Spaces List + Expanded( + child: SizedBox( + child: Column( + children: [ + Expanded( + flex: 2, + child: Container( + decoration: const BoxDecoration( + color: ColorsManager.circleRolesBackground, + borderRadius: BorderRadius.only( + topRight: Radius.circular(20), + topLeft: Radius.circular(20)), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all( + Radius.circular(20)), + border: Border.all( + color: ColorsManager.grayBorder)), + child: TextFormField( + style: const TextStyle(color: Colors.black), + // controller: _blocRole.firstNameController, + onChanged: (value) { + // _blocRole.add(SearchAnode( + // nodes: _blocRole.updatedCommunities, + // searchTerm: value)); + }, + decoration: + textBoxDecoration(radios: 20)!.copyWith( + fillColor: Colors.white, + suffixIcon: Padding( + padding: + const EdgeInsets.only(right: 16), + child: SvgPicture.asset( + Assets.textFieldSearch, + width: 24, + height: 24, + ), + ), + hintStyle: context.textTheme.bodyMedium + ?.copyWith( + fontWeight: FontWeight.w400, + fontSize: 12, + color: ColorsManager.textGray), + ), + ), + ), + ), + ], + ), + ), + ), + ), + Expanded( + flex: 7, + child: Container( + color: ColorsManager.circleRolesBackground, + padding: const EdgeInsets.all(8.0), + child: Container( + color: ColorsManager.whiteColors, + child: TreeView(userId: '')))) + ], + ), + ), + ), + + // Buttons + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + _buildButton("Cancel", Colors.grey, () { + Navigator.of(context).pop(); + }), + _buildButton("Confirm", Colors.blueAccent, () { + Navigator.of(context).pop(); + }), + ], + ), + ], + ), + ), + ); + } + + // Method to build a detail row + Widget _buildDetailRow(String label, String value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Row( + children: [ + Expanded( + child: Text( + label, + style: TextStyle(fontWeight: FontWeight.bold), + ), + ), + const SizedBox(width: 8), + Expanded( + child: Text( + value, + style: + TextStyle(fontWeight: FontWeight.bold, color: Colors.black), + ), + ), + ], + ), + ); + } + + // Button Widget + Widget _buildButton(String text, Color color, VoidCallback onPressed) { + return TextButton( + onPressed: onPressed, + style: TextButton.styleFrom( + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + backgroundColor: color.withOpacity(0.2), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + ), + child: Text( + text, + style: TextStyle(color: color, fontWeight: FontWeight.bold), + ), + ); + } +} diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/linking_attention_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/linking_attention_dialog.dart new file mode 100644 index 00000000..a0807dba --- /dev/null +++ b/lib/pages/spaces_management/space_model/widgets/dialog/linking_attention_dialog.dart @@ -0,0 +1,111 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/confirm_merge_dialog.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; + +class LinkingAttentionDialog extends StatelessWidget { + const LinkingAttentionDialog({super.key}); + + @override + Widget build(BuildContext context) { + return AlertDialog( + backgroundColor: ColorsManager.whiteColors, + title: Center( + child: Text( + 'Linking Attention', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.w400, fontSize: 30), + )), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + 'Do you want to merge or overwrite?', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.w400, fontSize: 18), + ), + const SizedBox(height: 8), + Text( + 'Selected spaces already have commissioned Devices', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.w400, fontSize: 14), + ), + const SizedBox(height: 25), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + // Cancel Button + Expanded( + child: ElevatedButton( + onPressed: () { + Navigator.pop(context); + showDialog( + context: context, + builder: (BuildContext dialogContext) { + return const ConfirmOverwriteDialog(); + }, + ); + }, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 14), + backgroundColor: ColorsManager.boxColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 3, + ), + child: Text( + "Overwrite", + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.w400, fontSize: 16), + + ), + ), + ), + const SizedBox(width: 10), + + // OK Button + Expanded( + child: ElevatedButton( + onPressed: () { + Navigator.pop(context); + showDialog( + context: context, + builder: (BuildContext dialogContext) { + return const ConfirmMergeDialog(); + }, + ); + }, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 14), + backgroundColor: ColorsManager.boxColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 3, + ), + child: Text( + "Merge", + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.w400, fontSize: 16), + ), + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart new file mode 100644 index 00000000..3d207968 --- /dev/null +++ b/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart @@ -0,0 +1,112 @@ +import 'package:flutter/material.dart'; + +void showOverwriteDialog(BuildContext context) { + showDialog( + context: context, + barrierDismissible: false, // Prevent closing by tapping outside + builder: (BuildContext context) { + return Container( + child: Dialog( + shape: + RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), + elevation: 10, + backgroundColor: Colors.white, + child: Container( + width: MediaQuery.of(context).size.width * 0.3, + child: Padding( + padding: EdgeInsets.symmetric(vertical: 30, horizontal: 20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Title + Text( + "Overwrite", + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + SizedBox(height: 15), + + // Description + Text( + "Are you sure you want to overwrite?", + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + textAlign: TextAlign.center, + ), + SizedBox(height: 5), + Text( + "Selected spaces already have linked space model / sub-spaces and devices", + style: TextStyle( + fontSize: 14, + color: Colors.grey[600], + ), + textAlign: TextAlign.center, + ), + SizedBox(height: 25), + + // Buttons + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + // Cancel Button + Expanded( + child: ElevatedButton( + onPressed: () => Navigator.of(context).pop(), + style: ElevatedButton.styleFrom( + padding: EdgeInsets.symmetric(vertical: 14), + backgroundColor: Colors.grey[200], + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 0, + ), + child: Text( + "Cancel", + style: TextStyle( + fontSize: 16, + color: Colors.black, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + SizedBox(width: 10), + + // OK Button + Expanded( + child: ElevatedButton( + onPressed: () { + Navigator.of(context).pop(); + // Add action for OK button + }, + style: ElevatedButton.styleFrom( + padding: EdgeInsets.symmetric(vertical: 14), + backgroundColor: Colors.blue, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 3, + ), + child: Text( + "OK", + style: TextStyle( + fontSize: 16, + color: Colors.white, + fontWeight: FontWeight.w500, + ), + ), + ), + ), + ], + ), + ], + ), + ), + ), + ), + ); + }, + ); +} 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 0056c96f..52b0fa6c 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 @@ -1,8 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.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/link_space_model_spaces_dialog.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/linking_attention_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_product_widget.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_room_widget.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; class SpaceModelCardWidget extends StatelessWidget { final SpaceTemplateModel model; @@ -34,7 +38,7 @@ class SpaceModelCardWidget extends StatelessWidget { return LayoutBuilder( builder: (context, constraints) { bool showOnlyName = constraints.maxWidth < 250; - return Container( + return Container( padding: const EdgeInsets.all(16.0), decoration: BoxDecoration( color: Colors.white, @@ -51,14 +55,53 @@ class SpaceModelCardWidget extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - model.modelName, - style: Theme.of(context).textTheme.headlineMedium?.copyWith( - color: Colors.black, - fontWeight: FontWeight.bold, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + model.modelName, + style: Theme.of(context).textTheme.headlineMedium?.copyWith( + color: Colors.black, + fontWeight: FontWeight.bold, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + Row( + children: [ + InkWell( + onTap: () { + showDialog( + context: context, + builder: (BuildContext dialogContext) { + return LinkSpaceModelSpacesDialog( + spaceModel: model, + ); + }, + ); + }, + child: SvgPicture.asset( + Assets.spaceLinkIcon, + fit: BoxFit.contain, + ), + ), + InkWell( + onTap: () { + showDialog( + context: context, + builder: (BuildContext dialogContext) { + return const LinkingAttentionDialog(); + }, + ); + }, + child: SvgPicture.asset( + Assets.deleteSpaceLinkIcon, + fit: BoxFit.contain, + ), + ), + ], + ) + ], ), if (!showOnlyName) ...[ const SizedBox(height: 10), diff --git a/lib/services/space_mana_api.dart b/lib/services/space_mana_api.dart index c4877c98..788b9455 100644 --- a/lib/services/space_mana_api.dart +++ b/lib/services/space_mana_api.dart @@ -281,6 +281,7 @@ class CommunitySpaceManagementApi { .replaceAll('{communityId}', communityId) .replaceAll('{projectId}', TempConst.projectId), expectedResponseModel: (json) { + print('json space=$json'); final spaceModels = (json['data'] as List) .map((spaceJson) => SpaceModel.fromJson(spaceJson)) .toList(); diff --git a/lib/utils/color_manager.dart b/lib/utils/color_manager.dart index 4d3dbb0c..63456ff7 100644 --- a/lib/utils/color_manager.dart +++ b/lib/utils/color_manager.dart @@ -52,7 +52,7 @@ abstract class ColorsManager { static const Color semiTransparentBlackColor = Color(0x3F000000); static const Color transparentColor = Color(0x00000000); static const Color spaceColor = Color(0xB2023DFE); - static const Color counterBackgroundColor = Color(0xCCF4F4F4); + static const Color counterBackgroundColor = Color.fromARGB(204, 105, 2, 2); static const Color neutralGray = Color(0xFFE5E5E5); static const Color warningRed = Color(0xFFFF6465); static const Color borderColor = Color(0xFFE5E5E5); diff --git a/lib/utils/constants/assets.dart b/lib/utils/constants/assets.dart index d5d216c5..e1b7658b 100644 --- a/lib/utils/constants/assets.dart +++ b/lib/utils/constants/assets.dart @@ -401,5 +401,9 @@ class Assets { static const String link = 'assets/icons/link.svg'; static const String duplicate = 'assets/icons/duplicate.svg'; static const String spaceDelete = 'assets/icons/space_delete.svg'; + + static const String deleteSpaceLinkIcon = + 'assets/icons/delete_space_link_icon.svg'; + static const String spaceLinkIcon = 'assets/icons/space_link_icon.svg'; } -//user_management.svg +//space_link_icon.svg From 009ede7d081b5d4dea38d45753fc06113e9ec502 Mon Sep 17 00:00:00 2001 From: mohammad Date: Tue, 18 Feb 2025 12:37:00 +0300 Subject: [PATCH 2/8] overwrite dialog and progress indicator and success dialog --- assets/icons/success_icon.svg | 3 + .../ac/view/ac_device_control.dart | 10 +- .../space_tree/view/space_tree_view.dart | 169 +++++++++--- .../models/space_template_model.dart | 2 +- .../dialog/confirm_overwrite_dialog.dart | 12 +- .../widgets/dialog/custom_loading_dialog.dart | 43 +-- .../link_space_model_spaces_dialog.dart | 255 ++++++++++-------- .../dialog/linking_attention_dialog.dart | 1 - .../widgets/dialog/linking_successful.dart | 33 +++ .../widgets/dialog/overwrite_dialog.dart | 8 +- lib/services/space_mana_api.dart | 1 - lib/utils/constants/assets.dart | 3 +- 12 files changed, 337 insertions(+), 203 deletions(-) create mode 100644 assets/icons/success_icon.svg create mode 100644 lib/pages/spaces_management/space_model/widgets/dialog/linking_successful.dart diff --git a/assets/icons/success_icon.svg b/assets/icons/success_icon.svg new file mode 100644 index 00000000..6f5dbf9e --- /dev/null +++ b/assets/icons/success_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/lib/pages/device_managment/ac/view/ac_device_control.dart b/lib/pages/device_managment/ac/view/ac_device_control.dart index 5197d722..071344d7 100644 --- a/lib/pages/device_managment/ac/view/ac_device_control.dart +++ b/lib/pages/device_managment/ac/view/ac_device_control.dart @@ -24,7 +24,8 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout { final isLarge = isLargeScreenSize(context); final isMedium = isMediumScreenSize(context); return BlocProvider( - create: (context) => AcBloc(deviceId: device.uuid!)..add(AcFetchDeviceStatusEvent(device.uuid!)), + create: (context) => AcBloc(deviceId: device.uuid!) + ..add(AcFetchDeviceStatusEvent(device.uuid!)), child: BlocBuilder( builder: (context, state) { if (state is ACStatusLoaded) { @@ -98,7 +99,8 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout { ), Text( 'h', - style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor), + style: context.textTheme.bodySmall! + .copyWith(color: ColorsManager.blackColor), ), Text( '30', @@ -107,7 +109,9 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout { fontWeight: FontWeight.bold, ), ), - Text('m', style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor)), + Text('m', + style: context.textTheme.bodySmall! + .copyWith(color: ColorsManager.blackColor)), IconButton( padding: const EdgeInsets.all(0), onPressed: () {}, diff --git a/lib/pages/space_tree/view/space_tree_view.dart b/lib/pages/space_tree/view/space_tree_view.dart index de9d088e..3954f200 100644 --- a/lib/pages/space_tree/view/space_tree_view.dart +++ b/lib/pages/space_tree/view/space_tree_view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:syncrow_web/common/widgets/search_bar.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart'; @@ -8,11 +9,14 @@ import 'package:syncrow_web/pages/space_tree/view/custom_expansion.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/style.dart'; class SpaceTreeView extends StatefulWidget { + final bool? isSide; final Function onSelect; - const SpaceTreeView({required this.onSelect, super.key}); + const SpaceTreeView({required this.onSelect, this.isSide, super.key}); @override State createState() => _SpaceTreeViewState(); @@ -29,20 +33,77 @@ class _SpaceTreeViewState extends State { @override Widget build(BuildContext context) { - return BlocBuilder(builder: (context, state) { - List list = state.isSearching ? state.filteredCommunity : state.communityList; + return BlocBuilder( + builder: (context, state) { + List list = + state.isSearching ? state.filteredCommunity : state.communityList; return Container( height: MediaQuery.sizeOf(context).height, - decoration: subSectionContainerDecoration, + decoration: + widget.isSide == true ? subSectionContainerDecoration : null, child: state is SpaceTreeLoadingState ? const Center(child: CircularProgressIndicator()) : Column( children: [ - CustomSearchBar( - onSearchChanged: (query) { - context.read().add(SearchQueryEvent(query)); - }, - ), + widget.isSide == true + ? Container( + decoration: const BoxDecoration( + color: ColorsManager.circleRolesBackground, + borderRadius: BorderRadius.only( + topRight: Radius.circular(20), + topLeft: Radius.circular(20)), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all( + Radius.circular(20)), + border: Border.all( + color: ColorsManager.grayBorder)), + child: TextFormField( + style: + const TextStyle(color: Colors.black), + onChanged: (value) { + context + .read() + .add(SearchQueryEvent(value)); + }, + decoration: textBoxDecoration(radios: 20)! + .copyWith( + fillColor: Colors.white, + suffixIcon: Padding( + padding: + const EdgeInsets.only(right: 16), + child: SvgPicture.asset( + Assets.textFieldSearch, + width: 24, + height: 24, + ), + ), + hintStyle: context.textTheme.bodyMedium + ?.copyWith( + fontWeight: FontWeight.w400, + fontSize: 12, + color: ColorsManager.textGray), + ), + ), + ), + ), + ], + ), + ), + ) + : CustomSearchBar( + onSearchChanged: (query) { + context + .read() + .add(SearchQueryEvent(query)); + }, + ), const SizedBox(height: 16), Expanded( child: ListView( @@ -56,14 +117,18 @@ class _SpaceTreeViewState extends State { ? Center( child: Text( 'No results found', - style: Theme.of(context).textTheme.bodySmall!.copyWith( + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( color: ColorsManager.lightGrayColor, fontWeight: FontWeight.w400, ), ), ) : Scrollbar( - scrollbarOrientation: ScrollbarOrientation.left, + scrollbarOrientation: + ScrollbarOrientation.left, thumbVisibility: true, controller: _scrollController, child: Padding( @@ -73,47 +138,68 @@ class _SpaceTreeViewState extends State { shrinkWrap: true, children: list .map( - (community) => CustomExpansionTileSpaceTree( + (community) => + CustomExpansionTileSpaceTree( title: community.name, - isSelected: state.selectedCommunities + isSelected: state + .selectedCommunities .contains(community.uuid), - isSoldCheck: state.selectedCommunities + isSoldCheck: state + .selectedCommunities .contains(community.uuid), onExpansionChanged: () { context .read() - .add(OnCommunityExpanded(community.uuid)); + .add(OnCommunityExpanded( + community.uuid)); }, - isExpanded: state.expandedCommunities + isExpanded: state + .expandedCommunities .contains(community.uuid), onItemSelected: () { - context.read().add( - OnCommunitySelected( - community.uuid, community.spaces)); + context + .read() + .add(OnCommunitySelected( + community.uuid, + community.spaces)); widget.onSelect(); }, - children: community.spaces.map((space) { + children: + community.spaces.map((space) { return CustomExpansionTileSpaceTree( title: space.name, - isExpanded: - state.expandedSpaces.contains(space.uuid), + isExpanded: state + .expandedSpaces + .contains(space.uuid), onItemSelected: () { - context.read().add( - OnSpaceSelected(community.uuid, - space.uuid ?? '', space.children)); + context + .read() + .add(OnSpaceSelected( + community.uuid, + space.uuid ?? '', + space.children)); widget.onSelect(); }, onExpansionChanged: () { - context.read().add( - OnSpaceExpanded( - community.uuid, space.uuid ?? '')); + context + .read() + .add(OnSpaceExpanded( + community.uuid, + space.uuid ?? '')); }, - isSelected: - state.selectedSpaces.contains(space.uuid) || - state.soldCheck.contains(space.uuid), - isSoldCheck: state.soldCheck.contains(space.uuid), + isSelected: state + .selectedSpaces + .contains( + space.uuid) || + state.soldCheck + .contains(space.uuid), + isSoldCheck: state.soldCheck + .contains(space.uuid), children: _buildNestedSpaces( - context, state, space, community.uuid), + context, + state, + space, + community.uuid), ); }).toList(), ), @@ -195,23 +281,24 @@ class _SpaceTreeViewState extends State { }); } - List _buildNestedSpaces( - BuildContext context, SpaceTreeState state, SpaceModel space, String communityId) { + List _buildNestedSpaces(BuildContext context, SpaceTreeState state, + SpaceModel space, String communityId) { return space.children.map((child) { return CustomExpansionTileSpaceTree( - isSelected: - state.selectedSpaces.contains(child.uuid) || state.soldCheck.contains(child.uuid), + isSelected: state.selectedSpaces.contains(child.uuid) || + state.soldCheck.contains(child.uuid), isSoldCheck: state.soldCheck.contains(child.uuid), title: child.name, isExpanded: state.expandedSpaces.contains(child.uuid), onItemSelected: () { - context - .read() - .add(OnSpaceSelected(communityId, child.uuid ?? '', child.children)); + context.read().add( + OnSpaceSelected(communityId, child.uuid ?? '', child.children)); widget.onSelect(); }, onExpansionChanged: () { - context.read().add(OnSpaceExpanded(communityId, child.uuid ?? '')); + context + .read() + .add(OnSpaceExpanded(communityId, child.uuid ?? '')); }, children: _buildNestedSpaces(context, state, child, communityId), ); 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 aca986bf..3323fe6e 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 @@ -11,7 +11,7 @@ class SpaceTemplateModel extends Equatable { List? subspaceModels; final List? tags; String internalId; - DateTime? createdAt; + String? createdAt; @override List get props => [modelName, subspaceModels, tags]; diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart index 7e7c5641..ba1d261d 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/linking_successful.dart'; import 'package:syncrow_web/utils/color_manager.dart'; class ConfirmOverwriteDialog extends StatelessWidget { @@ -56,7 +57,16 @@ class ConfirmOverwriteDialog extends StatelessWidget { const SizedBox(width: 10), Expanded( child: ElevatedButton( - onPressed: () {}, + onPressed: () { + Navigator.pop(context); + + showDialog( + context: context, + builder: (BuildContext dialogContext) { + return const LinkingSuccessful(); + }, + ); + }, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 14), backgroundColor: ColorsManager.secondaryColor, diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart index 2d50d93b..e0260887 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart @@ -1,42 +1,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/linking_successful.dart'; -void showCustomLoadingDialog(BuildContext context) { - showDialog( - context: context, - barrierDismissible: false, // Prevent closing by tapping outside - builder: (BuildContext context) { - Future.delayed(Duration(seconds: 3), () { - Navigator.of(context).pop(); // Auto-close after 3 seconds - }); - - return Dialog( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), - elevation: 10, - backgroundColor: Colors.white, - child: Padding( - padding: EdgeInsets.symmetric(vertical: 30, horizontal: 50), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - // Custom loader - CustomLoadingIndicator(), - SizedBox(height: 20), - Text( - "Linking in progress", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Colors.black87, - ), - ), - ], - ), - ), - ); - }, - ); -} class CustomLoadingIndicator extends StatefulWidget { @override @@ -52,8 +17,8 @@ class _CustomLoadingIndicatorState extends State super.initState(); _controller = AnimationController( vsync: this, - duration: Duration(seconds: 1), // Rotation speed - )..repeat(); // Infinite animation + duration: const Duration(seconds: 1), + )..repeat(); } @override @@ -71,7 +36,7 @@ class _CustomLoadingIndicatorState extends State animation: _controller, builder: (context, child) { return Transform.rotate( - angle: _controller.value * 2 * pi, // Full rotation + angle: _controller.value * 2 * pi, child: CustomPaint( painter: LoadingPainter(), ), diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart index ff38152e..abcbedd8 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart @@ -1,11 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/view/build_tree_view.dart'; +import 'package:syncrow_web/pages/space_tree/view/space_tree_view.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/confirm_overwrite_dialog.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart'; import 'package:syncrow_web/utils/color_manager.dart'; -import 'package:syncrow_web/utils/constants/assets.dart'; -import 'package:syncrow_web/utils/extension/build_context_x.dart'; -import 'package:syncrow_web/utils/style.dart'; class LinkSpaceModelSpacesDialog extends StatelessWidget { final SpaceTemplateModel spaceModel; @@ -16,114 +14,69 @@ class LinkSpaceModelSpacesDialog extends StatelessWidget { @override Widget build(BuildContext context) { return AlertDialog( + contentPadding: EdgeInsets.zero, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), backgroundColor: Colors.white, - contentPadding: const EdgeInsets.all(20), content: SizedBox( width: MediaQuery.of(context).size.width * 0.4, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - // Title - const Center( - child: Text( - "Link Space Model to Spaces", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.blueAccent, - ), - ), - ), - const Divider(), - const SizedBox(height: 16), - - // Details Section - _buildDetailRow("Space model name:", spaceModel.modelName), - _buildDetailRow("Creation date and time:", spaceModel.modelName), - _buildDetailRow("Created by:", "Admin"), - const SizedBox(height: 12), - - // Link to Section - const Text( - "Link to:", - style: TextStyle(fontWeight: FontWeight.bold), - ), - const Text( - "Please select all the spaces where you would like to link the Routine.", - style: TextStyle(fontSize: 12, color: Colors.grey), - ), - - const SizedBox(height: 8), - - // Spaces List Expanded( - child: SizedBox( + child: Padding( + padding: const EdgeInsets.all(15.0), child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded( - flex: 2, - child: Container( - decoration: const BoxDecoration( - color: ColorsManager.circleRolesBackground, - borderRadius: BorderRadius.only( - topRight: Radius.circular(20), - topLeft: Radius.circular(20)), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Expanded( - child: Container( - decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(20)), - border: Border.all( - color: ColorsManager.grayBorder)), - child: TextFormField( - style: const TextStyle(color: Colors.black), - // controller: _blocRole.firstNameController, - onChanged: (value) { - // _blocRole.add(SearchAnode( - // nodes: _blocRole.updatedCommunities, - // searchTerm: value)); - }, - decoration: - textBoxDecoration(radios: 20)!.copyWith( - fillColor: Colors.white, - suffixIcon: Padding( - padding: - const EdgeInsets.only(right: 16), - child: SvgPicture.asset( - Assets.textFieldSearch, - width: 24, - height: 24, - ), - ), - hintStyle: context.textTheme.bodyMedium - ?.copyWith( - fontWeight: FontWeight.w400, - fontSize: 12, - color: ColorsManager.textGray), - ), - ), - ), - ), - ], - ), + const Center( + child: Text( + "Link Space Model to Spaces", + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.blueAccent, ), ), ), + const Divider(), + const SizedBox(height: 16), + _buildDetailRow("Space model name:", + spaceModel.modelName), + _buildDetailRow("Creation date and time:", + spaceModel.createdAt.toString()), + _buildDetailRow("Created by:", "Admin"), + const SizedBox(height: 12), + const Text( + "Link to:", + style: TextStyle(fontWeight: FontWeight.bold), + ), + const Text( + "Please select all the spaces where you would like to link the Routine.", + style: TextStyle(fontSize: 12, color: Colors.grey), + ), + const SizedBox(height: 8), Expanded( - flex: 7, - child: Container( - color: ColorsManager.circleRolesBackground, - padding: const EdgeInsets.all(8.0), - child: Container( - color: ColorsManager.whiteColors, - child: TreeView(userId: '')))) + child: SizedBox( + child: Column( + children: [ + Expanded( + flex: 7, + child: Container( + color: ColorsManager.whiteColors, + child: SpaceTreeView( + isSide: true, onSelect: () { + + })) + ) + ], + ), + ), + ), + const SizedBox( + height: 20, + ), ], ), ), @@ -131,14 +84,98 @@ class LinkSpaceModelSpacesDialog extends StatelessWidget { // Buttons Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - _buildButton("Cancel", Colors.grey, () { - Navigator.of(context).pop(); - }), - _buildButton("Confirm", Colors.blueAccent, () { - Navigator.of(context).pop(); - }), + Expanded( + child: Container( + height: 50, + decoration: const BoxDecoration( + border: Border( + right: BorderSide( + color: ColorsManager.grayColor, + width: 0.5, + ), + top: BorderSide( + color: ColorsManager.grayColor, + width: 1, + ), + ), + ), + child: _buildButton("Cancel", Colors.grey, () { + Navigator.of(context).pop(); + }), + ), + ), + Expanded( + child: Container( + height: 50, + decoration: const BoxDecoration( + border: Border( + left: BorderSide( + color: ColorsManager.grayColor, + width: 0.5, + ), + top: BorderSide( + color: ColorsManager.grayColor, + width: 1.0, + ), + ), + ), + child: _buildButton( + "Confirm", ColorsManager.onSecondaryColor, () { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20)), + elevation: 10, + backgroundColor: Colors.white, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 30, horizontal: 50), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + CustomLoadingIndicator(), + const SizedBox(height: 20), + const Text( + "Linking in progress", + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.black87, + ), + ), + ], + ), + ), + ); + }, + ).then( + (value) {}, + ); + Future.delayed(const Duration(seconds: 3), () { + Navigator.of(context).pop(); + Navigator.of(context).pop(); + + // showDialog( + // context: context, + // builder: (BuildContext dialogContext) { + // return const LinkingSuccessful(); + // }, + // ); + + showDialog( + context: context, + builder: (BuildContext dialogContext) { + return const ConfirmOverwriteDialog(); + }, + ); + }); + }), + ), + ), ], ), ], @@ -176,14 +213,10 @@ class LinkSpaceModelSpacesDialog extends StatelessWidget { Widget _buildButton(String text, Color color, VoidCallback onPressed) { return TextButton( onPressed: onPressed, - style: TextButton.styleFrom( - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), - backgroundColor: color.withOpacity(0.2), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - ), child: Text( text, - style: TextStyle(color: color, fontWeight: FontWeight.bold), + style: + TextStyle(color: color, fontWeight: FontWeight.w400, fontSize: 14), ), ); } diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/linking_attention_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/linking_attention_dialog.dart index a0807dba..15d92029 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/linking_attention_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/linking_attention_dialog.dart @@ -67,7 +67,6 @@ class LinkingAttentionDialog extends StatelessWidget { .textTheme .bodyMedium ?.copyWith(fontWeight: FontWeight.w400, fontSize: 16), - ), ), ), diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/linking_successful.dart b/lib/pages/spaces_management/space_model/widgets/dialog/linking_successful.dart new file mode 100644 index 00000000..6a228fc1 --- /dev/null +++ b/lib/pages/spaces_management/space_model/widgets/dialog/linking_successful.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; + +class LinkingSuccessful extends StatelessWidget { + const LinkingSuccessful({super.key}); + + @override + Widget build(BuildContext context) { + return AlertDialog( + backgroundColor: ColorsManager.whiteColors, + title: Center( + child: SvgPicture.asset( + Assets.successIcon, + )), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + 'Linking successful', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(fontWeight: FontWeight.w400, fontSize: 18), + ), + const SizedBox(height: 25), + ], + ), + ); + } +} diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart index 3d207968..8659b7b5 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; void showOverwriteDialog(BuildContext context) { showDialog( context: context, - barrierDismissible: false, // Prevent closing by tapping outside + barrierDismissible: false, builder: (BuildContext context) { return Container( child: Dialog( @@ -19,7 +19,7 @@ void showOverwriteDialog(BuildContext context) { mainAxisSize: MainAxisSize.min, children: [ // Title - Text( + const Text( "Overwrite", style: TextStyle( fontSize: 22, @@ -30,7 +30,7 @@ void showOverwriteDialog(BuildContext context) { SizedBox(height: 15), // Description - Text( + const Text( "Are you sure you want to overwrite?", style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), textAlign: TextAlign.center, @@ -70,7 +70,7 @@ void showOverwriteDialog(BuildContext context) { fontWeight: FontWeight.w500, ), ), - ), + ), ), SizedBox(width: 10), diff --git a/lib/services/space_mana_api.dart b/lib/services/space_mana_api.dart index 788b9455..c4877c98 100644 --- a/lib/services/space_mana_api.dart +++ b/lib/services/space_mana_api.dart @@ -281,7 +281,6 @@ class CommunitySpaceManagementApi { .replaceAll('{communityId}', communityId) .replaceAll('{projectId}', TempConst.projectId), expectedResponseModel: (json) { - print('json space=$json'); final spaceModels = (json['data'] as List) .map((spaceJson) => SpaceModel.fromJson(spaceJson)) .toList(); diff --git a/lib/utils/constants/assets.dart b/lib/utils/constants/assets.dart index e1b7658b..79efdaaf 100644 --- a/lib/utils/constants/assets.dart +++ b/lib/utils/constants/assets.dart @@ -405,5 +405,6 @@ class Assets { static const String deleteSpaceLinkIcon = 'assets/icons/delete_space_link_icon.svg'; static const String spaceLinkIcon = 'assets/icons/space_link_icon.svg'; + static const String successIcon = 'assets/icons/success_icon.svg'; + } -//space_link_icon.svg From 1054970a6307d33cb5d5eca0d4f21555534084be Mon Sep 17 00:00:00 2001 From: mohammad Date: Tue, 18 Feb 2025 16:34:29 +0300 Subject: [PATCH 3/8] validation LinkSpaceModelSpacesDialog --- .../bloc/link_space_model_bloc.dart | 60 ++++++++++++++++++- .../bloc/link_space_model_event.dart | 6 ++ .../dialog/confirm_overwrite_dialog.dart | 10 ++++ .../link_space_model_spaces_dialog.dart | 38 ++++++++---- .../widgets/space_model_card_widget.dart | 11 +++- 5 files changed, 108 insertions(+), 17 deletions(-) diff --git a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart b/lib/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart index aa9a446d..4018ae60 100644 --- a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart +++ b/lib/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart @@ -1,12 +1,68 @@ +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/spaces_management/link_space_model/bloc/link_space_model_event.dart'; import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart'; - +import 'package:syncrow_web/utils/navigation_service.dart'; class SpaceModelBloc extends Bloc { SpaceModelBloc() : super(SpaceModelInitial()) { + on(_getSpaceIds); on((event, emit) { emit(SpaceModelSelectedState(event.selectedIndex)); }); } -} \ No newline at end of file + + // Future getSpaceIds( + // SpaceModelSelectedIdsEvent event, Emitter emit) async { + // try { + // BuildContext context = NavigationService.navigatorKey.currentContext!; + // var spaceBloc = context.read(); + // for (var communityId in spaceBloc.state.selectedCommunities) { + // List spacesList = + // spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; + // for (var spaceId in spacesList) { + // print('spaceId===$spaceId'); + // } + // } + // } catch (e) { + // print('Error fetching space IDs: $e'); + // } + // } + + bool hasSelectedSpaces = false; + + Future _getSpaceIds( + SpaceModelSelectedIdsEvent event, Emitter emit) async { + try { + BuildContext context = NavigationService.navigatorKey.currentContext!; + var spaceBloc = context.read(); + for (var communityId in spaceBloc.state.selectedCommunities) { + List spacesList = + spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; + for (var spaceId in spacesList) { + print('spaceId===$spaceId'); + } + } + // Check if any community has selected spaces + hasSelectedSpaces = + spaceBloc.state.selectedCommunities.any((communityId) { + List spacesList = + spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; + return spacesList.isNotEmpty; + }); + + // Optionally, you could emit a state here if you want to rebuild the UI + // emit(SpaceModelSelectionUpdatedState(hasSelectedSpaces)); + + // Debug output + if (hasSelectedSpaces) { + print("At least one space is selected."); + } else { + print("No spaces selected."); + } + } catch (e) { + print("Error in _getSpaceIds: $e"); + } + } +} diff --git a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart b/lib/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart index 8bff0202..87b1e368 100644 --- a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart +++ b/lib/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart @@ -5,3 +5,9 @@ class SpaceModelSelectedEvent extends SpaceModelEvent { SpaceModelSelectedEvent(this.selectedIndex); } + + + +class SpaceModelSelectedIdsEvent extends SpaceModelEvent { + +} diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart index ba1d261d..0497b570 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/confirm_overwrite_dialog.dart @@ -28,6 +28,16 @@ class ConfirmOverwriteDialog extends StatelessWidget { .bodyMedium ?.copyWith(fontWeight: FontWeight.w400, fontSize: 18), ), + Center( + child: Text( + 'Selected spaces already have linked space \nmodel / sub-spaces and devices', + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w400, + fontSize: 14, + color: ColorsManager.grayColor), + textAlign: TextAlign.center, + ), + ), const SizedBox(height: 25), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart index abcbedd8..d6482a05 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart @@ -1,5 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.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/confirm_overwrite_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart'; @@ -42,8 +45,7 @@ class LinkSpaceModelSpacesDialog extends StatelessWidget { ), const Divider(), const SizedBox(height: 16), - _buildDetailRow("Space model name:", - spaceModel.modelName), + _buildDetailRow("Space model name:", spaceModel.modelName), _buildDetailRow("Creation date and time:", spaceModel.createdAt.toString()), _buildDetailRow("Created by:", "Admin"), @@ -66,10 +68,11 @@ class LinkSpaceModelSpacesDialog extends StatelessWidget { child: Container( color: ColorsManager.whiteColors, child: SpaceTreeView( - isSide: true, onSelect: () { - - })) - ) + isSide: true, + onSelect: () { + context.read().add( + SpaceModelSelectedIdsEvent()); + }))) ], ), ), @@ -122,6 +125,15 @@ class LinkSpaceModelSpacesDialog extends StatelessWidget { ), child: _buildButton( "Confirm", ColorsManager.onSecondaryColor, () { + final spaceModelBloc = context.read(); + if (!spaceModelBloc.hasSelectedSpaces) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: + Text("Please select at least one space")), + ); + return; + } showDialog( context: context, barrierDismissible: false, @@ -211,12 +223,14 @@ class LinkSpaceModelSpacesDialog extends StatelessWidget { // Button Widget Widget _buildButton(String text, Color color, VoidCallback onPressed) { - return TextButton( - onPressed: onPressed, - child: Text( - text, - style: - TextStyle(color: color, fontWeight: FontWeight.w400, fontSize: 14), + return InkWell( + onTap: onPressed, + child: Center( + child: Text( + text, + style: TextStyle( + color: color, fontWeight: FontWeight.w400, fontSize: 14), + ), ), ); } 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 52b0fa6c..6ae786be 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 @@ -1,5 +1,7 @@ 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/link_space_model/bloc/link_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/link_space_model_spaces_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/linking_attention_dialog.dart'; @@ -73,9 +75,12 @@ class SpaceModelCardWidget extends StatelessWidget { onTap: () { showDialog( context: context, - builder: (BuildContext dialogContext) { - return LinkSpaceModelSpacesDialog( - spaceModel: model, + builder: (context) { + return BlocProvider( + create: (_) => SpaceModelBloc(), + child: LinkSpaceModelSpacesDialog( + spaceModel: model, + ), ); }, ); From b1348235514492fc2cd99c3c81879469ec12b8ff Mon Sep 17 00:00:00 2001 From: mohammad Date: Tue, 18 Feb 2025 16:56:10 +0300 Subject: [PATCH 4/8] SpaceModelSelectedIds --- .../link_space_model_spaces_dialog.dart | 20 ++++++++++++++++--- .../widgets/space_model_card_widget.dart | 2 ++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart index d6482a05..668fee60 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart @@ -8,12 +8,25 @@ import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/c import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart'; import 'package:syncrow_web/utils/color_manager.dart'; -class LinkSpaceModelSpacesDialog extends StatelessWidget { +class LinkSpaceModelSpacesDialog extends StatefulWidget { final SpaceTemplateModel spaceModel; LinkSpaceModelSpacesDialog({super.key, required this.spaceModel}); + @override + State createState() => + _LinkSpaceModelSpacesDialogState(); +} + +class _LinkSpaceModelSpacesDialogState + extends State { TextEditingController searchController = TextEditingController(); + @override + void initState() { + context.read().add(SpaceModelSelectedIdsEvent()); + super.initState(); + } + @override Widget build(BuildContext context) { return AlertDialog( @@ -45,9 +58,10 @@ class LinkSpaceModelSpacesDialog extends StatelessWidget { ), const Divider(), const SizedBox(height: 16), - _buildDetailRow("Space model name:", spaceModel.modelName), + _buildDetailRow( + "Space model name:", widget.spaceModel.modelName), _buildDetailRow("Creation date and time:", - spaceModel.createdAt.toString()), + widget.spaceModel.createdAt.toString()), _buildDetailRow("Created by:", "Admin"), const SizedBox(height: 12), const Text( 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 6ae786be..c7d9c72f 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 @@ -2,6 +2,7 @@ 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/link_space_model/bloc/link_space_model_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.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/link_space_model_spaces_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/linking_attention_dialog.dart'; @@ -73,6 +74,7 @@ class SpaceModelCardWidget extends StatelessWidget { children: [ InkWell( onTap: () { + showDialog( context: context, builder: (context) { From 215dd9cfa4576c535af8af5e7422af94e182b335 Mon Sep 17 00:00:00 2001 From: mohammad Date: Wed, 5 Mar 2025 14:37:52 +0300 Subject: [PATCH 5/8] link space model api integration --- .../bloc/link_space_model_bloc.dart | 84 ++- .../bloc/link_space_model_event.dart | 15 +- .../bloc/link_space_model_state.dart | 32 +- .../link_space_model_spaces_dialog.dart | 660 ++++++++++++------ .../widgets/dialog/overwrite_dialog.dart | 42 +- .../widgets/space_model_card_widget.dart | 94 ++- lib/services/space_model_mang_api.dart | 36 + lib/utils/constants/api_const.dart | 68 +- 8 files changed, 758 insertions(+), 273 deletions(-) diff --git a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart b/lib/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart index 4018ae60..cb9f5d43 100644 --- a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart +++ b/lib/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart @@ -1,36 +1,26 @@ +import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/common/bloc/project_manager.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart'; import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart'; +import 'package:syncrow_web/services/space_model_mang_api.dart'; import 'package:syncrow_web/utils/navigation_service.dart'; class SpaceModelBloc extends Bloc { SpaceModelBloc() : super(SpaceModelInitial()) { on(_getSpaceIds); + on(_handleLinkSpaceModel); + on(_validateLinkSpaceModel); on((event, emit) { emit(SpaceModelSelectedState(event.selectedIndex)); }); } - // Future getSpaceIds( - // SpaceModelSelectedIdsEvent event, Emitter emit) async { - // try { - // BuildContext context = NavigationService.navigatorKey.currentContext!; - // var spaceBloc = context.read(); - // for (var communityId in spaceBloc.state.selectedCommunities) { - // List spacesList = - // spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; - // for (var spaceId in spacesList) { - // print('spaceId===$spaceId'); - // } - // } - // } catch (e) { - // print('Error fetching space IDs: $e'); - // } - // } - + List spacesListIds = []; bool hasSelectedSpaces = false; + String validate = ''; Future _getSpaceIds( SpaceModelSelectedIdsEvent event, Emitter emit) async { @@ -40,22 +30,17 @@ class SpaceModelBloc extends Bloc { for (var communityId in spaceBloc.state.selectedCommunities) { List spacesList = spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; + spacesListIds = spacesList; for (var spaceId in spacesList) { print('spaceId===$spaceId'); } } - // Check if any community has selected spaces hasSelectedSpaces = spaceBloc.state.selectedCommunities.any((communityId) { List spacesList = spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; return spacesList.isNotEmpty; }); - - // Optionally, you could emit a state here if you want to rebuild the UI - // emit(SpaceModelSelectionUpdatedState(hasSelectedSpaces)); - - // Debug output if (hasSelectedSpaces) { print("At least one space is selected."); } else { @@ -65,4 +50,57 @@ class SpaceModelBloc extends Bloc { print("Error in _getSpaceIds: $e"); } } + + Future _handleLinkSpaceModel( + LinkSpaceModelEvent event, + Emitter emit, + ) async { + emit(SpaceModelLoading()); + try { + final projectUuid = await ProjectManager.getProjectUUID() ?? ''; + await SpaceModelManagementApi().linkSpaceModel( + spaceModelUuid: event.selectedSpaceMode!, + projectId: projectUuid, + spaceUuids: spacesListIds, + isOverWrite: event.isOverWrite); + emit(SpaceModelLinkSuccess()); + } on DioException catch (e) { + final errorMessage = _parseDioError(e); + emit(SpaceModelOperationFailure(errorMessage)); + } catch (e) { + emit(SpaceModelOperationFailure('Unexpected error: $e')); + } + } + + Future _validateLinkSpaceModel( + ValidateSpaceModelEvent event, + Emitter emit, + ) async { + emit(SpaceModelLoading()); + try { + final projectUuid = await ProjectManager.getProjectUUID() ?? ''; + await SpaceModelManagementApi().validateSpaceModel( + projectUuid, + spacesListIds, + ); + emit(SpaceValidationSuccess()); + } on DioException catch (e) { + final errorMessage = _parseDioError(e); + if (errorMessage == + 'Selected spaces already have linked space model / sub-spaces and devices') { + emit(const AlreadyHaveLinkedState()); + } else { + emit(SpaceModelOperationFailure(errorMessage)); + } + } catch (e) { + emit(SpaceModelOperationFailure('Unexpected error: $e')); + } + } + + String _parseDioError(DioException e) { + if (e.response?.data is Map) { + return e.response!.data['error']['message'] ?? 'Unknown error occurred'; + } + return e.message ?? 'Network request failed'; + } } diff --git a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart b/lib/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart index 87b1e368..1595e695 100644 --- a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart +++ b/lib/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart @@ -1,3 +1,5 @@ +import 'package:flutter/material.dart'; + abstract class SpaceModelEvent {} class SpaceModelSelectedEvent extends SpaceModelEvent { @@ -6,8 +8,15 @@ class SpaceModelSelectedEvent extends SpaceModelEvent { SpaceModelSelectedEvent(this.selectedIndex); } +class SpaceModelSelectedIdsEvent extends SpaceModelEvent {} - -class SpaceModelSelectedIdsEvent extends SpaceModelEvent { - +class LinkSpaceModelEvent extends SpaceModelEvent { + final String? selectedSpaceMode; + final bool isOverWrite; + LinkSpaceModelEvent({this.selectedSpaceMode, this.isOverWrite = false}); +} + +class ValidateSpaceModelEvent extends SpaceModelEvent { + BuildContext? context; + ValidateSpaceModelEvent({this.context}); } diff --git a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart b/lib/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart index cc745e4d..b7cb7c3f 100644 --- a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart +++ b/lib/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart @@ -1,9 +1,35 @@ -abstract class SpaceModelState {} +abstract class SpaceModelState { + const SpaceModelState(); +} class SpaceModelInitial extends SpaceModelState {} +class SpaceModelLoading extends SpaceModelState {} + class SpaceModelSelectedState extends SpaceModelState { final int selectedIndex; - - SpaceModelSelectedState(this.selectedIndex); + const SpaceModelSelectedState(this.selectedIndex); +} + +class SpaceModelSelectionUpdated extends SpaceModelState { + final bool hasSelectedSpaces; + const SpaceModelSelectionUpdated(this.hasSelectedSpaces); +} + +class SpaceValidationSuccess extends SpaceModelState {} + +class SpaceModelLinkSuccess extends SpaceModelState {} + +class ValidationError extends SpaceModelState { + final String message; + const ValidationError(this.message); +} + +class SpaceModelOperationFailure extends SpaceModelState { + final String message; + const SpaceModelOperationFailure(this.message); +} + +class AlreadyHaveLinkedState extends SpaceModelState { + const AlreadyHaveLinkedState(); } diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart index 668fee60..844513d3 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart @@ -1,16 +1,241 @@ +// import 'package:flutter/material.dart'; +// import 'package:flutter_bloc/flutter_bloc.dart'; +// import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart'; +// import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart'; +// import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.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/confirm_overwrite_dialog.dart'; +// import 'package:syncrow_web/utils/color_manager.dart'; + +// class LinkSpaceModelSpacesDialog extends StatefulWidget { +// final SpaceTemplateModel spaceModel; +// LinkSpaceModelSpacesDialog({super.key, required this.spaceModel}); + +// @override +// State createState() => +// _LinkSpaceModelSpacesDialogState(); +// } + +// class _LinkSpaceModelSpacesDialogState +// extends State { +// TextEditingController searchController = TextEditingController(); + +// @override +// void initState() { +// context.read().add(SpaceModelSelectedIdsEvent()); +// super.initState(); +// } + +// @override +// Widget build(BuildContext context) { +// return AlertDialog( +// contentPadding: EdgeInsets.zero, +// shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), +// backgroundColor: Colors.white, +// content: SizedBox( +// width: MediaQuery.of(context).size.width * 0.4, +// child: Column( +// mainAxisSize: MainAxisSize.min, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// Expanded( +// child: Padding( +// padding: const EdgeInsets.all(15.0), +// child: Column( +// mainAxisSize: MainAxisSize.min, +// crossAxisAlignment: CrossAxisAlignment.start, +// children: [ +// const Center( +// child: Text( +// "Link Space Model to Spaces", +// style: TextStyle( +// fontSize: 18, +// fontWeight: FontWeight.bold, +// color: Colors.blueAccent, +// ), +// ), +// ), +// const Divider(), +// const SizedBox(height: 16), +// _buildDetailRow( +// "Space model name:", widget.spaceModel.modelName), +// _buildDetailRow("Creation date and time:", +// widget.spaceModel.createdAt.toString()), +// _buildDetailRow("Created by:", "Admin"), +// const SizedBox(height: 12), +// const Text( +// "Link to:", +// style: TextStyle(fontWeight: FontWeight.bold), +// ), +// const Text( +// "Please select all the spaces where you would like to link the Routine.", +// style: TextStyle(fontSize: 12, color: Colors.grey), +// ), +// const SizedBox(height: 8), +// Expanded( +// child: SizedBox( +// child: Column( +// children: [ +// Expanded( +// flex: 7, +// child: Container( +// color: ColorsManager.whiteColors, +// child: SpaceTreeView( +// isSide: true, +// onSelect: () { +// context.read().add( +// SpaceModelSelectedIdsEvent()); +// }))) +// ], +// ), +// ), +// ), +// const SizedBox( +// height: 20, +// ), +// ], +// ), +// ), +// ), + +// // Buttons +// Row( +// children: [ +// Expanded( +// child: Container( +// height: 50, +// decoration: const BoxDecoration( +// border: Border( +// right: BorderSide( +// color: ColorsManager.grayColor, +// width: 0.5, +// ), +// top: BorderSide( +// color: ColorsManager.grayColor, +// width: 1, +// ), +// ), +// ), +// child: _buildButton("Cancel", Colors.grey, () { +// Navigator.of(context).pop(); +// }), +// ), +// ), +// Expanded( +// child: Container( +// height: 50, +// decoration: const BoxDecoration( +// border: Border( +// left: BorderSide( +// color: ColorsManager.grayColor, +// width: 0.5, +// ), +// top: BorderSide( +// color: ColorsManager.grayColor, +// width: 1.0, +// ), +// ), +// ), +// child: _buildButton( +// "Confirm", ColorsManager.onSecondaryColor, () { +// final spaceModelBloc = context.read(); +// if (!spaceModelBloc.hasSelectedSpaces) { +// ScaffoldMessenger.of(context).showSnackBar( +// const SnackBar( +// content: +// Text("Please select at least one space")), +// ); +// return; +// } else { +// // spaceModelBloc.add(LinkSpaceModelEvent( +// // selectedSpaceMode: widget.spaceModel.uuid)); + +// spaceModelBloc.add(ValidateSpaceModelEvent(context: context)); +// } + +// Future.delayed(const Duration(seconds: 3), () { +// Navigator.of(context).pop(); +// Navigator.of(context).pop(); + +// // showDialog( +// // context: context, +// // builder: (BuildContext dialogContext) { +// // return const LinkingSuccessful(); +// // }, +// // ); + +// showDialog( +// context: context, +// builder: (BuildContext dialogContext) { +// return const ConfirmOverwriteDialog(); +// }, +// ); +// }); +// }), +// ), +// ), +// ], +// ), +// ], +// ), +// ), +// ); +// } + +// // Method to build a detail row +// Widget _buildDetailRow(String label, String value) { +// return Padding( +// padding: const EdgeInsets.symmetric(vertical: 4), +// child: Row( +// children: [ +// Expanded( +// child: Text( +// label, +// style: TextStyle(fontWeight: FontWeight.bold), +// ), +// ), +// const SizedBox(width: 8), +// Expanded( +// child: Text( +// value, +// style: +// TextStyle(fontWeight: FontWeight.bold, color: Colors.black), +// ), +// ), +// ], +// ), +// ); +// } + +// Widget _buildButton(String text, Color color, VoidCallback onPressed) { +// return InkWell( +// onTap: onPressed, +// child: Center( +// child: Text( +// text, +// style: TextStyle( +// color: color, fontWeight: FontWeight.w400, fontSize: 14), +// ), +// ), +// ); +// } +// } + import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart'; import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_state.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/confirm_overwrite_dialog.dart'; -import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/custom_loading_dialog.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart'; import 'package:syncrow_web/utils/color_manager.dart'; class LinkSpaceModelSpacesDialog extends StatefulWidget { final SpaceTemplateModel spaceModel; - LinkSpaceModelSpacesDialog({super.key, required this.spaceModel}); + + const LinkSpaceModelSpacesDialog({super.key, required this.spaceModel}); @override State createState() => @@ -19,7 +244,8 @@ class LinkSpaceModelSpacesDialog extends StatefulWidget { class _LinkSpaceModelSpacesDialogState extends State { - TextEditingController searchController = TextEditingController(); + final TextEditingController _searchController = TextEditingController(); + bool _isLoading = false; @override void initState() { @@ -39,213 +265,253 @@ class _LinkSpaceModelSpacesDialogState mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded( - child: Padding( - padding: const EdgeInsets.all(15.0), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Center( - child: Text( - "Link Space Model to Spaces", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.blueAccent, - ), - ), - ), - const Divider(), - const SizedBox(height: 16), - _buildDetailRow( - "Space model name:", widget.spaceModel.modelName), - _buildDetailRow("Creation date and time:", - widget.spaceModel.createdAt.toString()), - _buildDetailRow("Created by:", "Admin"), - const SizedBox(height: 12), - const Text( - "Link to:", - style: TextStyle(fontWeight: FontWeight.bold), - ), - const Text( - "Please select all the spaces where you would like to link the Routine.", - style: TextStyle(fontSize: 12, color: Colors.grey), - ), - const SizedBox(height: 8), - Expanded( - child: SizedBox( - child: Column( - children: [ - Expanded( - flex: 7, - child: Container( - color: ColorsManager.whiteColors, - child: SpaceTreeView( - isSide: true, - onSelect: () { - context.read().add( - SpaceModelSelectedIdsEvent()); - }))) - ], - ), - ), - ), - const SizedBox( - height: 20, - ), - ], - ), - ), - ), - - // Buttons - Row( - children: [ - Expanded( - child: Container( - height: 50, - decoration: const BoxDecoration( - border: Border( - right: BorderSide( - color: ColorsManager.grayColor, - width: 0.5, - ), - top: BorderSide( - color: ColorsManager.grayColor, - width: 1, - ), - ), - ), - child: _buildButton("Cancel", Colors.grey, () { - Navigator.of(context).pop(); - }), - ), - ), - Expanded( - child: Container( - height: 50, - decoration: const BoxDecoration( - border: Border( - left: BorderSide( - color: ColorsManager.grayColor, - width: 0.5, - ), - top: BorderSide( - color: ColorsManager.grayColor, - width: 1.0, - ), - ), - ), - child: _buildButton( - "Confirm", ColorsManager.onSecondaryColor, () { - final spaceModelBloc = context.read(); - if (!spaceModelBloc.hasSelectedSpaces) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text("Please select at least one space")), - ); - return; - } - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(20)), - elevation: 10, - backgroundColor: Colors.white, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 30, horizontal: 50), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - CustomLoadingIndicator(), - const SizedBox(height: 20), - const Text( - "Linking in progress", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Colors.black87, - ), - ), - ], - ), - ), - ); - }, - ).then( - (value) {}, - ); - Future.delayed(const Duration(seconds: 3), () { - Navigator.of(context).pop(); - Navigator.of(context).pop(); - - // showDialog( - // context: context, - // builder: (BuildContext dialogContext) { - // return const LinkingSuccessful(); - // }, - // ); - - showDialog( - context: context, - builder: (BuildContext dialogContext) { - return const ConfirmOverwriteDialog(); - }, - ); - }); - }), - ), - ), - ], - ), + _buildDialogContent(), + _buildActionButtons(), ], ), ), ); } - // Method to build a detail row - Widget _buildDetailRow(String label, String value) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 4), - child: Row( - children: [ - Expanded( - child: Text( - label, - style: TextStyle(fontWeight: FontWeight.bold), - ), + Widget _buildDialogContent() { + return Expanded( + child: Padding( + padding: const EdgeInsets.all(15.0), + child: SizedBox( + width: MediaQuery.of(context).size.width * 0.4, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(15.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Center( + child: Text( + "Link Space Model to Spaces", + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.blueAccent, + ), + ), + ), + const Divider(), + const SizedBox(height: 16), + _buildDetailRow( + "Space model name:", widget.spaceModel.modelName), + _buildDetailRow("Creation date and time:", + widget.spaceModel.createdAt.toString()), + _buildDetailRow("Created by:", "Admin"), + const SizedBox(height: 12), + const Text( + "Link to:", + style: TextStyle(fontWeight: FontWeight.bold), + ), + const Text( + "Please select all the spaces where you would like to link the Routine.", + style: TextStyle(fontSize: 12, color: Colors.grey), + ), + const SizedBox(height: 8), + Expanded( + child: SizedBox( + child: Column( + children: [ + Expanded( + flex: 7, + child: Container( + color: ColorsManager.whiteColors, + child: SpaceTreeView( + isSide: true, + onSelect: () { + context.read().add( + SpaceModelSelectedIdsEvent()); + }))) + ], + ), + ), + ), + const SizedBox( + height: 20, + ), + ], + ), + ), + ), + ], ), - const SizedBox(width: 8), - Expanded( - child: Text( - value, - style: - TextStyle(fontWeight: FontWeight.bold, color: Colors.black), - ), - ), - ], + ), ), ); } - // Button Widget - Widget _buildButton(String text, Color color, VoidCallback onPressed) { - return InkWell( - onTap: onPressed, - child: Center( - child: Text( - text, - style: TextStyle( - color: color, fontWeight: FontWeight.w400, fontSize: 14), + Widget _buildActionButtons() { + return Row( + children: [ + Expanded( + child: Container( + height: 50, + decoration: const BoxDecoration( + border: Border( + right: BorderSide( + color: ColorsManager.grayColor, + width: 0.5, + ), + top: BorderSide( + color: ColorsManager.grayColor, + width: 1, + ), + ), + ), + child: _buildButton("Cancel", Colors.grey, () { + Navigator.of(context).pop(); + }), + ), + ), + Expanded( + child: Container( + height: 50, + decoration: const BoxDecoration( + border: Border( + left: BorderSide( + color: ColorsManager.grayColor, + width: 0.5, + ), + top: BorderSide( + color: ColorsManager.grayColor, + width: 1.0, + ), + ), + ), + child: _buildButton( + "Confirm", + ColorsManager.onSecondaryColor, + () { + final spaceModelBloc = context.read(); + if (!spaceModelBloc.hasSelectedSpaces) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text("Please select at least one space")), + ); + return; + } else { + spaceModelBloc.add(ValidateSpaceModelEvent(context: context)); + } + }, + ), + ), + ), + ], + ); + } + + void _handleConfirm() { + final bloc = context.read(); + if (!bloc.hasSelectedSpaces) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text("Please select at least one space")), + ); + return; + } + + // Trigger validation + bloc.add(ValidateSpaceModelEvent()); + } + + void _showLoadingDialog() { + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => const _LoadingDialog(), + ); + } + + void _handleValidationSuccess() { + Navigator.of(context).pop(); // Close loading dialog + + // Show overwrite confirmation + showDialog( + context: context, + builder: (context) => const ConfirmOverwriteDialog(), + ).then((_) { + // Close main dialog after confirmation + if (mounted) Navigator.of(context).pop(); + }); + } + + void _handleValidationError(String message) { + Navigator.of(context).pop(); // Close loading dialog + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(message)), + ); + } + + void _handleCancel() { + if (mounted) Navigator.of(context).pop(); + } + + // Rest of your helper methods (_buildDetailRow, _buildButton, etc.) +} + +class _LoadingDialog extends StatelessWidget { + const _LoadingDialog(); + + @override + Widget build(BuildContext context) { + return Dialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), + child: const Padding( + padding: EdgeInsets.all(20.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + CircularProgressIndicator(), + SizedBox(height: 16), + Text("Linking in progress..."), + ], ), ), ); } } + +// Method to build a detail row +Widget _buildDetailRow(String label, String value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Row( + children: [ + Expanded( + child: Text( + label, + style: TextStyle(fontWeight: FontWeight.bold), + ), + ), + const SizedBox(width: 8), + Expanded( + child: Text( + value, + style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black), + ), + ), + ], + ), + ); +} + +Widget _buildButton(String text, Color color, VoidCallback onPressed) { + return InkWell( + onTap: onPressed, + child: Center( + child: Text( + text, + style: + TextStyle(color: color, fontWeight: FontWeight.w400, fontSize: 14), + ), + ), + ); +} diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart index 8659b7b5..6a34002f 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart @@ -1,24 +1,27 @@ import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart'; -void showOverwriteDialog(BuildContext context) { +void showOverwriteDialog( + BuildContext context, SpaceModelBloc bloc, SpaceTemplateModel model) { showDialog( context: context, - barrierDismissible: false, + barrierDismissible: false, builder: (BuildContext context) { - return Container( + return SizedBox( child: Dialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), elevation: 10, backgroundColor: Colors.white, - child: Container( + child: SizedBox( width: MediaQuery.of(context).size.width * 0.3, child: Padding( - padding: EdgeInsets.symmetric(vertical: 30, horizontal: 20), + padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20), child: Column( mainAxisSize: MainAxisSize.min, children: [ - // Title const Text( "Overwrite", style: TextStyle( @@ -27,15 +30,13 @@ void showOverwriteDialog(BuildContext context) { color: Colors.black, ), ), - SizedBox(height: 15), - - // Description + const SizedBox(height: 15), const Text( "Are you sure you want to overwrite?", style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), textAlign: TextAlign.center, ), - SizedBox(height: 5), + const SizedBox(height: 5), Text( "Selected spaces already have linked space model / sub-spaces and devices", style: TextStyle( @@ -44,25 +45,22 @@ void showOverwriteDialog(BuildContext context) { ), textAlign: TextAlign.center, ), - SizedBox(height: 25), - - // Buttons + const SizedBox(height: 25), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - // Cancel Button Expanded( child: ElevatedButton( onPressed: () => Navigator.of(context).pop(), style: ElevatedButton.styleFrom( - padding: EdgeInsets.symmetric(vertical: 14), + padding: const EdgeInsets.symmetric(vertical: 14), backgroundColor: Colors.grey[200], shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), elevation: 0, ), - child: Text( + child: const Text( "Cancel", style: TextStyle( fontSize: 16, @@ -72,24 +70,24 @@ void showOverwriteDialog(BuildContext context) { ), ), ), - SizedBox(width: 10), - - // OK Button + const SizedBox(width: 10), Expanded( child: ElevatedButton( onPressed: () { + bloc.add(LinkSpaceModelEvent( + isOverWrite: true, + selectedSpaceMode: model.uuid)); Navigator.of(context).pop(); - // Add action for OK button }, style: ElevatedButton.styleFrom( - padding: EdgeInsets.symmetric(vertical: 14), + padding: const EdgeInsets.symmetric(vertical: 14), backgroundColor: Colors.blue, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), elevation: 3, ), - child: Text( + child: const Text( "OK", style: TextStyle( fontSize: 16, 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 c7d9c72f..56ba5d3b 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 @@ -3,9 +3,13 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_state.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/custom_loading_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/linking_attention_dialog.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/linking_successful.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_product_widget.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dynamic_room_widget.dart'; import 'package:syncrow_web/utils/color_manager.dart'; @@ -74,14 +78,96 @@ class SpaceModelCardWidget extends StatelessWidget { children: [ InkWell( onTap: () { - showDialog( context: context, - builder: (context) { + builder: (BuildContext dialogContext) { return BlocProvider( create: (_) => SpaceModelBloc(), - child: LinkSpaceModelSpacesDialog( - spaceModel: model, + child: BlocListener( + listener: (context, state) { + final _bloc = + BlocProvider.of( + context); + if (state is SpaceModelLoading) { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(20)), + elevation: 10, + backgroundColor: Colors.white, + child: Padding( + padding: + const EdgeInsets.symmetric( + vertical: 30, + horizontal: 50), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + CustomLoadingIndicator(), + const SizedBox(height: 20), + const Text( + "Linking in progress", + style: TextStyle( + fontSize: 16, + fontWeight: + FontWeight.w500, + color: Colors.black87, + ), + ), + ], + ), + ), + ); + }, + ); + } else if (state + is AlreadyHaveLinkedState) { + Navigator.of(dialogContext).pop(); + showOverwriteDialog( + context, _bloc, model); + } else if (state + is SpaceValidationSuccess) { + _bloc.add(LinkSpaceModelEvent( + isOverWrite: false, + selectedSpaceMode: model.uuid)); + + Future.delayed(const Duration(seconds: 1), + () { + Navigator.of(dialogContext).pop(); + Navigator.of(dialogContext).pop(); + Navigator.of(dialogContext).pop(); + }); + + showDialog( + context: context, + builder: (BuildContext dialogContext) { + return const LinkingSuccessful(); + }, + ).then((v) { + Future.delayed( + const Duration(seconds: 2), () { + Navigator.of(dialogContext).pop(); + }); + }); + } else if (state is SpaceModelLinkSuccess) { + Navigator.of(dialogContext).pop(); + Navigator.of(dialogContext).pop(); + showDialog( + context: context, + builder: (BuildContext dialogContext) { + return const LinkingSuccessful(); + }, + ); + } + }, + child: LinkSpaceModelSpacesDialog( + spaceModel: model, + ), ), ); }, diff --git a/lib/services/space_model_mang_api.dart b/lib/services/space_model_mang_api.dart index d9e295e0..4af8caa9 100644 --- a/lib/services/space_model_mang_api.dart +++ b/lib/services/space_model_mang_api.dart @@ -60,4 +60,40 @@ class SpaceModelManagementApi { ); return response; } + + Future linkSpaceModel( + {required String spaceModelUuid, + required String projectId, + required List spaceUuids, + required bool isOverWrite}) async { + print(spaceModelUuid); + print(projectId); + print(spaceUuids); + print(isOverWrite); + + final response = await HTTPService().post( + path: ApiEndpoints.linkSpaceModel + .replaceAll('{projectId}', projectId) + .replaceAll('{spaceModelUuid}', spaceModelUuid), + showServerMessage: true, + body: {"spaceUuids": spaceUuids, "overwrite": isOverWrite}, + expectedResponseModel: (json) { + return json; + }, + ); + return response; + } + + Future validateSpaceModel(String projectId, List spaceUuids) async { + final response = await HTTPService().post( + path: + ApiEndpoints.validateSpaceModel.replaceAll('{projectId}', projectId), + showServerMessage: true, + body: {"spacesUuids": spaceUuids}, + expectedResponseModel: (json) { + return json; + }, + ); + return response; + } } diff --git a/lib/utils/constants/api_const.dart b/lib/utils/constants/api_const.dart index 72a2b778..d3cd6001 100644 --- a/lib/utils/constants/api_const.dart +++ b/lib/utils/constants/api_const.dart @@ -9,15 +9,19 @@ abstract class ApiEndpoints { static const String sendOtp = '/authentication/user/send-otp'; static const String verifyOtp = '/authentication/user/verify-otp'; static const String getRegion = '/region'; - static const String visitorPassword = '/projects/{projectId}/visitor-password'; - static const String getDevices = '/projects/{projectId}/visitor-password/devices'; + static const String visitorPassword = + '/projects/{projectId}/visitor-password'; + static const String getDevices = + '/projects/{projectId}/visitor-password/devices'; - static const String sendOnlineOneTime = '/visitor-password/temporary-password/online/one-time'; + static const String sendOnlineOneTime = + '/visitor-password/temporary-password/online/one-time'; static const String sendOnlineMultipleTime = '/visitor-password/temporary-password/online/multiple-time'; //offline Password - static const String sendOffLineOneTime = '/visitor-password/temporary-password/offline/one-time'; + static const String sendOffLineOneTime = + '/visitor-password/temporary-password/offline/one-time'; static const String sendOffLineMultipleTime = '/visitor-password/temporary-password/offline/multiple-time'; @@ -39,32 +43,45 @@ abstract class ApiEndpoints { static const String getDeviceLogs = '/device/report-logs/{uuid}?code={code}'; // Space Module - static const String createSpace = '/projects/{projectId}/communities/{communityId}/spaces'; - static const String listSpaces = '/projects/{projectId}/communities/{communityId}/spaces'; + static const String createSpace = + '/projects/{projectId}/communities/{communityId}/spaces'; + static const String listSpaces = + '/projects/{projectId}/communities/{communityId}/spaces'; static const String deleteSpace = '/projects/{projectId}/communities/{communityId}/spaces/{spaceId}'; static const String updateSpace = '/projects/{projectId}/communities/{communityId}/spaces/{spaceId}'; - static const String getSpace = '/projects/{projectId}/communities/{communityId}/spaces/{spaceId}'; - static const String getSpaceHierarchy = '/projects/{projectId}/communities/{communityId}/spaces'; + static const String getSpace = + '/projects/{projectId}/communities/{communityId}/spaces/{spaceId}'; + static const String getSpaceHierarchy = + '/projects/{projectId}/communities/{communityId}/spaces'; // Community Module static const String createCommunity = '/projects/{projectId}/communities'; static const String getCommunityList = '/projects/{projectId}/communities'; - static const String getCommunityById = '/projects/{projectId}/communities/{communityId}'; - static const String updateCommunity = '/projects/{projectId}/communities/{communityId}'; - static const String deleteCommunity = '/projects/{projectId}communities/{communityId}'; - static const String getUserCommunities = '/projects/{projectId}/communities/user/{userUuid}'; - static const String createUserCommunity = '/projects/{projectId}/communities/user'; + static const String getCommunityById = + '/projects/{projectId}/communities/{communityId}'; + static const String updateCommunity = + '/projects/{projectId}/communities/{communityId}'; + static const String deleteCommunity = + '/projects/{projectId}communities/{communityId}'; + static const String getUserCommunities = + '/projects/{projectId}/communities/user/{userUuid}'; + static const String createUserCommunity = + '/projects/{projectId}/communities/user'; static const String getDeviceLogsByDate = '/device/report-logs/{uuid}?code={code}&startTime={startTime}&endTime={endTime}'; static const String scheduleByDeviceId = '/schedule/{deviceUuid}'; - static const String getScheduleByDeviceId = '/schedule/{deviceUuid}?category={category}'; - static const String deleteScheduleByDeviceId = '/schedule/{deviceUuid}/{scheduleUuid}'; - static const String updateScheduleByDeviceId = '/schedule/enable/{deviceUuid}'; + static const String getScheduleByDeviceId = + '/schedule/{deviceUuid}?category={category}'; + static const String deleteScheduleByDeviceId = + '/schedule/{deviceUuid}/{scheduleUuid}'; + static const String updateScheduleByDeviceId = + '/schedule/enable/{deviceUuid}'; static const String factoryReset = '/device/factory/reset/{deviceUuid}'; - static const String powerClamp = '/device/{powerClampUuid}/power-clamp/status'; + static const String powerClamp = + '/device/{powerClampUuid}/power-clamp/status'; //product static const String listProducts = '/products'; @@ -75,7 +92,8 @@ abstract class ApiEndpoints { static const String createAutomation = '/automation'; static const String getUnitScenes = '/projects/{projectId}/communities/{communityUuid}/spaces/{spaceUuid}/scenes'; - static const String getAutomationDetails = '/automation/details/{automationId}'; + static const String getAutomationDetails = + '/automation/details/{automationId}'; static const String getScene = '/scene/tap-to-run/{sceneId}'; static const String deleteScene = '/scene/tap-to-run/{sceneId}'; @@ -87,8 +105,15 @@ abstract class ApiEndpoints { //space model static const String listSpaceModels = '/projects/{projectId}/space-models'; static const String createSpaceModel = '/projects/{projectId}/space-models'; - static const String getSpaceModel = '/projects/{projectId}/space-models/{spaceModelUuid}'; - static const String updateSpaceModel = '/projects/{projectId}/space-models/{spaceModelUuid}'; + static const String getSpaceModel = + '/projects/{projectId}/space-models/{spaceModelUuid}'; + static const String updateSpaceModel = + '/projects/{projectId}/space-models/{spaceModelUuid}'; + static const String linkSpaceModel = + '/projects/{projectId}/space-models/{spaceModelUuid}/spaces/link'; + + static const String validateSpaceModel = + '/projects/{projectId}/spaces/validate'; static const String roleTypes = '/role/types'; static const String permission = '/permission/{roleUuid}'; @@ -99,7 +124,8 @@ abstract class ApiEndpoints { static const String getUserById = '/projects/{projectUuid}/user/{userUuid}'; static const String editUser = '/invite-user/{inviteUserUuid}'; static const String deleteUser = '/invite-user/{inviteUserUuid}'; - static const String changeUserStatus = '/invite-user/{invitedUserUuid}/disable'; + static const String changeUserStatus = + '/invite-user/{invitedUserUuid}/disable'; static const String terms = '/terms'; static const String policy = '/policy'; static const String userAgreements = '/user/agreements/web/{userUuid}'; From 048a7c0e8fcad2303bb9c9de8df014c570aab714 Mon Sep 17 00:00:00 2001 From: mohammad Date: Thu, 6 Mar 2025 11:10:53 +0300 Subject: [PATCH 6/8] change model name --- .../bloc/link_space_model_event.dart | 22 ----- .../bloc/link_space_model_state.dart | 35 -------- ...loc.dart => link_space_to_model_bloc.dart} | 21 ++--- .../bloc/link_space_to_model_event.dart | 22 +++++ .../bloc/link_space_to_model_state.dart | 35 ++++++++ .../view/link_space_model_dialog.dart | 18 ++-- .../link_space_model_spaces_dialog.dart | 86 ++----------------- .../widgets/dialog/overwrite_dialog.dart | 6 +- .../widgets/space_model_card_widget.dart | 16 ++-- 9 files changed, 97 insertions(+), 164 deletions(-) delete mode 100644 lib/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart delete mode 100644 lib/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart rename lib/pages/spaces_management/link_space_model/bloc/{link_space_model_bloc.dart => link_space_to_model_bloc.dart} (86%) create mode 100644 lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart create mode 100644 lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_state.dart diff --git a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart b/lib/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart deleted file mode 100644 index 1595e695..00000000 --- a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:flutter/material.dart'; - -abstract class SpaceModelEvent {} - -class SpaceModelSelectedEvent extends SpaceModelEvent { - final int selectedIndex; - - SpaceModelSelectedEvent(this.selectedIndex); -} - -class SpaceModelSelectedIdsEvent extends SpaceModelEvent {} - -class LinkSpaceModelEvent extends SpaceModelEvent { - final String? selectedSpaceMode; - final bool isOverWrite; - LinkSpaceModelEvent({this.selectedSpaceMode, this.isOverWrite = false}); -} - -class ValidateSpaceModelEvent extends SpaceModelEvent { - BuildContext? context; - ValidateSpaceModelEvent({this.context}); -} diff --git a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart b/lib/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart deleted file mode 100644 index b7cb7c3f..00000000 --- a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart +++ /dev/null @@ -1,35 +0,0 @@ -abstract class SpaceModelState { - const SpaceModelState(); -} - -class SpaceModelInitial extends SpaceModelState {} - -class SpaceModelLoading extends SpaceModelState {} - -class SpaceModelSelectedState extends SpaceModelState { - final int selectedIndex; - const SpaceModelSelectedState(this.selectedIndex); -} - -class SpaceModelSelectionUpdated extends SpaceModelState { - final bool hasSelectedSpaces; - const SpaceModelSelectionUpdated(this.hasSelectedSpaces); -} - -class SpaceValidationSuccess extends SpaceModelState {} - -class SpaceModelLinkSuccess extends SpaceModelState {} - -class ValidationError extends SpaceModelState { - final String message; - const ValidationError(this.message); -} - -class SpaceModelOperationFailure extends SpaceModelState { - final String message; - const SpaceModelOperationFailure(this.message); -} - -class AlreadyHaveLinkedState extends SpaceModelState { - const AlreadyHaveLinkedState(); -} diff --git a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart b/lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart similarity index 86% rename from lib/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart rename to lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart index cb9f5d43..98491538 100644 --- a/lib/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart +++ b/lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart @@ -3,17 +3,18 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/common/bloc/project_manager.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; -import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart'; -import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_state.dart'; import 'package:syncrow_web/services/space_model_mang_api.dart'; import 'package:syncrow_web/utils/navigation_service.dart'; -class SpaceModelBloc extends Bloc { - SpaceModelBloc() : super(SpaceModelInitial()) { - on(_getSpaceIds); +class LinkSpaceToModelBloc + extends Bloc { + LinkSpaceToModelBloc() : super(SpaceModelInitial()) { + on(_getSpaceIds); on(_handleLinkSpaceModel); on(_validateLinkSpaceModel); - on((event, emit) { + on((event, emit) { emit(SpaceModelSelectedState(event.selectedIndex)); }); } @@ -22,8 +23,8 @@ class SpaceModelBloc extends Bloc { bool hasSelectedSpaces = false; String validate = ''; - Future _getSpaceIds( - SpaceModelSelectedIdsEvent event, Emitter emit) async { + Future _getSpaceIds(LinkSpaceModelSelectedIdsEvent event, + Emitter emit) async { try { BuildContext context = NavigationService.navigatorKey.currentContext!; var spaceBloc = context.read(); @@ -53,7 +54,7 @@ class SpaceModelBloc extends Bloc { Future _handleLinkSpaceModel( LinkSpaceModelEvent event, - Emitter emit, + Emitter emit, ) async { emit(SpaceModelLoading()); try { @@ -74,7 +75,7 @@ class SpaceModelBloc extends Bloc { Future _validateLinkSpaceModel( ValidateSpaceModelEvent event, - Emitter emit, + Emitter emit, ) async { emit(SpaceModelLoading()); try { diff --git a/lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart b/lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart new file mode 100644 index 00000000..694358db --- /dev/null +++ b/lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart @@ -0,0 +1,22 @@ +import 'package:flutter/material.dart'; + +abstract class LinkSpaceToModelEvent {} + +class LinkSpaceModelSelectedEvent extends LinkSpaceToModelEvent { + final int selectedIndex; + + LinkSpaceModelSelectedEvent(this.selectedIndex); +} + +class LinkSpaceModelSelectedIdsEvent extends LinkSpaceToModelEvent {} + +class LinkSpaceModelEvent extends LinkSpaceToModelEvent { + final String? selectedSpaceMode; + final bool isOverWrite; + LinkSpaceModelEvent({this.selectedSpaceMode, this.isOverWrite = false}); +} + +class ValidateSpaceModelEvent extends LinkSpaceToModelEvent { + BuildContext? context; + ValidateSpaceModelEvent({this.context}); +} diff --git a/lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_state.dart b/lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_state.dart new file mode 100644 index 00000000..047567a9 --- /dev/null +++ b/lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_state.dart @@ -0,0 +1,35 @@ +abstract class LinkSpaceToModelState { + const LinkSpaceToModelState(); +} + +class SpaceModelInitial extends LinkSpaceToModelState {} + +class SpaceModelLoading extends LinkSpaceToModelState {} + +class SpaceModelSelectedState extends LinkSpaceToModelState { + final int selectedIndex; + const SpaceModelSelectedState(this.selectedIndex); +} + +class SpaceModelSelectionUpdated extends LinkSpaceToModelState { + final bool hasSelectedSpaces; + const SpaceModelSelectionUpdated(this.hasSelectedSpaces); +} + +class SpaceValidationSuccess extends LinkSpaceToModelState {} + +class SpaceModelLinkSuccess extends LinkSpaceToModelState {} + +class ValidationError extends LinkSpaceToModelState { + final String message; + const ValidationError(this.message); +} + +class SpaceModelOperationFailure extends LinkSpaceToModelState { + final String message; + const SpaceModelOperationFailure(this.message); +} + +class AlreadyHaveLinkedState extends LinkSpaceToModelState { + const AlreadyHaveLinkedState(); +} diff --git a/lib/pages/spaces_management/link_space_model/view/link_space_model_dialog.dart b/lib/pages/spaces_management/link_space_model/view/link_space_model_dialog.dart index 69023857..bbd0de36 100644 --- a/lib/pages/spaces_management/link_space_model/view/link_space_model_dialog.dart +++ b/lib/pages/spaces_management/link_space_model/view/link_space_model_dialog.dart @@ -2,9 +2,9 @@ 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/link_space_model/bloc/link_space_model_bloc.dart'; -import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart'; -import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_state.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/space_model_card_widget.dart'; import 'package:syncrow_web/utils/color_manager.dart'; @@ -24,13 +24,13 @@ class LinkSpaceModelDialog extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => SpaceModelBloc() + create: (context) => LinkSpaceToModelBloc() ..add( - SpaceModelSelectedEvent(initialSelectedIndex ?? -1), + LinkSpaceModelSelectedEvent(initialSelectedIndex ?? -1), ), child: Builder( builder: (context) { - final bloc = context.read(); + final bloc = context.read(); return AlertDialog( backgroundColor: ColorsManager.whiteColors, title: const Text('Link a space model'), @@ -39,7 +39,7 @@ class LinkSpaceModelDialog extends StatelessWidget { color: ColorsManager.textFieldGreyColor, width: MediaQuery.of(context).size.width * 0.7, height: MediaQuery.of(context).size.height * 0.6, - child: BlocBuilder( + child: BlocBuilder( builder: (context, state) { int selectedIndex = -1; if (state is SpaceModelSelectedState) { @@ -59,7 +59,7 @@ class LinkSpaceModelDialog extends StatelessWidget { final isSelected = selectedIndex == index; return GestureDetector( onTap: () { - bloc.add(SpaceModelSelectedEvent(index)); + bloc.add(LinkSpaceModelSelectedEvent(index)); }, child: Container( margin: const EdgeInsets.all(10.0), @@ -93,7 +93,7 @@ class LinkSpaceModelDialog extends StatelessWidget { label: 'Cancel', ), const SizedBox(width: 10), - BlocBuilder( + BlocBuilder( builder: (context, state) { final isEnabled = state is SpaceModelSelectedState && state.selectedIndex >= 0; diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart index 844513d3..f67f8b2c 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart @@ -224,9 +224,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart'; -import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart'; -import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart'; -import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_state.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/confirm_overwrite_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart'; @@ -249,7 +249,7 @@ class _LinkSpaceModelSpacesDialogState @override void initState() { - context.read().add(SpaceModelSelectedIdsEvent()); + context.read().add(LinkSpaceModelSelectedIdsEvent()); super.initState(); } @@ -328,8 +328,10 @@ class _LinkSpaceModelSpacesDialogState child: SpaceTreeView( isSide: true, onSelect: () { - context.read().add( - SpaceModelSelectedIdsEvent()); + context + .read() + .add( + LinkSpaceModelSelectedIdsEvent()); }))) ], ), @@ -391,7 +393,7 @@ class _LinkSpaceModelSpacesDialogState "Confirm", ColorsManager.onSecondaryColor, () { - final spaceModelBloc = context.read(); + final spaceModelBloc = context.read(); if (!spaceModelBloc.hasSelectedSpaces) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( @@ -408,78 +410,8 @@ class _LinkSpaceModelSpacesDialogState ], ); } - - void _handleConfirm() { - final bloc = context.read(); - if (!bloc.hasSelectedSpaces) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text("Please select at least one space")), - ); - return; - } - - // Trigger validation - bloc.add(ValidateSpaceModelEvent()); - } - - void _showLoadingDialog() { - showDialog( - context: context, - barrierDismissible: false, - builder: (context) => const _LoadingDialog(), - ); - } - - void _handleValidationSuccess() { - Navigator.of(context).pop(); // Close loading dialog - - // Show overwrite confirmation - showDialog( - context: context, - builder: (context) => const ConfirmOverwriteDialog(), - ).then((_) { - // Close main dialog after confirmation - if (mounted) Navigator.of(context).pop(); - }); - } - - void _handleValidationError(String message) { - Navigator.of(context).pop(); // Close loading dialog - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(message)), - ); - } - - void _handleCancel() { - if (mounted) Navigator.of(context).pop(); - } - - // Rest of your helper methods (_buildDetailRow, _buildButton, etc.) } -class _LoadingDialog extends StatelessWidget { - const _LoadingDialog(); - - @override - Widget build(BuildContext context) { - return Dialog( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), - child: const Padding( - padding: EdgeInsets.all(20.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - CircularProgressIndicator(), - SizedBox(height: 16), - Text("Linking in progress..."), - ], - ), - ), - ); - } -} - -// Method to build a detail row Widget _buildDetailRow(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4), diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart index 6a34002f..9f57a4b1 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart'; -import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart'; void showOverwriteDialog( - BuildContext context, SpaceModelBloc bloc, SpaceTemplateModel model) { + BuildContext context, LinkSpaceToModelBloc bloc, SpaceTemplateModel model) { showDialog( context: context, barrierDismissible: false, 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 56ba5d3b..c563a6e2 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 @@ -1,9 +1,9 @@ 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/link_space_model/bloc/link_space_model_bloc.dart'; -import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.dart'; -import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_state.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart'; +import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_state.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/custom_loading_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart'; @@ -81,13 +81,13 @@ class SpaceModelCardWidget extends StatelessWidget { showDialog( context: context, builder: (BuildContext dialogContext) { - return BlocProvider( - create: (_) => SpaceModelBloc(), - child: BlocListener( + return BlocProvider( + create: (_) => LinkSpaceToModelBloc(), + child: BlocListener( listener: (context, state) { final _bloc = - BlocProvider.of( + BlocProvider.of( context); if (state is SpaceModelLoading) { showDialog( From add34b327f5eca2e2e645c794f1a89271804bc41 Mon Sep 17 00:00:00 2001 From: mohammad Date: Thu, 6 Mar 2025 11:50:47 +0300 Subject: [PATCH 7/8] space model changes --- .../widgets/space_model_card_widget.dart | 104 +++++++++--------- 1 file changed, 50 insertions(+), 54 deletions(-) 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 51386cb4..1ecc247c 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 @@ -188,63 +188,59 @@ class SpaceModelCardWidget extends StatelessWidget { fit: BoxFit.contain, ), ), - InkWell( - onTap: () { - showDialog( - context: context, - builder: (BuildContext dialogContext) { - return const LinkingAttentionDialog(); - }, - ); - }, - child: SvgPicture.asset( - Assets.deleteSpaceLinkIcon, - fit: BoxFit.contain, - ), - ), - ], - ), - Expanded( - child: Text( - model.modelName, - style: - Theme.of(context).textTheme.headlineMedium?.copyWith( - color: Colors.black, - fontWeight: FontWeight.bold, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - if (!topActionsDisabled) - GestureDetector( - onTap: () => _showDeleteDialog(context), - child: Container( - width: 36, // Adjust size as needed - height: 36, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.white, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - spreadRadius: 2, - blurRadius: 5, - offset: const Offset(0, 2), - ), - ], - ), - child: Center( + if (!topActionsDisabled) + InkWell( + onTap: () { + _showDeleteDialog(context); + }, child: SvgPicture.asset( - Assets.deleteSpaceModel, // Your actual SVG path - width: 20, - height: 20, - colorFilter: const ColorFilter.mode( - Colors.grey, BlendMode.srcIn), + Assets.deleteSpaceLinkIcon, + fit: BoxFit.contain, ), ), - ), - ), + ], + ), + // Expanded( + // child: Text( + // model.modelName, + // style: + // Theme.of(context).textTheme.headlineMedium?.copyWith( + // color: Colors.black, + // fontWeight: FontWeight.bold, + // ), + // maxLines: 1, + // overflow: TextOverflow.ellipsis, + // ), + // ), + // if (!topActionsDisabled) + // GestureDetector( + // onTap: () => _showDeleteDialog(context), + // child: Container( + // width: 36, // Adjust size as needed + // height: 36, + // decoration: BoxDecoration( + // shape: BoxShape.circle, + // color: Colors.white, + // boxShadow: [ + // BoxShadow( + // color: Colors.black.withOpacity(0.1), + // spreadRadius: 2, + // blurRadius: 5, + // offset: const Offset(0, 2), + // ), + // ], + // ), + // child: Center( + // child: SvgPicture.asset( + // Assets.deleteSpaceModel, // Your actual SVG path + // width: 20, + // height: 20, + // colorFilter: const ColorFilter.mode( + // Colors.grey, BlendMode.srcIn), + // ), + // ), + // ), + // ), ], ), if (!showOnlyName) ...[ From 54a250ea2fcb8b50b7efcecc89f8299390cd4b2c Mon Sep 17 00:00:00 2001 From: mohammad Date: Thu, 6 Mar 2025 12:51:30 +0300 Subject: [PATCH 8/8] remove unused code --- .../bloc/link_space_to_model_bloc.dart | 9 +- .../link_space_model_spaces_dialog.dart | 234 +----------------- lib/services/space_model_mang_api.dart | 7 +- 3 files changed, 7 insertions(+), 243 deletions(-) diff --git a/lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart b/lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart index 98491538..c789c2a9 100644 --- a/lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart +++ b/lib/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart @@ -32,9 +32,6 @@ class LinkSpaceToModelBloc List spacesList = spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? []; spacesListIds = spacesList; - for (var spaceId in spacesList) { - print('spaceId===$spaceId'); - } } hasSelectedSpaces = spaceBloc.state.selectedCommunities.any((communityId) { @@ -43,12 +40,12 @@ class LinkSpaceToModelBloc return spacesList.isNotEmpty; }); if (hasSelectedSpaces) { - print("At least one space is selected."); + debugPrint("At least one space is selected."); } else { - print("No spaces selected."); + debugPrint("No spaces selected."); } } catch (e) { - print("Error in _getSpaceIds: $e"); + debugPrint("Error in _getSpaceIds: $e"); } } diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart index f67f8b2c..8c6ef3e9 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/link_space_model_spaces_dialog.dart @@ -1,235 +1,9 @@ -// import 'package:flutter/material.dart'; -// import 'package:flutter_bloc/flutter_bloc.dart'; -// import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart'; -// import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_bloc.dart'; -// import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_model_event.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/confirm_overwrite_dialog.dart'; -// import 'package:syncrow_web/utils/color_manager.dart'; - -// class LinkSpaceModelSpacesDialog extends StatefulWidget { -// final SpaceTemplateModel spaceModel; -// LinkSpaceModelSpacesDialog({super.key, required this.spaceModel}); - -// @override -// State createState() => -// _LinkSpaceModelSpacesDialogState(); -// } - -// class _LinkSpaceModelSpacesDialogState -// extends State { -// TextEditingController searchController = TextEditingController(); - -// @override -// void initState() { -// context.read().add(SpaceModelSelectedIdsEvent()); -// super.initState(); -// } - -// @override -// Widget build(BuildContext context) { -// return AlertDialog( -// contentPadding: EdgeInsets.zero, -// shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), -// backgroundColor: Colors.white, -// content: SizedBox( -// width: MediaQuery.of(context).size.width * 0.4, -// child: Column( -// mainAxisSize: MainAxisSize.min, -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// Expanded( -// child: Padding( -// padding: const EdgeInsets.all(15.0), -// child: Column( -// mainAxisSize: MainAxisSize.min, -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// const Center( -// child: Text( -// "Link Space Model to Spaces", -// style: TextStyle( -// fontSize: 18, -// fontWeight: FontWeight.bold, -// color: Colors.blueAccent, -// ), -// ), -// ), -// const Divider(), -// const SizedBox(height: 16), -// _buildDetailRow( -// "Space model name:", widget.spaceModel.modelName), -// _buildDetailRow("Creation date and time:", -// widget.spaceModel.createdAt.toString()), -// _buildDetailRow("Created by:", "Admin"), -// const SizedBox(height: 12), -// const Text( -// "Link to:", -// style: TextStyle(fontWeight: FontWeight.bold), -// ), -// const Text( -// "Please select all the spaces where you would like to link the Routine.", -// style: TextStyle(fontSize: 12, color: Colors.grey), -// ), -// const SizedBox(height: 8), -// Expanded( -// child: SizedBox( -// child: Column( -// children: [ -// Expanded( -// flex: 7, -// child: Container( -// color: ColorsManager.whiteColors, -// child: SpaceTreeView( -// isSide: true, -// onSelect: () { -// context.read().add( -// SpaceModelSelectedIdsEvent()); -// }))) -// ], -// ), -// ), -// ), -// const SizedBox( -// height: 20, -// ), -// ], -// ), -// ), -// ), - -// // Buttons -// Row( -// children: [ -// Expanded( -// child: Container( -// height: 50, -// decoration: const BoxDecoration( -// border: Border( -// right: BorderSide( -// color: ColorsManager.grayColor, -// width: 0.5, -// ), -// top: BorderSide( -// color: ColorsManager.grayColor, -// width: 1, -// ), -// ), -// ), -// child: _buildButton("Cancel", Colors.grey, () { -// Navigator.of(context).pop(); -// }), -// ), -// ), -// Expanded( -// child: Container( -// height: 50, -// decoration: const BoxDecoration( -// border: Border( -// left: BorderSide( -// color: ColorsManager.grayColor, -// width: 0.5, -// ), -// top: BorderSide( -// color: ColorsManager.grayColor, -// width: 1.0, -// ), -// ), -// ), -// child: _buildButton( -// "Confirm", ColorsManager.onSecondaryColor, () { -// final spaceModelBloc = context.read(); -// if (!spaceModelBloc.hasSelectedSpaces) { -// ScaffoldMessenger.of(context).showSnackBar( -// const SnackBar( -// content: -// Text("Please select at least one space")), -// ); -// return; -// } else { -// // spaceModelBloc.add(LinkSpaceModelEvent( -// // selectedSpaceMode: widget.spaceModel.uuid)); - -// spaceModelBloc.add(ValidateSpaceModelEvent(context: context)); -// } - -// Future.delayed(const Duration(seconds: 3), () { -// Navigator.of(context).pop(); -// Navigator.of(context).pop(); - -// // showDialog( -// // context: context, -// // builder: (BuildContext dialogContext) { -// // return const LinkingSuccessful(); -// // }, -// // ); - -// showDialog( -// context: context, -// builder: (BuildContext dialogContext) { -// return const ConfirmOverwriteDialog(); -// }, -// ); -// }); -// }), -// ), -// ), -// ], -// ), -// ], -// ), -// ), -// ); -// } - -// // Method to build a detail row -// Widget _buildDetailRow(String label, String value) { -// return Padding( -// padding: const EdgeInsets.symmetric(vertical: 4), -// child: Row( -// children: [ -// Expanded( -// child: Text( -// label, -// style: TextStyle(fontWeight: FontWeight.bold), -// ), -// ), -// const SizedBox(width: 8), -// Expanded( -// child: Text( -// value, -// style: -// TextStyle(fontWeight: FontWeight.bold, color: Colors.black), -// ), -// ), -// ], -// ), -// ); -// } - -// Widget _buildButton(String text, Color color, VoidCallback onPressed) { -// return InkWell( -// onTap: onPressed, -// child: Center( -// child: Text( -// text, -// style: TextStyle( -// color: color, fontWeight: FontWeight.w400, fontSize: 14), -// ), -// ), -// ); -// } -// } - import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart'; import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_event.dart'; -import 'package:syncrow_web/pages/spaces_management/link_space_model/bloc/link_space_to_model_state.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/confirm_overwrite_dialog.dart'; -import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/overwrite_dialog.dart'; import 'package:syncrow_web/utils/color_manager.dart'; class LinkSpaceModelSpacesDialog extends StatefulWidget { @@ -244,9 +18,6 @@ class LinkSpaceModelSpacesDialog extends StatefulWidget { class _LinkSpaceModelSpacesDialogState extends State { - final TextEditingController _searchController = TextEditingController(); - bool _isLoading = false; - @override void initState() { context.read().add(LinkSpaceModelSelectedIdsEvent()); @@ -420,14 +191,15 @@ Widget _buildDetailRow(String label, String value) { Expanded( child: Text( label, - style: TextStyle(fontWeight: FontWeight.bold), + style: const TextStyle(fontWeight: FontWeight.bold), ), ), const SizedBox(width: 8), Expanded( child: Text( value, - style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black), + style: const TextStyle( + fontWeight: FontWeight.bold, color: Colors.black), ), ), ], diff --git a/lib/services/space_model_mang_api.dart b/lib/services/space_model_mang_api.dart index d4fa06f4..5253c73e 100644 --- a/lib/services/space_model_mang_api.dart +++ b/lib/services/space_model_mang_api.dart @@ -2,7 +2,6 @@ import 'package:syncrow_web/pages/spaces_management/space_model/models/create_sp import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart'; import 'package:syncrow_web/services/api/http_service.dart'; import 'package:syncrow_web/utils/constants/api_const.dart'; -import 'package:syncrow_web/utils/constants/temp_const.dart'; class SpaceModelManagementApi { Future> listSpaceModels( @@ -66,11 +65,6 @@ class SpaceModelManagementApi { required String projectId, required List spaceUuids, required bool isOverWrite}) async { - print(spaceModelUuid); - print(projectId); - print(spaceUuids); - print(isOverWrite); - final response = await HTTPService().post( path: ApiEndpoints.linkSpaceModel .replaceAll('{projectId}', projectId) @@ -93,6 +87,7 @@ class SpaceModelManagementApi { expectedResponseModel: (json) { return json; }); + return response; } Future deleteSpaceModel(String spaceModelUuid, String projectId) async {