Membuat Aplikasi To-Do List di DartPad di-Generate ke APK


Membuat Aplikasi To-Do List di DartPad yang Nantinya Bisa di-Generate ke APK



Di era digital seperti sekarang, hampir semua kegiatan dapat dibantu dengan aplikasi. Salah satu aplikasi sederhana tetapi sangat bermanfaat untuk belajar pemrograman adalah To-Do List.

Aplikasi To-Do List digunakan untuk mencatat berbagai tugas atau kegiatan yang perlu dilakukan. Selain bermanfaat dalam kehidupan sehari-hari, proyek ini juga cocok bagi pelajar yang sedang mempelajari Dart dan Flutter, karena kita dapat belajar membuat tampilan aplikasi, mengelola data, menggunakan widget, serta memahami logika pemrograman.

Pada artikel ini, kita akan mempelajari bagaimana membuat aplikasi To-Do List menggunakan DartPad, kemudian memahami bagaimana kode tersebut dapat dikembangkan menjadi project Flutter dan akhirnya di-generate menjadi file APK Android.


Apa Itu To-Do List?

To-Do List adalah daftar berisi tugas, pekerjaan, atau kegiatan yang ingin diselesaikan.

Contohnya:

  • Belajar Flutter

  • Mengerjakan tugas sekolah

  • Membaca buku

  • Membuat project

  • Mengumpulkan tugas

  • Mempersiapkan presentasi

Dengan adanya To-Do List, pengguna dapat mengetahui kegiatan apa saja yang belum selesai dan kegiatan mana yang sudah dikerjakan.

Dalam aplikasi digital, To-Do List biasanya dilengkapi dengan fitur seperti:

  • Menambahkan tugas

  • Mengedit tugas

  • Menghapus tugas

  • Menandai tugas selesai

  • Menampilkan jumlah tugas

  • Menyimpan data tugas


Apa Itu DartPad?

DartPad merupakan editor online yang memungkinkan kita mencoba kode Dart secara langsung melalui browser. DartPad juga mendukung Flutter sehingga kita dapat membuat dan menjalankan contoh aplikasi Flutter tanpa harus langsung membuat project Flutter secara lokal. (Dart)

Hal ini sangat membantu bagi pemula karena kita dapat mempelajari dasar-dasar Flutter tanpa harus langsung melakukan konfigurasi project yang cukup panjang.

DartPad juga menyediakan fitur seperti autocomplete, formatter, pemeriksaan error, serta preview hasil aplikasi. (Dart)


Mengapa Membuat To-Do List?

To-Do List merupakan salah satu project yang bagus untuk latihan karena memiliki tingkat kesulitan yang relatif mudah tetapi sudah memperkenalkan banyak konsep penting dalam Flutter.

Melalui project ini, kita dapat mempelajari:

  1. Struktur dasar aplikasi Flutter.

  2. Penggunaan widget.

  3. StatelessWidget dan StatefulWidget.

  4. Penggunaan TextField.

  5. Penggunaan ListView.

  6. Penggunaan Checkbox.

  7. Penggunaan tombol.

  8. Penggunaan setState().

  9. Pengelolaan data dalam sebuah list.

  10. Konsep CRUD sederhana.

CRUD merupakan singkatan dari:

  • Create → membuat atau menambahkan tugas.

  • Read → menampilkan tugas.

  • Update → mengubah tugas.

  • Delete → menghapus tugas.

Dengan satu project sederhana, kita sudah dapat mempraktikkan banyak konsep pemrograman aplikasi.


Persiapan

Sebelum mulai, kita membutuhkan:

  • Browser seperti Chrome atau Edge.

  • Koneksi internet.

  • DartPad.

  • Pengetahuan dasar Dart.

  • Kemauan untuk mencoba dan memahami kode.

Untuk tahap awal, kita dapat menggunakan DartPad tanpa harus langsung menginstal Flutter di komputer.


Membuat Project To-Do List di DartPad

Buka DartPad dan pilih mode Flutter.

Kemudian masukkan kode berikut:

import 'package:flutter/material.dart';

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

class TodoApp extends StatelessWidget {
  const TodoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'To-Do List',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        useMaterial3: true,
      ),
      home: const TodoPage(),
    );
  }
}

class Todo {
  String title;
  bool isDone;

  Todo({
    required this.title,
    this.isDone = false,
  });
}

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

  @override
  State<TodoPage> createState() => _TodoPageState();
}

class _TodoPageState extends State<TodoPage> {
  final List<Todo> todos = [
    Todo(title: 'Belajar Flutter'),
    Todo(title: 'Mengerjakan tugas sekolah'),
    Todo(title: 'Membaca materi Dart'),
  ];

  final TextEditingController controller = TextEditingController();

  void addTodo() {
    if (controller.text.trim().isEmpty) return;

    setState(() {
      todos.add(
        Todo(title: controller.text.trim()),
      );
    });

    controller.clear();
    Navigator.pop(context);
  }

  void showAddTodoDialog() {
    controller.clear();

    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: const Text('Tambah Tugas'),
          content: TextField(
            controller: controller,
            autofocus: true,
            decoration: const InputDecoration(
              hintText: 'Masukkan tugas...',
              border: OutlineInputBorder(),
            ),
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('Batal'),
            ),
            ElevatedButton(
              onPressed: addTodo,
              child: const Text('Tambah'),
            ),
          ],
        );
      },
    );
  }

  void editTodo(int index) {
    controller.text = todos[index].title;

    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: const Text('Edit Tugas'),
          content: TextField(
            controller: controller,
            autofocus: true,
            decoration: const InputDecoration(
              hintText: 'Edit tugas...',
              border: OutlineInputBorder(),
            ),
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('Batal'),
            ),
            ElevatedButton(
              onPressed: () {
                if (controller.text.trim().isEmpty) return;

                setState(() {
                  todos[index].title = controller.text.trim();
                });

                controller.clear();
                Navigator.pop(context);
              },
              child: const Text('Simpan'),
            ),
          ],
        );
      },
    );
  }

  void deleteTodo(int index) {
    setState(() {
      todos.removeAt(index);
    });

    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        content: Text('Tugas berhasil dihapus'),
      ),
    );
  }

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

  @override
  Widget build(BuildContext context) {
    int completed = todos.where((todo) => todo.isDone).length;

    return Scaffold(
      backgroundColor: const Color(0xFFF5F7FA),

      appBar: AppBar(
        title: const Text(
          'To-Do List',
          style: TextStyle(
            fontWeight: FontWeight.bold,
          ),
        ),
        centerTitle: true,
        backgroundColor: Colors.blue,
        foregroundColor: Colors.white,
      ),

      body: Column(
        children: [
          Container(
            width: double.infinity,
            margin: const EdgeInsets.all(16),
            padding: const EdgeInsets.all(20),
            decoration: BoxDecoration(
              color: Colors.blue,
              borderRadius: BorderRadius.circular(20),
            ),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const Text(
                  'Daftar Tugas',
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 24,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                const SizedBox(height: 8),
                Text(
                  '$completed dari ${todos.length} tugas selesai',
                  style: const TextStyle(
                    color: Colors.white70,
                    fontSize: 16,
                  ),
                ),
              ],
            ),
          ),

          Expanded(
            child: todos.isEmpty
                ? const Center(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Icon(
                          Icons.check_circle_outline,
                          size: 80,
                          color: Colors.grey,
                        ),
                        SizedBox(height: 15),
                        Text(
                          'Tidak ada tugas',
                          style: TextStyle(
                            fontSize: 20,
                            color: Colors.grey,
                          ),
                        ),
                      ],
                    ),
                  )
                : ListView.builder(
                    padding: const EdgeInsets.symmetric(horizontal: 16),
                    itemCount: todos.length,
                    itemBuilder: (context, index) {
                      final todo = todos[index];

                      return Card(
                        margin: const EdgeInsets.only(bottom: 10),
                        elevation: 2,
                        shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(15),
                        ),
                        child: ListTile(
                          leading: Checkbox(
                            value: todo.isDone,
                            onChanged: (value) {
                              setState(() {
                                todo.isDone = value ?? false;
                              });
                            },
                          ),

                          title: Text(
                            todo.title,
                            style: TextStyle(
                              fontSize: 16,
                              fontWeight: FontWeight.w500,
                              decoration: todo.isDone
                                  ? TextDecoration.lineThrough
                                  : TextDecoration.none,
                              color: todo.isDone
                                  ? Colors.grey
                                  : Colors.black,
                            ),
                          ),

                          trailing: Row(
                            mainAxisSize: MainAxisSize.min,
                            children: [
                              IconButton(
                                icon: const Icon(
                                  Icons.edit,
                                  color: Colors.orange,
                                ),
                                onPressed: () => editTodo(index),
                              ),

                              IconButton(
                                icon: const Icon(
                                  Icons.delete,
                                  color: Colors.red,
                                ),
                                onPressed: () => deleteTodo(index),
                              ),
                            ],
                          ),
                        ),
                      );
                    },
                  ),
          ),
        ],
      ),

      floatingActionButton: FloatingActionButton.extended(
        onPressed: showAddTodoDialog,
        backgroundColor: Colors.blue,
        foregroundColor: Colors.white,
        icon: const Icon(Icons.add),
        label: const Text('Tambah Tugas'),
      ),
    );
  }
}

Penjelasan Program

1. MaterialApp

MaterialApp(
  title: 'To-Do List',
  home: const TodoPage(),
)

MaterialApp merupakan widget utama yang digunakan untuk membangun aplikasi dengan desain Material.

Di dalamnya kita menentukan judul aplikasi dan halaman pertama yang akan ditampilkan.


2. Class Todo

class Todo {
  String title;
  bool isDone;
}

Class Todo digunakan sebagai model data untuk menyimpan sebuah tugas.

title digunakan untuk menyimpan nama tugas, sedangkan isDone digunakan untuk mengetahui apakah tugas sudah selesai.


3. StatefulWidget

Halaman utama menggunakan StatefulWidget.

Alasannya adalah isi aplikasi dapat berubah ketika pengguna:

  • Menambahkan tugas.

  • Menghapus tugas.

  • Mengedit tugas.

  • Mencentang tugas.

Perubahan tersebut membutuhkan setState() agar tampilan aplikasi diperbarui.


4. TextEditingController

final TextEditingController controller =
    TextEditingController();

Controller digunakan untuk mengambil teks yang dimasukkan pengguna melalui TextField.

Contohnya ketika pengguna menulis:

Mengerjakan tugas Flutter

teks tersebut dapat diambil melalui:

controller.text

5. Menambahkan Tugas

Fungsi:

void addTodo()

digunakan untuk menambahkan tugas baru ke dalam list.

Data ditambahkan menggunakan:

todos.add(
  Todo(title: controller.text.trim()),
);

Setelah itu setState() membuat tampilan aplikasi diperbarui.


6. Menandai Tugas Selesai

Aplikasi menggunakan:

Checkbox(
  value: todo.isDone,
)

Ketika checkbox dicentang, nilai isDone berubah menjadi true.

Teks tugas kemudian diberikan efek:

TextDecoration.lineThrough

sehingga tugas terlihat seperti sudah selesai.


7. Mengedit Tugas

Tombol edit menggunakan:

IconButton(
  icon: const Icon(Icons.edit),
)

Ketika ditekan, aplikasi membuka dialog untuk mengubah nama tugas.


8. Menghapus Tugas

Tugas dapat dihapus menggunakan:

todos.removeAt(index);

Kemudian setState() digunakan agar tugas tersebut langsung hilang dari tampilan.


Hasil Aplikasi

Setelah kode dijalankan, kita akan mendapatkan aplikasi sederhana dengan tampilan seperti:

┌──────────────────────────────┐
│          To-Do List          │
├──────────────────────────────┤
│                              │
│  Daftar Tugas                │
│  1 dari 3 tugas selesai      │
│                              │
├──────────────────────────────┤
│                              │
│ ☑ Belajar Flutter       ✏ 🗑 │
│                              │
│ ☐ Mengerjakan tugas     ✏ 🗑 │
│                              │
│ ☐ Membaca materi Dart   ✏ 🗑 │
│                              │
│                    +         │
│              Tambah Tugas    │
└──────────────────────────────┘

Tampilan tersebut masih dapat dikembangkan sesuai kebutuhan.


Apakah DartPad Bisa Langsung Menghasilkan APK?

Tidak secara langsung.

DartPad sangat cocok untuk belajar, mencoba, dan menguji kode Flutter melalui browser. Namun, untuk menghasilkan aplikasi Android dalam bentuk APK, kode tersebut perlu dipindahkan ke project Flutter lokal. DartPad sendiri merupakan playground online, sedangkan proses build Android dilakukan menggunakan toolchain Flutter/Android. (Dart)

Alurnya adalah:

DartPad
    ↓
Membuat dan menguji kode
    ↓
Flutter Project
    ↓
VS Code / Android Studio
    ↓
Testing
    ↓
flutter build apk
    ↓
app-release.apk

Memindahkan Project ke VS Code

Setelah aplikasi berhasil dicoba di DartPad, kita dapat membuat project Flutter baru.

Buka terminal VS Code dan jalankan:

flutter create todo_list

Masuk ke folder project:

cd todo_list

Kemudian buka project tersebut:

code .

Selanjutnya buka:

lib/main.dart

Hapus kode bawaan Flutter dan masukkan kode To-Do List yang telah dibuat.

Untuk menjalankan aplikasi:

flutter run

Flutter juga menyediakan perintah flutter run untuk menjalankan aplikasi ketika melakukan pengujian melalui command line. (GitHub)


Membuat APK

Setelah aplikasi selesai dibuat dan diuji, kita dapat membuat file APK menggunakan:

flutter build apk

Flutter mendukung pembuatan APK release melalui perintah tersebut. Untuk APK yang dipisahkan berdasarkan arsitektur perangkat, Flutter menyediakan:

flutter build apk --split-per-abi

Hasil APK akan berada di dalam folder:

build/app/outputs/flutter-apk/

Dokumentasi resmi Flutter juga menjelaskan bahwa --split-per-abi dapat menghasilkan APK untuk beberapa arsitektur Android, seperti armeabi-v7a, arm64-v8a, dan x86_64. (Dokumentasi Flutter)

Jika hanya ingin satu APK yang lebih universal, perintah tanpa --split-per-abi dapat digunakan, meskipun ukuran file bisa lebih besar karena memuat beberapa binary arsitektur. (Dokumentasi Flutter)


APK dan AAB, Apa Bedanya?

Dalam pengembangan Android terdapat dua format yang sering digunakan:

APK

.apk merupakan file aplikasi Android yang dapat digunakan untuk memasang aplikasi pada perangkat Android.

Format ini cocok ketika kita ingin menguji atau membagikan aplikasi secara langsung.

AAB

.aab atau Android App Bundle merupakan format yang direkomendasikan Google Play untuk distribusi aplikasi. Dokumentasi Flutter menyebutkan bahwa Google Play lebih memilih app bundle dibandingkan APK. (Dokumentasi Flutter)

Untuk membuat AAB:

flutter build appbundle

Hasilnya berada di:

build/app/outputs/bundle/release/app.aab

Pengembangan Selanjutnya

Aplikasi To-Do List yang kita buat masih merupakan versi dasar. Banyak fitur menarik yang dapat ditambahkan agar aplikasi menjadi lebih lengkap.

Beberapa pengembangan yang dapat dilakukan adalah:

1. Kategori Tugas

Contohnya:

  • Sekolah

  • Pribadi

  • Project

  • Belanja

2. Prioritas

Setiap tugas dapat memiliki prioritas:

  • 🔴 Tinggi

  • 🟡 Sedang

  • 🟢 Rendah

3. Deadline

Tambahkan tanggal dan waktu untuk setiap tugas.

4. Pencarian

Pengguna dapat mencari tugas berdasarkan kata tertentu.

5. Dark Mode

Tambahkan pilihan tema terang dan gelap.

6. Penyimpanan Permanen

Versi sederhana pada artikel ini menyimpan data selama aplikasi berjalan. Untuk aplikasi yang lebih serius, data dapat disimpan menggunakan database lokal atau mekanisme penyimpanan lokal.

7. Notifikasi

Aplikasi dapat dikembangkan agar memberikan pengingat ketika deadline tugas sudah dekat.


Kesimpulan

Membuat aplikasi To-Do List merupakan salah satu cara yang menarik untuk memulai belajar Flutter dan Dart. Walaupun aplikasinya terlihat sederhana, project ini memperkenalkan banyak konsep penting seperti widget, state, list, input pengguna, event, CRUD, dan pengelolaan data.

DartPad dapat digunakan sebagai tempat awal untuk mencoba dan memahami kode Flutter secara cepat melalui browser. Setelah kode berhasil dan aplikasi ingin dikembangkan lebih lanjut, project dapat dipindahkan ke Flutter di komputer menggunakan VS Code atau Android Studio. (Dart)

Tahap akhirnya adalah melakukan proses build menggunakan Flutter sehingga aplikasi dapat menghasilkan file APK Android. Untuk kebutuhan distribusi melalui Google Play, format AAB lebih disarankan, sedangkan APK sangat berguna untuk pengujian dan distribusi langsung. (Dokumentasi Flutter)

Dengan project sederhana ini, kita tidak hanya belajar membuat sebuah aplikasi, tetapi juga belajar memahami alur pengembangan aplikasi dari kode hingga menjadi aplikasi Android yang dapat dijalankan pada perangkat.

Belajar coding tidak harus dimulai dari project yang rumit. Mulailah dari aplikasi sederhana, pahami setiap baris kode, kemudian kembangkan sedikit demi sedikit. Dari satu To-Do List, kita bisa belajar banyak hal tentang dunia pengembangan aplikasi.

Komentar

Postingan populer dari blog ini

Transformasi Digital: Dari Sekadar Scroll HP, Kini Saatnya Bikin Aplikasi Sendiri!

Kupas Tuntas Pembuatan BMI calculator