contacts_service 0.0.9

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 91

contacts_service

pub package Build Status Coverage Status

A Flutter plugin to access and manage the device's contacts.

Usage

To use this plugin, add contacts_service as a dependency in your pubspec.yaml file.

Make sure you add the following permissions to your Android Manifest:

<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />

On iOS, make sure to set NSContactsUsageDescription in the Info.plist file

<key>NSContactsUsageDescription</key>
<string>This app requires contacts access to function properly.</string>

To check and request user permission to access contacts, I recommend using the following plugin: flutter_simple_permissions

Example

// Import package
import 'package:contacts_service/contacts_service.dart';

// Get all contacts
Iterable<Contact> contacts = await ContactsService.getContacts();

// Get contacts matching a string
Iterable<Contact> johns = await ContactsService.getContacts(query : "john");

// Add a contact
// The contact must have a firstName / lastName to be successfully addded
await ContactsService.addContact(newContact);

//Delete a contact
await ContactsService.deleteContact(contact);

Example

Todo

  • [ ] update contact
  • [ ] add withThumbnails optional parameter in getContacts method

Contributions

Contributions are welcome! If you find a bug or want a feature, please fill an issue.

If you want to contribute code please create a pull request.

Credits

Heavily inspired from rt2zz's react native plugin

[0.0.9] - October 10th, 2018

  • Fix an issue when fetching contacts on Android

[0.0.8] - August 16th, 2018

  • Fix an issue with phones being added to emails on Android
  • Update plugin for dart 2

[0.0.7] - July 10th, 2018

  • Fix PlatformException on iOS
  • Add a refresh to the contacts list in the sample app when you add a contact
  • Return more meaningful errors when addContact() fails on iOS
  • Code tidy up

[0.0.6] - April 13th, 2018

  • Add contact thumbnails

[0.0.5] - April 5th, 2018

  • Fix with dart2 compatibility

[0.0.4] - February 1st, 2018

  • Implement deleteContact(Contact c) for Android and iOS

[0.0.3] - January 31st, 2018

  • Implement addContact(Contact c) for Android and iOS

[0.0.2] - January 30th, 2018

  • Now retrieving contacts' prefixes and suffixes

[0.0.1] - January 30th, 2018

  • All contacts can be retrieved
  • Contacts matching a string can be retrieved

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:contacts_service/contacts_service.dart';

void main() => runApp(ContactsExampleApp());

class ContactsExampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(routes: <String, WidgetBuilder>{
      '/add': (BuildContext context) => AddContactPage()
    }, home: ContactListPage());
  }
}

class ContactListPage extends StatefulWidget {
  @override
  _ContactListPageState createState() => _ContactListPageState();
}

class _ContactListPageState extends State<ContactListPage> {
  Iterable<Contact> _contacts;

  @override
  initState() {
    super.initState();
    refreshContacts();
  }

  refreshContacts() async {
    var contacts = await ContactsService.getContacts();
    setState(() {
      _contacts = contacts;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Contacts Plugin Example')),
      floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: () {
            Navigator.of(context).pushNamed("/add").then((_) {
              refreshContacts();
            });
          }),
      body: SafeArea(
        child: _contacts != null
            ? ListView.builder(
                itemCount: _contacts?.length ?? 0,
                itemBuilder: (BuildContext context, int index) {
                  Contact c = _contacts?.elementAt(index);
                  return ListTile(
                    onTap: () {
                      Navigator.of(context).push(MaterialPageRoute(
                          builder: (BuildContext context) =>
                              ContactDetailsPage(c)));
                    },
                    leading: (c.avatar != null && c.avatar.length > 0)
                        ? CircleAvatar(backgroundImage: MemoryImage(c.avatar))
                        : CircleAvatar(
                            child: Text(c.displayName.length > 1
                                ? c.displayName?.substring(0, 2)
                                : "")),
                    title: Text(c.displayName ?? ""),
                  );
                },
              )
            : Center(child: CircularProgressIndicator()),
      ),
    );
  }
}

class ContactDetailsPage extends StatelessWidget {
  ContactDetailsPage(this._contact);
  final Contact _contact;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar:
            AppBar(title: Text(_contact.displayName ?? ""), actions: <Widget>[
          FlatButton(
              child: Icon(Icons.delete),
              onPressed: () {
                ContactsService.deleteContact(_contact);
              })
        ]),
        body: SafeArea(
          child: ListView(
            children: <Widget>[
              ListTile(
                  title: Text("Name"),
                  trailing: Text(_contact.givenName ?? "")),
              ListTile(
                  title: Text("Middle name"),
                  trailing: Text(_contact.middleName ?? "")),
              ListTile(
                  title: Text("Family name"),
                  trailing: Text(_contact.familyName ?? "")),
              ListTile(
                  title: Text("Prefix"), trailing: Text(_contact.prefix ?? "")),
              ListTile(
                  title: Text("Suffix"), trailing: Text(_contact.suffix ?? "")),
              ListTile(
                  title: Text("Company"),
                  trailing: Text(_contact.company ?? "")),
              ListTile(
                  title: Text("Job"), trailing: Text(_contact.jobTitle ?? "")),
              AddressesTile(_contact.postalAddresses),
              ItemsTile("Phones", _contact.phones),
              ItemsTile("Emails", _contact.emails)
            ],
          ),
        ));
  }
}

class AddressesTile extends StatelessWidget {
  AddressesTile(this._addresses);
  final Iterable<PostalAddress> _addresses;

  Widget build(BuildContext context) {
    return Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          ListTile(title: Text("Addresses")),
          Column(
              children: _addresses
                  .map((a) => Padding(
                        padding: const EdgeInsets.symmetric(horizontal: 16.0),
                        child: Column(
                          children: <Widget>[
                            ListTile(
                                title: Text("Street"),
                                trailing: Text(a.street)),
                            ListTile(
                                title: Text("Postcode"),
                                trailing: Text(a.postcode)),
                            ListTile(
                                title: Text("City"), trailing: Text(a.city)),
                            ListTile(
                                title: Text("Region"),
                                trailing: Text(a.region)),
                            ListTile(
                                title: Text("Country"),
                                trailing: Text(a.country)),
                          ],
                        ),
                      ))
                  .toList())
        ]);
  }
}

class ItemsTile extends StatelessWidget {
  ItemsTile(this._title, this._items);
  final Iterable<Item> _items;
  final String _title;

  @override
  Widget build(BuildContext context) {
    return Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          ListTile(title: Text(_title)),
          Column(
              children: _items
                  .map((i) => Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 16.0),
                      child: ListTile(
                          title: Text(i.label ?? ""),
                          trailing: Text(i.value ?? ""))))
                  .toList())
        ]);
  }
}

class AddContactPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _AddContactPageState();
}

class _AddContactPageState extends State<AddContactPage> {
  Contact contact = Contact();
  PostalAddress address = PostalAddress(label: "Home");
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Add a contact"),
        actions: <Widget>[
          FlatButton(
              onPressed: () {
                _formKey.currentState.save();
                contact.postalAddresses = [address];
                ContactsService.addContact(contact);
                Navigator.of(context).pop();
              },
              child: Icon(Icons.save, color: Colors.white))
        ],
      ),
      body: Container(
        padding: EdgeInsets.all(12.0),
        child: Form(
            key: _formKey,
            child: ListView(
              children: <Widget>[
                TextFormField(
                    decoration: const InputDecoration(labelText: 'First name'),
                    onSaved: (v) => contact.givenName = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Middle name'),
                    onSaved: (v) => contact.middleName = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Last name'),
                    onSaved: (v) => contact.familyName = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Prefix'),
                    onSaved: (v) => contact.prefix = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Suffix'),
                    onSaved: (v) => contact.suffix = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Phone'),
                    onSaved: (v) =>
                        contact.phones = [Item(label: "mobile", value: v)],
                    keyboardType: TextInputType.phone),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'E-mail'),
                    onSaved: (v) =>
                        contact.emails = [Item(label: "work", value: v)],
                    keyboardType: TextInputType.emailAddress),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Company'),
                    onSaved: (v) => contact.company = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Job'),
                    onSaved: (v) => contact.jobTitle = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Street'),
                    onSaved: (v) => address.street = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'City'),
                    onSaved: (v) => address.city = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Region'),
                    onSaved: (v) => address.region = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Postal code'),
                    onSaved: (v) => address.postcode = v),
                TextFormField(
                    decoration: const InputDecoration(labelText: 'Country'),
                    onSaved: (v) => address.country = v),
              ],
            )),
      ),
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  contacts_service: ^0.0.9

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter packages get

Alternatively, your editor might support flutter packages get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:contacts_service/contacts_service.dart';
  
Version Uploaded Documentation Archive
0.0.9 Oct 10, 2018 Go to the documentation of contacts_service 0.0.9 Download contacts_service 0.0.9 archive
0.0.8 Aug 16, 2018 Go to the documentation of contacts_service 0.0.8 Download contacts_service 0.0.8 archive
0.0.7 Jul 10, 2018 Go to the documentation of contacts_service 0.0.7 Download contacts_service 0.0.7 archive
0.0.6 Apr 13, 2018 Go to the documentation of contacts_service 0.0.6 Download contacts_service 0.0.6 archive
0.0.5 Apr 5, 2018 Go to the documentation of contacts_service 0.0.5 Download contacts_service 0.0.5 archive
0.0.4 Feb 1, 2018 Go to the documentation of contacts_service 0.0.4 Download contacts_service 0.0.4 archive
0.0.3 Jan 31, 2018 Go to the documentation of contacts_service 0.0.3 Download contacts_service 0.0.3 archive
0.0.2 Jan 30, 2018 Go to the documentation of contacts_service 0.0.2 Download contacts_service 0.0.2 archive
0.0.1 Jan 30, 2018 Go to the documentation of contacts_service 0.0.1 Download contacts_service 0.0.1 archive
Popularity:
Describes how popular the package is relative to other packages. [more]
92
Health:
Code health derived from static analysis. [more]
91
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
90
Overall:
Weighted score of the above. [more]
91
Learn more about scoring.

We analyzed this package on Dec 5, 2018, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.1.0
  • pana: 0.12.7
  • Flutter: 1.0.0

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health issues and suggestions

Document public APIs (-9.25 points)

49 out of 53 API elements (library, class, field or method) have no adequate dartdoc content. Good documentation improves code readability and discoverability through search.

Maintenance suggestions

Package is pre-v0.1 release. (-10 points)

While there is nothing inherently wrong with versions of 0.0.*, it usually means that the author is still experimenting with the general direction of the API.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev.58.0.flutter-f981f09760 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11
meta 1.1.6
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test
test ^1.3.0