Skip to content
Snippets Groups Projects
contacts_page.dart 9.37 KiB
Newer Older
vjrj's avatar
vjrj committed
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
vjrj's avatar
vjrj committed
import 'package:share_plus/share_plus.dart';
vjrj's avatar
vjrj committed

import '../../../data/models/bottom_nav_cubit.dart';
vjrj's avatar
vjrj committed
import '../../../data/models/contact.dart';
import '../../../data/models/contact_cubit.dart';
vjrj's avatar
vjrj committed
import '../../../data/models/contact_sort_type.dart';
vjrj's avatar
vjrj committed
import '../../../data/models/payment_cubit.dart';
vjrj's avatar
vjrj committed
import '../../../g1/g1_helper.dart';
vjrj's avatar
vjrj committed
import '../../contacts_cache.dart';
vjrj's avatar
vjrj committed
import '../../ui_helpers.dart';
import '../bottom_widget.dart';
vjrj's avatar
vjrj committed
import 'contact_form_dialog.dart';
vjrj's avatar
vjrj committed

class ContactsPage extends StatefulWidget {
  const ContactsPage({super.key});

  @override
  State<ContactsPage> createState() => _ContactsPageState();
}

class _ContactsPageState extends State<ContactsPage> {
  final TextEditingController _searchController = TextEditingController();

  @override
  void initState() {
    super.initState();
vjrj's avatar
vjrj committed
    context.read<ContactsCubit>().resetFilter();
vjrj's avatar
vjrj committed
  }

  @override
  void dispose() {
    _searchController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
vjrj's avatar
vjrj committed
    final ContactsCubit cubit = context.watch<ContactsCubit>();
    return Padding(
        padding: const EdgeInsets.symmetric(horizontal: 16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
vjrj's avatar
vjrj committed
            Container(
                decoration: BoxDecoration(
                    color: Theme.of(context).colorScheme.background),
                child: Row(children: <Widget>[
                  Expanded(
                      child: TextField(
                          controller: _searchController,
                          decoration: InputDecoration(
                            hintText: tr('search_contacts'),
                            border: const OutlineInputBorder(),
                          ),
                          onChanged: (String query) {
                            context.read<ContactsCubit>().filterContacts(query);
                          })),
                  PopupMenuButton<ContactsSortType>(
                    icon: const Icon(Icons.sort),
                    onSelected: (ContactsSortType result) {
                      context.read<ContactsCubit>().sortContacts(result);
                    },
                    itemBuilder: (BuildContext context) {
                      final ContactsSortType currentOrder =
                          context.read<ContactsCubit>().state.order;

                      return <PopupMenuEntry<ContactsSortType>>[
                        PopupMenuItem<ContactsSortType>(
                          value: ContactsSortType.date,
                          child: ListTile(
                            leading: Icon(
                              Icons.date_range,
                              color: currentOrder == ContactsSortType.date
                                  ? Colors.blue
                                  : null,
                            ),
                            title: Text(tr('contacts_sort_by_date')),
                            trailing: currentOrder == ContactsSortType.date
                                ? const Icon(Icons.check)
                                : null,
                          ),
                        ),
                        PopupMenuItem<ContactsSortType>(
                          value: ContactsSortType.alpha,
                          child: ListTile(
                            leading: Icon(
                              Icons.sort_by_alpha,
                              color: currentOrder == ContactsSortType.alpha
                                  ? Colors.blue
                                  : null,
                            ),
                            title: Text(tr('contacts_sort_by_name')),
                            trailing: currentOrder == ContactsSortType.alpha
                                ? const Icon(Icons.check)
                                : null,
                          ),
                        ),
                      ];
                    },
                  )
                ])),
vjrj's avatar
vjrj committed
            const SizedBox(height: 20),
            if (cubit.state.filteredContacts.isEmpty)
              const NoElements(text: 'no_contacts')
            else
              Expanded(
                  child: ListView.builder(
                itemCount: cubit.state.filteredContacts.length,
                itemBuilder: (BuildContext context, int index) {
                  final Contact contact = cubit.state.filteredContacts[index];
                  return Slidable(
                      // Specify a key if the Slidable is dismissible.
                      key: ValueKey<int>(index),
                      // The start action pane is the one at the left or the top side.
                      startActionPane: ActionPane(
                        // A motion is a widget used to control how the pane animates.
                        motion: const ScrollMotion(),
vjrj's avatar
vjrj committed

vjrj's avatar
vjrj committed
                        // All actions are defined in the children parameter.
                        children: <SlidableAction>[
                          // A SlidableAction can have an icon and/or a label.
                          SlidableAction(
                            onPressed: (BuildContext c) {
                              context
                                  .read<ContactsCubit>()
                                  .removeContact(contact);
                            },
vjrj's avatar
vjrj committed
                            backgroundColor: deleteColor,
vjrj's avatar
vjrj committed
                            foregroundColor: Colors.white,
                            icon: Icons.delete,
                            label: tr('delete_contact'),
                          ),
                          if (showShare())
vjrj's avatar
vjrj committed
                            SlidableAction(
vjrj's avatar
vjrj committed
                              onPressed: (BuildContext c) =>
                                  Share.share(contact.pubKey),
vjrj's avatar
vjrj committed
                              backgroundColor:
vjrj's avatar
vjrj committed
                                  Theme.of(context).secondaryHeaderColor,
                              foregroundColor: Theme.of(context).primaryColor,
                              icon: Icons.share,
                              label: tr('share_this_key'),
vjrj's avatar
vjrj committed
                            ),
vjrj's avatar
vjrj committed
                        ],
                      ),
                      // The end action pane is the one at the right or the bottom side.
                      endActionPane: ActionPane(
                        motion: const ScrollMotion(),
vjrj's avatar
vjrj committed
                        /* dismissible: DismissiblePane(onDismissed: () {
vjrj's avatar
vjrj committed
                          onSent(context, contact);
vjrj's avatar
vjrj committed
                        }), */
vjrj's avatar
vjrj committed
                        children: <SlidableAction>[
                          SlidableAction(
                            onPressed: (BuildContext c) {
vjrj's avatar
vjrj committed
                              showQrDialog(
                                  context: context,
vjrj's avatar
vjrj committed
                                  publicKey: getFullPubKey(contact.pubKey),
vjrj's avatar
vjrj committed
                                  noTitle: true,
                                  feedbackText: 'some_key_copied_to_clipboard');
vjrj's avatar
vjrj committed
                            },
vjrj's avatar
vjrj committed
                            backgroundColor: Theme.of(context).primaryColorDark,
                            foregroundColor: Colors.white,
                            icon: Icons.copy,
                            label: tr('copy_contact_key'),
                          ),
                          SlidableAction(
                            onPressed: (BuildContext c) {
                              onSent(c, contact);
                            },
                            backgroundColor: Theme.of(context).primaryColor,
                            foregroundColor: Colors.white,
                            icon: Icons.send,
                            label: tr('send_g1'),
                          ),
                        ],
                      ),
                      child: SlidableContactTile(contact,
                          index: index, context: context, onLongPress: () {
vjrj's avatar
vjrj committed
                        showDialog(
                          context: context,
                          builder: (BuildContext context) {
vjrj's avatar
vjrj committed
                            return ContactFormDialog(
vjrj's avatar
vjrj committed
                                contact: contact,
                                onSave: (Contact c) {
                                  context
                                      .read<ContactsCubit>()
                                      .updateContact(c);
                                  ContactsCache().saveContact(c);
                                });
                          },
                        );
                      }, onTap: () {
                        ScaffoldMessenger.of(context).showSnackBar(
                          SnackBar(
                            content: Text(tr('long_press_to_edit')),
                          ),
                        );
                      }));
                },
              )),
            const BottomWidget()
          ],
        ));
vjrj's avatar
vjrj committed
  }

  void onSent(BuildContext c, Contact contact) {
vjrj's avatar
vjrj committed
    c.read<PaymentCubit>().selectUser(contact);
vjrj's avatar
vjrj committed
    c.read<BottomNavCubit>().updateIndex(0);
  }
}

class NoElements extends StatelessWidget {
  const NoElements({super.key, required this.text});

  final String text;

  @override
  Widget build(BuildContext context) {
    return Expanded(child: Center(child: Text(tr(text))));
  }
}