Search code examples
flutterbloc

Unable to display contact names from phone in a list view widget in flutter


I am trying to use bloc to fetch contacts from contact service and display the contact names in an overlay widget in a list view. Can you please check my code and let me know what is wrong as it is not able to fetch any contacts and display the name.

Thank you for your time in advance.

P.S. I have added print statements but none of them are displaying the contact details(name).

File1: main.dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:invite_friends/contactsBloc.dart';
import 'accessContacts.dart';
void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(scaffoldBackgroundColor: Colors.white),
      home: BlocProvider
        (create: (BuildContext context) => ContactCubit(),
        child: AccessContacts()),
    );
  }
}

File 2: accessContacts.dart


import 'package:contacts_service/contacts_service.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:permission_handler/permission_handler.dart';
import 'contactDetails.dart';
import 'contactsBloc.dart';

class AccessContacts extends StatelessWidget {
  late OverlayEntry _overlayEntry;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Padding(
        padding: const EdgeInsets.only(left: 16, top: 80),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            ElevatedButton(onPressed: ()  {
              _overlayEntry = showOverlayContacts(context);
              Overlay.of(context)?.insert(_overlayEntry);
            }, child: const Text('Grant permission to access contacts'),
              style: ElevatedButton.styleFrom(
                  minimumSize: const Size(199, 41),
                  elevation: 5.0,
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(5.0)),
                  shadowColor: const Color(0xFFE5E5E5),
                  primary: const Color(0xFFE5E5E5),
                  onPrimary: const Color(0xFFB13937),
                  textStyle: const TextStyle(fontFamily: 'Poppins',
                      fontSize: 14)),),
          ],
        ),
      ),
    );
  }

// check contacts permission
  Future<PermissionStatus> _getPermission() async {
    final PermissionStatus permission = await Permission.contacts.request();
    print(permission);
    return permission;
  }

  showOverlayContacts(BuildContext context)  {

    final ContactCubit _contactBloc = BlocProvider.of<ContactCubit>(context);
    BlocProvider.of<ContactCubit>(context).getContacts();

    TextEditingController editingController = TextEditingController();
    OverlayState? overlayState = Overlay.of(context);
    return OverlayEntry(builder: (context) =>
        Positioned(
          bottom: 350,
          width: MediaQuery
              .of(context)
              .size
              .width,
          height: MediaQuery
              .of(context)
              .size
              .height / 2,
          child: Card(
            elevation: 20,
            child: searchContacts(editingController,_contactBloc),
          ),
        ), opaque: false);
  }
 
  Column searchContacts(TextEditingController editingController,_contactBloc) {

    List<Contact> contacts;
    return Column(
        // mainAxisAlignment: MainAxisAlignment.start,
        // crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Padding(
            padding: const EdgeInsets.only(top: 22, left: 16, right: 16),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: const [
                Text('Find contacts (upto 5) ',
                    style: TextStyle(fontFamily: 'Poppins',
                        fontSize: 14)),
                Icon(Icons.cancel),
              ],
            ),
          ),
          const Divider(
              color: Colors.grey
          ),
          Padding(
            padding: const EdgeInsets.only(left: 16),
            child: TextField(
              onChanged: (value)  {

                print(value);
              },
              controller: editingController,
              showCursor: true,
              autofocus: true,

              decoration: const InputDecoration(
                border: InputBorder.none,
                isDense: true,
                suffixIcon: Padding(
                  padding: EdgeInsets.only(right: 16),
                  child: Icon(Icons.search, size: 30,),
                ),
                suffixIconConstraints: BoxConstraints(
                  minWidth: 20,
                  minHeight: 20,
                ),

              ),


            ),
          ),
          const Divider(
              color: Colors.grey
          ),
          BlocBuilder<ContactCubit, List<Contact>>(bloc: _contactBloc, builder: (BuildContext context, List<Contact> contacts){
          return Expanded(
            child: ListView.builder(itemCount: 3,itemBuilder: (context, index) {
                    Contact contact = contacts.elementAt(index);
                    return Text(contact.displayName ?? '');
   
                  },
                ),
          );},)

        ],);


  }}

File3: contactsBloc.dart
import 'package:contacts_service/contacts_service.dart';
import 'package:invite_friends/contactDetails.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:invite_friends/getContactList.dart';
import '';
class ContactCubit extends Cubit<List<Contact>> {
  ContactCubit() : super([]);
  final _dataService = DataService();

  Future getContacts() async {
    await _dataService.getPhoneContacts();
    print(state.length);
  // _dataService.getPhoneContacts();
    emit(state);
  }

}

File 4: getContactList.dart
import 'package:contacts_service/contacts_service.dart';
import 'package:permission_handler/permission_handler.dart';

import 'contactDetails.dart';

class DataService {
  Future getPhoneContacts() async {
    try{
      Contact contact;
    final PermissionStatus permissionStatus = await Permission.contacts.request();
    if (permissionStatus == PermissionStatus.granted) {
      // Get all contacts without thumbnail (faster)
      List<Contact> contacts = await ContactsService.getContacts(withThumbnails: false);
      for(contact in contacts){
        print(contact.displayName);
      }
    } }
    catch(e){
      rethrow;
    }
    return [];


  }


}

Solution

  • In your DataService class, when you call getPhoneContacts() you fetch the List of contacts List<Contact> contacts but only print it to console.

    I think what you want to do is return it to your Bloc, so you have to add return contacts; and change the return type of getPhoneContacts() to Future<List<Contact>>.

    In your ContactCubit you have to assign the result of your await _dataService.getPhoneContacts(); to a variable and emit this as State, e.g.:

    Future getContacts() async {
        final contacts = await _dataService.getPhoneContacts();
        print(contacts.length);
        emit(contacts);
      }
    

    And in your widget you can then access the contact by using a BlocBuilder like this:

    BlocBuilder.of<ContactCubit, List<Contact>>(
      bloc: _contactBloc,
      (context, contacts) {
        return Expanded(
          child: ListView.builder(
            itemCount: contacts.length,
            itemBuilder: (context, index) {
              Contact contact = contacts.elementAt(index);
              return Text(contact.displayName ?? '');
            },
          ),
        ),
      }
    )