import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:logging/logging.dart'; import '../controls/app_bottom_nav_bar.dart'; import '../controls/connection_list_widget.dart'; import '../controls/current_profile_button.dart'; import '../controls/responsive_max_width.dart'; import '../controls/standard_app_drawer.dart'; import '../controls/status_and_refresh_button.dart'; import '../models/auth/profile.dart'; import '../models/connection.dart'; import '../riverpod_controllers/account_services.dart'; import '../riverpod_controllers/connection_manager_services.dart'; import '../riverpod_controllers/networking/network_status_services.dart'; import '../utils/snackbar_builder.dart'; class ContactsScreen extends ConsumerStatefulWidget { const ContactsScreen({super.key}); @override ConsumerState createState() => _ContactsScreenState(); } class _ContactsScreenState extends ConsumerState { static final _logger = Logger('$ContactsScreen'); var filterText = ''; var updateBeingProcessed = false; @override Widget build(BuildContext context) { final profile = ref.watch(activeProfileProvider); final loading = ref.watch(connectionsLoadingProvider(profile)); final allContacts = switch (ref.watch(myContactsProvider(profile))) { AsyncData(:final value) => value, _ => [] }; final filterTextLC = filterText.toLowerCase(); final contacts = allContacts .where((c) => filterText.isEmpty || c.name.toLowerCase().contains(filterTextLC) || c.handle.toLowerCase().contains(filterTextLC)) .toList(); contacts.sort((c1, c2) => c1.name.compareTo(c2.name)); _logger.finer( () => '# Contacts: ${allContacts.length}, #filtered: ${contacts.length}', ); late Widget body; if (contacts.isEmpty) { body = const SingleChildScrollView( physics: AlwaysScrollableScrollPhysics(), child: Center( child: Text('No contacts'), )); } else { body = ResponsiveMaxWidth( child: ListView.separated( physics: const AlwaysScrollableScrollPhysics(), itemBuilder: (context, index) { return ConnectionListWidget(contactId: contacts[index].id); }, separatorBuilder: (context, index) => const Divider(), itemCount: contacts.length), ); } return Scaffold( drawer: const StandardAppDrawer(skipPopDismiss: false), body: SafeArea( child: RefreshIndicator( onRefresh: () async { if (loading) { return; } await performFullUpdate(profile); }, child: Column( children: [ Row( children: [ const SizedBox(width: 50.0, child: CurrentProfileButton()), Expanded( child: Padding( padding: const EdgeInsets.all(8.0), child: TextField( onChanged: (value) { setState(() { filterText = value.toLowerCase(); }); }, decoration: InputDecoration( labelText: 'Filter By Name', alignLabelWithHint: true, border: OutlineInputBorder( borderSide: BorderSide( color: Theme.of(context).highlightColor, ), borderRadius: BorderRadius.circular(5.0), ), ), ), ), ), Padding( padding: const EdgeInsets.all(8.0), child: StatusAndRefreshButton( executing: loading, refreshFunction: () async { if (loading) { return; } await performFullUpdate(profile); }), ) ], ), Text(ref.watch(updateStatusProvider(profile))), if (loading) const LinearProgressIndicator(), Expanded(child: body), ], ), ), ), bottomNavigationBar: const AppBottomNavBar( currentButton: NavBarButtons.contacts, ), ); } Future performFullUpdate( Profile profile, ) async { if (updateBeingProcessed) { buildSnackbar( context, 'Update already underway and cannot be requested again.', ); return; } buildSnackbar( context, 'Beginning updating contact list which takes some time...', ); updateBeingProcessed = true; await ref .read(allContactsUpdaterProvider(profile).notifier) .updateAllContacts(false); updateBeingProcessed = false; } }