Awesome Flutter Contact App, A Flutter Mini Project

The best way to learn is to do. What better way to sharpen your flutter skills than to follow a contact flutter app mini project?

Awesome Flutter Contact App

A contact book app built with Flutter

Getting Started

This project is a starting point for a Flutter application.

To clone this project, open your terminal or cmd

cd folder/to/clone-into/
git clone https://github.com/nengii/AwesomeContactApp.git

Then locate the project on your system and open with android studio or Vscode or intellij IDE.

To Run:

C:\path\to\project> flutter pub get

then run:

C:\path\to\project> flutter run

Build release version

run: flutter build <OS PLATFORM> e.g flutter build ios --release

Resources

A few resources to get you started if this is your first Flutter project:

For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.

Prerequisites

What things you need to run the app

* Android Studio/Vscode/Intellij IDE
* Flutter SDK
* Android SDK
* MacBook / Windows / Linux

Source Code

  • main.dart
import 'package:awesome_contact_app/home_view.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Contact App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomeView(),
    );
  }
}
  • contact_details_view.dart
import 'package:awesome_contact_app/contact_model.dart';
import 'package:flutter/material.dart';

class ContactDettailsView extends StatelessWidget {
  const ContactDettailsView({Key? key, required this.contact})
      : super(key: key);

  final Contact contact;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        backgroundColor: Colors.white,
        elevation: 0,
        centerTitle: true,
        iconTheme: const IconThemeData(color: Colors.black),
        title: const Text(
          'Contact',
          style: TextStyle(
              fontSize: 24, fontWeight: FontWeight.w600, color: Colors.black),
        ),
        actions: [
          IconButton(onPressed: () {}, icon: const Icon(Icons.more_vert))
        ],
      ),
      body: ListView(
        children: [
          const CircleAvatar(
            radius: 70,
            backgroundImage: AssetImage('assets/person5.png'),
          ),
          const SizedBox(
            height: 25,
          ),
          Center(
              child: Text(
            contact.name,
            style: const TextStyle(fontSize: 22, fontWeight: FontWeight.w600),
          )),
          Center(
              child: Text(
            '${contact.region},${contact.country}',
            style: const TextStyle(fontSize: 20, fontWeight: FontWeight.normal),
          )),
          const SizedBox(
            height: 30,
          ),
          Container(
            color: const Color(0xff9AADBE),
            child: Column(
              children: [
                ListTile(
                  title: const Text(
                    'Mobile',
                    style: TextStyle(fontWeight: FontWeight.w600, fontSize: 18),
                  ),
                  subtitle: Text(
                    contact.phone,
                    style: const TextStyle(
                        fontWeight: FontWeight.normal,
                        fontSize: 16,
                        color: Color(0xff333333)),
                  ),
                  trailing: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      TextButton(
                        onPressed: () {},
                        child: const Icon(
                          Icons.message,
                          color: Colors.black,
                        ),
                        style: TextButton.styleFrom(
                            backgroundColor: Colors.white,
                            shape: const CircleBorder()),
                      ),
                      TextButton(
                          onPressed: () {},
                          child: const Icon(
                            Icons.call,
                            color: Colors.black,
                          ),
                          style: TextButton.styleFrom(
                              backgroundColor: Colors.white,
                              shape: const CircleBorder()))
                    ],
                  ),
                ),
                ListTile(
                  title: const Text(
                    'Email',
                    style: TextStyle(fontWeight: FontWeight.w600, fontSize: 18),
                  ),
                  subtitle: Text(
                    contact.email,
                    style: const TextStyle(
                        fontWeight: FontWeight.normal,
                        fontSize: 16,
                        color: Color(0xff333333)),
                  ),
                  trailing: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      TextButton(
                        onPressed: () {},
                        child: const Icon(
                          Icons.email,
                          color: Colors.black,
                        ),
                        style: TextButton.styleFrom(
                            backgroundColor: Colors.white,
                            shape: const CircleBorder()),
                      ),
                    ],
                  ),
                ),
                const ListTile(
                  title: Text(
                    'Group',
                    style: TextStyle(fontWeight: FontWeight.w600, fontSize: 18),
                  ),
                  subtitle: Text(
                    'Uni Friends',
                    style: TextStyle(
                        fontWeight: FontWeight.normal,
                        fontSize: 16,
                        color: Color(0xff333333)),
                  ),
                ),
              ],
            ),
          ),
          const Padding(
            padding: EdgeInsets.all(16.0),
            child: Text(
              'Account Linked',
              style: TextStyle(fontWeight: FontWeight.w600, fontSize: 18),
            ),
          ),
          Container(
            color: const Color(0xff9AADBE),
            child: Column(
              children: [
                ListTile(
                  title: const Text(
                    'Telegram',
                    style: TextStyle(fontSize: 18),
                  ),
                  trailing: Image.asset('assets/telegram.png'),
                ),
                ListTile(
                  title: const Text(
                    'WhatsApp',
                    style: TextStyle(fontSize: 18),
                  ),
                  trailing: Image.asset('assets/whatsapp.png'),
                )
              ],
            ),
          ),
          const Padding(
            padding: EdgeInsets.all(16.0),
            child: Text(
              'More Options',
              style: TextStyle(fontWeight: FontWeight.w600, fontSize: 18),
            ),
          ),
          Container(
            color: const Color(0xff9AADBE),
            child: Column(
              children: const [
                ListTile(
                  title: Text(
                    'Share Contact',
                    style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
                  ),
                ),
                ListTile(
                  title: Text(
                    'QR Code',
                    style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
                  ),
                )
              ],
            ),
          )
        ],
      ),
    );
  }
}
  • contact_model.dart
// To parse this JSON data, do
//
//     final contact = contactFromJson(jsonString);

import 'dart:convert';

Contact contactFromJson(String str) => Contact.fromJson(json.decode(str));

String contactToJson(Contact data) => json.encode(data.toJson());

class Contact {
  Contact({
    required this.name,
    required this.phone,
    required this.email,
    required this.country,
    required this.region,
  });

  String name;
  String phone;
  String email;
  String country;
  String region;

  factory Contact.fromJson(Map<String, dynamic> json) => Contact(
        name: json["name"],
        phone: json["phone"],
        email: json["email"],
        country: json["country"],
        region: json["region"],
      );

  Map<String, dynamic> toJson() => {
        "name": name,
        "phone": phone,
        "email": email,
        "country": country,
        "region": region,
      };
}
  • home_view.dart
import 'package:awesome_contact_app/contact_details_view.dart';
import 'package:awesome_contact_app/contact_model.dart';
import 'package:flutter/material.dart';
import 'package:grouped_list/grouped_list.dart';

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

  final ScrollController _scrollController = ScrollController();

  final List<Map<String, String>> data = [
    {
      "name": "Maryam Christensen",
      "phone": "(708) 401-1432",
      "email": "[email protected]",
      "country": "United States",
      "region": "Akwa Ibom"
    },
    {
      "name": "Conan Newton",
      "phone": "1-245-615-3179",
      "email": "[email protected]",
      "country": "Australia",
      "region": "Xīběi"
    },
    {
      "name": "Aphrodite Landry",
      "phone": "(870) 863-5867",
      "email": "[email protected]",
      "country": "India",
      "region": "Sachsen"
    },
    {
      "name": "Eugenia Levine",
      "phone": "(775) 735-8020",
      "email": "[email protected]",
      "country": "Russian Federation",
      "region": "New Brunswick"
    },
    {
      "name": "Fuller Ray",
      "phone": "1-546-386-4878",
      "email": "[email protected]",
      "country": "Mexico",
      "region": "Minnesota"
    },
    {
      "name": "Quin Crane",
      "phone": "1-500-381-7960",
      "email": "[email protected]",
      "country": "Germany",
      "region": "Mecklenburg-Vorpommern"
    },
    {
      "name": "Meredith Craig",
      "phone": "1-618-723-2387",
      "email": "[email protected]",
      "country": "Austria",
      "region": "Umbria"
    },
    {
      "name": "Bareina Lindsey",
      "phone": "1-638-212-4639",
      "email": "[email protected]",
      "country": "South Korea",
      "region": "Antwerpen"
    },
    {
      "name": "Declan Mcmillan",
      "phone": "(840) 478-8507",
      "email": "[email protected]",
      "country": "Germany",
      "region": "Maranhão"
    },
    {
      "name": "Phillip Charles",
      "phone": "(626) 471-2874",
      "email": "[email protected]",
      "country": "India",
      "region": "Andalucía"
    }
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        centerTitle: false,
        title: const Text(
          'My Contacts',
          style: TextStyle(
              fontSize: 24, fontWeight: FontWeight.w600, color: Colors.black),
        ),
        actions: const [
          Padding(
            padding: EdgeInsets.only(right: 10),
            child: Center(
              child: CircleAvatar(
                radius: 25,
                backgroundImage: AssetImage('assets/avatar.png'),
              ),
            ),
          )
        ],
        elevation: 0,
        backgroundColor: Colors.white,
        bottom: PreferredSize(
          preferredSize: const Size.fromHeight(90),
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 15),
            child: TextField(
              decoration: InputDecoration(
                  border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(12)),
                  hintText: 'Search by name or number',
                  prefixIcon: const Icon(Icons.search)),
            ),
          ),
        ),
      ),
      body: SafeArea(
        child: ListView(
          controller: _scrollController,
          children: [
            const Padding(
              padding: EdgeInsets.symmetric(horizontal: 16),
              child: Text(
                'Recent',
                style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
              ),
            ),
            ListView.separated(
              controller: _scrollController,
              shrinkWrap: true,
              itemBuilder: (context, index) {
                return ListTile(
                    onTap: () {
                      Navigator.push(context,
                          MaterialPageRoute(builder: (context) {
                        return ContactDettailsView(
                            contact: Contact(
                                country: ' Ghana',
                                name: 'Nengi Aberenika',
                                phone: '+233 20 15 60 888',
                                email: '[email protected]',
                                region: 'Western Region'));
                      }));
                    },
                    leading: const CircleAvatar(
                      radius: 25,
                      backgroundImage: AssetImage('assets/person_1.png'),
                    ),
                    title: const Text(
                      'Nengi Aberenika',
                      style:
                          TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
                    ),
                    subtitle: const Text('+233 20 156 0888'),
                    trailing: const IconButton(
                      onPressed: null,
                      icon: Icon(Icons.more_horiz),
                    ));
              },
              separatorBuilder: (context, index) {
                return const Divider(
                  indent: 25,
                  thickness: 2,
                );
              },
              itemCount: 3,
            ),
            const Padding(
              padding: EdgeInsets.symmetric(horizontal: 16),
              child: Text(
                'Contacts',
                style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
              ),
            ),
            GroupedListView<Map<String, String>, String>(
              shrinkWrap: true,
              elements: data,
              groupBy: (element) => element['name'].toString().substring(0, 1),
              groupSeparatorBuilder: (String groupByValue) => SizedBox(
                width: MediaQuery.of(context).size.width,
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 16),
                  child: Text(
                    groupByValue.substring(0, 1),
                    textAlign: TextAlign.right,
                    style: const TextStyle(
                        fontWeight: FontWeight.w600, fontSize: 18),
                  ),
                ),
              ),
              itemBuilder: (context, Map<String, String> element) {
                Contact contact = Contact.fromJson(element);
                return Column(
                  children: [
                    ListTile(
                      onTap: () {
                        Navigator.push(context,
                            MaterialPageRoute(builder: (context) {
                          return ContactDettailsView(
                            contact: contact,
                          );
                        }));
                      },
                      leading: const CircleAvatar(
                        radius: 25,
                        backgroundImage: AssetImage('assets/person_1.png'),
                      ),
                      title: Text(
                        '${element['name']}',
                        style: const TextStyle(
                            fontSize: 16, fontWeight: FontWeight.w600),
                      ),
                      subtitle: Text('${element['phone']}'),
                      trailing: const IconButton(
                        onPressed: null,
                        icon: Icon(Icons.more_horiz),
                      ),
                    ),
                    const Divider(
                      indent: 25,
                      thickness: 2,
                    )
                  ],
                );
              },
              itemComparator: (item1, item2) =>
                  item1['name']!.compareTo(item2['name']!), // optional
              useStickyGroupSeparators: true, // optional
              floatingHeader: true, // optional
              order: GroupedListOrder.ASC, // optional
            )
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        backgroundColor: const Color(0xff1A4ADA),
        onPressed: () {},
        child: const Icon(Icons.add),
      ),
    );
  }
}

Output

GitHub Repository

Source Code and Assets: Awesome Flutter Contact App.

SHARE Awesome Flutter Contact App, A Flutter Mini Project

You may also like...

Leave a Reply

Your email address will not be published.

Share