import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; import 'package:syncrow_web/common/widgets/search_bar.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart'; import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart'; import 'package:syncrow_web/pages/space_tree/view/custom_expansion.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/style.dart'; class SpaceTreeView extends StatefulWidget { final bool? isSide; final Function onSelect; const SpaceTreeView({required this.onSelect, this.isSide, super.key}); @override State createState() => _SpaceTreeViewState(); } class _SpaceTreeViewState extends State { final ScrollController _scrollController = ScrollController(); @override void dispose() { _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return BlocBuilder(builder: (context, state) { List list = state.searchQuery.isNotEmpty ? state.filteredCommunity : state.communityList; return Container( height: MediaQuery.sizeOf(context).height, decoration: widget.isSide == true ? 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, ), ), hintStyle: context.textTheme.bodyMedium?.copyWith( fontWeight: FontWeight.w400, fontSize: 12, color: ColorsManager.textGray), ), ), ), ), ], ), ), ) : CustomSearchBar( onSearchChanged: (query) { context.read().add(SearchQueryEvent(query)); }, ), const SizedBox(height: 16), Expanded( child: 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(), ); }), ), ), ), ), ], ), ), if (state.paginationIsLoading) const CircularProgressIndicator(), ], ), ); }); } List _buildNestedSpaces( 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), 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)); widget.onSelect(); }, onExpansionChanged: () { context.read().add(OnSpaceExpanded(community.uuid, child.uuid ?? '')); }, children: _buildNestedSpaces(context, state, child, community), ); }).toList(); } }