🎯 Pendahuluan
Jajan di kantin itu urusan serius. Apalagi saat jam istirahat — antrean panjang, waktu mepet, belum lagi rebutan kursi. Bayangkan kalau ada satu orang yang ditugaskan jastip (jasa titip), tapi semua pesanan harus dicatat manual lewat chat WhatsApp yang berantakan.
Nah, di praktikum kali ini, kita akan membangun aplikasi Flutter untuk mengelola jastip jajan kantin — dari memilih warung, memilih menu, memasukkan ke keranjang, sampai mengirim pesanan terformat ke WhatsApp jastip.
Yang menarik: semua ini kita kerjakan dalam 1 pertemuan (3 jam) dengan bantuan AI sebagai co-pilot coding.
🎓 Tujuan Praktikum
Setelah menyelesaikan praktikum ini, siswa diharapkan mampu:
Memahami alur aplikasi nyata dari sisi user flow, bukan cuma "belajar widget"
Menerapkan navigasi antar halaman di Flutter
Mengelola state sederhana (keranjang) dengan
setStateMelakukan integrasi eksternal dengan
url_launcherke WhatsAppMemanfaatkan AI sebagai asisten belajar, bukan sebagai mesin copy-paste
🗺️ Alur Aplikasi
Sebelum ngoding, pahami dulu alurnya:
[Pilih Warung] → [Lihat Menu Warung] → [Tambah ke Keranjang]
↓
[Kirim ke WA Jastip] ← [Isi Data & Checkout] ← [Lihat Keranjang]Struktur data sederhana:
Warung → Menu (nama, harga) → Keranjang (menu + qty) → Order → WhatsApp
Prinsip yang dipegang di praktikum ini: alur jalan dulu, polish belakangan. Tidak ada database, tidak ada login, tidak ada riwayat pesanan. Fokus ke alur inti.
📁 Struktur Folder Projek
lib/
├── main.dart // Entry point + state keranjang
├── models.dart // Warung, Menu, CartItem
├── data_dummy.dart // Data warung & menu
└── screens/
├── home_screen.dart // Daftar warung
├── menu_screen.dart // Menu per warung
└── cart_screen.dart // Keranjang + checkout WAKenapa sesederhana ini? Supaya siswa bisa fokus ke alur, bukan terjebak konfigurasi folder.
⚙️ Persiapan
1. Buat projek baru:
flutter create jastip_kantin
cd jastip_kantin2. Tambahkan dependency di pubspec.yaml:
dependencies: flutter: sdk: flutter url_launcher: ^6.2.5
3. Jalankan:
flutter pub get
🧩 Bagian 1 — Models & Data Dummy
Buat file lib/models.dart:
class Warung { final String nama; final String emoji; Warung({required this.nama, required this.emoji}); } class Menu { final String nama; final int harga; final String warungNama; Menu({required this.nama, required this.harga, required this.warungNama}); } class CartItem { final Menu menu; int qty; CartItem({required this.menu, this.qty = 1}); int get subtotal => menu.harga * qty; }
Buat file lib/data_dummy.dart:
import 'models.dart'; final List<Warung> daftarWarung = [ Warung(nama: 'Warung Bu Siti', emoji: '🍜'), Warung(nama: 'Kantin Pak Budi', emoji: '🍛'), Warung(nama: 'Kantin Sehat', emoji: '🥗'), ]; final List<Menu> daftarMenu = [ Menu(nama: 'Indomie Goreng', harga: 8000, warungNama: 'Warung Bu Siti'), Menu(nama: 'Es Teh', harga: 3000, warungNama: 'Warung Bu Siti'), Menu(nama: 'Nasi Ayam', harga: 12000, warungNama: 'Kantin Pak Budi'), Menu(nama: 'Nasi Telur', harga: 10000, warungNama: 'Kantin Pak Budi'), Menu(nama: 'Salad Buah', harga: 15000, warungNama: 'Kantin Sehat'), Menu(nama: 'Jus Alpukat', harga: 10000, warungNama: 'Kantin Sehat'), ];
💡 Catatan untuk siswa: Perhatikan bahwa
CartItem.qtytidakfinalkarena nilainya berubah saat user menambah/mengurangi jumlah. SedangkanMenu.hargafinalkarena tidak akan berubah.
🧩 Bagian 2 — State Keranjang di Root
Buka lib/main.dart, kita taruh state keranjang di root widget supaya bisa diakses dari semua halaman:
import 'package:flutter/material.dart'; import 'screens/home_screen.dart'; import 'models.dart'; void main() => runApp(const MyApp()); class MyApp extends StatefulWidget { const MyApp({super.key}); State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final List<CartItem> keranjang = []; void tambahKeKeranjang(Menu menu) { setState(() { final idx = keranjang.indexWhere((c) => c.menu.nama == menu.nama); if (idx >= 0) { keranjang[idx].qty++; } else { keranjang.add(CartItem(menu: menu)); } }); } Widget build(BuildContext context) { return MaterialApp( title: 'Jastip Kantin', theme: ThemeData(primarySwatch: Colors.orange), home: HomeScreen( keranjang: keranjang, onTambah: tambahKeKeranjang, ), ); } }
💡 Diskusi: Kenapa state keranjang ditaruh di
MyApp, bukan diCartScreen? Karena keranjang harus tetap hidup saat user berpindah halaman. Kalau ditaruh diCartScreen, begitu user keluar dari halaman itu, keranjangnya hilang.
🧩 Bagian 3 — Halaman Daftar Warung
Buat lib/screens/home_screen.dart:
import 'package:flutter/material.dart'; import '../models.dart'; import '../data_dummy.dart'; import 'menu_screen.dart'; import 'cart_screen.dart'; class HomeScreen extends StatelessWidget { final List<CartItem> keranjang; final Function(Menu) onTambah; const HomeScreen({super.key, required this.keranjang, required this.onTambah}); Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Jastip Kantin'), actions: [ IconButton( icon: Badge( label: Text('${keranjang.fold(0, (s, c) => s + c.qty)}'), isLabelVisible: keranjang.isNotEmpty, child: const Icon(Icons.shopping_cart), ), onPressed: () => Navigator.push(context, MaterialPageRoute( builder: (_) => CartScreen(keranjang: keranjang), )), ), ], ), body: ListView.builder( itemCount: daftarWarung.length, itemBuilder: (context, i) { final w = daftarWarung[i]; return Card( margin: const EdgeInsets.all(8), child: ListTile( leading: Text(w.emoji, style: const TextStyle(fontSize: 32)), title: Text(w.nama), trailing: const Icon(Icons.chevron_right), onTap: () => Navigator.push(context, MaterialPageRoute( builder: (_) => MenuScreen( warung: w, keranjang: keranjang, onTambah: onTambah, ), )), ), ); }, ), ); } }
🧩 Bagian 4 — Halaman Menu Warung
Buat lib/screens/menu_screen.dart:
import 'package:flutter/material.dart'; import '../models.dart'; import '../data_dummy.dart'; class MenuScreen extends StatelessWidget { final Warung warung; final List<CartItem> keranjang; final Function(Menu) onTambah; const MenuScreen({ super.key, required this.warung, required this.keranjang, required this.onTambah, }); Widget build(BuildContext context) { final menuWarung = daftarMenu.where((m) => m.warungNama == warung.nama).toList(); return Scaffold( appBar: AppBar(title: Text('${warung.emoji} ${warung.nama}')), body: ListView.builder( itemCount: menuWarung.length, itemBuilder: (context, i) { final m = menuWarung[i]; return ListTile( title: Text(m.nama), subtitle: Text('Rp ${m.harga}'), trailing: IconButton( icon: const Icon(Icons.add_circle, color: Colors.orange), onPressed: () { onTambah(m); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('${m.nama} ditambahkan'), duration: const Duration(seconds: 1), ), ); }, ), ); }, ), ); } }
🧩 Bagian 5 — Halaman Keranjang & Checkout WA
Buat lib/screens/cart_screen.dart:
import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; import '../models.dart'; class CartScreen extends StatefulWidget { final List<CartItem> keranjang; const CartScreen({super.key, required this.keranjang}); State<CartScreen> createState() => _CartScreenState(); } class _CartScreenState extends State<CartScreen> { final namaCtrl = TextEditingController(); final kelasCtrl = TextEditingController(); final catatanCtrl = TextEditingController(); final String nomorJastip = '6281234567890'; // Ganti dengan nomor WA jastip int get total => widget.keranjang.fold(0, (s, c) => s + c.subtotal); Future<void> kirimWA() async { if (widget.keranjang.isEmpty) return; if (namaCtrl.text.isEmpty || kelasCtrl.text.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Nama & kelas wajib diisi')), ); return; } final pesan = ''' Halo Kak Jastip! 🛒 Nama: ${namaCtrl.text} Kelas: ${kelasCtrl.text} Pesanan: ${widget.keranjang.map((c) => '- ${c.menu.nama} x${c.qty} = Rp${c.subtotal}').join('\n')} Total: Rp$total Catatan: ${catatanCtrl.text} '''; final url = Uri.parse( 'https://wa.me/$nomorJastip?text=${Uri.encodeComponent(pesan)}', ); if (await canLaunchUrl(url)) { await launchUrl(url, mode: LaunchMode.externalApplication); } } Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Keranjang')), body: widget.keranjang.isEmpty ? const Center(child: Text('Keranjang kosong 🛒')) : Column( children: [ Expanded( child: ListView.builder( itemCount: widget.keranjang.length, itemBuilder: (context, i) { final c = widget.keranjang[i]; return ListTile( title: Text(c.menu.nama), subtitle: Text('Rp ${c.menu.harga}'), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: const Icon(Icons.remove), onPressed: () => setState(() { if (c.qty > 1) { c.qty--; } else { widget.keranjang.removeAt(i); } }), ), Text('${c.qty}'), IconButton( icon: const Icon(Icons.add), onPressed: () => setState(() => c.qty++), ), ], ), ); }, ), ), Padding( padding: const EdgeInsets.all(16), child: Column( children: [ TextField( controller: namaCtrl, decoration: const InputDecoration(labelText: 'Nama'), ), TextField( controller: kelasCtrl, decoration: const InputDecoration(labelText: 'Kelas'), ), TextField( controller: catatanCtrl, decoration: const InputDecoration( labelText: 'Catatan (opsional)', ), ), const SizedBox(height: 12), Text( 'Total: Rp $total', style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 12), SizedBox( width: double.infinity, child: ElevatedButton.icon( icon: const Icon(Icons.send), label: const Text('Kirim ke WA Jastip'), onPressed: kirimWA, ), ), ], ), ), ], ), ); } }
⚠️ Penting: Ganti
nomorJastipdengan nomor WhatsApp asli jastip (format62...tanpa+dan tanpa0di depan).
✅ Uji Coba Aplikasi
Setelah semua file selesai, jalankan:
flutter run
Cek alur lengkap:
Pilih Warung Bu Siti → tambah Indomie Goreng + Es Teh
Kembali, pilih Kantin Pak Budi → tambah Nasi Ayam
Tap ikon keranjang di kanan atas → lihat badge jumlah item
Isi nama, kelas, catatan → tap Kirim ke WA Jastip
WhatsApp terbuka dengan pesan terformat rapi
Kalau semua jalan — selamat, aplikasimu sudah live! 🎉
🧠 Refleksi Belajar
Coba jawab pertanyaan berikut untuk mengukur pemahaman:
Kenapa state keranjang ditaruh di
MyApp, bukan diCartScreen?Kenapa
CartScreenpakaiStatefulWidgetsedangkanHomeScreenStatelessWidget?Apa fungsi
Uri.encodeComponent()pada URL WhatsApp?Bagaimana cara menambah fitur "pilih beberapa warung sekaligus dalam 1 pesanan"?
Apa yang perlu diubah kalau ingin menambah warung ke-4?
🚀 Tantangan Lanjutan
Untuk yang sudah selesai lebih cepat, coba tambahkan:
Level 1 (+5 menit): Tombol hapus item di keranjang
Level 2 (+10 menit): Format harga jadi
Rp 8.000pakai packageintlLevel 3 (+15 menit): Fitur pencarian menu di
MenuScreenLevel 4 (bonus): Simpan riwayat pesanan pakai
shared_preferences
💡 Tips Belajar dengan AI
AI itu co-pilot, bukan autopilot. Pola prompt yang sehat:
| ✅ Prompt Baik | ❌ Prompt Kurang Baik |
|---|---|
"Jelaskan konsep setState sebelum aku pakai" | "Buatkan aplikasi jastip lengkap" |
| "Error ini artinya apa dan kenapa muncul?" | "Fix kode ini" |
| "Tunjukkan 2 cara berbeda untuk passing data" | "Bikin yang paling bagus" |
| "Refactor kode ini biar lebih rapi" | "Ganti semua jadi clean architecture" |
Aturan main:
Ketik sendiri, jangan copy-paste
Harus bisa jelaskan setiap barisnya
Test dulu sebelum lanjut
Jangan minta AI buatkan 1 projek penuh sekaligus
📋 Checklist Praktikum
Centang kalau sudah selesai:
- □
Projek Flutter dibuat &
url_launcherterinstall - □
3 model (
Warung,Menu,CartItem) dibuat - □
Data dummy warung & menu terisi
- □
Halaman daftar warung tampil
- □
Halaman menu per warung tampil
- □
Tombol tambah berfungsi & badge update
- □
Halaman keranjang tampil dengan qty +/-
- □
Tombol kirim ke WA membuka WhatsApp
- □
Pesan WhatsApp terformat rapi
🏁 Penutup
Selamat! Dalam 3 jam, kamu sudah membangun aplikasi Flutter nyata dengan alur lengkap: dari memilih warung, memilih menu, mengelola keranjang, sampai integrasi ke WhatsApp.
Yang lebih penting dari aplikasinya: kamu sudah belajar berpikir dalam alur aplikasi, bukan cuma menumpuk widget. Skill ini yang akan kamu pakai di projek-projek berikutnya.
Tugas Akhir Praktikum:
📝 Tulis postingan blog pribadi yang berisi:
Screenshot aplikasi yang sudah kamu buat (minimal 3: home, menu, cart, WA)
Penjelasan singkat alur aplikasi versimu
Kendala yang kamu hadapi + cara mengatasinya (boleh karena bantuan AI)
Refleksi: apa hal baru yang kamu pahami tentang Flutter?
Link postinganmu, tempel di kolom komentar postingan ini 👇
Selamat berkarya, calon developer! 🚀
📝 Template Postingan Blog untuk Siswa
Petunjuk untuk siswa: Copy template di bawah ini ke blog kalian (WordPress/Medium/Hashnode/Blogger), lalu ganti semua bagian yang ada tanda [...] dengan isi kalian sendiri. Hapus bagian petunjuk yang tidak perlu.
📋 TEMPLATE — Mulai Copy dari Sini
Praktikum Flutter: Aplikasi Jastip Jajan Kantin — [Nama Kalian]
Nama: [Nama Lengkap]
Kelas: [Kelas]
Tanggal Praktikum: [DD MMMM YYYY]
Link Repo GitHub: [URL repo kalian, jika ada]
🎯 Pendahuluan
Pada praktikum kali ini, saya membuat aplikasi Jastip Jajan Kantin menggunakan Flutter. Aplikasi ini bertujuan untuk mempermudah proses pemesanan jajan di kantin melalui jasa titip (jastip), mulai dari memilih warung, memilih menu, mengelola keranjang, hingga mengirim pesanan ke WhatsApp jastip.
Alasan saya memilih/mengerjakan projek ini: [tulis 2-3 kalimat — misal: karena ingin belajar alur aplikasi nyata, atau karena tertarik dengan integrasi WhatsApp]
🗺️ Alur Aplikasi Versi Saya
[Gambarkan alur aplikasi yang kalian buat, bisa berupa teks atau diagram sederhana]
[Pilih Warung] → [Lihat Menu] → [Tambah ke Keranjang] → [Checkout] → [Kirim ke WA]
Penjelasan singkat alur:
[Langkah 1 — misal: User membuka aplikasi dan melihat daftar warung]
[Langkah 2 — ...]
[Langkah 3 — ...]
[Langkah 4 — ...]
[Langkah 5 — ...]
🛠️ Teknologi & Tools yang Digunakan
Framework: Flutter [versi]
Bahasa: Dart
Package tambahan:
[url_launcher / intl / dll]Editor: [VS Code / Android Studio]
Bantuan AI: [ChatGPT / Claude / Gemini / lainnya]
📸 Screenshot Aplikasi
Wajib: Minimal 4 screenshot — home, menu, keranjang, dan WhatsApp terbuka.
1. Halaman Daftar Warung

Deskripsi: [jelaskan singkat apa yang tampil di halaman ini]
2. Halaman Menu Warung

Deskripsi: [jelaskan singkat]
3. Halaman Keranjang

Deskripsi: [jelaskan singkat]
4. Pesan Terkirim ke WhatsApp

Deskripsi: [jelaskan singkat]
💻 Potongan Kode Penting
Pilih 2-3 bagian kode yang menurut kalian paling penting atau paling menantang, lalu jelaskan.
Kode 1: [Nama fitur — misal: State Keranjang di Root]
[tempel kode kalian di sini]
Penjelasan: [jelaskan kenapa kode ini penting, apa fungsinya, dan kenapa kalian memilih cara ini]
Kode 2: [Nama fitur — misal: Generate Pesan WhatsApp]
[tempel kode kalian di sini]
Penjelasan: [jelaskan]
Kode 3 (opsional): [Nama fitur]
[tempel kode kalian di sini]
Penjelasan: [jelaskan]
🚧 Kendala yang Dihadapi & Cara Mengatasinya
Bagian ini paling penting — tunjukkan proses berpikir kalian, bukan cuma hasil akhir.
Kendala 1: [Judul kendala — misal: Badge keranjang tidak update]
Masalah: [jelaskan apa yang terjadi]
Pesan error (jika ada):
[tempel pesan error]
Cara saya mengatasinya: [jelaskan langkah-langkah — apakah tanya AI, baca dokumentasi, coba-coba sendiri?]
Pelajaran yang saya ambil: [1-2 kalimat]
Kendala 2: [Judul kendala]
Masalah: [jelaskan]
Cara saya mengatasinya: [jelaskan]
Pelajaran yang saya ambil: [jelaskan]
Kendala 3 (opsional): [Judul kendala]
Masalah: [jelaskan]
Cara saya mengatasinya: [jelaskan]
Pelajaran yang saya ambil: [jelaskan]
🤖 Peran AI dalam Proses Belajar Saya
Refleksikan bagaimana kalian menggunakan AI selama praktikum ini.
Prompt yang paling membantu saya:
"[tulis 1 prompt yang menurut kalian paling berguna]"
Prompt yang ternyata tidak membantu:
"[tulis 1 prompt yang hasilnya kurang memuaskan, dan kenapa]"
Yang saya sadari tentang belajar dengan AI:
[tulis 2-3 kalimat — misal: AI membantu ketika saya stuck, tapi saya tetap harus paham logikanya]
🎓 Refleksi Belajar
Jawab pertanyaan berikut dengan bahasa kalian sendiri:
1. Kenapa state keranjang ditaruh di MyApp, bukan di CartScreen?
[Jawaban kalian]
2. Apa fungsi Uri.encodeComponent() pada URL WhatsApp?
[Jawaban kalian]
3. Bagaimana cara menambah warung ke-4 di aplikasi?
[Jawaban kalian]
4. Konsep Flutter apa yang paling saya kuasai setelah praktikum ini?
[Jawaban kalian]
5. Konsep apa yang masih ingin saya pelajari lebih dalam?
[Jawaban kalian]
🚀 Tantangan yang Saya Coba (Opsional)
Centang tantangan yang berhasil kalian selesaikan.
- □
Level 1: Tombol hapus item di keranjang
- □
Level 2: Format harga jadi
Rp 8.000pakaiintl - □
Level 3: Fitur pencarian menu
- □
Level 4 (bonus): Simpan riwayat pesanan
Screenshot tantangan (jika ada):

Penjelasan singkat: [jelaskan tantangan yang dikerjakan dan bagaimana hasilnya]
🏁 Kesimpulan
[tulis 3-5 kalimat — apa yang kalian dapat dari praktikum ini, apa rencana pengembangan selanjutnya, dan bagaimana perasaan kalian setelah berhasil menyelesaikan aplikasi]
🔗 Link Terkait
Repo GitHub: [URL]
Video demo (opsional): [URL YouTube/Drive]
Postingan guru (acuan): [URL postingan guru kalian]
Postingan ini dibuat sebagai bukti praktikum Flutter — [Nama Kalian], [Kelas], [Tanggal]







Tidak ada komentar:
Posting Komentar