Flutter Functions

 

Creating a ToDo App with Flutter: Managing Tasks and Reminders

In the fast-paced world we live in, staying organized is crucial to success. Whether it’s for work, school, or personal life, keeping track of tasks and deadlines is a common challenge. This is where a ToDo app comes in handy. With the power of Flutter, Google’s open-source UI software development toolkit, you can build a feature-rich ToDo app that not only manages tasks but also reminds you to complete them. In this comprehensive guide, we’ll take you through the process of creating your own ToDo app using Flutter. Let’s dive in!

Creating a ToDo App with Flutter: Managing Tasks and Reminders

1. Prerequisites

Before we embark on our journey to create a ToDo app with Flutter, make sure you have the following prerequisites in place:

1.1. Flutter Installation

Ensure that you have Flutter installed on your system. If not, follow the official installation guide for your specific operating system: Flutter Installation Guide.

1.2. Flutter IDE

You can use your favorite code editor or IDE to develop Flutter applications. Some popular choices include Android Studio, Visual Studio Code, and IntelliJ IDEA. Make sure you have one of these set up and ready.

1.3. Basic Dart Knowledge

Flutter is built using the Dart programming language, so having a basic understanding of Dart will be beneficial. If you’re new to Dart, you can learn its fundamentals on the Dart Language Tour page.

1.4. Emulator or Physical Device

You’ll need an Android or iOS emulator or a physical device for testing your app during development. Ensure that your emulator is set up and functioning correctly.

Now that you’ve got your prerequisites in place, let’s start building our ToDo app step by step.

Step 1: Creating a New Flutter Project

To begin, let’s create a new Flutter project. Open your preferred code editor and run the following command:

bash
flutter create todo_app

This command will create a new Flutter project named “todo_app” in the current directory.

Step 2: Designing the User Interface

Define the Task Class

Before we design the user interface, let’s define the Task class, which will represent individual tasks in our ToDo app. Open the lib/main.dart file and define the Task class as follows:

dart
class Task {
  final String title;
  final DateTime dueDate;

  Task(this.title, this.dueDate);
}

Create the Task List View

Now, let’s create the task list view. Replace the contents of the lib/main.dart file with the following code:

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ToDo App',
      home: ToDoScreen(),
    );
  }
}

class ToDoScreen extends StatefulWidget {
  @override
  _ToDoScreenState createState() => _ToDoScreenState();
}

class _ToDoScreenState extends State<ToDoScreen> {
  List<Task> tasks = []; // Initialize an empty list of tasks.

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ToDo App'),
      ),
      body: ListView.builder(
        itemCount: tasks.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(tasks[index].title),
            subtitle: Text('Due on: ${tasks[index].dueDate.toString()}'),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // Add a new task when the FAB is pressed.
          _addTask();
        },
        child: Icon(Icons.add),
      ),
    );
  }

  // Function to add a new task.
  void _addTask() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Add Task'),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              TextField(
                decoration: InputDecoration(labelText: 'Task Title'),
              ),
              SizedBox(height: 16.0),
              Text('Due Date:'),
              SizedBox(height: 8.0),
              TextButton(
                onPressed: () {
                  // Implement date picker here.
                },
                child: Text('Select Date'),
              ),
            ],
          ),
          actions: <Widget>[
            ElevatedButton(
              onPressed: () {
                // Implement task addition logic here.
                Navigator.of(context).pop();
              },
              child: Text('Add'),
            ),
          ],
        );
      },
    );
  }
}

In this code, we have created a basic Flutter app with a ToDoScreen widget that displays a list of tasks using a ListView.builder. The floatingActionButton allows you to add new tasks by showing a dialog when pressed.

Implementing the Date Picker

To implement the date picker for selecting the due date of a task, add the following code to your lib/main.dart file:

dart
// ...

class _ToDoScreenState extends State<ToDoScreen> {
  // ...

  DateTime _selectedDate = DateTime.now(); // Initialize with the current date.

  // Function to show the date picker.
  Future<void> _selectDate(BuildContext context) async {
    final DateTime picked = await showDatePicker(
      context: context,
      initialDate: _selectedDate,
      firstDate: DateTime(2000),
      lastDate: DateTime(2101),
    );
    if (picked != null && picked != _selectedDate)
      setState(() {
        _selectedDate = picked;
      });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ToDo App'),
      ),
      body: ListView.builder(
        itemCount: tasks.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(tasks[index].title),
            subtitle: Text('Due on: ${tasks[index].dueDate.toString()}'),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // Add a new task when the FAB is pressed.
          _addTask();
        },
        child: Icon(Icons.add),
      ),
    );
  }

  // ...
}

In this code, we added the _selectedDate variable to keep track of the selected date and implemented the _selectDate function to show the date picker when the “Select Date” button is pressed.

Step 3: Adding Task Functionality

Now that we have the basic UI in place, let’s add functionality to add tasks and display them in the list.

Adding Tasks

Add the following code to the _addTask function in your lib/main.dart file to add tasks to the list:

dart
void _addTask() {
  showDialog(
    context: context,
    builder: (BuildContext context) {
      return AlertDialog(
        title: Text('Add Task'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            TextField(
              decoration: InputDecoration(labelText: 'Task Title'),
              onChanged: (value) {
                setState(() {
                  // Update the task title when text changes.
                  _taskTitle = value;
                });
              },
            ),
            SizedBox(height: 16.0),
            Text('Due Date: ${_selectedDate.toString()}'),
            SizedBox(height: 8.0),
            TextButton(
              onPressed: () {
                // Show the date picker when the button is pressed.
                _selectDate(context);
              },
              child: Text('Select Date'),
            ),
          ],
        ),
        actions: <Widget>[
          ElevatedButton(
            onPressed: () {
              if (_taskTitle.isNotEmpty) {
                // Add the task to the list if the title is not empty.
                setState(() {
                  tasks.add(Task(_taskTitle, _selectedDate));
                });
                Navigator.of(context).pop();
              }
            },
            child: Text('Add'),
          ),
        ],
      );
    },
  );
}

In this code, we’ve added logic to capture the task title from the TextField and added a check to ensure that an empty title is not added to the list of tasks.

Displaying Tasks

To display the tasks in the list, we’ve already set up the ListView.builder widget. Now, we just need to update the task list whenever a new task is added. This is done by calling setState after adding a task to the list.

Step 4: Adding Task Reminders

The real power of a ToDo app comes from its ability to remind you of upcoming tasks. To add this feature, we’ll use Flutter’s flutter_local_notifications package.

Adding the flutter_local_notifications Package

Add the flutter_local_notifications package to your pubspec.yaml file under dependencies:

yaml
dependencies:
  flutter:
    sdk: flutter
  flutter_local_notifications: ^5.0.0

Run flutter pub get to fetch the package.

Initializing Notifications

Initialize the notifications in your lib/main.dart file as follows:

dart
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
    FlutterLocalNotificationsPlugin();

Initialize the notifications in the main function:

dart
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final initializationSettingsAndroid =
      AndroidInitializationSettings('@mipmap/ic_launcher');
  final initializationSettingsIOS = IOSInitializationSettings(
      requestAlertPermission: true,
      requestBadgePermission: true,
      requestSoundPermission: true,
      onDidReceiveLocalNotification:
          (int id, String title, String body, String payload) async {});
  final initializationSettings = InitializationSettings(
      android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
  await flutterLocalNotificationsPlugin.initialize(initializationSettings,
      onSelectNotification: (String payload) async {});
  runApp(MyApp());
}

Ensure that you have the necessary permissions in your AndroidManifest.xml file for Android and the appropriate settings for iOS.

Adding Reminders

To add reminders for tasks, you can modify the _addTask function as follows:

dart
void _addTask() async {
  showDialog(
    context: context,
    builder: (BuildContext context) {
      return AlertDialog(
        title: Text('Add Task'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            TextField(
              decoration: InputDecoration(labelText: 'Task Title'),
              onChanged: (value) {
                setState(() {
                  _taskTitle = value;
                });
              },
            ),
            SizedBox(height: 16.0),
            Text('Due Date: ${_selectedDate.toString()}'),
            SizedBox(height: 8.0),
            TextButton(
              onPressed: () {
                _selectDate(context);
              },
              child: Text('Select Date'),
            ),
          ],
        ),
        actions: <Widget>[
          ElevatedButton(
            onPressed: () async {
              if (_taskTitle.isNotEmpty) {
                // Add the task to the list.
                setState(() {
                  tasks.add(Task(_taskTitle, _selectedDate));
                });
                // Schedule a notification for the task's due date.
                await _scheduleNotification(_taskTitle, _selectedDate);
                Navigator.of(context).pop();
              }
            },
            child: Text('Add'),
          ),
        ],
      );
    },
  );
}

The _scheduleNotification function can be implemented as follows:

dart
Future<void> _scheduleNotification(String title, DateTime dueDate) async {
  final now = DateTime.now();
  final difference = dueDate.difference(now);
  final scheduledDate = now.add(difference);

  final androidPlatformChannelSpecifics = AndroidNotificationDetails(
    'channel_id',
    'channel_name',
    'channel_description',
    importance: Importance.max,
    priority: Priority.high,
  );
  final iOSPlatformChannelSpecifics = IOSNotificationDetails();
  final platformChannelSpecifics = NotificationDetails(
    android: androidPlatformChannelSpecifics,
    iOS: iOSPlatformChannelSpecifics,
  );

  await flutterLocalNotificationsPlugin.schedule(
    0,
    'Task Reminder',
    'Your task "$title" is due today!',
    scheduledDate,
    platformChannelSpecifics,
  );
}

In this code, we calculate the difference between the due date and the current date to schedule the notification accordingly. We set up platform-specific notification details for Android and iOS and then schedule the notification using flutter_local_notifications.

Step 5: Testing the ToDo App

With the ToDo app now complete, you can test it on an emulator or a physical device. Make sure to run the following command in your project directory to launch the app:

bash
flutter run

You can add tasks, set due dates, and see the reminders in action. Congratulations! You’ve successfully created a ToDo app with Flutter that not only manages tasks but also sends reminders.

Conclusion

In this tutorial, we’ve learned how to create a ToDo app with Flutter that excels in task management and reminders. We started by setting up a new Flutter project, designed the user interface, added task functionality, and integrated task reminders using the flutter_local_notifications package. Building this app is just the beginning; you can further enhance it by adding features like task categories, priority levels, and cloud synchronization to make it even more powerful and user-friendly. Happy coding!

Remember that Flutter offers endless possibilities for creating versatile and user-friendly apps. By diving into Flutter development, you’ll be equipped to build a wide range of applications with a single codebase for both Android and iOS platforms. So, keep exploring, learning, and building amazing Flutter apps!

Previously at
Flag Argentina
Brazil
time icon
GMT-3
Full Stack Systems Analyst with a strong focus on Flutter development. Over 5 years of expertise in Flutter, creating mobile applications with a user-centric approach.