import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.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_state.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'; import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/community_tile.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/sidebar_header.dart'; import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/space_tile_widget.dart'; 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/style.dart'; import '../../../space_tree/bloc/space_tree_event.dart'; class SidebarWidget extends StatefulWidget { final List communities; final String? selectedSpaceUuid; final void Function(String name, String description) onCreateCommunity; const SidebarWidget({ required this.communities, required this.onCreateCommunity, this.selectedSpaceUuid, super.key, }); @override State createState() => _SidebarWidgetState(); } class _SidebarWidgetState extends State { late final ScrollController _scrollController; Timer? _debounce; String _searchQuery = ''; String? _selectedSpaceUuid; String? _selectedId; @override void initState() { super.initState(); _scrollController = ScrollController(); _scrollController.addListener(_onScroll); _selectedId = widget.selectedSpaceUuid; _searchQuery = ''; context.read().add(ClearCachedData()); } void _onScroll() { if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 100) { // Trigger pagination event final bloc = context.read(); if (!bloc.state.paginationIsLoading && bloc.state.paginationModel?.hasNext == true) { bloc.add( PaginationEvent( bloc.state.paginationModel!, bloc.state.communityList, ), ); } } } @override void dispose() { _scrollController.removeListener(_onScroll); _scrollController.dispose(); _debounce?.cancel(); super.dispose(); } void _onSearchChanged(String query) { if (_debounce?.isActive ?? false) _debounce?.cancel(); _debounce = Timer(const Duration(milliseconds: 500), () { setState(() { _searchQuery = query; }); context.read().add(SearchQueryEvent(query)); }); } @override void didUpdateWidget(covariant SidebarWidget oldWidget) { if (widget.selectedSpaceUuid != oldWidget.selectedSpaceUuid) { setState(() => _selectedId = widget.selectedSpaceUuid); } super.didUpdateWidget(oldWidget); } bool _isSpaceOrChildSelected(SpaceModel space) { final isSpaceSelected = _selectedSpaceUuid == space.uuid; final anySubSpaceIsSelected = space.children.any(_isSpaceOrChildSelected); return isSpaceSelected || anySubSpaceIsSelected; } static const _width = 300.0; @override Widget build(BuildContext context) { final spaceTreeState = context.watch().state; final filteredCommunities = spaceTreeState.searchQuery.isNotEmpty ? spaceTreeState.filteredCommunity : spaceTreeState.communityList; return Container( width: _width, decoration: subSectionContainerDecoration, child: spaceTreeState is SpaceTreeLoadingState ? const Center(child: CircularProgressIndicator()) : Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ SidebarHeader(onAddCommunity: _onAddCommunity), CustomSearchBar( onSearchChanged: _onSearchChanged, ), const SizedBox(height: 16), Expanded( child: Builder( builder: (_) { return SidebarCommunitiesList( scrollController: _scrollController, onScrollToEnd: () {}, communities: filteredCommunities, itemBuilder: (context, index) { if (index == filteredCommunities.length) { final spaceTreeState = context.read().state; if (spaceTreeState.paginationIsLoading) { return const Padding( padding: EdgeInsets.all(8.0), child: Center(child: CircularProgressIndicator()), ); } else { return const SizedBox.shrink(); } } return _buildCommunityTile(context, filteredCommunities[index]); }, ); }, ), ), if (spaceTreeState.paginationIsLoading || spaceTreeState.isSearching) Center( child: CircularProgressIndicator(), ) ], ), ); } Widget _buildCommunityTile(BuildContext context, CommunityModel community) { final spaces = community.spaces .where( (space) => { SpaceStatus.deleted, SpaceStatus.parentDeleted, }.contains(space.status) == false, ) .map((space) => _buildSpaceTile(space: space, community: community)) .toList(); return CommunityTile( title: community.name, key: ValueKey(community.uuid), isSelected: _selectedId == community.uuid, isExpanded: false, onItemSelected: () { setState(() { _selectedId = community.uuid; _selectedSpaceUuid = null; }); context.read().add(CommunitySelectedEvent()); context.read().add( SelectCommunityEvent(selectedCommunity: community), ); }, onExpansionChanged: (title, expanded) {}, children: spaces, ); } Widget _buildSpaceTile({ required SpaceModel space, required CommunityModel community, }) { final spaceIsExpanded = _isSpaceOrChildSelected(space); final isSelected = _selectedId == space.uuid; return Padding( padding: const EdgeInsetsDirectional.only(start: 16.0), child: SpaceTile( title: space.name, key: ValueKey(space.uuid), isSelected: isSelected, initiallyExpanded: spaceIsExpanded, onExpansionChanged: (expanded) {}, onItemSelected: () { setState(() { _selectedId = space.uuid; _selectedSpaceUuid = space.uuid; }); context.read().add( SelectSpaceEvent(selectedCommunity: community, selectedSpace: space), ); }, children: space.children .map( (childSpace) => _buildSpaceTile( space: childSpace, community: community, ), ) .toList(), ), ); } void _onAddCommunity() => _selectedId?.isNotEmpty ?? true ? _clearSelection() : _showCreateCommunityDialog(); void _clearSelection() { setState(() => _selectedId = ''); context.read().add( NewCommunityEvent(communities: widget.communities), ); } void _showCreateCommunityDialog() { showDialog( context: context, builder: (context) => CreateCommunityDialog( isEditMode: false, existingCommunityNames: widget.communities.map((e) => e.name).toList(), onCreateCommunity: widget.onCreateCommunity, ), ); } }