relatica/lib/screens/contacts_screen.dart

153 wiersze
5.1 KiB
Dart

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<ContactsScreen> createState() => _ContactsScreenState();
}
class _ContactsScreenState extends ConsumerState<ContactsScreen> {
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,
_ => <Connection>[]
};
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<void> 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;
}
}