From 91c4c772b5bf8f1af8f80dcd2cee38889a24a45d Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 13:08:38 +0300 Subject: [PATCH 01/14] SP-1330. --- .../all_spaces/widgets/sidebar_widget.dart | 66 ++++++++++++++++--- 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart index 3eb1c001..34cb9a70 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart @@ -11,6 +11,8 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/space_til import 'package:syncrow_web/pages/spaces_management/create_community/view/create_community_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_event.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/style.dart'; class SidebarWidget extends StatefulWidget { @@ -30,6 +32,8 @@ class SidebarWidget extends StatefulWidget { } class _SidebarWidgetState extends State { + late final ScrollController _scrollController; + String _searchQuery = ''; String? _selectedSpaceUuid; String? _selectedId; @@ -37,9 +41,16 @@ class _SidebarWidgetState extends State { @override void initState() { _selectedId = widget.selectedSpaceUuid; + _scrollController = ScrollController(); super.initState(); } + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + @override void didUpdateWidget(covariant SidebarWidget oldWidget) { if (widget.selectedSpaceUuid != oldWidget.selectedSpaceUuid) { @@ -86,12 +97,14 @@ class _SidebarWidgetState extends State { return isSpaceSelected || anySubSpaceIsSelected; } + static const _width = 300.0; + @override Widget build(BuildContext context) { final filteredCommunities = _filteredCommunities(); return Container( - width: 300, + width: _width, decoration: subSectionContainerDecoration, child: Column( mainAxisSize: MainAxisSize.min, @@ -103,10 +116,42 @@ class _SidebarWidgetState extends State { ), const SizedBox(height: 16), Expanded( - child: ListView( - children: filteredCommunities - .map((community) => _buildCommunityTile(context, community)) - .toList(), + child: Visibility( + visible: filteredCommunities.isNotEmpty, + replacement: Center( + child: Text( + 'No results found', + textAlign: TextAlign.center, + style: context.textTheme.bodySmall?.copyWith( + color: ColorsManager.lightGreyColor, + fontWeight: FontWeight.w400, + ), + ), + ), + child: ListView( + shrinkWrap: true, + scrollDirection: Axis.horizontal, + children: [ + SizedBox( + width: context.screenWidth * 0.5, + child: Scrollbar( + scrollbarOrientation: ScrollbarOrientation.left, + thumbVisibility: true, + controller: _scrollController, + child: ListView.builder( + padding: const EdgeInsetsDirectional.only(start: 16), + shrinkWrap: true, + itemCount: filteredCommunities.length, + controller: _scrollController, + itemBuilder: (context, index) => _buildCommunityTile( + context, + filteredCommunities[index], + ), + ), + ), + ), + ], + ), ), ), ], @@ -134,11 +179,12 @@ class _SidebarWidgetState extends State { }, onExpansionChanged: (title, expanded) {}, children: community.spaces - .where((space) { - final isDeleted = space.status != SpaceStatus.deleted; - final isParentDeleted = space.status != SpaceStatus.parentDeleted; - return (isDeleted || isParentDeleted); - }) + .where( + (space) => { + SpaceStatus.deleted, + SpaceStatus.parentDeleted, + }.contains(space.status), + ) .map((space) => _buildSpaceTile(space: space, community: community)) .toList(), ); From dce44e20ec6a87d173b1f84cfa4b80d75a393a6c Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 13:11:56 +0300 Subject: [PATCH 02/14] Extracted `EmptyResultsWidget` into its own widget and file for reusability. --- .../widgets/empty_search_result_widget.dart | 26 +++++++++++++++++++ .../all_spaces/widgets/sidebar_widget.dart | 13 ++-------- 2 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 lib/common/widgets/empty_search_result_widget.dart diff --git a/lib/common/widgets/empty_search_result_widget.dart b/lib/common/widgets/empty_search_result_widget.dart new file mode 100644 index 00000000..493974d4 --- /dev/null +++ b/lib/common/widgets/empty_search_result_widget.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; + +class EmptySearchResultWidget extends StatelessWidget { + const EmptySearchResultWidget({ + this.message = 'No results found', + super.key, + }); + + final String message; + + @override + Widget build(BuildContext context) { + return Center( + child: Text( + message, + textAlign: TextAlign.center, + style: context.textTheme.bodySmall?.copyWith( + color: ColorsManager.lightGreyColor, + fontWeight: FontWeight.w400, + ), + ), + ); + } +} diff --git a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart index 34cb9a70..6d03c0d0 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/common/widgets/empty_search_result_widget.dart'; import 'package:syncrow_web/common/widgets/search_bar.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart'; @@ -11,7 +12,6 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/space_til import 'package:syncrow_web/pages/spaces_management/create_community/view/create_community_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_event.dart'; -import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/style.dart'; @@ -118,16 +118,7 @@ class _SidebarWidgetState extends State { Expanded( child: Visibility( visible: filteredCommunities.isNotEmpty, - replacement: Center( - child: Text( - 'No results found', - textAlign: TextAlign.center, - style: context.textTheme.bodySmall?.copyWith( - color: ColorsManager.lightGreyColor, - fontWeight: FontWeight.w400, - ), - ), - ), + replacement: const EmptySearchResultWidget(), child: ListView( shrinkWrap: true, scrollDirection: Axis.horizontal, From fc1d394509b0866d3046e1105727738222dd504b Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 13:17:09 +0300 Subject: [PATCH 03/14] Extracted `SidebarCommunitiesList` into a reusable widget. --- .../widgets/sidebar_communities_list.dart | 55 +++++++++++++++++++ .../all_spaces/widgets/sidebar_widget.dart | 31 +++-------- 2 files changed, 62 insertions(+), 24 deletions(-) create mode 100644 lib/common/widgets/sidebar_communities_list.dart diff --git a/lib/common/widgets/sidebar_communities_list.dart b/lib/common/widgets/sidebar_communities_list.dart new file mode 100644 index 00000000..f5f34f24 --- /dev/null +++ b/lib/common/widgets/sidebar_communities_list.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; + +class SidebarCommunitiesList extends StatefulWidget { + const SidebarCommunitiesList({ + required this.communities, + required this.itemBuilder, + super.key, + }); + + final List communities; + final Widget Function(BuildContext context, int index) itemBuilder; + + @override + State createState() => _SidebarCommunitiesListState(); +} + +class _SidebarCommunitiesListState extends State { + late final ScrollController _scrollController; + + @override + void initState() { + _scrollController = ScrollController(); + super.initState(); + } + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: SizedBox( + width: context.screenWidth * 0.5, + child: Scrollbar( + scrollbarOrientation: ScrollbarOrientation.left, + thumbVisibility: true, + controller: _scrollController, + child: ListView.builder( + padding: const EdgeInsetsDirectional.only(start: 16), + shrinkWrap: true, + itemCount: widget.communities.length, + controller: _scrollController, + itemBuilder: widget.itemBuilder, + ), + ), + ), + ); + } +} diff --git a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart index 6d03c0d0..9be0c746 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/common/widgets/empty_search_result_widget.dart'; import 'package:syncrow_web/common/widgets/search_bar.dart'; +import 'package:syncrow_web/common/widgets/sidebar_communities_list.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/bloc/space_management_event.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart'; @@ -12,7 +13,6 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/space_til import 'package:syncrow_web/pages/spaces_management/create_community/view/create_community_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/structure_selector/bloc/center_body_event.dart'; -import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/style.dart'; class SidebarWidget extends StatefulWidget { @@ -119,29 +119,12 @@ class _SidebarWidgetState extends State { child: Visibility( visible: filteredCommunities.isNotEmpty, replacement: const EmptySearchResultWidget(), - child: ListView( - shrinkWrap: true, - scrollDirection: Axis.horizontal, - children: [ - SizedBox( - width: context.screenWidth * 0.5, - child: Scrollbar( - scrollbarOrientation: ScrollbarOrientation.left, - thumbVisibility: true, - controller: _scrollController, - child: ListView.builder( - padding: const EdgeInsetsDirectional.only(start: 16), - shrinkWrap: true, - itemCount: filteredCommunities.length, - controller: _scrollController, - itemBuilder: (context, index) => _buildCommunityTile( - context, - filteredCommunities[index], - ), - ), - ), - ), - ], + child: SidebarCommunitiesList( + communities: filteredCommunities, + itemBuilder: (context, index) => _buildCommunityTile( + context, + filteredCommunities[index], + ), ), ), ), From afdd44e098b28ec148d6daf5a8b15fa91a653149 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 13:18:52 +0300 Subject: [PATCH 04/14] removed comments from `SpaceTreeView`. --- .../space_tree/view/space_tree_view.dart | 62 ------------------- 1 file changed, 62 deletions(-) diff --git a/lib/pages/space_tree/view/space_tree_view.dart b/lib/pages/space_tree/view/space_tree_view.dart index 5b70da06..5b6d5593 100644 --- a/lib/pages/space_tree/view/space_tree_view.dart +++ b/lib/pages/space_tree/view/space_tree_view.dart @@ -191,68 +191,6 @@ class _SpaceTreeViewState extends State { ), ), if (state.paginationIsLoading) const CircularProgressIndicator(), - // Expanded( - // child: Padding( - // padding: const EdgeInsets.all(8.0), - // child: list.isEmpty - // ? Center( - // child: Text( - // 'No results found', - // style: Theme.of(context).textTheme.bodySmall!.copyWith( - // color: ColorsManager.lightGrayColor, // Gray when not selected - // fontWeight: FontWeight.w400, - // ), - // ), - // ) - // : ListView( - // shrinkWrap: true, - // children: list - // .map( - // (community) => CustomExpansionTileSpaceTree( - // title: community.name, - // isSelected: - // state.selectedCommunities.contains(community.uuid), - // isSoldCheck: - // state.selectedCommunities.contains(community.uuid), - // onExpansionChanged: () { - // context - // .read() - // .add(OnCommunityExpanded(community.uuid)); - // }, - // isExpanded: - // state.expandedCommunities.contains(community.uuid), - // onItemSelected: () { - // context.read().add( - // OnCommunitySelected(community.uuid, community.spaces)); - - // onSelect(); - // }, - // children: community.spaces.map((space) { - // return CustomExpansionTileSpaceTree( - // title: space.name, - // isExpanded: state.expandedSpaces.contains(space.uuid), - // onItemSelected: () { - // context.read().add(OnSpaceSelected( - // community.uuid, space.uuid ?? '', space.children)); - // onSelect(); - // }, - // onExpansionChanged: () { - // context.read().add( - // OnSpaceExpanded(community.uuid, space.uuid ?? '')); - // }, - // isSelected: state.selectedSpaces.contains(space.uuid) || - // state.soldCheck.contains(space.uuid), - // isSoldCheck: state.soldCheck.contains(space.uuid), - // children: _buildNestedSpaces( - // context, state, space, community.uuid), - // ); - // }).toList(), - // ), - // ) - // .toList(), - // ), - // ), - // ), ], ), ); From 8b441aaf46a7697c10c4512722cb04aa1dc2898a Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 14:09:36 +0300 Subject: [PATCH 05/14] Refactor SidebarCommunitiesList to be a StatelessWidget and update its usage across SpaceTreeView and SidebarWidget for improved performance and maintainability. --- .../widgets/sidebar_communities_list.dart | 48 ++- .../space_tree/view/space_tree_view.dart | 283 +++++++++--------- .../all_spaces/widgets/sidebar_widget.dart | 2 + 3 files changed, 167 insertions(+), 166 deletions(-) diff --git a/lib/common/widgets/sidebar_communities_list.dart b/lib/common/widgets/sidebar_communities_list.dart index f5f34f24..acc8471d 100644 --- a/lib/common/widgets/sidebar_communities_list.dart +++ b/lib/common/widgets/sidebar_communities_list.dart @@ -2,34 +2,19 @@ import 'package:flutter/material.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart'; -class SidebarCommunitiesList extends StatefulWidget { +class SidebarCommunitiesList extends StatelessWidget { const SidebarCommunitiesList({ required this.communities, required this.itemBuilder, + required this.scrollController, + required this.onScrollToEnd, super.key, }); final List communities; final Widget Function(BuildContext context, int index) itemBuilder; - - @override - State createState() => _SidebarCommunitiesListState(); -} - -class _SidebarCommunitiesListState extends State { - late final ScrollController _scrollController; - - @override - void initState() { - _scrollController = ScrollController(); - super.initState(); - } - - @override - void dispose() { - _scrollController.dispose(); - super.dispose(); - } + final ScrollController scrollController; + final void Function() onScrollToEnd; @override Widget build(BuildContext context) { @@ -40,13 +25,22 @@ class _SidebarCommunitiesListState extends State { child: Scrollbar( scrollbarOrientation: ScrollbarOrientation.left, thumbVisibility: true, - controller: _scrollController, - child: ListView.builder( - padding: const EdgeInsetsDirectional.only(start: 16), - shrinkWrap: true, - itemCount: widget.communities.length, - controller: _scrollController, - itemBuilder: widget.itemBuilder, + controller: scrollController, + child: NotificationListener( + onNotification: (notification) { + if (notification is ScrollEndNotification && + notification.metrics.extentAfter == 0) { + onScrollToEnd.call(); + } + return false; + }, + child: ListView.builder( + padding: const EdgeInsetsDirectional.only(start: 16), + shrinkWrap: true, + itemCount: communities.length, + controller: scrollController, + itemBuilder: itemBuilder, + ), ), ), ), diff --git a/lib/pages/space_tree/view/space_tree_view.dart b/lib/pages/space_tree/view/space_tree_view.dart index 5b6d5593..cae4af1c 100644 --- a/lib/pages/space_tree/view/space_tree_view.dart +++ b/lib/pages/space_tree/view/space_tree_view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; import 'package:syncrow_web/common/widgets/search_bar.dart'; +import 'package:syncrow_web/common/widgets/sidebar_communities_list.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/pages/space_tree/bloc/space_tree_state.dart'; @@ -34,160 +35,158 @@ class _SpaceTreeViewState extends State { @override Widget build(BuildContext context) { return BlocBuilder(builder: (context, state) { - List list = - state.searchQuery.isNotEmpty ? state.filteredCommunity : state.communityList; + final communities = state.searchQuery.isNotEmpty + ? state.filteredCommunity + : state.communityList; return Container( height: MediaQuery.sizeOf(context).height, decoration: widget.isSide == true - ? subSectionContainerDecoration.copyWith(color: ColorsManager.whiteColors) + ? subSectionContainerDecoration.copyWith( + color: ColorsManager.whiteColors) : const BoxDecoration(color: ColorsManager.whiteColors), child: state is SpaceTreeLoadingState ? const Center(child: CircularProgressIndicator()) : Column( children: [ - widget.isSide == true - ? Container( - decoration: const BoxDecoration( - color: ColorsManager.circleRolesBackground, - borderRadius: BorderRadius.only( - topRight: Radius.circular(20), topLeft: Radius.circular(20)), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Expanded( - child: Container( - decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(20)), - border: Border.all(color: ColorsManager.grayBorder)), - child: TextFormField( - style: context.textTheme.bodyMedium - ?.copyWith(color: ColorsManager.blackColor), - onChanged: (value) { - context.read().add(SearchQueryEvent(value)); - }, - decoration: textBoxDecoration(radios: 20)!.copyWith( - fillColor: Colors.white, - suffixIcon: Padding( - padding: const EdgeInsets.only(right: 16), - child: SvgPicture.asset( - Assets.textFieldSearch, - width: 24, - height: 24, + if (widget.isSide == true) + Container( + decoration: const BoxDecoration( + color: ColorsManager.circleRolesBackground, + borderRadius: BorderRadius.only( + topRight: Radius.circular(20), + topLeft: Radius.circular(20), + ), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Expanded( + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all( + Radius.circular(20), + ), + border: Border.all( + color: ColorsManager.grayBorder, + ), + ), + child: TextFormField( + style: context.textTheme.bodyMedium?.copyWith( + color: ColorsManager.blackColor, + ), + onChanged: (value) => + context.read().add( + SearchQueryEvent(value), ), - ), - hintStyle: context.textTheme.bodyMedium?.copyWith( - fontWeight: FontWeight.w400, - fontSize: 12, - color: ColorsManager.textGray), + decoration: + textBoxDecoration(radios: 20)?.copyWith( + fillColor: Colors.white, + suffixIcon: Padding( + padding: const EdgeInsets.only(right: 16), + child: SvgPicture.asset( + Assets.textFieldSearch, + width: 24, + height: 24, ), ), + hintStyle: + context.textTheme.bodyMedium?.copyWith( + fontWeight: FontWeight.w400, + fontSize: 12, + color: ColorsManager.textGray, + ), ), ), - ], + ), ), - ), - ) - : CustomSearchBar( - onSearchChanged: (query) { - context.read().add(SearchQueryEvent(query)); - }, + ], ), + ), + ) + else + CustomSearchBar( + onSearchChanged: (query) => context.read().add( + SearchQueryEvent(query), + ), + ), const SizedBox(height: 16), Expanded( child: state.isSearching ? const Center(child: CircularProgressIndicator()) - : ListView( - shrinkWrap: true, - scrollDirection: Axis.horizontal, - children: [ - Container( - width: MediaQuery.sizeOf(context).width * 0.5, - padding: const EdgeInsets.all(8.0), - child: list.isEmpty - ? Center( - child: Text( - 'No results found', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: ColorsManager.lightGrayColor, - fontWeight: FontWeight.w400, - ), - ), - ) - : Scrollbar( - scrollbarOrientation: ScrollbarOrientation.left, - thumbVisibility: true, - controller: _scrollController, - child: NotificationListener( - onNotification: (notification) { - if (notification is ScrollEndNotification && - notification.metrics.extentAfter == 0) { - // If the user has reached the end of the list Load more data - context.read().add(PaginationEvent( - state.paginationModel, state.communityList)); - } - return false; - }, - child: Padding( - padding: const EdgeInsets.only(left: 16), - child: ListView.builder( - shrinkWrap: true, - itemCount: list.length, - controller: _scrollController, - itemBuilder: (context, index) { - return CustomExpansionTileSpaceTree( - title: list[index].name, - isSelected: state.selectedCommunities - .contains(list[index].uuid), - isSoldCheck: state.selectedCommunities - .contains(list[index].uuid), - onExpansionChanged: () { - context.read().add( - OnCommunityExpanded(list[index].uuid)); - }, - isExpanded: state.expandedCommunities - .contains(list[index].uuid), - onItemSelected: () { - context.read().add( - OnCommunitySelected(list[index].uuid, - list[index].spaces)); - widget.onSelect(); - }, - children: list[index].spaces.map((space) { - return CustomExpansionTileSpaceTree( - title: space.name, - isExpanded: state.expandedSpaces - .contains(space.uuid), - onItemSelected: () { - context.read().add( - OnSpaceSelected( - list[index], - space.uuid ?? '', - space.children)); - widget.onSelect(); - }, - onExpansionChanged: () { - context.read().add( - OnSpaceExpanded(list[index].uuid, - space.uuid ?? '')); - }, - isSelected: state.selectedSpaces - .contains(space.uuid) || - state.soldCheck.contains(space.uuid), - isSoldCheck: - state.soldCheck.contains(space.uuid), - children: _buildNestedSpaces( - context, state, space, list[index]), - ); - }).toList(), - ); - }), + : SidebarCommunitiesList( + onScrollToEnd: () => context.read().add( + PaginationEvent( + state.paginationModel, + state.communityList, + ), + ), + scrollController: _scrollController, + communities: communities, + itemBuilder: (context, index) { + return CustomExpansionTileSpaceTree( + title: communities[index].name, + isSelected: state.selectedCommunities + .contains(communities[index].uuid), + isSoldCheck: state.selectedCommunities + .contains(communities[index].uuid), + onExpansionChanged: () => + context.read().add( + OnCommunityExpanded( + communities[index].uuid, ), ), + isExpanded: state.expandedCommunities.contains( + communities[index].uuid, + ), + onItemSelected: () { + context.read().add( + OnCommunitySelected( + communities[index].uuid, + communities[index].spaces, + ), + ); + widget.onSelect(); + }, + children: communities[index].spaces.map( + (space) { + return CustomExpansionTileSpaceTree( + title: space.name, + isExpanded: + state.expandedSpaces.contains(space.uuid), + onItemSelected: () { + context.read().add( + OnSpaceSelected( + communities[index], + space.uuid ?? '', + space.children, + ), + ); + widget.onSelect(); + }, + onExpansionChanged: () => + context.read().add( + OnSpaceExpanded( + communities[index].uuid, + space.uuid ?? '', + ), + ), + isSelected: state.selectedSpaces + .contains(space.uuid) || + state.soldCheck.contains(space.uuid), + isSoldCheck: + state.soldCheck.contains(space.uuid), + children: _buildNestedSpaces( + context, + state, + space, + communities[index], ), - ), - ], + ); + }, + ).toList(), + ); + }, ), ), if (state.paginationIsLoading) const CircularProgressIndicator(), @@ -198,22 +197,28 @@ class _SpaceTreeViewState extends State { } List _buildNestedSpaces( - BuildContext context, SpaceTreeState state, SpaceModel space, CommunityModel community) { + BuildContext context, + SpaceTreeState state, + SpaceModel space, + CommunityModel community, + ) { return space.children.map((child) { return CustomExpansionTileSpaceTree( - isSelected: - state.selectedSpaces.contains(child.uuid) || state.soldCheck.contains(child.uuid), + isSelected: state.selectedSpaces.contains(child.uuid) || + state.soldCheck.contains(child.uuid), isSoldCheck: state.soldCheck.contains(child.uuid), title: child.name, isExpanded: state.expandedSpaces.contains(child.uuid), onItemSelected: () { - context - .read() - .add(OnSpaceSelected(community, child.uuid ?? '', child.children)); + context.read().add( + OnSpaceSelected(community, child.uuid ?? '', child.children), + ); widget.onSelect(); }, onExpansionChanged: () { - context.read().add(OnSpaceExpanded(community.uuid, child.uuid ?? '')); + context.read().add( + OnSpaceExpanded(community.uuid, child.uuid ?? ''), + ); }, children: _buildNestedSpaces(context, state, child, community), ); diff --git a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart index 9be0c746..198ebc51 100644 --- a/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart +++ b/lib/pages/spaces_management/all_spaces/widgets/sidebar_widget.dart @@ -120,6 +120,8 @@ class _SidebarWidgetState extends State { visible: filteredCommunities.isNotEmpty, replacement: const EmptySearchResultWidget(), child: SidebarCommunitiesList( + scrollController: _scrollController, + onScrollToEnd: () {}, communities: filteredCommunities, itemBuilder: (context, index) => _buildCommunityTile( context, From 4c38c5064989b4cf63301e6f067166c845cfadf0 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 14:29:39 +0300 Subject: [PATCH 06/14] Refactor notification handling in SidebarCommunitiesList for improved readability and maintainability. --- .../widgets/sidebar_communities_list.dart | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/common/widgets/sidebar_communities_list.dart b/lib/common/widgets/sidebar_communities_list.dart index acc8471d..191aab25 100644 --- a/lib/common/widgets/sidebar_communities_list.dart +++ b/lib/common/widgets/sidebar_communities_list.dart @@ -16,6 +16,16 @@ class SidebarCommunitiesList extends StatelessWidget { final ScrollController scrollController; final void Function() onScrollToEnd; + bool _onNotification(ScrollEndNotification notification) { + final hasReachedEnd = notification.metrics.extentAfter == 0; + if (hasReachedEnd) { + onScrollToEnd.call(); + return true; + } + + return false; + } + @override Widget build(BuildContext context) { return SingleChildScrollView( @@ -26,17 +36,11 @@ class SidebarCommunitiesList extends StatelessWidget { scrollbarOrientation: ScrollbarOrientation.left, thumbVisibility: true, controller: scrollController, - child: NotificationListener( - onNotification: (notification) { - if (notification is ScrollEndNotification && - notification.metrics.extentAfter == 0) { - onScrollToEnd.call(); - } - return false; - }, + child: NotificationListener( + onNotification: _onNotification, child: ListView.builder( - padding: const EdgeInsetsDirectional.only(start: 16), shrinkWrap: true, + padding: const EdgeInsetsDirectional.only(start: 16), itemCount: communities.length, controller: scrollController, itemBuilder: itemBuilder, From b4f03ab6c3bdb1795c0d1d24cea662a2c80bd927 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 14:36:37 +0300 Subject: [PATCH 07/14] Initialize ScrollController in initState for better state management in SpaceTreeView. --- lib/pages/space_tree/view/space_tree_view.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/pages/space_tree/view/space_tree_view.dart b/lib/pages/space_tree/view/space_tree_view.dart index cae4af1c..3d5d00bf 100644 --- a/lib/pages/space_tree/view/space_tree_view.dart +++ b/lib/pages/space_tree/view/space_tree_view.dart @@ -24,7 +24,13 @@ class SpaceTreeView extends StatefulWidget { } class _SpaceTreeViewState extends State { - final ScrollController _scrollController = ScrollController(); + late final ScrollController _scrollController; + + @override + void initState() { + _scrollController = ScrollController(); + super.initState(); + } @override void dispose() { From f1667d445895ec9f3ae062e1653552e336f3e359 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 14:44:11 +0300 Subject: [PATCH 08/14] Refactor type annotations for onExpansionChanged and onItemSelected in CustomExpansionTileSpaceTree for improved clarity. --- lib/pages/space_tree/view/custom_expansion.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pages/space_tree/view/custom_expansion.dart b/lib/pages/space_tree/view/custom_expansion.dart index 515a8448..c06816b4 100644 --- a/lib/pages/space_tree/view/custom_expansion.dart +++ b/lib/pages/space_tree/view/custom_expansion.dart @@ -8,8 +8,8 @@ class CustomExpansionTileSpaceTree extends StatelessWidget { final bool isSelected; final bool isSoldCheck; final bool isExpanded; - final Function? onExpansionChanged; - final Function? onItemSelected; + final void Function()? onExpansionChanged; + final void Function()? onItemSelected; const CustomExpansionTileSpaceTree( {super.key, From f709b92e1266901aa521bd83763d7576a5981cb6 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 14:44:31 +0300 Subject: [PATCH 09/14] Refactor constructor formatting and improve readability in CustomExpansionTileSpaceTree. --- .../space_tree/view/custom_expansion.dart | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/pages/space_tree/view/custom_expansion.dart b/lib/pages/space_tree/view/custom_expansion.dart index c06816b4..c9755180 100644 --- a/lib/pages/space_tree/view/custom_expansion.dart +++ b/lib/pages/space_tree/view/custom_expansion.dart @@ -11,16 +11,17 @@ class CustomExpansionTileSpaceTree extends StatelessWidget { final void Function()? onExpansionChanged; final void Function()? onItemSelected; - const CustomExpansionTileSpaceTree( - {super.key, - this.spaceId, - required this.title, - this.children, - this.isExpanded = false, - this.onExpansionChanged, - this.onItemSelected, - required this.isSelected, - this.isSoldCheck = false}); + const CustomExpansionTileSpaceTree({ + required this.isSelected, + required this.title, + this.spaceId, + this.children, + this.onExpansionChanged, + this.onItemSelected, + this.isExpanded = false, + this.isSoldCheck = false, + super.key, + }); @override Widget build(BuildContext context) { @@ -56,7 +57,9 @@ class CustomExpansionTileSpaceTree extends StatelessWidget { } }, child: Icon( - isExpanded ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_right, + isExpanded + ? Icons.keyboard_arrow_down + : Icons.keyboard_arrow_right, color: ColorsManager.lightGrayColor, size: 16.0, ), @@ -72,7 +75,8 @@ class CustomExpansionTileSpaceTree extends StatelessWidget { _capitalizeFirstLetter(title), style: Theme.of(context).textTheme.bodySmall!.copyWith( color: isSelected - ? ColorsManager.blackColor // Change color to black when selected + ? ColorsManager + .blackColor // Change color to black when selected : ColorsManager.lightGrayColor, // Gray when not selected fontWeight: FontWeight.w400, ), From 3de7606a00a6252477b73a505b5117408e1c1495 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 14:46:37 +0300 Subject: [PATCH 10/14] Refactor expansion icon handling in CustomExpansionTileSpaceTree for improved readability and maintainability. --- .../space_tree/view/custom_expansion.dart | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/pages/space_tree/view/custom_expansion.dart b/lib/pages/space_tree/view/custom_expansion.dart index c9755180..2d969489 100644 --- a/lib/pages/space_tree/view/custom_expansion.dart +++ b/lib/pages/space_tree/view/custom_expansion.dart @@ -49,21 +49,7 @@ class CustomExpansionTileSpaceTree extends StatelessWidget { }), checkColor: ColorsManager.whiteColors, ), - if (children != null && children!.isNotEmpty) - InkWell( - onTap: () { - if (onExpansionChanged != null) { - onExpansionChanged!(); - } - }, - child: Icon( - isExpanded - ? Icons.keyboard_arrow_down - : Icons.keyboard_arrow_right, - color: ColorsManager.lightGrayColor, - size: 16.0, - ), - ), + _buildExpansionIcon(), Expanded( child: GestureDetector( onTap: () { @@ -96,6 +82,20 @@ class CustomExpansionTileSpaceTree extends StatelessWidget { ); } + Widget _buildExpansionIcon() { + return Visibility( + visible: children != null && children!.isNotEmpty, + child: InkWell( + onTap: onExpansionChanged, + child: Icon( + isExpanded ? Icons.keyboard_arrow_down : Icons.keyboard_arrow_right, + color: ColorsManager.lightGrayColor, + size: 16.0, + ), + ), + ); + } + String _capitalizeFirstLetter(String text) { if (text.isEmpty) return text; return text[0].toUpperCase() + text.substring(1); From 0cc867a4ea1e863cb25127af81ac2b63305091de Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 14:47:19 +0300 Subject: [PATCH 11/14] Refactor text color assignment in CustomExpansionTileSpaceTree for improved readability. --- lib/pages/space_tree/view/custom_expansion.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/pages/space_tree/view/custom_expansion.dart b/lib/pages/space_tree/view/custom_expansion.dart index 2d969489..dc55cbe7 100644 --- a/lib/pages/space_tree/view/custom_expansion.dart +++ b/lib/pages/space_tree/view/custom_expansion.dart @@ -61,9 +61,8 @@ class CustomExpansionTileSpaceTree extends StatelessWidget { _capitalizeFirstLetter(title), style: Theme.of(context).textTheme.bodySmall!.copyWith( color: isSelected - ? ColorsManager - .blackColor // Change color to black when selected - : ColorsManager.lightGrayColor, // Gray when not selected + ? ColorsManager.blackColor + : ColorsManager.lightGrayColor, fontWeight: FontWeight.w400, ), ), From 52e1ff94dedc9b8095815cfe3a4aee1678db097a Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 14:47:42 +0300 Subject: [PATCH 12/14] Refactor onItemSelected handling in CustomExpansionTileSpaceTree for improved readability. --- lib/pages/space_tree/view/custom_expansion.dart | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/pages/space_tree/view/custom_expansion.dart b/lib/pages/space_tree/view/custom_expansion.dart index dc55cbe7..4aee79e9 100644 --- a/lib/pages/space_tree/view/custom_expansion.dart +++ b/lib/pages/space_tree/view/custom_expansion.dart @@ -52,11 +52,7 @@ class CustomExpansionTileSpaceTree extends StatelessWidget { _buildExpansionIcon(), Expanded( child: GestureDetector( - onTap: () { - if (onItemSelected != null) { - onItemSelected!(); - } - }, + onTap: onItemSelected, child: Text( _capitalizeFirstLetter(title), style: Theme.of(context).textTheme.bodySmall!.copyWith( From 3216d6b879ce6428ab721a0dc081127efc29b6e0 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 14:47:52 +0300 Subject: [PATCH 13/14] Refactor fillColor assignment in CustomExpansionTileSpaceTree for improved readability. --- lib/pages/space_tree/view/custom_expansion.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pages/space_tree/view/custom_expansion.dart b/lib/pages/space_tree/view/custom_expansion.dart index 4aee79e9..43087e05 100644 --- a/lib/pages/space_tree/view/custom_expansion.dart +++ b/lib/pages/space_tree/view/custom_expansion.dart @@ -43,9 +43,9 @@ class CustomExpansionTileSpaceTree extends StatelessWidget { fillColor: WidgetStateProperty.resolveWith((states) { if (states.contains(WidgetState.selected)) { return ColorsManager.blue1; - } else { - return ColorsManager.checkBoxFillColor; } + + return ColorsManager.checkBoxFillColor; }), checkColor: ColorsManager.whiteColors, ), From 01d5cb48cc08973cf9d0437edb788844e6a5f9cc Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 16 Apr 2025 14:49:20 +0300 Subject: [PATCH 14/14] Refactor onChanged callback in Checkbox for improved readability in CustomExpansionTileSpaceTree. --- lib/pages/space_tree/view/custom_expansion.dart | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/pages/space_tree/view/custom_expansion.dart b/lib/pages/space_tree/view/custom_expansion.dart index 43087e05..e4e7f423 100644 --- a/lib/pages/space_tree/view/custom_expansion.dart +++ b/lib/pages/space_tree/view/custom_expansion.dart @@ -31,15 +31,11 @@ class CustomExpansionTileSpaceTree extends StatelessWidget { children: [ Checkbox( value: isSoldCheck ? null : isSelected, - onChanged: (bool? value) { - if (onItemSelected != null) { - onItemSelected!(); - } - }, + onChanged: (value) => onItemSelected ?? () {}, tristate: true, - side: WidgetStateBorderSide.resolveWith((states) { - return const BorderSide(color: ColorsManager.grayBorder); - }), + side: WidgetStateBorderSide.resolveWith( + (states) => const BorderSide(color: ColorsManager.grayBorder), + ), fillColor: WidgetStateProperty.resolveWith((states) { if (states.contains(WidgetState.selected)) { return ColorsManager.blue1;