diff --git a/lib/pages/spaces_management/space_model/bloc/create_space_model_event.dart b/lib/pages/spaces_management/space_model/bloc/create_space_model_event.dart index d3fe8f93..6398c7ec 100644 --- a/lib/pages/spaces_management/space_model/bloc/create_space_model_event.dart +++ b/lib/pages/spaces_management/space_model/bloc/create_space_model_event.dart @@ -1,4 +1,5 @@ import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; abstract class CreateSpaceModelEvent {} diff --git a/lib/pages/spaces_management/space_model/bloc/subspace_model_bloc.dart b/lib/pages/spaces_management/space_model/bloc/subspace_model_bloc.dart index 7455d8a5..4aa3dd82 100644 --- a/lib/pages/spaces_management/space_model/bloc/subspace_model_bloc.dart +++ b/lib/pages/spaces_management/space_model/bloc/subspace_model_bloc.dart @@ -2,6 +2,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/subspace_model_event.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/subspace_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/models/subspace_template_model.dart'; import 'package:syncrow_web/utils/constants/action_enum.dart'; class SubSpaceModelBloc extends Bloc { diff --git a/lib/pages/spaces_management/space_model/bloc/subspace_model_event.dart b/lib/pages/spaces_management/space_model/bloc/subspace_model_event.dart index 2147d128..63629472 100644 --- a/lib/pages/spaces_management/space_model/bloc/subspace_model_event.dart +++ b/lib/pages/spaces_management/space_model/bloc/subspace_model_event.dart @@ -1,4 +1,4 @@ -import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; abstract class SubSpaceModelEvent {} diff --git a/lib/pages/spaces_management/space_model/bloc/subspace_model_state.dart b/lib/pages/spaces_management/space_model/bloc/subspace_model_state.dart index 9026cb06..ab60a813 100644 --- a/lib/pages/spaces_management/space_model/bloc/subspace_model_state.dart +++ b/lib/pages/spaces_management/space_model/bloc/subspace_model_state.dart @@ -1,4 +1,5 @@ import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; class SubSpaceModelState { final List subSpaces; 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 d6f8090e..51804178 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 @@ -1,4 +1,6 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart'; import 'package:syncrow_web/utils/constants/action_enum.dart'; import 'package:uuid/uuid.dart'; @@ -59,81 +61,6 @@ class SpaceTemplateModel { } } -class SubspaceTemplateModel { - final String? uuid; - final String subspaceName; - final bool disabled; - final List? tags; - - SubspaceTemplateModel({ - this.uuid, - required this.subspaceName, - required this.disabled, - this.tags, - }); - - factory SubspaceTemplateModel.fromJson(Map json) { - return SubspaceTemplateModel( - uuid: json['uuid'] ?? '', - subspaceName: json['subspaceName'] ?? '', - disabled: json['disabled'] ?? false, - tags: (json['tags'] as List) - .map((item) => TagModel.fromJson(item)) - .toList(), - ); - } - - Map toJson() { - return { - 'uuid': uuid, - 'subspaceName': subspaceName, - 'disabled': disabled, - 'tags': tags?.map((e) => e.toJson()).toList() ?? [], - }; - } -} - -class TagModel { - final String uuid; - final DateTime createdAt; - final DateTime updatedAt; - final String tag; - final bool disabled; - final ProductModel? product; - - TagModel({ - required this.uuid, - required this.createdAt, - required this.updatedAt, - required this.tag, - required this.disabled, - this.product, - }); - - factory TagModel.fromJson(Map json) { - return TagModel( - uuid: json['uuid'] ?? '', - createdAt: DateTime.parse(json['createdAt']), - updatedAt: DateTime.parse(json['updatedAt']), - tag: json['tag'] ?? '', - disabled: json['disabled'] ?? false, - product: json['product'] != null - ? ProductModel.fromMap(json['product']) - : null, - ); - } - - Map toJson() { - return { - 'uuid': uuid, - 'createdAt': createdAt.toIso8601String(), - 'updatedAt': updatedAt.toIso8601String(), - 'tag': tag, - 'disabled': disabled, - 'product': product?.toMap(), - }; - } -} class UpdateSubspaceTemplateModel { final String uuid; diff --git a/lib/pages/spaces_management/space_model/models/subspace_template_model.dart b/lib/pages/spaces_management/space_model/models/subspace_template_model.dart new file mode 100644 index 00000000..8f9d4d4d --- /dev/null +++ b/lib/pages/spaces_management/space_model/models/subspace_template_model.dart @@ -0,0 +1,35 @@ +import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_model.dart'; + +class SubspaceTemplateModel { + final String? uuid; + final String subspaceName; + final bool disabled; + final List? tags; + + SubspaceTemplateModel({ + this.uuid, + required this.subspaceName, + required this.disabled, + this.tags, + }); + + factory SubspaceTemplateModel.fromJson(Map json) { + return SubspaceTemplateModel( + uuid: json['uuid'] ?? '', + subspaceName: json['subspaceName'] ?? '', + disabled: json['disabled'] ?? false, + tags: (json['tags'] as List) + .map((item) => TagModel.fromJson(item)) + .toList(), + ); + } + + Map toJson() { + return { + 'uuid': uuid, + 'subspaceName': subspaceName, + 'disabled': disabled, + 'tags': tags?.map((e) => e.toJson()).toList() ?? [], + }; + } +} diff --git a/lib/pages/spaces_management/space_model/models/tag_model.dart b/lib/pages/spaces_management/space_model/models/tag_model.dart new file mode 100644 index 00000000..356368fc --- /dev/null +++ b/lib/pages/spaces_management/space_model/models/tag_model.dart @@ -0,0 +1,44 @@ +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart'; + +class TagModel { + final String uuid; + final DateTime createdAt; + final DateTime updatedAt; + final String tag; + final bool disabled; + final ProductModel? product; + + TagModel({ + required this.uuid, + required this.createdAt, + required this.updatedAt, + required this.tag, + required this.disabled, + this.product, + }); + + factory TagModel.fromJson(Map json) { + return TagModel( + uuid: json['uuid'] ?? '', + createdAt: DateTime.parse(json['createdAt']), + updatedAt: DateTime.parse(json['updatedAt']), + tag: json['tag'] ?? '', + disabled: json['disabled'] ?? false, + product: json['product'] != null + ? ProductModel.fromMap(json['product']) + : null, + ); + } + + Map toJson() { + return { + 'uuid': uuid, + 'createdAt': createdAt.toIso8601String(), + 'updatedAt': updatedAt.toIso8601String(), + 'tag': tag, + 'disabled': disabled, + 'product': product?.toMap(), + }; + } +} + diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/add_device_type_model_widget.dart b/lib/pages/spaces_management/space_model/widgets/dialog/add_device_type_model_widget.dart new file mode 100644 index 00000000..85285502 --- /dev/null +++ b/lib/pages/spaces_management/space_model/widgets/dialog/add_device_type_model_widget.dart @@ -0,0 +1,223 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_web/pages/common/buttons/default_button.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_product_model.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/counter_widget.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'; + +class AddDeviceTypeModelWidget extends StatefulWidget { + final List? products; + final ValueChanged>? onProductsSelected; + final List? initialSelectedProducts; + + const AddDeviceTypeModelWidget({ + super.key, + this.products, + this.initialSelectedProducts, + this.onProductsSelected, + }); + + @override + _AddDeviceWidgetState createState() => _AddDeviceWidgetState(); +} + +class _AddDeviceWidgetState extends State { + late final ScrollController _scrollController; + late List productCounts; + + @override + void initState() { + super.initState(); + _scrollController = ScrollController(); + productCounts = widget.initialSelectedProducts != null + ? List.from(widget.initialSelectedProducts!) + : []; + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final size = MediaQuery.of(context).size; + + // Adjust the GridView properties based on screen width + final crossAxisCount = size.width > 1200 + ? 8 + : size.width > 800 + ? 5 + : 3; + + return AlertDialog( + title: const Text('Add Devices'), + backgroundColor: ColorsManager.whiteColors, + content: SingleChildScrollView( + child: Container( + width: size.width * 0.9, + height: size.height * 0.65, + color: ColorsManager.textFieldGreyColor, + child: Column( + children: [ + const SizedBox(height: 16), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: Scrollbar( + controller: _scrollController, + thumbVisibility: false, + child: GridView.builder( + shrinkWrap: true, + controller: _scrollController, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: crossAxisCount, + mainAxisSpacing: 6, + crossAxisSpacing: 4, + childAspectRatio: .8, + ), + itemCount: widget.products?.length ?? 0, + itemBuilder: (context, index) { + final product = widget.products![index]; + return _buildDeviceTypeTile(product, size); + }, + ), + ), + ), + ), + ], + ), + ), + ), + actions: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + _buildActionButton( + 'Cancel', ColorsManager.boxColor, ColorsManager.blackColor, () { + Navigator.of(context).pop(); + }), + _buildActionButton( + 'Continue', ColorsManager.secondaryColor, Colors.white, () { + Navigator.of(context).pop(); + if (widget.onProductsSelected != null) { + widget.onProductsSelected!(productCounts); + } + }), + ], + ), + ], + ); + } + + Widget _buildDeviceTypeTile(ProductModel product, Size size) { + final selectedProduct = productCounts.firstWhere( + (p) => p.productId == product.uuid, + orElse: () => SelectedProduct(productId: product.uuid, count: 0), + ); + + return SizedBox( + width: size.width * 0.12, + height: size.height * 0.15, + child: Card( + elevation: 2, + color: ColorsManager.whiteColors, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + _buildDeviceIcon(product, size), + const SizedBox(height: 4), + _buildDeviceName(product, size), + const SizedBox(height: 4), + CounterWidget( + initialCount: selectedProduct.count, + onCountChanged: (newCount) { + setState(() { + if (newCount > 0) { + if (!productCounts.contains(selectedProduct)) { + productCounts.add(SelectedProduct( + productId: product.uuid, count: newCount)); + } else { + selectedProduct.count = newCount; + } + } else { + productCounts + .removeWhere((p) => p.productId == product.uuid); + } + + if (widget.onProductsSelected != null) { + widget.onProductsSelected!(productCounts); + } + }); + }, + ), + ], + ), + ), + ), + ); + } + + Widget _buildDeviceIcon(ProductModel product, Size size) { + return Container( + height: size.width > 800 ? 50 : 40, + width: size.width > 800 ? 50 : 40, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: ColorsManager.textFieldGreyColor, + border: Border.all( + color: ColorsManager.neutralGray, + width: 2, + ), + ), + child: Center( + child: SvgPicture.asset( + product.icon ?? Assets.sensors, + width: size.width > 800 ? 30 : 20, + height: size.width > 800 ? 30 : 20, + ), + ), + ); + } + + Widget _buildDeviceName(ProductModel product, Size size) { + return SizedBox( + height: size.width > 800 ? 35 : 25, + child: Text( + product.name ?? '', + style: context.textTheme.bodySmall + ?.copyWith(color: ColorsManager.blackColor), + textAlign: TextAlign.center, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ); + } + + Widget _buildActionButton( + String label, + Color backgroundColor, + Color foregroundColor, + VoidCallback onPressed, + ) { + return SizedBox( + width: 120, + child: DefaultButton( + onPressed: onPressed, + backgroundColor: backgroundColor, + foregroundColor: foregroundColor, + child: Text(label), + ), + ); + } +} diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart index 1e497f3d..e2095703 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart @@ -3,15 +3,17 @@ 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/all_spaces/model/product_model.dart'; -import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/add_device_type_widget.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_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/button_content_widget.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/add_device_type_model_widget.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import '../../models/subspace_template_model.dart'; + class CreateSpaceModelDialog extends StatelessWidget { final List? products; @@ -74,7 +76,7 @@ class CreateSpaceModelDialog extends StatelessWidget { final result = await showDialog( barrierDismissible: false, context: context, - builder: (context) => AddDeviceWidget( + builder: (context) => AddDeviceTypeModelWidget( products: products, ), ); diff --git a/lib/pages/spaces_management/space_model/widgets/dialog/create_subspace_model_dialog.dart b/lib/pages/spaces_management/space_model/widgets/dialog/create_subspace_model_dialog.dart index c603b025..65c85efa 100644 --- a/lib/pages/spaces_management/space_model/widgets/dialog/create_subspace_model_dialog.dart +++ b/lib/pages/spaces_management/space_model/widgets/dialog/create_subspace_model_dialog.dart @@ -5,7 +5,7 @@ import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/subspace_model_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/subspace_model_event.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/subspace_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/models/subspace_template_model.dart'; import 'package:syncrow_web/utils/color_manager.dart'; class CreateSubSpaceModelDialog extends StatelessWidget { diff --git a/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart b/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart index df37810a..0ccd929e 100644 --- a/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart +++ b/lib/pages/spaces_management/space_model/widgets/subspace_model_create_widget.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/bloc/create_space_model_event.dart'; +import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/button_content_widget.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/widgets/dialog/create_subspace_model_dialog.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/pages/spaces_management/space_model/bloc/create_space_model_bloc.dart';