IDENTITAS MODUL
| Item | Keterangan |
|---|---|
| Mata Pelajaran | Pemrograman Mobile (Flutter) |
| Kelas / Semester | XI PPLG / Ganjil |
| Alokasi Waktu | 14 JP (3 x pertemuan @ 1 pekan jadwal Blok) |
| Materi Pokok | Form, Validasi, Navigasi & Layout Lanjutan |
| Model Pembelajaran | Project Based Learning (PjBL) + Pair Programming |
TUJUAN PEMBELAJARAN
Setelah mengikuti praktikum ini, peserta didik mampu:
Kognitif (C2-C3)
- Menjelaskan fungsi Form, GlobalKey<FormState>, dan TextFormField
- Mengidentifikasi jenis-jenis validator pada form Flutter
- Menjelaskan alur navigasi antar halaman (Navigator.push & Navigator.pop)
Psikomotorik (C4-C6)
- Membuat form input transaksi kas dengan validasi lengkap
- Mengimplementasikan showDatePicker untuk input tanggal transaksi
- Menampilkan data transaksi ke ListView menggunakan Card dan ListTile
- Menghitung total pemasukan, pengeluaran, dan saldo kas secara otomatis
- Menerapkan Hero animation pada transisi antar halaman
- Membuat fitur edit & hapus transaksi
Afektif
- Menumbuhkan ketelitian dan kejujuran dalam pencatatan keuangan
- Mengembangkan inisiatif dengan menambah fitur kreatif
- Berpikir kritis dalam menyelesaikan error (debugging)
里 CAPAIAN PEMBELAJARAN (CP)
Peserta didik mampu mengembangkan aplikasi mobile sederhana menggunakan framework Flutter dengan menerapkan konsep widget, state management, form handling, dan navigasi antar halaman sesuai kebutuhan pengguna.
FITUR YANG HARUS DIBUAT
✅ Fitur Wajib
| No | Fitur | Widget/Konsep |
|---|---|---|
| 1 | Form input transaksi (Keterangan, Jumlah, Nama, Jenis, Tanggal, Catatan) | Form, TextFormField, Radio |
| 2 | Validasi tiap field | validator, GlobalKey<FormState> |
| 3 | Date picker untuk tanggal transaksi | showDatePicker |
| 4 | Kartu ringkasan: Total Pemasukan, Pengeluaran, dan Saldo | Card, Row, Text |
| 5 | Simpan ke List → tampil di ListView | ListView.builder, Card, ListTile |
| 6 | Tap item → Detail Page | Navigator.push, Hero |
| 7 | Edit & Hapus data (saldo otomatis ikut berubah) | showDialog, setState |
⭐ Fitur Nilai Tambahan (pilih minimal 1)
- Search / filter berdasarkan keterangan
- Filter tab: Semua / Pemasukan / Pengeluaran
- Dark mode toggle
- ⚠️ Peringatan jika saldo menjadi minus
- Simpan data ke shared_preferences
- Animasi transisi custom
- Grafik sederhana pemasukan vs pengeluaran
️ STRUKTUR PROJECT
kas_kelas/
├── lib/
│ ├── main.dart
│ ├── models/
│ │ └── transaksi.dart
│ ├── pages/
│ │ ├── form_page.dart
│ │ ├── list_page.dart
│ │ └── detail_page.dart
│ └── widgets/
│ └── ringkasan_kas.dart
└── pubspec.yaml
Tambahkan package intl pada pubspec.yaml untuk format tanggal dan rupiah:
dependencies:
flutter:
sdk: flutter
intl: ^0.19.0
STARTER CODE
1. lib/models/transaksi.dart
class Transaksi {
String id;
String keterangan;
int jumlah;
String jenis; // 'Pemasukan' atau 'Pengeluaran'
String nama; // penyetor / penerima
DateTime tanggal;
String? catatan;
Transaksi({
required this.id,
required this.keterangan,
required this.jumlah,
required this.jenis,
required this.nama,
required this.tanggal,
this.catatan,
});
bool get isPemasukan => jenis == 'Pemasukan';
}
2. lib/main.dart
import 'package:flutter/material.dart';
import 'pages/list_page.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Kas Kelas',
theme: ThemeData(
colorSchemeSeed: Colors.indigo,
useMaterial3: true,
),
home: const ListPage(),
);
}
}
3. lib/pages/list_page.dart (Starter)
import 'package:flutter/material.dart';
import '../models/transaksi.dart';
import 'form_page.dart';
import 'detail_page.dart';
class ListPage extends StatefulWidget {
const ListPage({super.key});
@override
State<ListPage> createState() => _ListPageState();
}
class _ListPageState extends State<ListPage> {
// TODO 1: Buat List<Transaksi> kosong untuk menampung data
// TODO 2: Buat getter totalPemasukan, totalPengeluaran, dan saldo
// Hint: gunakan where() dan fold()
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Kas Kelas XI PPLG')),
body: Column(
children: [
// TODO 3: Kartu ringkasan (Pemasukan, Pengeluaran, Saldo)
Expanded(
child: /* TODO 4: Tampilkan ListView.builder
- Jika list kosong, tampilkan ikon + tulisan "Belum ada transaksi"
- Jika ada data, tampilkan Card + ListTile
- Pemasukan: ikon panah naik hijau, Pengeluaran: ikon panah turun merah
*/
const Center(child: Text('Belum ada transaksi')),
),
],
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () async {
// TODO 5: Navigasi ke FormPage dan tunggu hasilnya
// Jika hasil != null, tambahkan ke list dan setState
},
),
);
}
}
4. lib/pages/form_page.dart (Starter)
import 'package:flutter/material.dart';
import '../models/transaksi.dart';
class FormPage extends StatefulWidget {
final Transaksi? transaksiEdit; // null = tambah baru, != null = edit
const FormPage({super.key, this.transaksiEdit});
@override
State<FormPage> createState() => _FormPageState();
}
class _FormPageState extends State<FormPage> {
final _formKey = GlobalKey<FormState>();
// TODO 1: Buat TextEditingController untuk keterangan, jumlah, nama, catatan
// TODO 2: Buat variabel DateTime _tanggal = DateTime.now()
// TODO 3: Buat variabel String _jenis = 'Pemasukan'
@override
void initState() {
super.initState();
// TODO 4: Jika widget.transaksiEdit != null, isi controller dengan data lama
}
@override
void dispose() {
// TODO 5: Dispose semua controller
super.dispose();
}
Future<void> _pilihTanggal() async {
// TODO 6: Gunakan showDatePicker
// Hint: firstDate: DateTime(2020), lastDate: DateTime.now()
}
void _simpan() {
// TODO 7: Validasi form dengan _formKey.currentState!.validate()
// Jika valid, buat objek Transaksi baru (jumlah: int.parse(...))
// Kembalikan ke halaman sebelumnya dengan Navigator.pop(context, transaksi)
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.transaksiEdit == null ? 'Tambah Transaksi' : 'Edit Transaksi'),
),
body: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.all(16),
children: [
// TODO 8: Radio button Jenis (Pemasukan / Pengeluaran)
// TODO 9: TextFormField Keterangan (validator: min 3 karakter)
// TODO 10: TextFormField Jumlah (keyboardType: number, validator: angka & > 0)
// TODO 11: TextFormField Nama Penyetor / Penerima
// TODO 12: Field Tanggal → InkWell + showDatePicker
// TODO 13: TextFormField Catatan (maxLines: 3, boleh kosong)
// TODO 14: Tombol Simpan
],
),
),
);
}
}
5. lib/pages/detail_page.dart (Starter)
import 'package:flutter/material.dart';
import '../models/transaksi.dart';
class DetailPage extends StatelessWidget {
final Transaksi transaksi;
const DetailPage({super.key, required this.transaksi});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Detail Transaksi')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: [
// TODO 1: Hero animation untuk ikon transaksi
// Hint: Hero(tag: transaksi.id, child: CircleAvatar(...))
// TODO 2: Card berisi info lengkap transaksi menggunakan ListTile
// TODO 3: Format tanggal dengan intl (dd MMMM yyyy)
// TODO 4: Format jumlah ke rupiah (NumberFormat.currency)
],
),
),
);
}
}
✅ CHECKLIST FITUR (Centang Sendiri)
Tandai / centang fitur yang sudah dikerjakan.
Fitur Wajib
- ☐ Halaman list menampilkan data dari List<Transaksi>
- ☐ Halaman list menampilkan pesan "Belum ada transaksi" saat kosong
- ☐ Kartu ringkasan menampilkan total pemasukan, pengeluaran, dan saldo
- ☐ Saldo berubah otomatis saat transaksi ditambah, diedit, atau dihapus
- ☐ Form memiliki 4 TextFormField (keterangan, jumlah, nama, catatan)
- ☐ Validator keterangan: tidak boleh kosong, minimal 3 karakter
- ☐ Validator jumlah: hanya angka dan harus lebih dari 0
- ☐ Validator nama: tidak boleh kosong
- ☐ Field tanggal menggunakan showDatePicker
- ☐ Radio button jenis (Pemasukan / Pengeluaran)
- ☐ Tombol Simpan memvalidasi form sebelum menyimpan
- ☐ Data baru muncul di ListView setelah disimpan
- ☐ Tap item → navigasi ke Detail Page
- ☐ Detail Page menampilkan semua field transaksi
- ☐ Tombol Edit → membuka Form dengan data terisi
- ☐ Tombol Hapus → konfirmasi dengan AlertDialog
- ☐ Hapus → data hilang dari list
- ☐ Jumlah ditampilkan dalam format rupiah (contoh: Rp 5.000)
- ☐ Warna dan ikon berbeda untuk pemasukan dan pengeluaran
- ☐ Menggunakan Card dan ListTile di list
- ☐ Menggunakan Hero animation pada ikon transaksi
⭐ Fitur Nilai Tambahan (pilih minimal 1)
- ☐ Search/filter berdasarkan keterangan
- ☐ Filter tab Semua / Pemasukan / Pengeluaran
- ☐ Dark mode toggle
- ☐ Peringatan saat saldo minus
- ☐ Simpan data ke shared_preferences
- ☐ Animasi transisi custom
PANDUAN CODE REVIEW (10 Menit Akhir)
Persiapkan jawaban terbaik untuk 3 pertanyaan acak:
- "Coba jelaskan apa fungsi GlobalKey<FormState> di kodemu?"
- "Kenapa TextEditingController harus di-dispose?"
- "Apa bedanya Navigator.push dan Navigator.pop?"
- "Bagaimana caramu menghitung saldo dari list transaksi?"
- "Apa fungsi setState di tombol hapus, dan kenapa saldo ikut berubah?"
Penilaian sikap: siswa yang bisa menjawab = bonus poin partisipasi.
TUGAS PENGUMPULAN
Format Artikel Blog (Wajib)
Judul: Praktikum Flutter — Aplikasi Kas Kelas
1. Identitas
Nama : ................
Kelas : ................
2. Tujuan Praktikum
(tulis 3-5 poin tujuan sesuai modul)
3. Screenshot Aplikasi
- Halaman Form Kosong
- Halaman Form Terisi
- Halaman List Transaksi + Ringkasan Saldo
- Halaman Detail
- Screenshot saat terjadi ERROR (WAJIB ADA!)
- Screenshot setelah error teratasi
4. Penjelasan Kode
- Jelaskan fungsi Form & GlobalKey
- Jelaskan cara kerja validator
- Jelaskan cara menghitung saldo
- Jelaskan alur navigasi
- Jelaskan fungsi Hero animation
5. Kendala & Solusi
(ceritakan minimal 1 error yang kamu alami + cara mengatasinya)
6. Fitur Kreatif yang Ditambahkan
(jelaskan fitur tambahan yang kamu buat)
7. Kesimpulan
(apa yang kamu pelajari dari praktikum ini)
Format Kirim ke Komentar Postingan ini
Nama :
Kelas :
Link Blog : https://...
Fitur Kreatif : (sebutkan)
Status : ✅ Selesai
KEBIJAKAN PENGGUNAAN AI
PENTING DIBACA SISWA!
- ✅ Boleh: Bertanya ke AI tentang konsep, error handling, atau penjelasan widget.
- ✅ Boleh: Minta AI menjelaskan kode yang sudah kamu tulis sendiri.
- ❌ Dilarang: Copy-paste 100% kode dari AI.
- ❌ Dilarang: Submit tanpa memahami kode.
- Wajib: Sertakan screenshot proses error + solusinya di blog. Ini bukti kamu benar-benar mengerjakan.
Sanksi: Jika terbukti copy-paste dan tidak bisa menjelaskan saat code review → nilai dianggap 0 dan wajib remedial.
RUBRIK PENILAIAN
| Aspek | Bobot | Kriteria |
|---|---|---|
| Kelengkapan Fitur Wajib | 40% | Semua checklist terpenuhi |
| Validasi Form | 15% | Validator berjalan & pesan error jelas |
| UI/UX & Layout | 15% | Rapi, konsisten, menggunakan Card/ListTile, saldo tampil jelas |
| Navigasi & Hero | 10% | Perpindahan halaman halus, Hero berfungsi |
| Artikel Blog | 10% | Lengkap, ada screenshot error & penjelasan |
| Fitur Kreatif | 5% | Ada fitur tambahan original |
| Code Review | 5% | Bisa menjelaskan kode sendiri |
Nilai Akhir = Total Skor (maks 100)
易 REFERENSI BELAJAR
- Flutter Form Docs
- Navigator & Routing
- Hero Animation
- DatePicker
- Package intl (format tanggal dan rupiah)
- YouTube: "Flutter Form Validation Tutorial"
Salam: Redaksi









