diff --git a/lib/common/tag_dialog_textfield_dropdown.dart b/lib/common/tag_dialog_textfield_dropdown.dart index 219e03ce..9fa85284 100644 --- a/lib/common/tag_dialog_textfield_dropdown.dart +++ b/lib/common/tag_dialog_textfield_dropdown.dart @@ -17,7 +17,8 @@ class TagDialogTextfieldDropdown extends StatefulWidget { }) : super(key: key); @override - _DialogTextfieldDropdownState createState() => _DialogTextfieldDropdownState(); + _DialogTextfieldDropdownState createState() => + _DialogTextfieldDropdownState(); } class _DialogTextfieldDropdownState extends State { @@ -36,6 +37,12 @@ class _DialogTextfieldDropdownState extends State { _focusNode.addListener(() { if (!_focusNode.hasFocus) { + // Call onSelected when focus is lost + final selectedTag = _filteredItems.firstWhere( + (tag) => tag.tag == _controller.text, + orElse: () => Tag(tag: _controller.text), + ); + widget.onSelected(selectedTag); _closeDropdown(); } }); @@ -43,7 +50,9 @@ class _DialogTextfieldDropdownState extends State { void _filterItems() { setState(() { - _filteredItems = widget.items.where((tag) => tag.product?.uuid == widget.product).toList(); + _filteredItems = widget.items; + // .where((tag) => tag.product?.uuid == widget.product) + // .toList(); }); } @@ -112,7 +121,9 @@ class _DialogTextfieldDropdownState extends State { style: Theme.of(context) .textTheme .bodyMedium - ?.copyWith(color: ColorsManager.textPrimaryColor)), + ?.copyWith( + color: ColorsManager + .textPrimaryColor)), onTap: () { _controller.text = tag.tag ?? ''; widget.onSelected(tag); @@ -156,13 +167,15 @@ class _DialogTextfieldDropdownState extends State { controller: _controller, focusNode: _focusNode, onFieldSubmitted: (value) { - final selectedTag = _filteredItems.firstWhere((tag) => tag.tag == value, + final selectedTag = _filteredItems.firstWhere( + (tag) => tag.tag == value, orElse: () => Tag(tag: value)); widget.onSelected(selectedTag); _closeDropdown(); }, onTapOutside: (event) { - widget.onSelected(_filteredItems.firstWhere((tag) => tag.tag == _controller.text, + widget.onSelected(_filteredItems.firstWhere( + (tag) => tag.tag == _controller.text, orElse: () => Tag(tag: _controller.text))); _closeDropdown(); }, diff --git a/lib/pages/device_managment/all_devices/view/device_managment_page.dart b/lib/pages/device_managment/all_devices/view/device_managment_page.dart index 755bc8b7..2379c22d 100644 --- a/lib/pages/device_managment/all_devices/view/device_managment_page.dart +++ b/lib/pages/device_managment/all_devices/view/device_managment_page.dart @@ -40,17 +40,18 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout { style: TextButton.styleFrom( backgroundColor: null, ), - onPressed: () { - BlocProvider.of(context) - .add(const ResetSelectedEvent()); + onPressed: !state.routineTab + ? null + : () { + BlocProvider.of(context) + .add(const ResetSelectedEvent()); - context - .read() - .add(const TriggerSwitchTabsEvent(isRoutineTab: false)); - context - .read() - .add(FetchDevices(context)); - }, + context.read().add( + const TriggerSwitchTabsEvent(isRoutineTab: false)); + context + .read() + .add(FetchDevices(context)); + }, child: Text( 'Devices', style: context.textTheme.titleMedium?.copyWith( @@ -66,14 +67,15 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout { style: TextButton.styleFrom( backgroundColor: null, ), - onPressed: () { - BlocProvider.of(context) - .add(const ResetSelectedEvent()); + onPressed: state.routineTab + ? null + : () { + BlocProvider.of(context) + .add(const ResetSelectedEvent()); - context - .read() - .add(const TriggerSwitchTabsEvent(isRoutineTab: true)); - }, + context.read().add( + const TriggerSwitchTabsEvent(isRoutineTab: true)); + }, child: Text( 'Routines', style: context.textTheme.titleMedium?.copyWith( diff --git a/lib/pages/home/bloc/home_bloc.dart b/lib/pages/home/bloc/home_bloc.dart index dc6a1280..ad6ed4d8 100644 --- a/lib/pages/home/bloc/home_bloc.dart +++ b/lib/pages/home/bloc/home_bloc.dart @@ -30,11 +30,13 @@ class HomeBloc extends Bloc { Future _fetchUserInfo(FetchUserInfo event, Emitter emit) async { try { - var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey); + var uuid = + await const FlutterSecureStorage().read(key: UserModel.userUuidKey); user = await HomeApi().fetchUserInfo(uuid); if (user != null && user!.project != null) { await ProjectManager.setProjectUUID(user!.project!.uuid); + } add(FetchTermEvent()); add(FetchPolicyEvent()); @@ -66,10 +68,12 @@ class HomeBloc extends Bloc { } } - Future _confirmUserAgreement(ConfirmUserAgreementEvent event, Emitter emit) async { + Future _confirmUserAgreement( + ConfirmUserAgreementEvent event, Emitter emit) async { try { emit(LoadingHome()); - var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey); + var uuid = + await const FlutterSecureStorage().read(key: UserModel.userUuidKey); policy = await HomeApi().confirmUserAgreements(uuid); emit(PolicyAgreement()); } catch (e) { @@ -122,5 +126,41 @@ class HomeBloc extends Bloc { }, color: const Color(0xFF023DFE), ), + + // HomeItemModel( + // title: 'Move in', + // icon: Assets.moveinIcon, + // active: false, + // onPress: (context) {}, + // color: ColorsManager.primaryColor, + // ), + // HomeItemModel( + // title: 'Construction', + // icon: Assets.constructionIcon, + // active: false, + // onPress: (context) {}, + // color: ColorsManager.primaryColor, + // ), + // HomeItemModel( + // title: 'Energy', + // icon: Assets.energyIcon, + // active: false, + // onPress: (context) {}, + // color: ColorsManager.slidingBlueColor.withOpacity(0.2), + // ), + // HomeItemModel( + // title: 'Integrations', + // icon: Assets.integrationsIcon, + // active: false, + // onPress: (context) {}, + // color: ColorsManager.slidingBlueColor.withOpacity(0.2), + // ), + // HomeItemModel( + // title: 'Asset', + // icon: Assets.assetIcon, + // active: false, + // onPress: (context) {}, + // color: ColorsManager.slidingBlueColor.withOpacity(0.2), + // ), ]; } diff --git a/lib/pages/home/view/home_page_web.dart b/lib/pages/home/view/home_page_web.dart index e6251c86..53a994f6 100644 --- a/lib/pages/home/view/home_page_web.dart +++ b/lib/pages/home/view/home_page_web.dart @@ -21,6 +21,7 @@ class _HomeWebPageState extends State { bool _dialogShown = false; + @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; @@ -50,7 +51,7 @@ class _HomeWebPageState extends State { _dialogShown = false; if (v != null) { homeBloc.add(ConfirmUserAgreementEvent()); - homeBloc.add(const FetchUserInfo()); + // homeBloc.add(const FetchUserInfo()); } }); }); diff --git a/lib/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart b/lib/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart index 759cea27..f666c078 100644 --- a/lib/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart +++ b/lib/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart @@ -21,7 +21,8 @@ import 'package:syncrow_web/services/space_mana_api.dart'; import 'package:syncrow_web/services/space_model_mang_api.dart'; import 'package:syncrow_web/utils/constants/action_enum.dart' as custom_action; -class SpaceManagementBloc extends Bloc { +class SpaceManagementBloc + extends Bloc { final CommunitySpaceManagementApi _api; final ProductApi _productApi; final SpaceModelManagementApi _spaceModelApi; @@ -62,7 +63,8 @@ class SpaceManagementBloc extends Bloc emit) async { + void _deleteSpaceModelFromCache(DeleteSpaceModelFromCache event, + Emitter emit) async { if (_cachedSpaceModels != null) { - _cachedSpaceModels = - _cachedSpaceModels!.where((model) => model.uuid != event.deletedUuid).toList(); + _cachedSpaceModels = _cachedSpaceModels! + .where((model) => model.uuid != event.deletedUuid) + .toList(); } else { _cachedSpaceModels = await fetchSpaceModels(); } await fetchTags(); emit(SpaceModelLoaded( - communities: - state is SpaceManagementLoaded ? (state as SpaceManagementLoaded).communities : [], + communities: state is SpaceManagementLoaded + ? (state as SpaceManagementLoaded).communities + : [], products: _cachedProducts ?? [], spaceModels: List.from(_cachedSpaceModels ?? []), allTags: _cachedTags ?? [])); @@ -122,8 +127,8 @@ class SpaceManagementBloc extends Bloc.from(previousState.communities); + final updatedCommunities = + List.from(previousState.communities); for (var community in updatedCommunities) { if (community.uuid == event.communityUuid) { community.name = event.name; @@ -212,7 +219,8 @@ class SpaceManagementBloc extends Bloc> _fetchSpacesForCommunity(String communityUuid) async { + Future> _fetchSpacesForCommunity( + String communityUuid) async { final projectUuid = await ProjectManager.getProjectUUID() ?? ''; return await _api.getSpaceHierarchy(communityUuid, projectUuid); @@ -242,20 +250,23 @@ class SpaceManagementBloc extends Bloc _onBlankState(BlankStateEvent event, Emitter emit) async { + Future _onBlankState( + BlankStateEvent event, Emitter emit) async { try { final previousState = state; final projectUuid = await ProjectManager.getProjectUUID() ?? ''; var spaceBloc = event.context.read(); var spaceTreeState = event.context.read().state; - List communities = await _waitForCommunityList(spaceBloc, spaceTreeState); + List communities = + await _waitForCommunityList(spaceBloc, spaceTreeState); await fetchSpaceModels(); - await fetchTags(); + // await fetchTags(); var prevSpaceModels = await fetchSpaceModels(); - if (previousState is SpaceManagementLoaded || previousState is BlankState) { + if (previousState is SpaceManagementLoaded || + previousState is BlankState) { final prevCommunities = (previousState as dynamic).communities ?? []; emit(BlankState( communities: List.from(prevCommunities), @@ -286,7 +297,8 @@ class SpaceManagementBloc extends Bloc communities = await _waitForCommunityList(spaceBloc, spaceTreeState); + List communities = + await _waitForCommunityList(spaceBloc, spaceTreeState); // Fetch space models after communities are available final prevSpaceModels = await fetchSpaceModels(); @@ -310,8 +322,9 @@ class SpaceManagementBloc extends Bloc>(); final subscription = spaceBloc.stream.listen((state) { if (!completer.isCompleted && state.communityList.isNotEmpty) { - completer - .complete(state.searchQuery.isNotEmpty ? state.filteredCommunity : state.communityList); + completer.complete(state.searchQuery.isNotEmpty + ? state.filteredCommunity + : state.communityList); } }); try { @@ -339,7 +352,8 @@ class SpaceManagementBloc extends Bloc.from( (previousState as dynamic).communities, ); @@ -459,12 +474,15 @@ class SpaceManagementBloc extends Bloc().state; - final updatedSpaces = - await saveSpacesHierarchically(event.context, event.spaces, event.communityUuid); + final updatedSpaces = await saveSpacesHierarchically( + event.context, event.spaces, event.communityUuid); final allSpaces = await _fetchSpacesForCommunity(event.communityUuid); - emit(SpaceCreationSuccess(spaces: updatedSpaces)); - + // emit(SpaceCreationSuccess(spaces: updatedSpaces)); + // updatedSpaces.forEach( + // (element) => element.uuid, + // ); + // final lastUpdatedSpaced = updatedSpaces..addAll(allSpaces); if (previousState is SpaceManagementLoaded) { await _updateLoadedState( spaceTreeState, @@ -475,7 +493,7 @@ class SpaceManagementBloc extends Bloc> saveSpacesHierarchically( - BuildContext context, List spaces, String communityUuid) async { + Future> saveSpacesHierarchically(BuildContext context, + List spaces, String communityUuid) async { final orderedSpaces = flattenHierarchy(spaces); final projectUuid = await ProjectManager.getProjectUUID() ?? ''; @@ -534,6 +554,14 @@ class SpaceManagementBloc extends Bloc community.uuid == communityUuid, + orElse: () => CommunityModel( + uuid: '', + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + name: '', + description: '', + spaces: spaces, + ), ); } catch (e) { return []; @@ -548,9 +576,7 @@ class SpaceManagementBloc extends Bloc parentsToDelete.contains(space)); @@ -564,7 +590,7 @@ class SpaceManagementBloc extends Bloc subspaceUpdates = []; final List? prevSubspaces = prevSpace?.subspaces; @@ -575,17 +601,19 @@ class SpaceManagementBloc extends Bloc subspace.uuid == prevSubspace.uuid); + final existsInNew = newSubspaces + .any((subspace) => subspace.uuid == prevSubspace.uuid); if (!existsInNew) { subspaceUpdates.add(UpdateSubspaceTemplateModel( - action: custom_action.Action.delete, uuid: prevSubspace.uuid)); + action: custom_action.Action.delete, + uuid: prevSubspace.uuid)); } } } else if (prevSubspaces != null && newSubspaces == null) { for (var prevSubspace in prevSubspaces) { subspaceUpdates.add(UpdateSubspaceTemplateModel( - action: custom_action.Action.delete, uuid: prevSubspace.uuid)); + action: custom_action.Action.delete, + uuid: prevSubspace.uuid)); } } @@ -613,7 +641,9 @@ class SpaceManagementBloc extends Bloc tag.toCreateTagBodyModel()).toList() ?? []; + final tagBodyModels = subspace.tags + ?.map((tag) => tag.toCreateTagBodyModel()) + .toList() ?? + []; return CreateSubspaceModel() ..subspaceName = subspace.subspaceName ..tags = tagBodyModels; @@ -671,7 +704,6 @@ class SpaceManagementBloc extends Bloc emit) async { + void _onLoadSpaceModel( + SpaceModelLoadEvent event, Emitter emit) async { emit(SpaceManagementLoading()); try { @@ -757,14 +791,17 @@ class SpaceManagementBloc extends Bloc newTag.uuid == prevTag.uuid); + final existsInNew = + newTags.any((newTag) => newTag.uuid == prevTag.uuid); if (!existsInNew) { - tagUpdates.add(TagModelUpdate(action: custom_action.Action.delete, uuid: prevTag.uuid)); + tagUpdates.add(TagModelUpdate( + action: custom_action.Action.delete, uuid: prevTag.uuid)); } } } else if (prevTags != null && newTags == null) { for (var prevTag in prevTags) { - tagUpdates.add(TagModelUpdate(action: custom_action.Action.delete, uuid: prevTag.uuid)); + tagUpdates.add(TagModelUpdate( + action: custom_action.Action.delete, uuid: prevTag.uuid)); } } @@ -807,15 +844,16 @@ class SpaceManagementBloc extends Bloc findMatchingSpaces(List spaces, String targetUuid) { + List findMatchingSpaces( + List spaces, String targetUuid) { List matched = []; for (var space in spaces) { if (space.uuid == targetUuid) { matched.add(space); } - matched - .addAll(findMatchingSpaces(space.children, targetUuid)); // Recursively search in children + matched.addAll(findMatchingSpaces( + space.children, targetUuid)); // Recursively search in children } return matched; diff --git a/lib/pages/spaces_management/all_spaces/model/connection_model.dart b/lib/pages/spaces_management/all_spaces/model/connection_model.dart index a774efe2..0799d81e 100644 --- a/lib/pages/spaces_management/all_spaces/model/connection_model.dart +++ b/lib/pages/spaces_management/all_spaces/model/connection_model.dart @@ -3,23 +3,26 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model class Connection { final SpaceModel startSpace; final SpaceModel endSpace; - final String direction; - Connection({required this.startSpace, required this.endSpace, required this.direction}); + Connection({ + required this.startSpace, + required this.endSpace, + }); Map toMap() { return { - 'startUuid': startSpace.uuid ?? 'unsaved-start-space-${startSpace.name}', // Fallback for unsaved spaces - 'endUuid': endSpace.uuid ?? 'unsaved-end-space-${endSpace.name}', // Fallback for unsaved spaces - 'direction': direction, + 'startUuid': startSpace.uuid ?? + 'unsaved-start-space-${startSpace.name}', // Fallback for unsaved spaces + 'endUuid': endSpace.uuid ?? + 'unsaved-end-space-${endSpace.name}', // Fallback for unsaved spaces }; } - static Connection fromMap(Map map, Map spaces) { + static Connection fromMap( + Map map, Map spaces) { return Connection( startSpace: spaces[map['startUuid']]!, endSpace: spaces[map['endUuid']]!, - direction: map['direction'], ); } } diff --git a/lib/pages/spaces_management/all_spaces/model/product_model.dart b/lib/pages/spaces_management/all_spaces/model/product_model.dart index a4ebd550..8f905032 100644 --- a/lib/pages/spaces_management/all_spaces/model/product_model.dart +++ b/lib/pages/spaces_management/all_spaces/model/product_model.dart @@ -1,5 +1,7 @@ import 'package:syncrow_web/utils/constants/assets.dart'; +import 'selected_product_model.dart'; + class ProductModel { final String uuid; final String catName; @@ -38,6 +40,15 @@ class ProductModel { }; } + SelectedProduct toSelectedProduct(int count) { + return SelectedProduct( + productId: uuid, + count: count, + productName: name!, + product: this, + ); + } + static String _mapIconToProduct(String prodType) { const iconMapping = { '1G': Assets.Gang1SwitchIcon, diff --git a/lib/pages/spaces_management/all_spaces/model/space_model.dart b/lib/pages/spaces_management/all_spaces/model/space_model.dart index 6e744a29..4956d472 100644 --- a/lib/pages/spaces_management/all_spaces/model/space_model.dart +++ b/lib/pages/spaces_management/all_spaces/model/space_model.dart @@ -101,7 +101,7 @@ class SpaceModel { spaceModel: json['spaceModel'] != null ? SpaceTemplateModel.fromJson(json['spaceModel']) : null, - tags: (json['tags'] as List?) + tags: (json['productAllocations'] as List?) ?.where((item) => item is Map) // Validate type .map((item) => Tag.fromJson(item as Map)) .toList() ?? @@ -116,7 +116,6 @@ class SpaceModel { instance.incomingConnection = Connection( startSpace: instance.parent ?? instance, // Parent space endSpace: instance, // This space instance - direction: conn['direction'], ); } diff --git a/lib/pages/spaces_management/all_spaces/model/subspace_model.dart b/lib/pages/spaces_management/all_spaces/model/subspace_model.dart index a89ec409..fd3e780e 100644 --- a/lib/pages/spaces_management/all_spaces/model/subspace_model.dart +++ b/lib/pages/spaces_management/all_spaces/model/subspace_model.dart @@ -27,7 +27,7 @@ class SubspaceModel { subspaceName: json['subspaceName'] ?? '', disabled: json['disabled'] ?? false, internalId: internalId, - tags: (json['tags'] as List?) + tags: (json['productAllocations'] as List?) ?.map((item) => Tag.fromJson(item)) .toList() ?? [], @@ -36,7 +36,7 @@ class SubspaceModel { Map toJson() { return { - 'uuid': uuid, + if (uuid != null) 'uuid': uuid, 'subspaceName': subspaceName, 'disabled': disabled, 'tags': tags?.map((e) => e.toJson()).toList() ?? [], diff --git a/lib/pages/spaces_management/all_spaces/model/tag.dart b/lib/pages/spaces_management/all_spaces/model/tag.dart index 8959986c..a7ec1e15 100644 --- a/lib/pages/spaces_management/all_spaces/model/tag.dart +++ b/lib/pages/spaces_management/all_spaces/model/tag.dart @@ -23,10 +23,13 @@ class Tag extends BaseTag { final String internalId = json['internalId'] ?? const Uuid().v4(); return Tag( - uuid: json['uuid'] ?? '', + //TODO:insure UUId for tag or prodAlloc + uuid: json['name'] != null ? json['uuid'] : json['tag']?['uuid'] ?? '', internalId: internalId, - tag: json['name'] ?? '', - product: json['product'] != null ? ProductModel.fromMap(json['product']) : null, + tag: json['name'] ?? json['tag']?['name'] ?? '', + product: json['product'] != null + ? ProductModel.fromMap(json['product']) + : null, ); } @@ -49,9 +52,10 @@ class Tag extends BaseTag { Map toJson() { return { - 'uuid': uuid, - 'tag': tag, - 'product': product?.toMap(), + if (uuid != null) 'uuid': uuid, + 'name': tag, + 'productUuid': product?.uuid, + // .toMap(), }; } } diff --git a/lib/pages/spaces_management/all_spaces/widgets/community_structure_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/community_structure_widget.dart index a93679d0..178f7659 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/community_structure_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/community_structure_widget.dart @@ -67,7 +67,8 @@ class _CommunityStructureAreaState extends State { void initState() { super.initState(); spaces = widget.spaces.isNotEmpty ? flattenSpaces(widget.spaces) : []; - connections = widget.spaces.isNotEmpty ? createConnections(widget.spaces) : []; + connections = + widget.spaces.isNotEmpty ? createConnections(widget.spaces) : []; _adjustCanvasSizeForSpaces(); _nameController = TextEditingController( text: widget.selectedCommunity?.name ?? '', @@ -96,13 +97,15 @@ class _CommunityStructureAreaState extends State { if (oldWidget.spaces != widget.spaces) { setState(() { spaces = widget.spaces.isNotEmpty ? flattenSpaces(widget.spaces) : []; - connections = widget.spaces.isNotEmpty ? createConnections(widget.spaces) : []; + connections = + widget.spaces.isNotEmpty ? createConnections(widget.spaces) : []; _adjustCanvasSizeForSpaces(); realignTree(); }); } - if (widget.selectedSpace != oldWidget.selectedSpace && widget.selectedSpace != null) { + if (widget.selectedSpace != oldWidget.selectedSpace && + widget.selectedSpace != null) { WidgetsBinding.instance.addPostFrameCallback((_) { _moveToSpace(widget.selectedSpace!); }); @@ -185,7 +188,8 @@ class _CommunityStructureAreaState extends State { connection, widget.selectedSpace) ? 1.0 : 0.3, // Adjust opacity - child: CustomPaint(painter: CurvedLinePainter([connection])), + child: CustomPaint( + painter: CurvedLinePainter([connection])), ), for (var entry in spaces.asMap().entries) if (entry.value.status != SpaceStatus.deleted && @@ -195,11 +199,11 @@ class _CommunityStructureAreaState extends State { top: entry.value.position.dy, child: SpaceCardWidget( index: entry.key, - onButtonTap: (int index, Offset newPosition, String direction) { + onButtonTap: (int index, Offset newPosition) { _showCreateSpaceDialog(screenSize, - position: spaces[index].position + newPosition, + position: + spaces[index].position + newPosition, parentIndex: index, - direction: direction, projectTags: widget.projectTags); }, position: entry.value.position, @@ -210,8 +214,9 @@ class _CommunityStructureAreaState extends State { _updateNodePosition(entry.value, newPosition); }, buildSpaceContainer: (int index) { - final bool isHighlighted = SpaceHelper.isHighlightedSpace( - spaces[index], widget.selectedSpace); + final bool isHighlighted = + SpaceHelper.isHighlightedSpace( + spaces[index], widget.selectedSpace); return Opacity( opacity: isHighlighted ? 1.0 : 0.3, @@ -289,7 +294,6 @@ class _CommunityStructureAreaState extends State { void _showCreateSpaceDialog(Size screenSize, {Offset? position, int? parentIndex, - String? direction, double? canvasWidth, double? canvasHeight, required List projectTags}) { @@ -299,19 +303,25 @@ class _CommunityStructureAreaState extends State { return CreateSpaceDialog( products: widget.products, spaceModels: widget.spaceModels, - allTags: TagHelper.getAllTagValues(widget.communities, widget.spaceModels), + allTags: + TagHelper.getAllTagValues(widget.communities, widget.spaceModels), parentSpace: parentIndex != null ? spaces[parentIndex] : null, projectTags: projectTags, - onCreateSpace: (String name, String icon, List selectedProducts, - SpaceTemplateModel? spaceModel, List? subspaces, List? tags) { + onCreateSpace: (String name, + String icon, + List selectedProducts, + SpaceTemplateModel? spaceModel, + List? subspaces, + List? tags) { setState(() { // Set the first space in the center or use passed position Offset newPosition; if (parentIndex != null) { - newPosition = - getBalancedChildPosition(spaces[parentIndex]); // Ensure balanced position + newPosition = getBalancedChildPosition( + spaces[parentIndex]); // Ensure balanced position } else { - newPosition = position ?? ConnectionHelper.getCenterPosition(screenSize); + newPosition = + position ?? ConnectionHelper.getCenterPosition(screenSize); } SpaceModel newSpace = SpaceModel( @@ -325,14 +335,13 @@ class _CommunityStructureAreaState extends State { subspaces: subspaces, tags: tags); - if (parentIndex != null && direction != null) { + if (parentIndex != null) { SpaceModel parentSpace = spaces[parentIndex]; parentSpace.internalId = spaces[parentIndex].internalId; newSpace.parent = parentSpace; final newConnection = Connection( startSpace: parentSpace, endSpace: newSpace, - direction: direction, ); connections.add(newConnection); newSpace.incomingConnection = newConnection; @@ -360,16 +369,21 @@ class _CommunityStructureAreaState extends State { name: widget.selectedSpace!.name, icon: widget.selectedSpace!.icon, projectTags: widget.projectTags, - parentSpace: - SpaceHelper.findSpaceByInternalId(widget.selectedSpace?.parent?.internalId, spaces), + parentSpace: SpaceHelper.findSpaceByInternalId( + widget.selectedSpace?.parent?.internalId, spaces), editSpace: widget.selectedSpace, currentSpaceModel: widget.selectedSpace?.spaceModel, tags: widget.selectedSpace?.tags, subspaces: widget.selectedSpace?.subspaces, isEdit: true, - allTags: TagHelper.getAllTagValues(widget.communities, widget.spaceModels), - onCreateSpace: (String name, String icon, List selectedProducts, - SpaceTemplateModel? spaceModel, List? subspaces, List? tags) { + allTags: TagHelper.getAllTagValues( + widget.communities, widget.spaceModels), + onCreateSpace: (String name, + String icon, + List selectedProducts, + SpaceTemplateModel? spaceModel, + List? subspaces, + List? tags) { setState(() { // Update the space's properties widget.selectedSpace!.name = name; @@ -379,7 +393,8 @@ class _CommunityStructureAreaState extends State { widget.selectedSpace!.tags = tags; if (widget.selectedSpace!.status != SpaceStatus.newSpace) { - widget.selectedSpace!.status = SpaceStatus.modified; // Mark as modified + widget.selectedSpace!.status = + SpaceStatus.modified; // Mark as modified } for (var space in spaces) { @@ -410,7 +425,8 @@ class _CommunityStructureAreaState extends State { Map idToSpace = {}; void flatten(SpaceModel space) { - if (space.status == SpaceStatus.deleted || space.status == SpaceStatus.parentDeleted) { + if (space.status == SpaceStatus.deleted || + space.status == SpaceStatus.parentDeleted) { return; } result.add(space); @@ -447,7 +463,6 @@ class _CommunityStructureAreaState extends State { Connection( startSpace: parent, endSpace: child, - direction: "down", ), ); @@ -532,13 +547,16 @@ class _CommunityStructureAreaState extends State { void _selectSpace(BuildContext context, SpaceModel space) { context.read().add( - SelectSpaceEvent(selectedCommunity: widget.selectedCommunity, selectedSpace: space), + SelectSpaceEvent( + selectedCommunity: widget.selectedCommunity, + selectedSpace: space), ); } void _deselectSpace(BuildContext context) { context.read().add( - SelectSpaceEvent(selectedCommunity: widget.selectedCommunity, selectedSpace: null), + SelectSpaceEvent( + selectedCommunity: widget.selectedCommunity, selectedSpace: null), ); } @@ -708,7 +726,8 @@ class _CommunityStructureAreaState extends State { SpaceModel duplicated = _deepCloneSpaceTree(space, parent: parent); - duplicated.position = Offset(space.position.dx + 300, space.position.dy + 100); + duplicated.position = + Offset(space.position.dx + 300, space.position.dy + 100); List duplicatedSubtree = []; void collectSubtree(SpaceModel node) { duplicatedSubtree.add(node); @@ -726,7 +745,6 @@ class _CommunityStructureAreaState extends State { final newConnection = Connection( startSpace: parent, endSpace: duplicated, - direction: "down", ); connections.add(newConnection); duplicated.incomingConnection = newConnection; @@ -739,7 +757,8 @@ class _CommunityStructureAreaState extends State { } SpaceModel _deepCloneSpaceTree(SpaceModel original, {SpaceModel? parent}) { - final duplicatedName = SpaceHelper.generateUniqueSpaceName(original.name, spaces); + final duplicatedName = + SpaceHelper.generateUniqueSpaceName(original.name, spaces); final newSpace = SpaceModel( name: duplicatedName, @@ -761,7 +780,6 @@ class _CommunityStructureAreaState extends State { final newConnection = Connection( startSpace: newSpace, endSpace: duplicatedChild, - direction: "down", ); connections.add(newConnection); diff --git a/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/devices_part_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/devices_part_widget.dart new file mode 100644 index 00000000..94896554 --- /dev/null +++ b/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/devices_part_widget.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; + +import '../../../../../common/edit_chip.dart'; +import '../../../../../utils/color_manager.dart'; +import '../../../helper/tag_helper.dart'; +import '../../../space_model/widgets/button_content_widget.dart'; +import '../../model/subspace_model.dart'; +import '../../model/tag.dart'; + +class DevicesPartWidget extends StatelessWidget { + const DevicesPartWidget({ + super.key, + required this.tags, + required this.subspaces, + required this.screenWidth, + required this.onEditChip, + required this.onTextButtonPressed, + required this.isTagsAndSubspaceModelDisabled, + }); + final bool isTagsAndSubspaceModelDisabled; + final void Function() onEditChip; + final void Function() onTextButtonPressed; + final double screenWidth; + final List? tags; + final List? subspaces; + @override + Widget build(BuildContext context) { + return Column( + children: [ + (tags?.isNotEmpty == true || + subspaces?.any( + (subspace) => subspace.tags?.isNotEmpty == true) == + true) + ? SizedBox( + width: screenWidth * 0.25, + child: Container( + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + color: ColorsManager.textFieldGreyColor, + borderRadius: BorderRadius.circular(15), + border: Border.all( + color: ColorsManager.textFieldGreyColor, + width: 3.0, // Border width + ), + ), + child: Wrap( + spacing: 8.0, + runSpacing: 8.0, + children: [ + // Combine tags from spaceModel and subspaces + ...TagHelper.groupTags([ + ...?tags, + ...?subspaces?.expand((subspace) => subspace.tags ?? []) + ]).entries.map( + (entry) => Chip( + avatar: SizedBox( + width: 24, + height: 24, + child: SvgPicture.asset( + entry.key.icon ?? 'assets/icons/gateway.svg', + fit: BoxFit.contain, + ), + ), + label: Text( + 'x${entry.value}', // Show count + style: Theme.of(context) + .textTheme + .bodySmall + ?.copyWith(color: ColorsManager.spaceColor), + ), + backgroundColor: ColorsManager.whiteColors, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + side: const BorderSide( + color: ColorsManager.spaceColor, + ), + ), + ), + ), + + EditChip(onTap: onEditChip) + ], + ), + ), + ) + : TextButton( + onPressed: onTextButtonPressed, + style: TextButton.styleFrom( + padding: EdgeInsets.zero, + ), + child: ButtonContentWidget( + icon: Icons.add, + label: 'Add Devices', + disabled: isTagsAndSubspaceModelDisabled, + ), + ) + ], + ); + } +} diff --git a/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/icon_choose_part_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/icon_choose_part_widget.dart new file mode 100644 index 00000000..59a100a3 --- /dev/null +++ b/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/icon_choose_part_widget.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; + +import '../../../../../utils/color_manager.dart'; +import '../../../../../utils/constants/assets.dart'; + +class IconChoosePartWidget extends StatelessWidget { + const IconChoosePartWidget({ + super.key, + required this.selectedIcon, + required this.showIconSelection, + required this.screenWidth, + }); + final double screenWidth; + final String selectedIcon; + final void Function() showIconSelection; + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + // crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 50), + Stack( + alignment: Alignment.center, + children: [ + Container( + width: screenWidth * 0.1, + height: screenWidth * 0.1, + decoration: const BoxDecoration( + color: ColorsManager.boxColor, + shape: BoxShape.circle, + ), + ), + SvgPicture.asset( + selectedIcon, + width: screenWidth * 0.04, + height: screenWidth * 0.04, + ), + Positioned( + top: 20, + right: 20, + child: InkWell( + onTap: showIconSelection, + child: Container( + width: 24, + height: 24, + decoration: const BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + child: SvgPicture.asset( + Assets.iconEdit, + width: 16, + height: 16, + ), + ), + ), + ), + ], + ), + ], + ); + } +} diff --git a/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/space_model_linking_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/space_model_linking_widget.dart new file mode 100644 index 00000000..cd9ae470 --- /dev/null +++ b/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/space_model_linking_widget.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; + +import '../../../../../utils/color_manager.dart'; +import '../../../../../utils/constants/assets.dart'; +import '../../../space_model/models/space_template_model.dart'; +import '../../../space_model/widgets/button_content_widget.dart'; + +class SpaceModelLinkingWidget extends StatelessWidget { + const SpaceModelLinkingWidget({ + super.key, + required this.onDeleted, + required this.onPressed, + required this.screenWidth, + required this.selectedSpaceModel, + required this.isSpaceModelDisabled, + }); + final bool isSpaceModelDisabled; + final void Function()? onDeleted; + final void Function()? onPressed; + final double screenWidth; + final SpaceTemplateModel? selectedSpaceModel; + @override + Widget build(BuildContext context) { + return Column( + children: [ + selectedSpaceModel == null + ? TextButton( + style: TextButton.styleFrom( + padding: EdgeInsets.zero, + ), + onPressed: onPressed, + child: ButtonContentWidget( + svgAssets: Assets.link, + label: 'Link a space model', + disabled: isSpaceModelDisabled, + ), + ) + : Container( + width: screenWidth * 0.25, + padding: const EdgeInsets.symmetric( + vertical: 10.0, horizontal: 16.0), + decoration: BoxDecoration( + color: ColorsManager.boxColor, + borderRadius: BorderRadius.circular(10), + ), + child: Wrap( + spacing: 8.0, + runSpacing: 8.0, + children: [ + Chip( + label: Text( + selectedSpaceModel?.modelName ?? '', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: ColorsManager.spaceColor), + ), + backgroundColor: ColorsManager.whiteColors, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: const BorderSide( + color: ColorsManager.transparentColor, + width: 0, + ), + ), + deleteIcon: Container( + width: 24, + height: 24, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: ColorsManager.lightGrayColor, + width: 1.5, + ), + ), + child: const Icon( + Icons.close, + size: 16, + color: ColorsManager.lightGrayColor, + ), + ), + onDeleted: onDeleted), + ], + ), + ), + ], + ); + } +} diff --git a/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/space_name_textfield_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/space_name_textfield_widget.dart new file mode 100644 index 00000000..600cb8ad --- /dev/null +++ b/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/space_name_textfield_widget.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +import '../../../../../utils/color_manager.dart'; + +class SpaceNameTextfieldWidget extends StatelessWidget { + SpaceNameTextfieldWidget({ + super.key, + required this.isNameFieldExist, + required this.isNameFieldInvalid, + required this.onChange, + required this.screenWidth, + required this.nameController, + }); + TextEditingController nameController; + final void Function(String value) onChange; + final double screenWidth; + bool isNameFieldExist; + bool isNameFieldInvalid; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + SizedBox( + width: screenWidth * 0.25, + child: TextField( + controller: nameController, + onChanged: onChange, + style: Theme.of(context).textTheme.bodyMedium, + decoration: InputDecoration( + hintText: 'Please enter the name', + hintStyle: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: ColorsManager.lightGrayColor), + filled: true, + fillColor: ColorsManager.boxColor, + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide( + color: isNameFieldInvalid || isNameFieldExist + ? ColorsManager.red + : ColorsManager.boxColor, + width: 1.5, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: const BorderSide( + color: ColorsManager.boxColor, + width: 1.5, + ), + ), + ), + ), + ), + if (isNameFieldInvalid) + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text( + '*Space name should not be empty.', + style: Theme.of(context) + .textTheme + .bodySmall + ?.copyWith(color: ColorsManager.red), + ), + ), + if (isNameFieldExist) + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text( + '*Name already exist', + style: Theme.of(context) + .textTheme + .bodySmall + ?.copyWith(color: ColorsManager.red), + ), + ), + ], + ); + } +} diff --git a/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/sub_space_part_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/sub_space_part_widget.dart new file mode 100644 index 00000000..e518877a --- /dev/null +++ b/lib/pages/spaces_management/all_spaces/widgets/create_space_widgets/sub_space_part_widget.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; + +import '../../../../../common/edit_chip.dart'; +import '../../../../../utils/color_manager.dart'; +import '../../../space_model/widgets/button_content_widget.dart'; +import '../../../space_model/widgets/subspace_name_label_widget.dart'; +import '../../model/subspace_model.dart'; + +class SubSpacePartWidget extends StatefulWidget { + SubSpacePartWidget({ + super.key, + required this.subspaces, + required this.onPressed, + required this.isTagsAndSubspaceModelDisabled, + required this.screenWidth, + required this.editChipOnTap, + }); + double screenWidth; + bool isTagsAndSubspaceModelDisabled; + final void Function() editChipOnTap; + List? subspaces; + final void Function() onPressed; + + @override + State createState() => _SubSpacePartWidgetState(); +} + +class _SubSpacePartWidgetState extends State { + @override + Widget build(BuildContext context) { + return Column( + children: [ + widget.subspaces == null || widget.subspaces!.isEmpty + ? TextButton( + style: TextButton.styleFrom( + padding: EdgeInsets.zero, + overlayColor: ColorsManager.transparentColor, + ), + onPressed: widget.onPressed, + child: ButtonContentWidget( + icon: Icons.add, + label: 'Create Sub Spaces', + disabled: widget.isTagsAndSubspaceModelDisabled, + ), + ) + : SizedBox( + width: widget.screenWidth * 0.25, + child: Container( + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + color: ColorsManager.textFieldGreyColor, + borderRadius: BorderRadius.circular(15), + border: Border.all( + color: ColorsManager.textFieldGreyColor, + width: 3.0, // Border width + ), + ), + child: Wrap( + spacing: 8.0, + runSpacing: 8.0, + children: [ + if (widget.subspaces != null) + ...widget.subspaces!.map((subspace) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SubspaceNameDisplayWidget( + text: subspace.subspaceName, + validateName: (updatedName) { + bool nameExists = widget.subspaces!.any((s) { + bool isSameId = + s.internalId == subspace.internalId; + bool isSameName = + s.subspaceName.trim().toLowerCase() == + updatedName.trim().toLowerCase(); + + return !isSameId && isSameName; + }); + + return !nameExists; + }, + onNameChanged: (updatedName) { + setState(() { + subspace.subspaceName = updatedName; + }); + }, + ), + ], + ); + }), + EditChip( + onTap: widget.editChipOnTap, + ) + ], + ), + ), + ) + ], + ); + } +} diff --git a/lib/pages/spaces_management/all_spaces/widgets/curved_line_painter.dart b/lib/pages/spaces_management/all_spaces/widgets/curved_line_painter.dart index 2b85acfd..d8291110 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/curved_line_painter.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/curved_line_painter.dart @@ -30,28 +30,13 @@ class CurvedLinePainter extends CustomPainter { Offset end = connection.endSpace.position + const Offset(75, 0); // Center top of end space - if (connection.direction == 'down') { - // Curved line for down connections - final controlPoint = Offset((start.dx + end.dx) / 2, start.dy + 50); - final path = Path() - ..moveTo(start.dx, start.dy) - ..quadraticBezierTo(controlPoint.dx, controlPoint.dy, end.dx, end.dy); - canvas.drawPath(path, paint); - } else if (connection.direction == 'right') { - start = connection.startSpace.position + - const Offset(150, 30); // Right center - end = connection.endSpace.position + const Offset(0, 30); // Left center + // Curved line for down connections + final controlPoint = Offset((start.dx + end.dx) / 2, start.dy + 50); + final path = Path() + ..moveTo(start.dx, start.dy) + ..quadraticBezierTo(controlPoint.dx, controlPoint.dy, end.dx, end.dy); + canvas.drawPath(path, paint); - canvas.drawLine(start, end, paint); - } else if (connection.direction == 'left') { - start = - connection.startSpace.position + const Offset(0, 30); // Left center - end = connection.endSpace.position + - const Offset(150, 30); // Right center - - canvas.drawLine(start, end, paint); - } - final dotPaint = Paint()..color = ColorsManager.blackColor; canvas.drawCircle(start, 5, dotPaint); // Start dot canvas.drawCircle(end, 5, dotPaint); // End dot diff --git a/lib/pages/spaces_management/all_spaces/widgets/dialogs/create_space_dialog.dart b/lib/pages/spaces_management/all_spaces/widgets/dialogs/create_space_dialog.dart index e9dde6f8..9e2f6dbb 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/dialogs/create_space_dialog.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/dialogs/create_space_dialog.dart @@ -1,6 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:syncrow_web/common/edit_chip.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/add_device_type/views/add_device_type_widget.dart'; @@ -9,6 +7,11 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_pr import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/create_space_widgets/devices_part_widget.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/create_space_widgets/icon_choose_part_widget.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/create_space_widgets/space_model_linking_widget.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/create_space_widgets/space_name_textfield_widget.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/create_space_widgets/sub_space_part_widget.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/dialogs/icon_selection_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/assign_tag/views/assign_tag_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/create_subspace/views/create_subspace_model_dialog.dart'; @@ -16,8 +19,6 @@ import 'package:syncrow_web/pages/spaces_management/helper/space_helper.dart'; import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart'; import 'package:syncrow_web/pages/spaces_management/link_space_model/view/link_space_model_dialog.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/subspace_name_label_widget.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/space_icon_const.dart'; @@ -82,8 +83,10 @@ class CreateSpaceDialogState extends State { super.initState(); selectedIcon = widget.icon ?? Assets.location; nameController = TextEditingController(text: widget.name ?? ''); - selectedProducts = widget.selectedProducts.isNotEmpty ? widget.selectedProducts : []; - isOkButtonEnabled = enteredName.isNotEmpty || nameController.text.isNotEmpty; + selectedProducts = + widget.selectedProducts.isNotEmpty ? widget.selectedProducts : []; + isOkButtonEnabled = + enteredName.isNotEmpty || nameController.text.isNotEmpty; if (widget.currentSpaceModel != null) { subspaces = []; tags = []; @@ -96,13 +99,15 @@ class CreateSpaceDialogState extends State { @override Widget build(BuildContext context) { - bool isSpaceModelDisabled = - (tags != null && tags!.isNotEmpty || subspaces != null && subspaces!.isNotEmpty); + bool isSpaceModelDisabled = (tags != null && tags!.isNotEmpty || + subspaces != null && subspaces!.isNotEmpty); bool isTagsAndSubspaceModelDisabled = (selectedSpaceModel != null); final screenWidth = MediaQuery.of(context).size.width; return AlertDialog( - title: widget.isEdit ? const Text('Edit Space') : const Text('Create New Space'), + title: widget.isEdit + ? const Text('Edit Space') + : const Text('Create New Space'), backgroundColor: ColorsManager.whiteColors, content: SizedBox( width: screenWidth * 0.5, @@ -112,50 +117,10 @@ class CreateSpaceDialogState extends State { children: [ Expanded( flex: 1, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - // crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 50), - Stack( - alignment: Alignment.center, - children: [ - Container( - width: screenWidth * 0.1, - height: screenWidth * 0.1, - decoration: const BoxDecoration( - color: ColorsManager.boxColor, - shape: BoxShape.circle, - ), - ), - SvgPicture.asset( - selectedIcon, - width: screenWidth * 0.04, - height: screenWidth * 0.04, - ), - Positioned( - top: 20, - right: 20, - child: InkWell( - onTap: _showIconSelectionDialog, - child: Container( - width: 24, - height: 24, - decoration: const BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, - ), - child: SvgPicture.asset( - Assets.iconEdit, - width: 16, - height: 16, - ), - ), - ), - ), - ], - ), - ], + child: IconChoosePartWidget( + selectedIcon: selectedIcon, + showIconSelection: _showIconSelectionDialog, + screenWidth: screenWidth, ), ), const SizedBox(width: 20), @@ -164,342 +129,146 @@ class CreateSpaceDialogState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - width: screenWidth * 0.25, - child: TextField( - controller: nameController, - onChanged: (value) { - enteredName = value.trim(); - setState(() { - isNameFieldExist = false; - isOkButtonEnabled = false; - isNameFieldInvalid = value.isEmpty; + SpaceNameTextfieldWidget( + isNameFieldExist: isNameFieldExist, + isNameFieldInvalid: isNameFieldInvalid, + nameController: nameController, + screenWidth: screenWidth, + onChange: (value) { + enteredName = value.trim(); + setState(() { + isNameFieldExist = false; + isOkButtonEnabled = false; + isNameFieldInvalid = value.isEmpty; - if (!isNameFieldInvalid) { - if (SpaceHelper.isNameConflict( - value, widget.parentSpace, widget.editSpace)) { - isNameFieldExist = true; - isOkButtonEnabled = false; - } else { - isNameFieldExist = false; - isOkButtonEnabled = true; - } + if (!isNameFieldInvalid) { + if (SpaceHelper.isNameConflict( + value, widget.parentSpace, widget.editSpace)) { + isNameFieldExist = true; + isOkButtonEnabled = false; + } else { + isNameFieldExist = false; + isOkButtonEnabled = true; } - }); - }, - style: Theme.of(context).textTheme.bodyMedium, - decoration: InputDecoration( - hintText: 'Please enter the name', - hintStyle: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: ColorsManager.lightGrayColor), - filled: true, - fillColor: ColorsManager.boxColor, - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - borderSide: BorderSide( - color: isNameFieldInvalid || isNameFieldExist - ? ColorsManager.red - : ColorsManager.boxColor, - width: 1.5, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - borderSide: const BorderSide( - color: ColorsManager.boxColor, - width: 1.5, - ), - ), - ), - ), + } + }); + }, ), - if (isNameFieldInvalid) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Text( - '*Space name should not be empty.', - style: Theme.of(context) - .textTheme - .bodySmall - ?.copyWith(color: ColorsManager.red), - ), - ), - if (isNameFieldExist) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Text( - '*Name already exist', - style: Theme.of(context) - .textTheme - .bodySmall - ?.copyWith(color: ColorsManager.red), - ), - ), const SizedBox(height: 10), - selectedSpaceModel == null - ? TextButton( - style: TextButton.styleFrom( - padding: EdgeInsets.zero, - ), - onPressed: () { - isSpaceModelDisabled ? null : _showLinkSpaceModelDialog(context); - }, - child: ButtonContentWidget( - svgAssets: Assets.link, - label: 'Link a space model', - disabled: isSpaceModelDisabled, - ), - ) - : Container( - width: screenWidth * 0.25, - padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 16.0), - decoration: BoxDecoration( - color: ColorsManager.boxColor, - borderRadius: BorderRadius.circular(10), - ), - child: Wrap( - spacing: 8.0, - runSpacing: 8.0, - children: [ - Chip( - label: Text( - selectedSpaceModel?.modelName ?? '', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: ColorsManager.spaceColor), - ), - backgroundColor: ColorsManager.whiteColors, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: const BorderSide( - color: ColorsManager.transparentColor, - width: 0, - ), - ), - deleteIcon: Container( - width: 24, - height: 24, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: ColorsManager.lightGrayColor, - width: 1.5, - ), - ), - child: const Icon( - Icons.close, - size: 16, - color: ColorsManager.lightGrayColor, - ), - ), - onDeleted: () => setState(() { - this.selectedSpaceModel = null; - subspaces = widget.subspaces ?? []; - tags = widget.tags ?? []; - })), - ], - ), - ), + // SpaceModelLinkingWidget( + // isSpaceModelDisabled: true, + // // isSpaceModelDisabled, + // onPressed: () { + // isSpaceModelDisabled + // ? null + // : _showLinkSpaceModelDialog(context); + // }, + // onDeleted: () => setState(() { + // selectedSpaceModel = null; + // subspaces = widget.subspaces ?? []; + // tags = widget.tags ?? []; + // }), + // screenWidth: screenWidth, + // selectedSpaceModel: selectedSpaceModel, + // ), const SizedBox(height: 25), - Row( - children: [ - const Expanded( - child: Divider( - color: ColorsManager.neutralGray, - thickness: 1.0, - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 6.0), - child: Text( - 'OR', - style: Theme.of(context) - .textTheme - .bodyMedium - ?.copyWith(fontWeight: FontWeight.bold), - ), - ), - const Expanded( - child: Divider( - color: ColorsManager.neutralGray, - thickness: 1.0, - ), - ), - ], + // Row( + // children: [ + // const Expanded( + // child: Divider( + // color: ColorsManager.neutralGray, + // thickness: 1.0, + // ), + // ), + // Padding( + // padding: const EdgeInsets.symmetric(horizontal: 6.0), + // child: Text( + // 'OR', + // style: Theme.of(context) + // .textTheme + // .bodyMedium + // ?.copyWith(fontWeight: FontWeight.bold), + // ), + // ), + // const Expanded( + // child: Divider( + // color: ColorsManager.neutralGray, + // thickness: 1.0, + // ), + // ), + // ], + // ), + const SizedBox(height: 25), + SubSpacePartWidget( + subspaces: subspaces, + onPressed: () { + isTagsAndSubspaceModelDisabled + ? null + : _showSubSpaceDialog( + context, + enteredName, + [], + false, + widget.products, + subspaces, + ); + }, + isTagsAndSubspaceModelDisabled: + isTagsAndSubspaceModelDisabled, + screenWidth: screenWidth, + editChipOnTap: () async { + _showSubSpaceDialog( + context, + enteredName, + [], + true, + widget.products, + subspaces, + ); + }, ), - const SizedBox(height: 25), - subspaces == null || subspaces!.isEmpty - ? TextButton( - style: TextButton.styleFrom( - padding: EdgeInsets.zero, - overlayColor: ColorsManager.transparentColor, - ), - onPressed: () async { - isTagsAndSubspaceModelDisabled - ? null - : _showSubSpaceDialog( - context, enteredName, [], false, widget.products, subspaces); - }, - child: ButtonContentWidget( - icon: Icons.add, - label: 'Create Sub Space', - disabled: isTagsAndSubspaceModelDisabled, - ), - ) - : SizedBox( - width: screenWidth * 0.25, - child: Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: ColorsManager.textFieldGreyColor, - borderRadius: BorderRadius.circular(15), - border: Border.all( - color: ColorsManager.textFieldGreyColor, - width: 3.0, // Border width - ), - ), - child: Wrap( - spacing: 8.0, - runSpacing: 8.0, - children: [ - if (subspaces != null) - ...subspaces!.map((subspace) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SubspaceNameDisplayWidget( - text: subspace.subspaceName, - validateName: (updatedName) { - bool nameExists = subspaces!.any((s) { - bool isSameId = s.internalId == subspace.internalId; - bool isSameName = - s.subspaceName.trim().toLowerCase() == - updatedName.trim().toLowerCase(); - - return !isSameId && isSameName; - }); - - return !nameExists; - }, - onNameChanged: (updatedName) { - setState(() { - subspace.subspaceName = updatedName; - }); - }, - ), - ], - ); - }), - EditChip( - onTap: () async { - _showSubSpaceDialog(context, enteredName, [], true, - widget.products, subspaces); - }, - ) - ], - ), - ), - ), const SizedBox(height: 10), - (tags?.isNotEmpty == true || - subspaces?.any((subspace) => subspace.tags?.isNotEmpty == true) == true) - ? SizedBox( - width: screenWidth * 0.25, - child: Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: ColorsManager.textFieldGreyColor, - borderRadius: BorderRadius.circular(15), - border: Border.all( - color: ColorsManager.textFieldGreyColor, - width: 3.0, // Border width - ), - ), - child: Wrap( - spacing: 8.0, - runSpacing: 8.0, - children: [ - // Combine tags from spaceModel and subspaces - ...TagHelper.groupTags([ - ...?tags, - ...?subspaces?.expand((subspace) => subspace.tags ?? []) - ]).entries.map( - (entry) => Chip( - avatar: SizedBox( - width: 24, - height: 24, - child: SvgPicture.asset( - entry.key.icon ?? 'assets/icons/gateway.svg', - fit: BoxFit.contain, - ), - ), - label: Text( - 'x${entry.value}', // Show count - style: Theme.of(context) - .textTheme - .bodySmall - ?.copyWith(color: ColorsManager.spaceColor), - ), - backgroundColor: ColorsManager.whiteColors, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - side: const BorderSide( - color: ColorsManager.spaceColor, - ), - ), - ), - ), - - EditChip(onTap: () async { - await showDialog( - context: context, - builder: (context) => AssignTagDialog( - products: widget.products, - subspaces: subspaces, - allTags: widget.allTags, - addedProducts: - TagHelper.createInitialSelectedProductsForTags( - tags ?? [], subspaces), - title: 'Edit Device', - initialTags: TagHelper.generateInitialForTags( - spaceTags: tags, subspaces: subspaces), - spaceName: widget.name ?? '', - projectTags: widget.projectTags, - onSave: (updatedTags, updatedSubspaces) { - setState(() { - tags = updatedTags; - subspaces = updatedSubspaces; - }); - }, - ), - ); - }) - ], - ), - ), - ) - : TextButton( - onPressed: () { - isTagsAndSubspaceModelDisabled - ? null - : _showTagCreateDialog( - context, - enteredName, - widget.isEdit, - widget.products, - ); + DevicesPartWidget( + tags: tags, + subspaces: subspaces, + screenWidth: screenWidth, + isTagsAndSubspaceModelDisabled: + isTagsAndSubspaceModelDisabled, + onEditChip: () async { + await showDialog( + context: context, + builder: (context) => AssignTagDialog( + products: widget.products, + subspaces: subspaces, + allTags: widget.allTags, + addedProducts: + TagHelper.createInitialSelectedProductsForTags( + tags ?? [], subspaces), + title: 'Edit Device', + initialTags: TagHelper.generateInitialForTags( + spaceTags: tags, subspaces: subspaces), + spaceName: widget.name ?? '', + projectTags: widget.projectTags, + onSave: (updatedTags, updatedSubspaces) { + setState(() { + tags = updatedTags; + subspaces = updatedSubspaces; + }); }, - style: TextButton.styleFrom( - padding: EdgeInsets.zero, - ), - child: ButtonContentWidget( - icon: Icons.add, - label: 'Add Devices', - disabled: isTagsAndSubspaceModelDisabled, - )) + ), + ); + }, + onTextButtonPressed: () { + isTagsAndSubspaceModelDisabled + ? null + : _showTagCreateDialog( + context, + enteredName, + widget.isEdit, + widget.products, + ); + }, + ) ], ), ), @@ -529,17 +298,32 @@ class CreateSpaceDialogState extends State { } else if (isNameFieldExist) { return; } else { - String newName = enteredName.isNotEmpty ? enteredName : (widget.name ?? ''); + String newName = enteredName.isNotEmpty + ? enteredName + : (widget.name ?? ''); if (newName.isNotEmpty) { - widget.onCreateSpace(newName, selectedIcon, selectedProducts, - selectedSpaceModel, subspaces, tags); + if (tags != null && tags!.isNotEmpty) { + if (tags!.any( + (tag) => tag.uuid == null || tag.uuid!.isEmpty, + )) { + return; + } + } + widget.onCreateSpace( + newName, + selectedIcon, + selectedProducts, + selectedSpaceModel, + subspaces, + tags); Navigator.of(context).pop(); } } }, borderRadius: 10, - backgroundColor: - isOkButtonEnabled ? ColorsManager.secondaryColor : ColorsManager.grayColor, + backgroundColor: isOkButtonEnabled + ? ColorsManager.secondaryColor + : ColorsManager.grayColor, foregroundColor: ColorsManager.whiteColors, child: const Text('OK'), ), @@ -550,6 +334,7 @@ class CreateSpaceDialogState extends State { ); } +//dialooogggs void _showIconSelectionDialog() { showDialog( context: context, @@ -586,26 +371,50 @@ class CreateSpaceDialogState extends State { ); } - void _showSubSpaceDialog(BuildContext context, String name, final List? spaceTags, - bool isEdit, List? products, final List? existingSubSpaces) { + void _showSubSpaceDialog( + BuildContext context, + String name, + final List? spaceTags, + bool isEdit, + List? products, + final List? existingSubSpaces, + ) { showDialog( context: context, builder: (BuildContext context) { return CreateSubSpaceDialog( spaceName: name, - dialogTitle: isEdit ? 'Edit Sub-space' : 'Create Sub-space', + dialogTitle: isEdit ? 'Edit Sub-spaces' : 'Create Sub-spaces', products: products, existingSubSpaces: existingSubSpaces, - onSave: (slectedSubspaces) { + onSave: (slectedSubspaces, updatedSubSpaces) { final List tagsToAppendToSpace = []; - if (slectedSubspaces != null) { - final updatedIds = slectedSubspaces.map((s) => s.internalId).toSet(); + if (slectedSubspaces != null && slectedSubspaces.isNotEmpty) { + final updatedIds = + slectedSubspaces.map((s) => s.internalId).toSet(); if (existingSubSpaces != null) { - final deletedSubspaces = - existingSubSpaces.where((s) => !updatedIds.contains(s.internalId)).toList(); + final deletedSubspaces = existingSubSpaces + .where((s) => !updatedIds.contains(s.internalId)) + .toList(); for (var s in deletedSubspaces) { if (s.tags != null) { + s.tags!.forEach( + (tag) => tag.location = null, + ); + tagsToAppendToSpace.addAll(s.tags!); + } + } + } + } else { + if (existingSubSpaces != null) { + final deletedSubspaces = existingSubSpaces; + + for (var s in deletedSubspaces) { + if (s.tags != null) { + s.tags!.forEach( + (tag) => tag.location = null, + ); tagsToAppendToSpace.addAll(s.tags!); } } @@ -623,15 +432,16 @@ class CreateSpaceDialogState extends State { ); } - void _showTagCreateDialog( - BuildContext context, String name, bool isEdit, List? products) { + void _showTagCreateDialog(BuildContext context, String name, bool isEdit, + List? products) { isEdit ? showDialog( context: context, builder: (BuildContext context) { return AssignTagDialog( title: 'Edit Device', - addedProducts: TagHelper.createInitialSelectedProductsForTags(tags, subspaces), + addedProducts: TagHelper.createInitialSelectedProductsForTags( + tags, subspaces), spaceName: name, products: products, subspaces: subspaces, @@ -646,7 +456,8 @@ class CreateSpaceDialogState extends State { if (subspaces != null) { for (final subspace in subspaces!) { for (final selectedSubspace in selectedSubspaces) { - if (subspace.subspaceName == selectedSubspace.subspaceName) { + if (subspace.subspaceName == + selectedSubspace.subspaceName) { subspace.tags = selectedSubspace.tags; } } @@ -670,7 +481,8 @@ class CreateSpaceDialogState extends State { allTags: widget.allTags, projectTags: widget.projectTags, initialSelectedProducts: - TagHelper.createInitialSelectedProductsForTags(tags, subspaces), + TagHelper.createInitialSelectedProductsForTags( + tags, subspaces), onSave: (selectedSpaceTags, selectedSubspaces) { setState(() { tags = selectedSpaceTags; @@ -680,7 +492,8 @@ class CreateSpaceDialogState extends State { if (subspaces != null) { for (final subspace in subspaces!) { for (final selectedSubspace in selectedSubspaces) { - if (subspace.subspaceName == selectedSubspace.subspaceName) { + if (subspace.subspaceName == + selectedSubspace.subspaceName) { subspace.tags = selectedSubspace.tags; } } diff --git a/lib/pages/spaces_management/all_spaces/widgets/plus_button_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/plus_button_widget.dart index 40be7284..6c5babaf 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/plus_button_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/plus_button_widget.dart @@ -5,7 +5,7 @@ class PlusButtonWidget extends StatelessWidget { final int index; final String direction; final Offset offset; - final Function(int index, Offset newPosition, String direction) onButtonTap; + final Function(int index, Offset newPosition) onButtonTap; const PlusButtonWidget({ super.key, @@ -17,35 +17,21 @@ class PlusButtonWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return Positioned( - left: offset.dx, - top: offset.dy, - child: GestureDetector( - onTap: () { - Offset newPosition; - switch (direction) { - case 'left': - newPosition = const Offset(-200, 0); - break; - case 'right': - newPosition = const Offset(200, 0); - break; - case 'down': - newPosition = const Offset(0, 150); - break; - default: - newPosition = Offset.zero; - } - onButtonTap(index, newPosition, direction); - }, - child: Container( - width: 30, - height: 30, - decoration: const BoxDecoration( - color: ColorsManager.spaceColor, - shape: BoxShape.circle, - ), - child: const Icon(Icons.add, color: ColorsManager.whiteColors, size: 20), + return GestureDetector( + onTap: () { + onButtonTap(index, const Offset(0, 150)); + }, + child: Container( + width: 30, + height: 30, + decoration: const BoxDecoration( + color: ColorsManager.spaceColor, + shape: BoxShape.circle, + ), + child: const Icon( + Icons.add, + color: ColorsManager.whiteColors, + size: 20, ), ), ); diff --git a/lib/pages/spaces_management/all_spaces/widgets/space_card_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/space_card_widget.dart index f3a476b2..7e6e132f 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/space_card_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/space_card_widget.dart @@ -7,7 +7,7 @@ class SpaceCardWidget extends StatelessWidget { final Offset position; final bool isHovered; final Function(int index, bool isHovered) onHoverChanged; - final Function(int index, Offset newPosition, String direction) onButtonTap; + final Function(int index, Offset newPosition) onButtonTap; final Widget Function(int index) buildSpaceContainer; final ValueChanged onPositionChanged; @@ -25,35 +25,34 @@ class SpaceCardWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return GestureDetector( - behavior: HitTestBehavior.opaque, - onPanUpdate: (details) { - // Call the provided callback to update the position - final newPosition = position + details.delta; - onPositionChanged(newPosition); - }, - child: MouseRegion( - onEnter: (_) { - // Call the provided callback to handle hover state - onHoverChanged(index, true); - }, - onExit: (_) { - // Call the provided callback to handle hover state - onHoverChanged(index, false); - }, + return MouseRegion( + onEnter: (_) => onHoverChanged(index, true), + onExit: (_) => onHoverChanged(index, false), + child: SizedBox( + width: 140, // Make sure this covers both card and plus button + height: 90, child: Stack( - clipBehavior: Clip - .none, // Allow hovering elements to be displayed outside the boundary + clipBehavior: Clip.none, children: [ - buildSpaceContainer(index), // Build the space container - if (isHovered) ...[ - PlusButtonWidget( - index: index, - direction: 'down', - offset: const Offset(63, 50), - onButtonTap: onButtonTap, + // Main card + Container( + width: 140, + height: 80, + alignment: Alignment.center, + color: Colors.transparent, + child: buildSpaceContainer(index), + ), + // Plus button (NO inner Positioned!) + if (isHovered) + Align( + alignment: Alignment.bottomCenter, + child: PlusButtonWidget( + index: index, + direction: 'down', + offset: Offset.zero, + onButtonTap: onButtonTap, + ), ), - ], ], ), ), diff --git a/lib/pages/spaces_management/assign_tag/bloc/assign_tag_bloc.dart b/lib/pages/spaces_management/assign_tag/bloc/assign_tag_bloc.dart index 74161b6f..afc0c852 100644 --- a/lib/pages/spaces_management/assign_tag/bloc/assign_tag_bloc.dart +++ b/lib/pages/spaces_management/assign_tag/bloc/assign_tag_bloc.dart @@ -13,7 +13,8 @@ class AssignTagBloc extends Bloc { final existingTagCounts = {}; for (var tag in initialTags) { if (tag.product != null) { - existingTagCounts[tag.product!.uuid] = (existingTagCounts[tag.product!.uuid] ?? 0) + 1; + existingTagCounts[tag.product!.uuid] = + (existingTagCounts[tag.product!.uuid] ?? 0) + 1; } } @@ -22,14 +23,17 @@ class AssignTagBloc extends Bloc { for (var selectedProduct in event.addedProducts) { final existingCount = existingTagCounts[selectedProduct.productId] ?? 0; - if (selectedProduct.count == 0 || selectedProduct.count <= existingCount) { - tags.addAll(initialTags.where((tag) => tag.product?.uuid == selectedProduct.productId)); + if (selectedProduct.count == 0 || + selectedProduct.count <= existingCount) { + tags.addAll(initialTags + .where((tag) => tag.product?.uuid == selectedProduct.productId)); continue; } final missingCount = selectedProduct.count - existingCount; - tags.addAll(initialTags.where((tag) => tag.product?.uuid == selectedProduct.productId)); + tags.addAll(initialTags + .where((tag) => tag.product?.uuid == selectedProduct.productId)); if (missingCount > 0) { tags.addAll(List.generate( @@ -85,7 +89,8 @@ class AssignTagBloc extends Bloc { final tags = List.from(currentState.tags); // Update the location - tags[event.index] = tags[event.index].copyWith(location: event.location); + tags[event.index] = + tags[event.index].copyWith(location: event.location); final updatedTags = _calculateAvailableTags(projectTags, tags); @@ -117,7 +122,8 @@ class AssignTagBloc extends Bloc { final currentState = state; if (currentState is AssignTagLoaded && currentState.tags.isNotEmpty) { - final tags = List.from(currentState.tags)..remove(event.tagToDelete); + final tags = List.from(currentState.tags) + ..remove(event.tagToDelete); // Recalculate available tags final updatedTags = _calculateAvailableTags(projectTags, tags); @@ -141,8 +147,10 @@ class AssignTagBloc extends Bloc { // Get validation error for duplicate tags String? _getValidationError(List tags) { - final nonEmptyTags = - tags.map((tag) => tag.tag?.trim() ?? '').where((tag) => tag.isNotEmpty).toList(); + final nonEmptyTags = tags + .map((tag) => tag.tag?.trim() ?? '') + .where((tag) => tag.isNotEmpty) + .toList(); final duplicateTags = nonEmptyTags .fold>({}, (map, tag) { @@ -168,9 +176,11 @@ class AssignTagBloc extends Bloc { .toSet(); final availableTags = allTags - .where((tag) => tag.tag != null && !selectedTagSet.contains(tag.tag!.trim())) + .where((tag) => + tag.tag != null && !selectedTagSet.contains(tag.tag!.trim())) .toList(); - return availableTags; + return projectTags; + // availableTags; } } diff --git a/lib/pages/spaces_management/assign_tag/views/assign_tag_dialog.dart b/lib/pages/spaces_management/assign_tag/views/assign_tag_dialog.dart index fd1454e5..21ba141c 100644 --- a/lib/pages/spaces_management/assign_tag/views/assign_tag_dialog.dart +++ b/lib/pages/spaces_management/assign_tag/views/assign_tag_dialog.dart @@ -1,10 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/common/dialog_dropdown.dart'; -import 'package:syncrow_web/common/tag_dialog_textfield_dropdown.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/add_device_type/views/add_device_type_widget.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/model/subspace_model.dart'; @@ -12,9 +7,10 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart'; import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_event.dart'; import 'package:syncrow_web/pages/spaces_management/assign_tag/bloc/assign_tag_state.dart'; -import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart'; +import 'package:syncrow_web/pages/spaces_management/assign_tag_models/views/widgets/assign_tags_tables_widget.dart'; import 'package:syncrow_web/utils/color_manager.dart'; -import 'package:uuid/uuid.dart'; + +import 'widgets/save_add_device_row_widget.dart'; class AssignTagDialog extends StatelessWidget { final List? products; @@ -29,7 +25,7 @@ class AssignTagDialog extends StatelessWidget { final List projectTags; const AssignTagDialog( - {Key? key, + {super.key, required this.products, required this.subspaces, required this.addedProducts, @@ -39,13 +35,14 @@ class AssignTagDialog extends StatelessWidget { required this.spaceName, required this.title, this.onSave, - required this.projectTags}) - : super(key: key); + required this.projectTags}); @override Widget build(BuildContext context) { - final List locations = - (subspaces ?? []).map((subspace) => subspace.subspaceName).toList()..add('Main Space'); + final List locations = (subspaces ?? []) + .map((subspace) => subspace.subspaceName) + .toList() + ..add('Main Space'); return BlocProvider( create: (_) => AssignTagBloc(projectTags) @@ -67,131 +64,31 @@ class AssignTagDialog extends StatelessWidget { content: SingleChildScrollView( child: Column( children: [ - ClipRRect( - borderRadius: BorderRadius.circular(20), - child: DataTable( - headingRowColor: WidgetStateProperty.all(ColorsManager.dataHeaderGrey), - key: ValueKey(state.tags.length), - border: TableBorder.all( - color: ColorsManager.dataHeaderGrey, - width: 1, - borderRadius: BorderRadius.circular(20), - ), - columns: [ - DataColumn( - label: Text('#', style: Theme.of(context).textTheme.bodyMedium)), - DataColumn( - label: Text('Device', style: Theme.of(context).textTheme.bodyMedium)), - DataColumn( - numeric: false, - label: Text('Tag', style: Theme.of(context).textTheme.bodyMedium)), - DataColumn( - label: - Text('Location', style: Theme.of(context).textTheme.bodyMedium)), - ], - rows: state.tags.isEmpty - ? [ - DataRow(cells: [ - DataCell( - Center( - child: Text('No Data Available', - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: ColorsManager.lightGrayColor, - )), - ), - ), - const DataCell(SizedBox()), - const DataCell(SizedBox()), - const DataCell(SizedBox()), - ]) - ] - : List.generate(state.tags.length, (index) { - final tag = state.tags[index]; - final controller = controllers[index]; + AssignTagsTable( + controllers: controllers, + locations: locations, + tags: state.tags, + updatedTags: state.updatedTags, + onDeleteDevice: ({required index, required tag}) { + context + .read() + .add(DeleteTag(tagToDelete: tag, tags: state.tags)); - return DataRow( - cells: [ - DataCell(Text((index + 1).toString())), - DataCell( - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - tag.product?.name ?? 'Unknown', - overflow: TextOverflow.ellipsis, - )), - const SizedBox(width: 10), - Container( - width: 20.0, - height: 20.0, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: ColorsManager.lightGrayColor, - width: 1.0, - ), - ), - child: IconButton( - icon: const Icon( - Icons.close, - color: ColorsManager.lightGreyColor, - size: 16, - ), - onPressed: () { - context.read().add( - DeleteTag(tagToDelete: tag, tags: state.tags)); - - controllers.removeAt(index); - }, - tooltip: 'Delete Tag', - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - ), - ), - ], - ), - ), - DataCell( - Container( - alignment: - Alignment.centerLeft, // Align cell content to the left - child: SizedBox( - width: double.infinity, - child: TagDialogTextfieldDropdown( - key: ValueKey('dropdown_${const Uuid().v4()}_$index'), - items: state.updatedTags, - product: tag.product?.uuid ?? 'Unknown', - initialValue: tag, - onSelected: (value) { - controller.text = value.tag ?? ''; - context.read().add(UpdateTagEvent( - index: index, - tag: value, - )); - }, - ), - ), - ), - ), - DataCell( - SizedBox( - width: double.infinity, - child: DialogDropdown( - items: locations, - selectedValue: tag.location ?? 'Main Space', - onSelected: (value) { - context.read().add(UpdateLocation( - index: index, - location: value, - )); - }, - )), - ), - ], - ); - }), - ), + controllers.removeAt(index); + }, + onTagDropDownSelected: ({required index, required tag}) { + context.read().add(UpdateTagEvent( + index: index, + tag: tag, + )); + }, + onLocationDropDownSelected: ( + {required index, required location}) { + context.read().add(UpdateLocation( + index: index, + location: location, + )); + }, ), if (state.errorMessage != null) Text(state.errorMessage!, @@ -203,69 +100,15 @@ class AssignTagDialog extends StatelessWidget { ), ), actions: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - const SizedBox(width: 10), - Expanded( - child: Builder( - builder: (buttonContext) => CancelButton( - label: 'Add New Device', - onPressed: () async { - final updatedTags = List.from(state.tags); - final result = TagHelper.processTags(updatedTags, subspaces); - - final processedTags = result['updatedTags'] as List; - final processedSubspaces = - List.from(result['subspaces'] as List); - - Navigator.of(context).pop(); - - await showDialog( - context: context, - builder: (context) => AddDeviceTypeWidget( - products: products, - subspaces: processedSubspaces, - projectTags: projectTags, - initialSelectedProducts: - TagHelper.createInitialSelectedProductsForTags( - processedTags, processedSubspaces), - spaceName: spaceName, - spaceTags: processedTags, - isCreate: false, - onSave: onSave, - allTags: allTags, - ), - ); - }, - ), - ), - ), - const SizedBox(width: 10), - Expanded( - child: DefaultButton( - borderRadius: 10, - backgroundColor: ColorsManager.secondaryColor, - foregroundColor: state.isSaveEnabled - ? ColorsManager.whiteColors - : ColorsManager.whiteColorsWithOpacity, - onPressed: state.isSaveEnabled - ? () async { - final updatedTags = List.from(state.tags); - final result = TagHelper.processTags(updatedTags, subspaces); - - final processedTags = result['updatedTags'] as List; - final processedSubspaces = - List.from(result['subspaces'] as List); - onSave?.call(processedTags, processedSubspaces); - Navigator.of(context).pop(); - } - : null, - child: const Text('Save'), - ), - ), - const SizedBox(width: 10), - ], + SaveAddDeviceRowWidget( + subspaces: subspaces, + products: products, + projectTags: projectTags, + spaceName: spaceName, + onSave: onSave, + allTags: allTags, + tags: state.tags, + isSaveEnabled: state.isSaveEnabled, ), ], ); diff --git a/lib/pages/spaces_management/assign_tag/views/widgets/save_add_device_row_widget.dart b/lib/pages/spaces_management/assign_tag/views/widgets/save_add_device_row_widget.dart new file mode 100644 index 00000000..a81b7ad0 --- /dev/null +++ b/lib/pages/spaces_management/assign_tag/views/widgets/save_add_device_row_widget.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/product_model.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_model.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.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/utils/color_manager.dart'; + +import '../../../add_device_type/views/add_device_type_widget.dart'; +import '../../../helper/tag_helper.dart'; + +class SaveAddDeviceRowWidget extends StatelessWidget { + const SaveAddDeviceRowWidget({ + super.key, + required this.subspaces, + required this.products, + required this.projectTags, + required this.spaceName, + required this.onSave, + required this.allTags, + required this.tags, + required this.isSaveEnabled, + }); + final List tags; + final List? subspaces; + final List? products; + final List projectTags; + final String spaceName; + final Function(List p1, List? p2)? onSave; + final List? allTags; + final bool isSaveEnabled; + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + const SizedBox(width: 10), + Expanded( + child: Builder( + builder: (buttonContext) => CancelButton( + label: 'Add New Device', + onPressed: () async { + final updatedTags = List.from(tags); + final result = TagHelper.processTags(updatedTags, subspaces); + + final processedTags = result['updatedTags'] as List; + final processedSubspaces = List.from( + result['subspaces'] as List); + + Navigator.of(context).pop(); + + await showDialog( + context: context, + builder: (context) => AddDeviceTypeWidget( + products: products, + subspaces: processedSubspaces, + projectTags: projectTags, + initialSelectedProducts: + TagHelper.createInitialSelectedProductsForTags( + processedTags, processedSubspaces), + spaceName: spaceName, + spaceTags: processedTags, + isCreate: false, + onSave: onSave, + allTags: allTags, + ), + ); + }, + ), + ), + ), + const SizedBox(width: 10), + Expanded( + child: DefaultButton( + borderRadius: 10, + backgroundColor: ColorsManager.secondaryColor, + foregroundColor: isSaveEnabled + ? ColorsManager.whiteColors + : ColorsManager.whiteColorsWithOpacity, + onPressed: isSaveEnabled + ? () async { + final updatedTags = List.from(tags); + final result = + TagHelper.processTags(updatedTags, subspaces); + + final processedTags = result['updatedTags'] as List; + final processedSubspaces = List.from( + result['subspaces'] as List); + onSave?.call(processedTags, processedSubspaces); + Navigator.of(context).pop(); + } + : null, + child: const Text('Save'), + ), + ), + const SizedBox(width: 10), + ], + ); + } +} diff --git a/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart b/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart index 85be3bf3..57ed93df 100644 --- a/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart +++ b/lib/pages/spaces_management/assign_tag_models/views/assign_tag_models_dialog.dart @@ -1,9 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/common/dialog_dropdown.dart'; -import 'package:syncrow_web/common/tag_dialog_textfield_dropdown.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/model/selected_product_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart'; @@ -12,11 +8,10 @@ import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assig import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_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/pages/spaces_management/space_model/widgets/dialog/create_space_model_dialog.dart'; -import 'package:syncrow_web/pages/spaces_management/tag_model/views/add_device_type_model_widget.dart'; import 'package:syncrow_web/utils/color_manager.dart'; -import 'package:syncrow_web/pages/spaces_management/helper/tag_helper.dart'; -import 'package:uuid/uuid.dart'; + +import 'widgets/RowOfCancelSaveWidget.dart'; +import 'widgets/assign_tags_tables_widget.dart'; class AssignTagModelsDialog extends StatelessWidget { final List? products; @@ -53,8 +48,10 @@ class AssignTagModelsDialog extends StatelessWidget { @override Widget build(BuildContext context) { - final List locations = - (subspaces ?? []).map((subspace) => subspace.subspaceName).toList()..add('Main Space'); + final List locations = (subspaces ?? []) + .map((subspace) => subspace.subspaceName) + .toList() + ..add('Main Space'); return BlocProvider( create: (_) => AssignTagModelBloc(projectTags) @@ -78,137 +75,38 @@ class AssignTagModelsDialog extends StatelessWidget { content: SingleChildScrollView( child: Column( children: [ - ClipRRect( - borderRadius: BorderRadius.circular(20), - child: DataTable( - headingRowColor: WidgetStateProperty.all(ColorsManager.dataHeaderGrey), - key: ValueKey(state.tags.length), - border: TableBorder.all( - color: ColorsManager.dataHeaderGrey, - width: 1, - borderRadius: BorderRadius.circular(20), - ), - columns: [ - DataColumn( - label: Text('#', style: Theme.of(context).textTheme.bodyMedium)), - DataColumn( - label: Text('Device', - style: Theme.of(context).textTheme.bodyMedium)), - DataColumn( - numeric: false, - label: - Text('Tag', style: Theme.of(context).textTheme.bodyMedium)), - DataColumn( - label: Text('Location', - style: Theme.of(context).textTheme.bodyMedium)), - ], - rows: state.tags.isEmpty - ? [ - DataRow(cells: [ - DataCell( - Center( - child: Text('No Devices Available', - style: - Theme.of(context).textTheme.bodyMedium?.copyWith( - color: ColorsManager.lightGrayColor, - )), - ), - ), - const DataCell(SizedBox()), - const DataCell(SizedBox()), - const DataCell(SizedBox()), - ]) - ] - : List.generate(state.tags.length, (index) { - final tag = state.tags[index]; - final controller = controllers[index]; - - return DataRow( - cells: [ - DataCell(Text((index + 1).toString())), - DataCell( - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - tag.product?.name ?? 'Unknown', - overflow: TextOverflow.ellipsis, - )), - const SizedBox(width: 10), - Container( - width: 20.0, - height: 20.0, - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - color: ColorsManager.lightGrayColor, - width: 1.0, - ), - ), - child: IconButton( - icon: const Icon( - Icons.close, - color: ColorsManager.lightGreyColor, - size: 16, - ), - onPressed: () { - context.read().add( - DeleteTagModel( - tagToDelete: tag, tags: state.tags)); - controllers.removeAt(index); - }, - tooltip: 'Delete Tag', - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - ), - ), - ], - ), - ), - DataCell( - Container( - alignment: Alignment - .centerLeft, // Align cell content to the left - child: SizedBox( - width: double.infinity, - child: TagDialogTextfieldDropdown( - key: ValueKey( - 'dropdown_${const Uuid().v4()}_$index'), - product: tag.product?.uuid ?? 'Unknown', - items: state.updatedTags, - initialValue: tag, - onSelected: (value) { - controller.text = value.tag ?? ''; - context.read().add(UpdateTag( - index: index, - tag: value, - )); - }, - ), - ), - ), - ), - DataCell( - SizedBox( - width: double.infinity, - child: DialogDropdown( - items: locations, - selectedValue: tag.location ?? 'Main Space', - onSelected: (value) { - context - .read() - .add(UpdateLocation( - index: index, - location: value, - )); - }, - )), - ), - ], - ); - }), - ), + AssignTagsTable( + controllers: controllers, + locations: locations, + tags: state.tags, + updatedTags: state.updatedTags, + onDeleteDevice: ({required index, required tag}) { + context + .read() + .add(DeleteTagModel( + tagToDelete: tag, + tags: state.tags, + )); + controllers.removeAt(index); + }, + onTagDropDownSelected: ( + {required index, required tag}) { + context.read().add( + UpdateTag( + index: index, + tag: tag, + ), + ); + }, + onLocationDropDownSelected: ( + {required index, required location}) { + context.read().add( + UpdateLocation( + index: index, + location: location, + ), + ); + }, ), if (state.errorMessage != null) Text(state.errorMessage!, @@ -220,101 +118,16 @@ class AssignTagModelsDialog extends StatelessWidget { ), ), actions: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - const SizedBox(width: 10), - Expanded( - child: Builder( - builder: (buttonContext) => CancelButton( - label: 'Add New Device', - onPressed: () async { - final updatedTags = List.from(state.tags); - final result = - TagHelper.updateSubspaceTagModels(updatedTags, subspaces); - - final processedTags = result['updatedTags'] as List; - final processedSubspaces = List.from( - result['subspaces'] as List); - - if (context.mounted) { - Navigator.of(context).pop(); - - await showDialog( - barrierDismissible: false, - context: context, - builder: (dialogContext) => AddDeviceTypeModelWidget( - products: products, - subspaces: processedSubspaces, - isCreate: false, - initialSelectedProducts: - TagHelper.createInitialSelectedProducts( - processedTags, processedSubspaces), - allTags: allTags, - spaceName: spaceName, - otherSpaceModels: otherSpaceModels, - spaceTagModels: processedTags, - pageContext: pageContext, - projectTags: projectTags, - spaceModel: SpaceTemplateModel( - modelName: spaceName, - tags: updatedTags, - uuid: spaceModel?.uuid, - internalId: spaceModel?.internalId, - subspaceModels: processedSubspaces)), - ); - } - }, - ), - ), - ), - const SizedBox(width: 10), - Expanded( - child: DefaultButton( - borderRadius: 10, - backgroundColor: ColorsManager.secondaryColor, - foregroundColor: state.isSaveEnabled - ? ColorsManager.whiteColors - : ColorsManager.whiteColorsWithOpacity, - onPressed: state.isSaveEnabled - ? () async { - final updatedTags = List.from(state.tags); - - final result = - TagHelper.updateSubspaceTagModels(updatedTags, subspaces); - - final processedTags = result['updatedTags'] as List; - final processedSubspaces = List.from( - result['subspaces'] as List); - - Navigator.of(context).popUntil((route) => route.isFirst); - - await showDialog( - context: context, - builder: (BuildContext dialogContext) { - return CreateSpaceModelDialog( - products: products, - allSpaceModels: allSpaceModels, - allTags: allTags, - projectTags: projectTags, - pageContext: pageContext, - otherSpaceModels: otherSpaceModels, - spaceModel: SpaceTemplateModel( - modelName: spaceName, - tags: processedTags, - uuid: spaceModel?.uuid, - internalId: spaceModel?.internalId, - subspaceModels: processedSubspaces), - ); - }, - ); - } - : null, - child: const Text('Save'), - ), - ), - const SizedBox(width: 10), - ], + RowOfSaveCancelWidget( + subspaces: subspaces, + products: products, + allTags: allTags, + spaceName: spaceName, + otherSpaceModels: otherSpaceModels, + pageContext: pageContext, + projectTags: projectTags, + spaceModel: spaceModel, + allSpaceModels: allSpaceModels, ), ], ); diff --git a/lib/pages/spaces_management/assign_tag_models/views/widgets/RowOfCancelSaveWidget.dart b/lib/pages/spaces_management/assign_tag_models/views/widgets/RowOfCancelSaveWidget.dart new file mode 100644 index 00000000..9b2a1367 --- /dev/null +++ b/lib/pages/spaces_management/assign_tag_models/views/widgets/RowOfCancelSaveWidget.dart @@ -0,0 +1,152 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../../../../../utils/color_manager.dart'; +import '../../../../common/buttons/cancel_button.dart'; +import '../../../../common/buttons/default_button.dart'; +import '../../../all_spaces/model/product_model.dart'; +import '../../../all_spaces/model/tag.dart'; +import '../../../helper/tag_helper.dart'; +import '../../../space_model/models/space_template_model.dart'; +import '../../../space_model/models/subspace_template_model.dart'; +import '../../../space_model/widgets/dialog/create_space_model_dialog.dart'; +import '../../../tag_model/views/add_device_type_model_widget.dart'; +import '../../bloc/assign_tag_model_bloc.dart'; +import '../../bloc/assign_tag_model_state.dart'; + +class RowOfSaveCancelWidget extends StatelessWidget { + const RowOfSaveCancelWidget({ + super.key, + required this.subspaces, + required this.products, + required this.allTags, + required this.spaceName, + required this.otherSpaceModels, + required this.pageContext, + required this.projectTags, + required this.spaceModel, + required this.allSpaceModels, + }); + + final List? subspaces; + final List? products; + final List? allTags; + final String spaceName; + final List? otherSpaceModels; + final BuildContext? pageContext; + final List projectTags; + final SpaceTemplateModel? spaceModel; + final List? allSpaceModels; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is AssignTagModelLoaded) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + const SizedBox(width: 10), + Expanded( + child: Builder( + builder: (buttonContext) => CancelButton( + label: 'Add New Device', + onPressed: () async { + final updatedTags = List.from(state.tags); + final result = TagHelper.updateSubspaceTagModels( + updatedTags, subspaces); + + final processedTags = result['updatedTags'] as List; + final processedSubspaces = + List.from( + result['subspaces'] as List); + + if (context.mounted) { + Navigator.of(context).pop(); + + await showDialog( + barrierDismissible: false, + context: context, + builder: (dialogContext) => AddDeviceTypeModelWidget( + products: products, + subspaces: processedSubspaces, + isCreate: false, + initialSelectedProducts: + TagHelper.createInitialSelectedProducts( + processedTags, processedSubspaces), + allTags: allTags, + spaceName: spaceName, + otherSpaceModels: otherSpaceModels, + spaceTagModels: processedTags, + pageContext: pageContext, + projectTags: projectTags, + spaceModel: SpaceTemplateModel( + modelName: spaceName, + tags: updatedTags, + uuid: spaceModel?.uuid, + internalId: spaceModel?.internalId, + subspaceModels: processedSubspaces)), + ); + } + }, + ), + ), + ), + const SizedBox(width: 10), + Expanded( + child: DefaultButton( + borderRadius: 10, + backgroundColor: ColorsManager.secondaryColor, + foregroundColor: state.isSaveEnabled + ? ColorsManager.whiteColors + : ColorsManager.whiteColorsWithOpacity, + onPressed: state.isSaveEnabled + ? () async { + final updatedTags = List.from(state.tags); + + final result = TagHelper.updateSubspaceTagModels( + updatedTags, subspaces); + + final processedTags = + result['updatedTags'] as List; + final processedSubspaces = + List.from( + result['subspaces'] as List); + + Navigator.of(context) + .popUntil((route) => route.isFirst); + + await showDialog( + context: context, + builder: (BuildContext dialogContext) { + return CreateSpaceModelDialog( + products: products, + allSpaceModels: allSpaceModels, + allTags: allTags, + projectTags: projectTags, + pageContext: pageContext, + otherSpaceModels: otherSpaceModels, + spaceModel: SpaceTemplateModel( + modelName: spaceName, + tags: processedTags, + uuid: spaceModel?.uuid, + internalId: spaceModel?.internalId, + subspaceModels: processedSubspaces), + ); + }, + ); + } + : null, + child: const Text('Save'), + ), + ), + const SizedBox(width: 10), + ], + ); + } else { + return const SizedBox(); + } + }, + ); + } +} diff --git a/lib/pages/spaces_management/assign_tag_models/views/widgets/assign_tags_tables_widget.dart b/lib/pages/spaces_management/assign_tag_models/views/widgets/assign_tags_tables_widget.dart new file mode 100644 index 00000000..0e17a0d7 --- /dev/null +++ b/lib/pages/spaces_management/assign_tag_models/views/widgets/assign_tags_tables_widget.dart @@ -0,0 +1,155 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart'; +import 'package:uuid/uuid.dart'; + +import '../../../../../common/dialog_dropdown.dart'; +import '../../../../../common/tag_dialog_textfield_dropdown.dart'; +import '../../../../../utils/color_manager.dart'; + +class AssignTagsTable extends StatelessWidget { + const AssignTagsTable({ + super.key, + required this.controllers, + required this.locations, + required this.tags, + required this.updatedTags, + required this.onDeleteDevice, + required this.onLocationDropDownSelected, + required this.onTagDropDownSelected, + }); + final void Function({required Tag tag, required int index}) + onTagDropDownSelected; + final void Function({required String location, required int index}) + onLocationDropDownSelected; + final void Function({required Tag tag, required int index}) onDeleteDevice; + final List tags; + final List updatedTags; + final List controllers; + final List locations; + + @override + Widget build(BuildContext context) { + return ClipRRect( + borderRadius: BorderRadius.circular(20), + child: DataTable( + headingRowColor: WidgetStateProperty.all(ColorsManager.dataHeaderGrey), + key: ValueKey(tags.length), + border: TableBorder.all( + color: ColorsManager.dataHeaderGrey, + width: 1, + borderRadius: BorderRadius.circular(20), + ), + columns: [ + DataColumn( + label: Text('#', style: Theme.of(context).textTheme.bodyMedium)), + DataColumn( + label: Text('Device', + style: Theme.of(context).textTheme.bodyMedium)), + DataColumn( + numeric: false, + label: + Text('Tag', style: Theme.of(context).textTheme.bodyMedium)), + DataColumn( + label: Text('Location', + style: Theme.of(context).textTheme.bodyMedium)), + ], + rows: tags.isEmpty + ? [ + DataRow(cells: [ + DataCell( + Center( + child: Text('No Devices Available', + style: + Theme.of(context).textTheme.bodyMedium?.copyWith( + color: ColorsManager.lightGrayColor, + )), + ), + ), + const DataCell(SizedBox()), + const DataCell(SizedBox()), + const DataCell(SizedBox()), + ]) + ] + : List.generate(tags.length, (index) { + final tag = tags[index]; + final controller = controllers[index]; + + return DataRow( + cells: [ + DataCell(Text((index + 1).toString())), + DataCell( + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + tag.product?.name ?? 'Unknown', + overflow: TextOverflow.ellipsis, + )), + const SizedBox(width: 10), + Container( + width: 20.0, + height: 20.0, + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: ColorsManager.lightGrayColor, + width: 1.0, + ), + ), + child: IconButton( + icon: const Icon( + Icons.close, + color: ColorsManager.lightGreyColor, + size: 16, + ), + onPressed: () { + onDeleteDevice(tag: tag, index: index); + }, + tooltip: 'Delete Tag', + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + ), + ), + ], + ), + ), + DataCell( + Container( + alignment: Alignment + .centerLeft, // Align cell content to the left + child: SizedBox( + width: double.infinity, + child: TagDialogTextfieldDropdown( + key: ValueKey( + 'dropdown_${const Uuid().v4()}_$index'), + product: tag.product?.uuid ?? 'Unknown', + items: updatedTags, + initialValue: tag, + onSelected: (value) { + controller.text = value.tag ?? ''; + onTagDropDownSelected(tag: value, index: index); + }, + ), + ), + ), + ), + DataCell( + SizedBox( + width: double.infinity, + child: DialogDropdown( + items: locations, + selectedValue: tag.location ?? 'Main Space', + onSelected: (value) { + onLocationDropDownSelected( + location: value, index: index); + }, + )), + ), + ], + ); + }), + ), + ); + } +} diff --git a/lib/pages/spaces_management/create_subspace/bloc/subspace_bloc.dart b/lib/pages/spaces_management/create_subspace/bloc/subspace_bloc.dart index b334a301..a2d44553 100644 --- a/lib/pages/spaces_management/create_subspace/bloc/subspace_bloc.dart +++ b/lib/pages/spaces_management/create_subspace/bloc/subspace_bloc.dart @@ -77,7 +77,7 @@ class SubSpaceBloc extends Bloc { emit(SubSpaceState( updatedSubSpaces, updatedSubspaceModels, - errorMessage, + errorMessage , updatedDuplicates, )); }); diff --git a/lib/pages/spaces_management/create_subspace/views/create_subspace_model_dialog.dart b/lib/pages/spaces_management/create_subspace/views/create_subspace_model_dialog.dart index 948028ed..82df866a 100644 --- a/lib/pages/spaces_management/create_subspace/views/create_subspace_model_dialog.dart +++ b/lib/pages/spaces_management/create_subspace/views/create_subspace_model_dialog.dart @@ -1,23 +1,23 @@ 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/all_spaces/model/product_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_model.dart'; import 'package:syncrow_web/pages/spaces_management/create_subspace/bloc/subspace_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/create_subspace/bloc/subspace_event.dart'; import 'package:syncrow_web/pages/spaces_management/create_subspace/bloc/subspace_state.dart'; -import 'package:syncrow_web/pages/spaces_management/create_subspace_model/widgets/subspace_chip.dart'; -import 'package:syncrow_web/pages/spaces_management/space_model/models/subspace_template_model.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart'; +import 'widgets/ok_cancel_sub_space_widget.dart'; +import 'widgets/textfield_sub_space_dialog_widget.dart'; + class CreateSubSpaceDialog extends StatefulWidget { final String dialogTitle; final List? existingSubSpaces; final String? spaceName; final List? products; - final void Function(List?)? onSave; + final void Function( + List?, List updatedSubSpaces)? onSave; const CreateSubSpaceDialog({ required this.dialogTitle, @@ -33,14 +33,7 @@ class CreateSubSpaceDialog extends StatefulWidget { } class _CreateSubSpaceDialogState extends State { - late final TextEditingController _subspaceNameController; - - @override - void initState() { - _subspaceNameController = TextEditingController(); - super.initState(); - } - + final TextEditingController _subspaceNameController = TextEditingController(); @override void dispose() { _subspaceNameController.dispose(); @@ -79,83 +72,26 @@ class _CreateSubSpaceDialogState extends State { color: ColorsManager.blackColor, ), ), + Row( + children: [ + Text( + 'press Enter to Save', + style: context.textTheme.headlineLarge?.copyWith( + fontWeight: FontWeight.w500, + fontSize: 10, + color: ColorsManager.grayColor, + ), + ), + const SizedBox( + width: 5, + ), + const Icon(Icons.save_as_sharp, size: 10), + ], + ), const SizedBox(height: 16), - Container( - width: context.screenWidth * 0.35, - padding: const EdgeInsets.symmetric( - vertical: 10, - horizontal: 16, - ), - decoration: BoxDecoration( - color: ColorsManager.boxColor, - borderRadius: BorderRadius.circular(10), - ), - child: Wrap( - spacing: 8, - runSpacing: 8, - alignment: WrapAlignment.start, - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - ...state.subSpaces.asMap().entries.map( - (entry) { - final index = entry.key; - final subSpace = entry.value; - - final lowerName = subSpace.subspaceName.toLowerCase(); - - final duplicateIndices = state.subSpaces - .asMap() - .entries - .where((e) => - e.value.subspaceName.toLowerCase() == lowerName) - .map((e) => e.key) - .toList(); - final isDuplicate = duplicateIndices.length > 1 && - duplicateIndices.indexOf(index) != 0; - return SubspaceChip( - subSpace: SubspaceTemplateModel( - subspaceName: entry.value.subspaceName, - disabled: entry.value.disabled, - ), - isDuplicate: isDuplicate, - onDeleted: () => context.read().add( - RemoveSubSpace(subSpace), - ), - ); - }, - ), - SizedBox( - width: 200, - child: TextField( - controller: _subspaceNameController, - decoration: InputDecoration( - border: InputBorder.none, - hintText: state.subSpaces.isEmpty - ? 'Please enter the name' - : null, - hintStyle: context.textTheme.bodySmall?.copyWith( - color: ColorsManager.lightGrayColor, - ), - ), - onSubmitted: (value) { - final trimmedValue = value.trim(); - if (trimmedValue.isNotEmpty) { - context.read().add( - AddSubSpace( - SubspaceModel( - subspaceName: trimmedValue, - disabled: false, - ), - ), - ); - _subspaceNameController.clear(); - } - }, - style: context.textTheme.bodyMedium, - ), - ), - ], - ), + TextFieldSubSpaceDialogWidget( + subspaceNameController: _subspaceNameController, + subSpaces: state.subSpaces, ), if (state.errorMessage.isNotEmpty) Padding( @@ -168,36 +104,10 @@ class _CreateSubSpaceDialogState extends State { ), ), const SizedBox(height: 16), - Row( - children: [ - Expanded( - child: CancelButton( - label: 'Cancel', - onPressed: () async { - Navigator.of(context).pop(); - }, - ), - ), - const SizedBox(width: 10), - Expanded( - child: DefaultButton( - onPressed: state.errorMessage.isEmpty - ? () { - final subSpacesBloc = context.read(); - final subSpaces = subSpacesBloc.state.subSpaces; - widget.onSave?.call(subSpaces); - Navigator.of(context).pop(); - } - : null, - backgroundColor: ColorsManager.secondaryColor, - borderRadius: 10, - foregroundColor: state.errorMessage.isNotEmpty - ? ColorsManager.whiteColorsWithOpacity - : ColorsManager.whiteColors, - child: const Text('OK'), - ), - ), - ], + OkCancelSubSpaceWidget( + subspaceNameController: _subspaceNameController, + errorMessage: state.errorMessage, + onSave: widget.onSave, ), ], ), diff --git a/lib/pages/spaces_management/create_subspace/views/widgets/ok_cancel_sub_space_widget.dart b/lib/pages/spaces_management/create_subspace/views/widgets/ok_cancel_sub_space_widget.dart new file mode 100644 index 00000000..3952e105 --- /dev/null +++ b/lib/pages/spaces_management/create_subspace/views/widgets/ok_cancel_sub_space_widget.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/subspace_model.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/pages/common/buttons/cancel_button.dart'; +import 'package:syncrow_web/pages/common/buttons/default_button.dart'; + +import '../../bloc/subspace_bloc.dart'; +import '../../bloc/subspace_event.dart'; + +class OkCancelSubSpaceWidget extends StatelessWidget { + const OkCancelSubSpaceWidget({ + super.key, + required this.subspaceNameController, + required this.onSave, + required this.errorMessage, + }); + + final TextEditingController subspaceNameController; + final void Function( + List?, List updatedSubSpaces)? onSave; + final String errorMessage; + @override + Widget build(BuildContext context) { + return Row( + children: [ + Expanded( + child: CancelButton( + label: 'Cancel', + onPressed: () async { + Navigator.of(context).pop(); + }, + ), + ), + const SizedBox(width: 10), + Expanded( + child: DefaultButton( + onPressed: errorMessage.isEmpty + ? () async { + final trimmedValue = subspaceNameController.text.trim(); + + final subSpacesBloc = context.read(); + if (trimmedValue.isNotEmpty) { + subSpacesBloc.add( + AddSubSpace( + SubspaceModel( + subspaceName: trimmedValue, + disabled: false, + ), + ), + ); + subspaceNameController.clear(); + } + + await Future.delayed(const Duration(milliseconds: 10)); + final subSpaces = subSpacesBloc.state.subSpaces; + + onSave?.call( + subSpaces, subSpacesBloc.state.updatedSubSpaceModels); + + Navigator.of(context).pop(); + } + : null, + backgroundColor: ColorsManager.secondaryColor, + borderRadius: 10, + foregroundColor: errorMessage.isNotEmpty + ? ColorsManager.whiteColorsWithOpacity + : ColorsManager.whiteColors, + child: const Text('OK'), + ), + ), + ], + ); + } +} diff --git a/lib/pages/spaces_management/create_subspace/views/widgets/textfield_sub_space_dialog_widget.dart b/lib/pages/spaces_management/create_subspace/views/widgets/textfield_sub_space_dialog_widget.dart new file mode 100644 index 00000000..f655e178 --- /dev/null +++ b/lib/pages/spaces_management/create_subspace/views/widgets/textfield_sub_space_dialog_widget.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; + +import '../../../../../utils/color_manager.dart'; +import '../../../all_spaces/model/subspace_model.dart'; +import '../../../create_subspace_model/widgets/subspace_chip.dart'; +import '../../../space_model/models/subspace_template_model.dart'; +import '../../bloc/subspace_bloc.dart'; +import '../../bloc/subspace_event.dart'; + +class TextFieldSubSpaceDialogWidget extends StatelessWidget { + const TextFieldSubSpaceDialogWidget({ + super.key, + required TextEditingController subspaceNameController, + required this.subSpaces, + }) : _subspaceNameController = subspaceNameController; + + final TextEditingController _subspaceNameController; + final List subSpaces; + @override + Widget build(BuildContext context) { + return Container( + width: context.screenWidth * 0.35, + padding: const EdgeInsets.symmetric( + vertical: 10, + horizontal: 16, + ), + decoration: BoxDecoration( + color: ColorsManager.boxColor, + borderRadius: BorderRadius.circular(10), + ), + child: Wrap( + spacing: 8, + runSpacing: 8, + alignment: WrapAlignment.start, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + ...subSpaces.asMap().entries.map( + (entry) { + final index = entry.key; + final subSpace = entry.value; + + final lowerName = subSpace.subspaceName.toLowerCase(); + + final duplicateIndices = subSpaces + .asMap() + .entries + .where((e) => e.value.subspaceName.toLowerCase() == lowerName) + .map((e) => e.key) + .toList(); + final isDuplicate = duplicateIndices.length > 1 && + duplicateIndices.indexOf(index) != 0; + return SubspaceChip( + subSpace: SubspaceTemplateModel( + subspaceName: entry.value.subspaceName, + disabled: entry.value.disabled, + ), + isDuplicate: isDuplicate, + onDeleted: () => context.read().add( + RemoveSubSpace(subSpace), + ), + ); + }, + ), + SizedBox( + width: 200, + child: TextField( + controller: _subspaceNameController, + decoration: InputDecoration( + border: InputBorder.none, + hintText: subSpaces.isEmpty ? 'Please enter the name' : null, + hintStyle: context.textTheme.bodySmall?.copyWith( + color: ColorsManager.lightGrayColor, + ), + ), + onSubmitted: (value) { + final trimmedValue = value.trim(); + if (trimmedValue.isNotEmpty) { + context.read().add( + AddSubSpace( + SubspaceModel( + subspaceName: trimmedValue, + disabled: false, + ), + ), + ); + _subspaceNameController.clear(); + } + }, + style: context.textTheme.bodyMedium, + ), + ), + ], + ), + ); + } +} diff --git a/lib/pages/spaces_management/structure_selector/view/center_body_widget.dart b/lib/pages/spaces_management/structure_selector/view/center_body_widget.dart index 0f40ddbb..0f63ebb1 100644 --- a/lib/pages/spaces_management/structure_selector/view/center_body_widget.dart +++ b/lib/pages/spaces_management/structure_selector/view/center_body_widget.dart @@ -14,11 +14,11 @@ class CenterBodyWidget extends StatelessWidget { if (state is InitialState) { context.read().add(CommunityStructureSelectedEvent()); } - if (state is CommunityStructureState) { + if (state is CommunityStructureState) { context.read().add(BlankStateEvent(context)); } - if (state is SpaceModelState) { + if (state is SpaceModelState) { context.read().add(SpaceModelLoadEvent(context)); } @@ -31,15 +31,19 @@ class CenterBodyWidget extends StatelessWidget { children: [ GestureDetector( onTap: () { - context.read().add(CommunityStructureSelectedEvent()); + context + .read() + .add(CommunityStructureSelectedEvent()); }, child: Text( 'Community Structure', style: Theme.of(context).textTheme.bodyLarge!.copyWith( - fontWeight: state is CommunityStructureState || state is CommunitySelectedState + fontWeight: state is CommunityStructureState || + state is CommunitySelectedState ? FontWeight.bold : FontWeight.normal, - color: state is CommunityStructureState || state is CommunitySelectedState + color: state is CommunityStructureState || + state is CommunitySelectedState ? Theme.of(context).textTheme.bodyLarge!.color : Theme.of(context) .textTheme @@ -50,26 +54,26 @@ class CenterBodyWidget extends StatelessWidget { ), ), const SizedBox(width: 20), - GestureDetector( - onTap: () { - context.read().add(SpaceModelSelectedEvent()); - }, - child: Text( - 'Space Model', - style: Theme.of(context).textTheme.bodyLarge!.copyWith( - fontWeight: state is SpaceModelState - ? FontWeight.bold - : FontWeight.normal, - color: state is SpaceModelState - ? Theme.of(context).textTheme.bodyLarge!.color - : Theme.of(context) - .textTheme - .bodyLarge! - .color! - .withOpacity(0.5), - ), - ), - ), + // GestureDetector( + // onTap: () { + // context.read().add(SpaceModelSelectedEvent()); + // }, + // child: Text( + // 'Space Model', + // style: Theme.of(context).textTheme.bodyLarge!.copyWith( + // fontWeight: state is SpaceModelState + // ? FontWeight.bold + // : FontWeight.normal, + // color: state is SpaceModelState + // ? Theme.of(context).textTheme.bodyLarge!.color + // : Theme.of(context) + // .textTheme + // .bodyLarge! + // .color! + // .withOpacity(0.5), + // ), + // ), + // ), ], ), ], diff --git a/lib/pages/spaces_management/tag_model/bloc/add_device_model_bloc.dart b/lib/pages/spaces_management/tag_model/bloc/add_device_model_bloc.dart index 9c617a12..a0081c22 100644 --- a/lib/pages/spaces_management/tag_model/bloc/add_device_model_bloc.dart +++ b/lib/pages/spaces_management/tag_model/bloc/add_device_model_bloc.dart @@ -24,37 +24,22 @@ class AddDeviceTypeModelBloc if (currentState is AddDeviceModelLoaded) { final existingProduct = currentState.selectedProducts.firstWhere( - (p) => p.productId == event.productId, - orElse: () => SelectedProduct( - productId: event.productId, - count: 0, - productName: event.productName, - product: event.product, - ), + (p) => p.productId == event.selectedProduct.productId, + orElse: () => event.selectedProduct, ); List updatedProducts; - if (event.count > 0) { + if (event.selectedProduct.count > 0) { if (!currentState.selectedProducts.contains(existingProduct)) { updatedProducts = [ ...currentState.selectedProducts, - SelectedProduct( - productId: event.productId, - count: event.count, - productName: event.productName, - product: event.product, - ), + event.selectedProduct, ]; } else { updatedProducts = currentState.selectedProducts.map((p) { - if (p.productId == event.productId) { - return SelectedProduct( - productId: p.productId, - count: event.count, - productName: p.productName, - product: p.product, - ); + if (p.productId == event.selectedProduct.productId) { + return event.selectedProduct; } return p; }).toList(); @@ -62,7 +47,7 @@ class AddDeviceTypeModelBloc } else { // Remove the product if the count is 0 updatedProducts = currentState.selectedProducts - .where((p) => p.productId != event.productId) + .where((p) => p.productId != event.selectedProduct.productId) .toList(); } diff --git a/lib/pages/spaces_management/tag_model/bloc/add_device_type_model_event.dart b/lib/pages/spaces_management/tag_model/bloc/add_device_type_model_event.dart index b9018b2b..27f183a6 100644 --- a/lib/pages/spaces_management/tag_model/bloc/add_device_type_model_event.dart +++ b/lib/pages/spaces_management/tag_model/bloc/add_device_type_model_event.dart @@ -10,20 +10,15 @@ abstract class AddDeviceTypeModelEvent extends Equatable { List get props => []; } - class UpdateProductCountEvent extends AddDeviceTypeModelEvent { - final String productId; - final int count; - final String productName; - final ProductModel product; + final SelectedProduct selectedProduct; - UpdateProductCountEvent({required this.productId, required this.count, required this.productName, required this.product}); + UpdateProductCountEvent({required this.selectedProduct}); @override - List get props => [productId, count]; + List get props => [selectedProduct]; } - class InitializeDeviceTypeModel extends AddDeviceTypeModelEvent { final List initialTags; final List addedProducts; diff --git a/lib/pages/spaces_management/tag_model/widgets/device_type_tile_widget.dart b/lib/pages/spaces_management/tag_model/widgets/device_type_tile_widget.dart index 7d103cdb..3d645d7c 100644 --- a/lib/pages/spaces_management/tag_model/widgets/device_type_tile_widget.dart +++ b/lib/pages/spaces_management/tag_model/widgets/device_type_tile_widget.dart @@ -54,10 +54,10 @@ class DeviceTypeTileWidget extends StatelessWidget { onCountChanged: (newCount) { context.read().add( UpdateProductCountEvent( - productId: product.uuid, - count: newCount, - productName: product.catName, - product: product), + selectedProduct: product.toSelectedProduct( + newCount, + ), + ), ); }, ), diff --git a/lib/services/api/http_service.dart b/lib/services/api/http_service.dart index b75f05cf..c76291bf 100644 --- a/lib/services/api/http_service.dart +++ b/lib/services/api/http_service.dart @@ -22,6 +22,18 @@ class HTTPService { ); client.interceptors.add(serviceLocator.get()); + // Add this interceptor for logging requests and responses + // client.interceptors.add( + // LogInterceptor( + // request: true, + // requestHeader: true, + // requestBody: true, + // responseHeader: false, + // responseBody: true, + // error: true, + // logPrint: (object) => print(object), + // ), + // ); return client; } diff --git a/lib/services/space_mana_api.dart b/lib/services/space_mana_api.dart index 8f8d1d07..14902bca 100644 --- a/lib/services/space_mana_api.dart +++ b/lib/services/space_mana_api.dart @@ -5,12 +5,15 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_m import 'package:syncrow_web/pages/spaces_management/all_spaces/model/create_subspace_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_response_model.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.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/tag_body_model.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/tag_update_model.dart'; import 'package:syncrow_web/services/api/http_service.dart'; import 'package:syncrow_web/utils/constants/api_const.dart'; +import '../pages/spaces_management/all_spaces/model/subspace_model.dart'; + class CommunitySpaceManagementApi { // Community Management APIs Future> fetchCommunities(String projectId, @@ -216,7 +219,6 @@ class CommunitySpaceManagementApi { {required String communityId, required String name, String? parentId, - String? direction, bool isPrivate = false, required Offset position, String? spaceModelUuid, @@ -230,7 +232,6 @@ class CommunitySpaceManagementApi { 'isPrivate': isPrivate, 'x': position.dx, 'y': position.dy, - 'direction': direction, 'icon': icon, }; if (parentId != null) { @@ -265,11 +266,10 @@ class CommunitySpaceManagementApi { required String name, String? parentId, String? icon, - String? direction, bool isPrivate = false, required Offset position, - List? tags, - List? subspaces, + List? tags, + List? subspaces, String? spaceModelUuid, required String projectId}) async { try { @@ -278,9 +278,8 @@ class CommunitySpaceManagementApi { 'isPrivate': isPrivate, 'x': position.dx, 'y': position.dy, - 'direction': direction, 'icon': icon, - 'subspace': subspaces, + 'subspaces': subspaces, 'tags': tags, 'spaceModelUuid': spaceModelUuid, }; diff --git a/lib/services/space_model_mang_api.dart b/lib/services/space_model_mang_api.dart index 5ae3e4d9..cbb9cfeb 100644 --- a/lib/services/space_model_mang_api.dart +++ b/lib/services/space_model_mang_api.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/create_space_template_body_model.dart'; import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart'; @@ -7,17 +9,23 @@ import 'package:syncrow_web/utils/constants/api_const.dart'; class SpaceModelManagementApi { Future> listSpaceModels( {required String projectId, int page = 1}) async { - final response = await HTTPService().get( - path: ApiEndpoints.listSpaceModels.replaceAll('{projectId}', projectId), - queryParameters: {'page': page}, - expectedResponseModel: (json) { - List jsonData = json['data']; - return jsonData.map((jsonItem) { - return SpaceTemplateModel.fromJson(jsonItem); - }).toList(); - }, - ); - return response; + try { + // final response = await HTTPService().get( + // path: ApiEndpoints.listSpaceModels.replaceAll('{projectId}', projectId), + // queryParameters: {'page': page}, + // expectedResponseModel: (json) { + // List jsonData = json['data']; + // return jsonData.map((jsonItem) { + // return SpaceTemplateModel.fromJson(jsonItem); + // }).toList(); + // }, + // ); + return []; + // response; + } catch (e) { + log(e.toString()); + return []; + } } Future createSpaceModel( @@ -33,8 +41,8 @@ class SpaceModelManagementApi { return response; } - Future updateSpaceModel( - CreateSpaceTemplateBodyModel spaceModel, String spaceModelUuid, String projectId) async { + Future updateSpaceModel(CreateSpaceTemplateBodyModel spaceModel, + String spaceModelUuid, String projectId) async { final response = await HTTPService().put( path: ApiEndpoints.updateSpaceModel .replaceAll('{projectId}', projectId) @@ -47,7 +55,8 @@ class SpaceModelManagementApi { return response; } - Future getSpaceModel(String spaceModelUuid, String projectId) async { + Future getSpaceModel( + String spaceModelUuid, String projectId) async { final response = await HTTPService().get( path: ApiEndpoints.getSpaceModel .replaceAll('{projectId}', projectId)