// SPDX-FileCopyrightText: 2019-Present Christian Kußowski // SPDX-FileCopyrightText: 2019-Present Contributors to FluffyChat // // SPDX-License-Identifier: AGPL-3.0-or-later import 'package:material_ui/material_ui.dart'; import 'package:matrix/matrix.dart'; import 'package:tatchat/l10n/l10n.dart'; import 'package:tatchat/pages/chat_list/chat_list.dart'; import 'package:tatchat/pages/chat_list/chat_list_item.dart'; import 'package:tatchat/pages/chat_list/tabs/chat_tab_header.dart'; import 'package:tatchat/pages/chat_list/tabs/empty_tab_view.dart'; import 'package:tatchat/pages/chat_list/tabs/home_tab.dart'; import 'package:tatchat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:tatchat/utils/matrix_sdk_extensions/room_extension.dart'; import 'package:tatchat/utils/stream_extension.dart'; import 'package:tatchat/widgets/matrix.dart'; class ChannelsTab extends StatefulWidget { final ChatListController controller; const ChannelsTab(this.controller, {super.key}); @override State createState() => _ChannelsTabState(); } class _ChannelsTabState extends State { final TextEditingController _searchController = TextEditingController(); final FocusNode _searchFocusNode = FocusNode(); bool _isSearchMode = false; @override void dispose() { _searchController.dispose(); _searchFocusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final client = Matrix.of(context).client; final theme = Theme.of(context); final searchText = _searchController.text.trim().toLowerCase(); return ChatTabScaffold( tab: HomeTab.channels, isSearchMode: _isSearchMode, onSearchPressed: () => setState(() => _isSearchMode = true), onSearchCancelled: () { setState(() { _isSearchMode = false; _searchController.clear(); }); }, searchController: _searchController, searchFocusNode: _searchFocusNode, onSearchChanged: (_) => setState(() {}), controller: widget.controller, child: StreamBuilder( key: ValueKey(client.userID.toString()), stream: client.onSync.stream .where((s) => s.hasRoomUpdate) .rateLimit(const Duration(seconds: 1)), builder: (context, _) { final channels = client.rooms .where((room) => !room.isLeftOrBanned) .where((room) => room.isCanal) .where( (room) => searchText.isEmpty || room .getLocalizedDisplayname(MatrixLocals(L10n.of(context))) .toLowerCase() .contains(searchText), ) .toList(); return ColoredBox( color: theme.colorScheme.surface, child: CustomScrollView( slivers: [ if (channels.isEmpty) SliverFillRemaining( hasScrollBody: false, child: EmptyTabView( icon: Icons.tag_outlined, title: L10n.of(context).noChannelsFound, ), ) else SliverList.builder( itemCount: channels.length, itemBuilder: (context, i) { final room = channels[i]; return ChatListItem( room, key: Key('channel_list_item_${room.id}'), onTap: () => widget.controller.onChatTap(room), onLongPress: (context) => widget.controller.chatContextAction(room, context), activeChat: widget.controller.activeChat == room.id, ); }, ), ], ), ); }, ), ); } }