import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'space_tree_dropdown_bloc.dart'; class DropdownMenuContent extends StatefulWidget { final String? selectedSpaceId; final ValueChanged onChanged; final VoidCallback onClose; const DropdownMenuContent({ super.key, required this.selectedSpaceId, required this.onChanged, required this.onClose, }); @override State createState() => _DropdownMenuContentState(); } class _DropdownMenuContentState extends State { final ScrollController _scrollController = ScrollController(); final TextEditingController _searchController = TextEditingController(); Timer? _debounceTimer; @override void initState() { super.initState(); _scrollController.addListener(_onScroll); } @override void dispose() { _debounceTimer?.cancel(); _scrollController.dispose(); _searchController.dispose(); super.dispose(); } void _onScroll() { final bloc = context.read(); final state = bloc.state; if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent - 30) { if (state.paginationModel?.hasNext == true && !state.paginationIsLoading) { bloc.add(PaginationEvent()); } } } void _handleSearch(String query) { _debounceTimer?.cancel(); _debounceTimer = Timer(const Duration(milliseconds: 500), () { context.read().add(SearchQueryEvent(query)); }); } @override Widget build(BuildContext context) { return ConstrainedBox( constraints: const BoxConstraints(maxHeight: 300), child: BlocBuilder( builder: (context, state) { final communities = state.searchQuery.isNotEmpty ? state.filteredCommunities : state.communities; return Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.all(8.0), child: TextFormField( controller: _searchController, onChanged: _handleSearch, style: const TextStyle(fontSize: 14, color: Colors.black), decoration: InputDecoration( hintText: 'Search for space...', prefixIcon: const Icon(Icons.search, size: 20), contentPadding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), isDense: true, ), ), ), Expanded( child: ListView.builder( controller: _scrollController, itemCount: communities.length + (state.paginationIsLoading ? 1 : 0), itemBuilder: (context, index) { if (index >= communities.length) { return state.paginationIsLoading ? const Padding( padding: EdgeInsets.all(8.0), child: Center( child: SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ), ), ) : const SizedBox.shrink(); } final community = communities[index]; final isSelected = community.uuid == widget.selectedSpaceId; return ListTile( title: Text( community.name, style: TextStyle( color: isSelected ? Colors.blue : Colors.black, fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, ), ), onTap: () { context .read() .add(SearchQueryEvent('')); widget.onChanged(community.uuid); widget.onClose(); }, ); }, ), ), ], ); }, ), ); } }