From 25acd673515c96a635625ba02aa0e83e518e8713 Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Wed, 19 Feb 2025 02:13:14 +0300 Subject: [PATCH 1/7] Bug fixes in the side tree --- .../space_tree/bloc/space_tree_bloc.dart | 145 +++++++++--------- .../space_tree/bloc/space_tree_event.dart | 7 +- .../space_tree/view/space_tree_view.dart | 14 +- 3 files changed, 83 insertions(+), 83 deletions(-) diff --git a/lib/pages/space_tree/bloc/space_tree_bloc.dart b/lib/pages/space_tree/bloc/space_tree_bloc.dart index 3325a721..6c3cee82 100644 --- a/lib/pages/space_tree/bloc/space_tree_bloc.dart +++ b/lib/pages/space_tree/bloc/space_tree_bloc.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/common/bloc/project_manager.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart'; @@ -6,18 +5,8 @@ import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; import 'package:syncrow_web/services/space_mana_api.dart'; -import 'package:syncrow_web/utils/constants/strings_manager.dart'; -import 'package:syncrow_web/utils/constants/temp_const.dart'; -import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart'; class SpaceTreeBloc extends Bloc { - // String selectedCommunityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9'; - // String selectedSpaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6'; - final TextEditingController textController = TextEditingController(); - - // String selectedCommunityId = 'aff21a57-2f91-4e5c-b99b-0182c3ab65a9'; - // String selectedSpaceId = '25c96044-fadf-44bb-93c7-3c079e527ce6'; - SpaceTreeBloc() : super(const SpaceTreeState()) { on(_fetchSpaces); on(_onCommunityExpanded); @@ -37,8 +26,8 @@ class SpaceTreeBloc extends Bloc { List updatedCommunities = await Future.wait( communities.map((community) async { - List spaces = await CommunitySpaceManagementApi() - .getSpaceHierarchy(community.uuid, projectUuid); + List spaces = + await CommunitySpaceManagementApi().getSpaceHierarchy(community.uuid, projectUuid); return CommunityModel( uuid: community.uuid, @@ -53,19 +42,15 @@ class SpaceTreeBloc extends Bloc { ); emit(state.copyWith( - communitiesList: updatedCommunities, - expandedCommunity: [], - expandedSpaces: [])); + communitiesList: updatedCommunities, expandedCommunity: [], expandedSpaces: [])); } catch (e) { emit(SpaceTreeErrorState('Error loading communities and spaces: $e')); } } - _onCommunityExpanded( - OnCommunityExpanded event, Emitter emit) async { + _onCommunityExpanded(OnCommunityExpanded event, Emitter emit) async { try { - List updatedExpandedCommunityList = - List.from(state.expandedCommunities); + List updatedExpandedCommunityList = List.from(state.expandedCommunities); if (updatedExpandedCommunityList.contains(event.communityId)) { updatedExpandedCommunityList.remove(event.communityId); @@ -97,17 +82,13 @@ class SpaceTreeBloc extends Bloc { } } - _onCommunitySelected( - OnCommunitySelected event, Emitter emit) async { + _onCommunitySelected(OnCommunitySelected event, Emitter emit) async { try { List updatedSelectedCommunities = List.from(state.selectedCommunities.toSet().toList()); - List updatedSelectedSpaces = - List.from(state.selectedSpaces.toSet().toList()); - List updatedSoldChecks = - List.from(state.soldCheck.toSet().toList()); - Map> communityAndSpaces = - Map.from(state.selectedCommunityAndSpaces); + List updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList()); + List updatedSoldChecks = List.from(state.soldCheck.toSet().toList()); + Map> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces); List childrenIds = _getAllChildIds(event.children); @@ -138,12 +119,9 @@ class SpaceTreeBloc extends Bloc { try { List updatedSelectedCommunities = List.from(state.selectedCommunities.toSet().toList()); - List updatedSelectedSpaces = - List.from(state.selectedSpaces.toSet().toList()); - List updatedSoldChecks = - List.from(state.soldCheck.toSet().toList()); - Map> communityAndSpaces = - Map.from(state.selectedCommunityAndSpaces); + List updatedSelectedSpaces = List.from(state.selectedSpaces.toSet().toList()); + List updatedSoldChecks = List.from(state.soldCheck.toSet().toList()); + Map> communityAndSpaces = Map.from(state.selectedCommunityAndSpaces); List childrenIds = _getAllChildIds(event.children); bool isChildSelected = false; @@ -158,16 +136,14 @@ class SpaceTreeBloc extends Bloc { !updatedSoldChecks.contains(event.spaceId)) { // First click: Select the space and all its children updatedSelectedSpaces.add(event.spaceId); - updatedSelectedCommunities.add(event.communityId); + updatedSelectedCommunities.add(event.communityModel.uuid); if (childrenIds.isNotEmpty) { updatedSelectedSpaces.addAll(childrenIds); } - List spaces = - _getThePathToChild(event.communityId, event.spaceId); + List spaces = _getThePathToChild(event.communityModel.uuid, event.spaceId); for (String space in spaces) { - if (!updatedSelectedSpaces.contains(space) && - !updatedSoldChecks.contains(space)) { + if (!updatedSelectedSpaces.contains(space) && !updatedSoldChecks.contains(space)) { updatedSoldChecks.add(space); } } @@ -187,17 +163,27 @@ class SpaceTreeBloc extends Bloc { updatedSoldChecks.remove(event.spaceId); List parents = - _getThePathToChild(event.communityId, event.spaceId); - if (!_parentSelected(parents, updatedSelectedSpaces)) { + _getThePathToChild(event.communityModel.uuid, event.spaceId).toSet().toList(); + + if (updatedSelectedSpaces.isEmpty) { updatedSoldChecks.removeWhere(parents.contains); - } - if (!_anySpacesSelectedInCommunity( - event.communityId, updatedSelectedSpaces, updatedSoldChecks)) { - updatedSelectedCommunities.remove(event.communityId); + updatedSelectedCommunities.remove(event.communityModel.uuid); + } else { + // Check if any parent has selected children + for (String space in parents) { + if (!_noChildrenSelected(event.communityModel, space, updatedSelectedSpaces, parents)) { + updatedSoldChecks.remove(space); + } + } + + if (!_anySpacesSelectedInCommunity( + event.communityModel, updatedSelectedSpaces, updatedSoldChecks)) { + updatedSelectedCommunities.remove(event.communityModel.uuid); + } } } - communityAndSpaces[event.communityId] = updatedSelectedSpaces; + communityAndSpaces[event.communityModel.uuid] = updatedSelectedSpaces; emit(state.copyWith( selectedCommunities: updatedSelectedCommunities.toSet().toList(), @@ -210,12 +196,24 @@ class SpaceTreeBloc extends Bloc { } } - _parentSelected(List parents, List selectedSpaces) { - for (String space in parents) { - if (selectedSpaces.contains(space)) { - return true; + _noChildrenSelected( + CommunityModel community, String spaceId, List selectedSpaces, List parents) { + if (selectedSpaces.contains(spaceId)) { + return true; + } + + List children = _getAllChildSpaces(community.spaces); + for (var child in children) { + if (spaceId == child.uuid) { + List ids = _getAllChildIds(child.children); + for (var id in ids) { + if (selectedSpaces.contains(id)) { + return true; + } + } } } + return false; } @@ -226,11 +224,10 @@ class SpaceTreeBloc extends Bloc { // Filter communities and expand only those that match the query filteredCommunity = communities.where((community) { - final containsQueryInCommunity = community.name - .toLowerCase() - .contains(event.searchQuery.toLowerCase()); - final containsQueryInSpaces = community.spaces.any( - (space) => _containsQuery(space, event.searchQuery.toLowerCase())); + final containsQueryInCommunity = + community.name.toLowerCase().contains(event.searchQuery.toLowerCase()); + final containsQueryInSpaces = + community.spaces.any((space) => _containsQuery(space, event.searchQuery.toLowerCase())); return containsQueryInCommunity || containsQueryInSpaces; }).toList(); @@ -247,8 +244,8 @@ class SpaceTreeBloc extends Bloc { // Helper function to determine if any space or its children match the search query bool _containsQuery(SpaceModel space, String query) { final matchesSpace = space.name.toLowerCase().contains(query); - final matchesChildren = space.children.any((child) => - _containsQuery(child, query)); // Recursive check for children + final matchesChildren = + space.children.any((child) => _containsQuery(child, query)); // Recursive check for children return matchesSpace || matchesChildren; } @@ -259,22 +256,26 @@ class SpaceTreeBloc extends Bloc { ids.add(child.uuid!); ids.addAll(_getAllChildIds(child.children)); } - return ids; + return ids.toSet().toList(); } - bool _anySpacesSelectedInCommunity(String communityId, - List selectedSpaces, List partialCheckedList) { + List _getAllChildSpaces(List spaces) { + List children = []; + for (var child in spaces) { + children.add(child); + children.addAll(_getAllChildSpaces(child.children)); + } + return children; + } + + bool _anySpacesSelectedInCommunity( + CommunityModel community, List selectedSpaces, List partialCheckedList) { bool result = false; - for (var community in state.communityList) { - if (community.uuid == communityId) { - List ids = _getAllChildIds(community.spaces); - for (var id in ids) { - result = - selectedSpaces.contains(id) || partialCheckedList.contains(id); - if (result) { - return result; - } - } + List ids = _getAllChildIds(community.spaces); + for (var id in ids) { + result = selectedSpaces.contains(id) || partialCheckedList.contains(id); + if (result) { + return result; } } return result; @@ -297,8 +298,7 @@ class SpaceTreeBloc extends Bloc { return ids; } - List _getAllParentsIds( - SpaceModel child, String spaceId, List listIds) { + List _getAllParentsIds(SpaceModel child, String spaceId, List listIds) { List ids = listIds; ids.add(child.uuid ?? ''); @@ -322,7 +322,6 @@ class SpaceTreeBloc extends Bloc { @override Future close() async { - textController.dispose(); super.close(); } } diff --git a/lib/pages/space_tree/bloc/space_tree_event.dart b/lib/pages/space_tree/bloc/space_tree_event.dart index 7b1b550c..5a44d7fb 100644 --- a/lib/pages/space_tree/bloc/space_tree_event.dart +++ b/lib/pages/space_tree/bloc/space_tree_event.dart @@ -1,4 +1,5 @@ import 'package:equatable/equatable.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; class SpaceTreeEvent extends Equatable { @@ -49,14 +50,14 @@ class OnSpaceExpanded extends SpaceTreeEvent { } class OnSpaceSelected extends SpaceTreeEvent { - final String communityId; final String spaceId; final List children; + final CommunityModel communityModel; - const OnSpaceSelected(this.communityId, this.spaceId, this.children); + const OnSpaceSelected(this.communityModel, this.spaceId, this.children); @override - List get props => [communityId, spaceId, children]; + List get props => [communityModel, spaceId, children]; } class SearchQueryEvent extends SpaceTreeEvent { diff --git a/lib/pages/space_tree/view/space_tree_view.dart b/lib/pages/space_tree/view/space_tree_view.dart index da038f7a..5d52a4d3 100644 --- a/lib/pages/space_tree/view/space_tree_view.dart +++ b/lib/pages/space_tree/view/space_tree_view.dart @@ -100,8 +100,8 @@ class _SpaceTreeViewState extends State { state.expandedSpaces.contains(space.uuid), onItemSelected: () { context.read().add( - OnSpaceSelected(community.uuid, - space.uuid ?? '', space.children)); + OnSpaceSelected(community, space.uuid ?? '', + space.children)); widget.onSelect(); }, onExpansionChanged: () { @@ -114,7 +114,7 @@ class _SpaceTreeViewState extends State { state.soldCheck.contains(space.uuid), isSoldCheck: state.soldCheck.contains(space.uuid), children: _buildNestedSpaces( - context, state, space, community.uuid), + context, state, space, community), ); }).toList(), ), @@ -197,7 +197,7 @@ class _SpaceTreeViewState extends State { } List _buildNestedSpaces( - BuildContext context, SpaceTreeState state, SpaceModel space, String communityId) { + BuildContext context, SpaceTreeState state, SpaceModel space, CommunityModel community) { return space.children.map((child) { return CustomExpansionTileSpaceTree( isSelected: @@ -208,13 +208,13 @@ class _SpaceTreeViewState extends State { onItemSelected: () { context .read() - .add(OnSpaceSelected(communityId, child.uuid ?? '', child.children)); + .add(OnSpaceSelected(community, child.uuid ?? '', child.children)); widget.onSelect(); }, onExpansionChanged: () { - context.read().add(OnSpaceExpanded(communityId, child.uuid ?? '')); + context.read().add(OnSpaceExpanded(community.uuid, child.uuid ?? '')); }, - children: _buildNestedSpaces(context, state, child, communityId), + children: _buildNestedSpaces(context, state, child, community), ); }).toList(); } From d89e3fac8e7022ace142f436d19782fc39282119 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Wed, 19 Feb 2025 17:53:20 +0400 Subject: [PATCH 2/7] change endpoint --- lib/services/user_permission.dart | 2 +- lib/utils/constants/api_const.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/services/user_permission.dart b/lib/services/user_permission.dart index a3fb2d96..3f02663d 100644 --- a/lib/services/user_permission.dart +++ b/lib/services/user_permission.dart @@ -14,7 +14,7 @@ class UserPermissionApi { Future> fetchUsers(String projectId) async { try { final response = await _httpService.get( - path: ApiEndpoints.getUsers.replaceAll('{projectUuid}', projectId), + path: ApiEndpoints.getUsers.replaceAll('{projectId}', projectId), showServerMessage: true, expectedResponseModel: (json) { debugPrint('fetchUsers Response: $json'); diff --git a/lib/utils/constants/api_const.dart b/lib/utils/constants/api_const.dart index 72a2b778..c7a91e1a 100644 --- a/lib/utils/constants/api_const.dart +++ b/lib/utils/constants/api_const.dart @@ -95,8 +95,8 @@ abstract class ApiEndpoints { static const String inviteUser = '/invite-user'; static const String checkEmail = '/invite-user/check-email'; - static const String getUsers = '/projects/{projectUuid}/user'; - static const String getUserById = '/projects/{projectUuid}/user/{userUuid}'; + static const String getUsers = '/projects/{projectId}/user'; + static const String getUserById = '/projects/{projectId}/user/{userUuid}'; static const String editUser = '/invite-user/{inviteUserUuid}'; static const String deleteUser = '/invite-user/{inviteUserUuid}'; static const String changeUserStatus = '/invite-user/{invitedUserUuid}/disable'; From eafb811d2e78d766b4c01922ba38e1dda1b933a5 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Thu, 20 Feb 2025 11:26:30 +0400 Subject: [PATCH 3/7] fixed cursor issue --- lib/common/dialog_textfield_dropdown.dart | 106 +++++++++++----------- 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/lib/common/dialog_textfield_dropdown.dart b/lib/common/dialog_textfield_dropdown.dart index 807f3417..9c508f28 100644 --- a/lib/common/dialog_textfield_dropdown.dart +++ b/lib/common/dialog_textfield_dropdown.dart @@ -20,15 +20,22 @@ class DialogTextfieldDropdown extends StatefulWidget { class _DialogTextfieldDropdownState extends State { bool _isOpen = false; - late OverlayEntry _overlayEntry; + OverlayEntry? _overlayEntry; final TextEditingController _controller = TextEditingController(); - late List _filteredItems; // Filtered items list + final FocusNode _focusNode = FocusNode(); + List _filteredItems = []; @override void initState() { super.initState(); - _controller.text = widget.initialValue ?? 'Select Tag'; - _filteredItems = List.from(widget.items); // Initialize filtered items + _controller.text = widget.initialValue ?? ''; + _filteredItems = List.from(widget.items); + + _focusNode.addListener(() { + if (!_focusNode.hasFocus) { + _closeDropdown(); + } + }); } void _toggleDropdown() { @@ -41,13 +48,16 @@ class _DialogTextfieldDropdownState extends State { void _openDropdown() { _overlayEntry = _createOverlayEntry(); - Overlay.of(context).insert(_overlayEntry); + Overlay.of(context).insert(_overlayEntry!); _isOpen = true; } void _closeDropdown() { - _overlayEntry.remove(); - _isOpen = false; + if (_isOpen && _overlayEntry != null) { + _overlayEntry!.remove(); + _overlayEntry = null; + _isOpen = false; + } } OverlayEntry _createOverlayEntry() { @@ -58,9 +68,7 @@ class _DialogTextfieldDropdownState extends State { return OverlayEntry( builder: (context) { return GestureDetector( - onTap: () { - _closeDropdown(); - }, + onTap: _closeDropdown, behavior: HitTestBehavior.translucent, child: Stack( children: [ @@ -72,40 +80,26 @@ class _DialogTextfieldDropdownState extends State { elevation: 4.0, child: Container( color: ColorsManager.whiteColors, - constraints: const BoxConstraints( - maxHeight: 200.0, - ), - child: ListView.builder( - shrinkWrap: true, - itemCount: _filteredItems.length, - itemBuilder: (context, index) { - final item = _filteredItems[index]; - return Container( - decoration: const BoxDecoration( - border: Border( - bottom: BorderSide( - color: ColorsManager.lightGrayBorderColor, - width: 1.0, + constraints: const BoxConstraints(maxHeight: 200.0), + child: StatefulBuilder( + builder: (context, setStateDropdown) { + return ListView.builder( + shrinkWrap: true, + itemCount: _filteredItems.length, + itemBuilder: (context, index) { + final item = _filteredItems[index]; + return ListTile( + title: Text( + item, + style: const TextStyle(color: Colors.black), ), - ), - ), - child: ListTile( - title: Text(item, - style: Theme.of(context) - .textTheme - .bodyMedium - ?.copyWith( - color: ColorsManager.textPrimaryColor)), - onTap: () { - _controller.text = item; - widget.onSelected(item); - setState(() { - _filteredItems - .remove(item); // Remove selected item - }); - _closeDropdown(); - }, - ), + onTap: () { + _controller.text = item; + widget.onSelected(item); + _closeDropdown(); + }, + ); + }, ); }, ), @@ -122,7 +116,8 @@ class _DialogTextfieldDropdownState extends State { @override Widget build(BuildContext context) { return GestureDetector( - onTap: _toggleDropdown, + onTap: () => FocusScope.of(context).unfocus(), + behavior: HitTestBehavior.opaque, child: Container( padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), decoration: BoxDecoration( @@ -135,23 +130,26 @@ class _DialogTextfieldDropdownState extends State { Expanded( child: TextFormField( controller: _controller, - onChanged: (value) { - setState(() { - _filteredItems = widget.items - .where((item) => - item.toLowerCase().contains(value.toLowerCase())) - .toList(); // Filter items dynamically - }); + focusNode: _focusNode, + onFieldSubmitted: (value) { widget.onSelected(value); + _closeDropdown(); }, - style: Theme.of(context).textTheme.bodyMedium, + onTapOutside: (event) { + widget.onSelected(_controller.text); + _closeDropdown(); + }, + style: const TextStyle(color: Colors.black), decoration: const InputDecoration( - hintText: 'Enter or Select tag', + hintText: 'Enter or Select a tag', border: InputBorder.none, ), ), ), - const Icon(Icons.arrow_drop_down), + GestureDetector( + onTap: _toggleDropdown, + child: const Icon(Icons.arrow_drop_down), + ), ], ), ), From 57c5f4752c224b75489d3dff6fa3946af24ac471 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Thu, 20 Feb 2025 11:36:08 +0400 Subject: [PATCH 4/7] fixed theme --- lib/common/dialog_textfield_dropdown.dart | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/common/dialog_textfield_dropdown.dart b/lib/common/dialog_textfield_dropdown.dart index 9c508f28..a63f095a 100644 --- a/lib/common/dialog_textfield_dropdown.dart +++ b/lib/common/dialog_textfield_dropdown.dart @@ -89,10 +89,13 @@ class _DialogTextfieldDropdownState extends State { itemBuilder: (context, index) { final item = _filteredItems[index]; return ListTile( - title: Text( - item, - style: const TextStyle(color: Colors.black), - ), + title: Text(item, + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith( + color: + ColorsManager.textPrimaryColor)), onTap: () { _controller.text = item; widget.onSelected(item); @@ -139,7 +142,7 @@ class _DialogTextfieldDropdownState extends State { widget.onSelected(_controller.text); _closeDropdown(); }, - style: const TextStyle(color: Colors.black), + style: Theme.of(context).textTheme.bodyMedium, decoration: const InputDecoration( hintText: 'Enter or Select a tag', border: InputBorder.none, From 7ee7681e09b3e98307cca3e62d19a90896163cbc Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Thu, 20 Feb 2025 11:47:58 +0400 Subject: [PATCH 5/7] fixed theme --- lib/common/dialog_textfield_dropdown.dart | 41 ++++++++++++++++------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/lib/common/dialog_textfield_dropdown.dart b/lib/common/dialog_textfield_dropdown.dart index a63f095a..ac88e5dc 100644 --- a/lib/common/dialog_textfield_dropdown.dart +++ b/lib/common/dialog_textfield_dropdown.dart @@ -88,19 +88,34 @@ class _DialogTextfieldDropdownState extends State { itemCount: _filteredItems.length, itemBuilder: (context, index) { final item = _filteredItems[index]; - return ListTile( - title: Text(item, - style: Theme.of(context) - .textTheme - .bodyMedium - ?.copyWith( - color: - ColorsManager.textPrimaryColor)), - onTap: () { - _controller.text = item; - widget.onSelected(item); - _closeDropdown(); - }, + + return Container( + decoration: const BoxDecoration( + border: Border( + bottom: BorderSide( + color: ColorsManager.lightGrayBorderColor, + width: 1.0, + ), + ), + ), + child: ListTile( + title: Text(item, + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith( + color: ColorsManager + .textPrimaryColor)), + onTap: () { + _controller.text = item; + widget.onSelected(item); + setState(() { + _filteredItems + .remove(item); // Remove selected item + }); + _closeDropdown(); + }, + ), ); }, ); From e634154fb326b26cc7485d4cbecf18505deb0ef5 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Thu, 20 Feb 2025 13:31:31 +0400 Subject: [PATCH 6/7] fixed device endpoint --- lib/utils/constants/api_const.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils/constants/api_const.dart b/lib/utils/constants/api_const.dart index c7a91e1a..1022d734 100644 --- a/lib/utils/constants/api_const.dart +++ b/lib/utils/constants/api_const.dart @@ -25,7 +25,7 @@ abstract class ApiEndpoints { ////// Devices Management //////////////// - static const String getAllDevices = '/projects/{projectId}/device'; + static const String getAllDevices = '/projects/{projectId}/devices'; static const String getSpaceDevices = '/projects/{projectId}/communities/{communityUuid}/spaces/{spaceUuid}/devices'; static const String getDeviceStatus = '/device/{uuid}/functions/status'; From 010176cc25af2a3d3654a891470ab238a3166b8d Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Thu, 20 Feb 2025 12:53:59 +0300 Subject: [PATCH 7/7] Added clear data and cached events in space tree --- lib/pages/auth/bloc/auth_bloc.dart | 39 +++++++------------ lib/pages/home/bloc/home_bloc.dart | 20 +++++----- .../space_tree/bloc/space_tree_bloc.dart | 38 ++++++++++++++++++ .../space_tree/bloc/space_tree_event.dart | 4 ++ 4 files changed, 67 insertions(+), 34 deletions(-) diff --git a/lib/pages/auth/bloc/auth_bloc.dart b/lib/pages/auth/bloc/auth_bloc.dart index c2aa01a4..b22dae7b 100644 --- a/lib/pages/auth/bloc/auth_bloc.dart +++ b/lib/pages/auth/bloc/auth_bloc.dart @@ -10,9 +10,12 @@ import 'package:syncrow_web/pages/auth/model/region_model.dart'; import 'package:syncrow_web/pages/auth/model/token.dart'; import 'package:syncrow_web/pages/auth/model/user_model.dart'; import 'package:syncrow_web/pages/common/bloc/project_manager.dart'; +import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; +import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart'; import 'package:syncrow_web/services/auth_api.dart'; import 'package:syncrow_web/utils/constants/strings_manager.dart'; import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart'; +import 'package:syncrow_web/utils/navigation_service.dart'; import 'package:syncrow_web/utils/snack_bar.dart'; class AuthBloc extends Bloc { @@ -32,8 +35,7 @@ class AuthBloc extends Bloc { ////////////////////////////// forget password ////////////////////////////////// final TextEditingController forgetEmailController = TextEditingController(); - final TextEditingController forgetPasswordController = - TextEditingController(); + final TextEditingController forgetPasswordController = TextEditingController(); final TextEditingController forgetOtp = TextEditingController(); final forgetFormKey = GlobalKey(); final forgetEmailKey = GlobalKey(); @@ -50,8 +52,7 @@ class AuthBloc extends Bloc { return; } _remainingTime = 1; - add(UpdateTimerEvent( - remainingTime: _remainingTime, isButtonEnabled: false)); + add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false)); try { forgetEmailValidate = ''; _remainingTime = (await AuthenticationAPI.sendOtp( @@ -88,8 +89,7 @@ class AuthBloc extends Bloc { _timer?.cancel(); add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true)); } else { - add(UpdateTimerEvent( - remainingTime: _remainingTime, isButtonEnabled: false)); + add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false)); } }); } @@ -99,8 +99,7 @@ class AuthBloc extends Bloc { emit(const TimerState(isButtonEnabled: true, remainingTime: 0)); } - Future changePassword( - ChangePasswordEvent event, Emitter emit) async { + Future changePassword(ChangePasswordEvent event, Emitter emit) async { emit(LoadingForgetState()); try { var response = await AuthenticationAPI.verifyOtp( @@ -116,8 +115,7 @@ class AuthBloc extends Bloc { } } on DioException catch (e) { final errorData = e.response!.data; - String errorMessage = - errorData['error']['message'] ?? 'something went wrong'; + String errorMessage = errorData['error']['message'] ?? 'something went wrong'; validate = errorMessage; emit(AuthInitialState()); } @@ -131,9 +129,7 @@ class AuthBloc extends Bloc { } void _onUpdateTimer(UpdateTimerEvent event, Emitter emit) { - emit(TimerState( - isButtonEnabled: event.isButtonEnabled, - remainingTime: event.remainingTime)); + emit(TimerState(isButtonEnabled: event.isButtonEnabled, remainingTime: event.remainingTime)); } ///////////////////////////////////// login ///////////////////////////////////// @@ -183,15 +179,13 @@ class AuthBloc extends Bloc { if (token.accessTokenIsNotEmpty) { FlutterSecureStorage storage = const FlutterSecureStorage(); - await storage.write( - key: Token.loginAccessTokenKey, value: token.accessToken); + await storage.write(key: Token.loginAccessTokenKey, value: token.accessToken); const FlutterSecureStorage().write( key: UserModel.userUuidKey, value: Token.decodeToken(token.accessToken)['uuid'].toString()); user = UserModel.fromToken(token); loginEmailController.clear(); loginPasswordController.clear(); - debugPrint("token " + token.accessToken); emit(LoginSuccess()); } else { emit(const LoginFailure(error: 'Something went wrong')); @@ -342,14 +336,12 @@ class AuthBloc extends Bloc { static Future getTokenAndValidate() async { try { const storage = FlutterSecureStorage(); - final firstLaunch = await SharedPreferencesHelper.readBoolFromSP( - StringsManager.firstLaunch) ?? - true; + final firstLaunch = + await SharedPreferencesHelper.readBoolFromSP(StringsManager.firstLaunch) ?? true; if (firstLaunch) { storage.deleteAll(); } - await SharedPreferencesHelper.saveBoolToSP( - StringsManager.firstLaunch, false); + await SharedPreferencesHelper.saveBoolToSP(StringsManager.firstLaunch, false); final value = await storage.read(key: Token.loginAccessTokenKey) ?? ''; if (value.isEmpty) { return 'Token not found'; @@ -402,9 +394,7 @@ class AuthBloc extends Bloc { final String formattedTime = [ if (days > 0) '${days}d', // Append 'd' for days if (days > 0 || hours > 0) - hours - .toString() - .padLeft(2, '0'), // Show hours if there are days or hours + hours.toString().padLeft(2, '0'), // Show hours if there are days or hours minutes.toString().padLeft(2, '0'), seconds.toString().padLeft(2, '0'), ].join(':'); @@ -445,6 +435,7 @@ class AuthBloc extends Bloc { static Future logout(BuildContext context) async { final storage = FlutterSecureStorage(); ProjectManager.clearProjectUUID(); + context.read().add(ClearAllData()); storage.deleteAll(); } } diff --git a/lib/pages/home/bloc/home_bloc.dart b/lib/pages/home/bloc/home_bloc.dart index f23e87ed..25b8b98d 100644 --- a/lib/pages/home/bloc/home_bloc.dart +++ b/lib/pages/home/bloc/home_bloc.dart @@ -2,20 +2,19 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:go_router/go_router.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -// import 'package:graphview/GraphView.dart'; import 'package:syncrow_web/pages/auth/model/user_model.dart'; import 'package:syncrow_web/pages/common/bloc/project_manager.dart'; import 'package:syncrow_web/pages/home/bloc/home_event.dart'; import 'package:syncrow_web/pages/home/bloc/home_state.dart'; import 'package:syncrow_web/pages/home/home_model/home_item_model.dart'; import 'package:syncrow_web/pages/routines/bloc/routine_bloc/routine_bloc.dart'; +import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; +import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart'; import 'package:syncrow_web/services/home_api.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/routes_const.dart'; -import 'package:syncrow_web/utils/constants/strings_manager.dart'; -import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart'; +import 'package:syncrow_web/utils/navigation_service.dart'; class HomeBloc extends Bloc { // final Graph graph = Graph()..isTree = true; @@ -52,12 +51,12 @@ 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); + NavigationService.navigatorKey.currentContext!.read().add(InitialEvent()); } add(FetchTermEvent()); add(FetchPolicyEvent()); @@ -93,12 +92,10 @@ 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,6 +119,7 @@ class HomeBloc extends Bloc { icon: Assets.accessIcon, active: true, onPress: (context) { + context.read().add(ClearCachedData()); context.go(RoutesConst.accessManagementPage); }, color: null, @@ -131,6 +129,7 @@ class HomeBloc extends Bloc { icon: Assets.spaseManagementIcon, active: true, onPress: (context) { + context.read().add(ClearCachedData()); context.go(RoutesConst.spacesManagementPage); }, color: ColorsManager.primaryColor, @@ -140,6 +139,7 @@ class HomeBloc extends Bloc { icon: Assets.devicesIcon, active: true, onPress: (context) { + context.read().add(ClearCachedData()); BlocProvider.of(context) .add(const TriggerSwitchTabsEvent(isRoutineTab: false)); context.go(RoutesConst.deviceManagementPage); diff --git a/lib/pages/space_tree/bloc/space_tree_bloc.dart b/lib/pages/space_tree/bloc/space_tree_bloc.dart index 6c3cee82..c2a26164 100644 --- a/lib/pages/space_tree/bloc/space_tree_bloc.dart +++ b/lib/pages/space_tree/bloc/space_tree_bloc.dart @@ -14,6 +14,8 @@ class SpaceTreeBloc extends Bloc { on(_onCommunitySelected); on(_onSpaceSelected); on(_onSearch); + on(_clearAllData); + on(_clearCachedData); } _fetchSpaces(InitialEvent event, Emitter emit) async { @@ -241,6 +243,42 @@ class SpaceTreeBloc extends Bloc { } } + _clearAllData(ClearAllData event, Emitter emit) async { + try { + emit(state.copyWith( + communitiesList: [], + filteredCommunity: [], + isSearching: false, + soldCheck: [], + selectedSpaces: [], + selectedCommunities: [], + selectedCommunityAndSpaces: {}, + searchQuery: '', + expandedSpaces: [], + expandedCommunity: [])); + } catch (e) { + emit(const SpaceTreeErrorState('Something went wrong')); + } + } + + _clearCachedData(ClearCachedData event, Emitter emit) async { + try { + emit(state.copyWith( + communitiesList: state.communityList, + filteredCommunity: [], + isSearching: false, + soldCheck: [], + selectedSpaces: [], + selectedCommunities: [], + selectedCommunityAndSpaces: {}, + searchQuery: '', + expandedSpaces: [], + expandedCommunity: [])); + } catch (e) { + emit(const SpaceTreeErrorState('Something went wrong')); + } + } + // Helper function to determine if any space or its children match the search query bool _containsQuery(SpaceModel space, String query) { final matchesSpace = space.name.toLowerCase().contains(query); diff --git a/lib/pages/space_tree/bloc/space_tree_event.dart b/lib/pages/space_tree/bloc/space_tree_event.dart index 5a44d7fb..e8fa996f 100644 --- a/lib/pages/space_tree/bloc/space_tree_event.dart +++ b/lib/pages/space_tree/bloc/space_tree_event.dart @@ -68,3 +68,7 @@ class SearchQueryEvent extends SpaceTreeEvent { @override List get props => [searchQuery]; } + +class ClearAllData extends SpaceTreeEvent {} + +class ClearCachedData extends SpaceTreeEvent {}