📱 Membuat Aplikasi Kantin SMKN 1 Banjar dengan Flutter

Modul Praktikum RPL – Mobile Programming

Di era digital, pemesanan makanan tidak lagi harus datang langsung ke kantin. Dengan aplikasi mobile, siswa bisa memesan makanan dan minuman langsung dari kelas, lalu pesanan dikirim melalui WhatsApp ke kurir/jastip.

Pada praktikum ini, kita akan membuat Aplikasi Kantin SMKN 1 Banjar menggunakan Flutter (Dart) yang dapat:

  • Menampilkan daftar menu

  • Menambahkan item ke keranjang

  • Menghitung total harga otomatis

  • Checkout dan mengirim pesanan ke WhatsApp

  • Menyimpan nomor WhatsApp admin


🎯 Tujuan Pembelajaran

Setelah mengikuti praktikum ini, peserta didik mampu:

  1. Memahami struktur dasar project Flutter.

  2. Membuat tampilan UI menggunakan Widget.

  3. Mengelola state sederhana (keranjang belanja).

  4. Menggunakan package eksternal (url_launcher).

  5. Menghubungkan aplikasi dengan WhatsApp.

  6. Build APK aplikasi Android.


🧠 Konsep yang Dipelajari

KonsepPenjelasan
StatelessWidgetWidget yang tidak berubah
StatefulWidgetWidget yang bisa berubah (dynamic)
List & ObjectMenyimpan data menu
setState()Mengubah tampilan saat data berubah
url_launcherMembuka WhatsApp dari aplikasi
Build APKMengubah project menjadi file install Android

🛠 Persiapan Alat

Pastikan sudah terinstall:

  • Flutter SDK

  • Android Studio (Emulator)

  • VS Code + Extension Flutter

Cek dengan:

flutter doctor

🚀 Langkah Praktikum

1️⃣ Membuat Project Baru

flutter create kantin_smkn1banjar
cd kantin_smkn1banjar
code .

2️⃣ Tambahkan Dependency

Buka pubspec.yaml, tambahkan:

dependencies:
  flutter:
    sdk: flutter
  url_launcher: ^6.2.5

Lalu jalankan:

flutter pub get

📦 Struktur Aplikasi

Aplikasi ini memiliki fitur:

  • Beranda (Daftar Menu)

  • Keranjang

  • Checkout

  • Kirim ke WhatsApp


💻 FULL SOURCE CODE (main.dart)

Salin seluruh kode berikut ke:

lib/main.dart

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

void main() {
  runApp(KantinApp());
}

class KantinApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Kantin SMKN 1 Banjar',
      theme: ThemeData(primarySwatch: Colors.green),
      home: HomeScreen(),
    );
  }
}

class MenuItem {
  final String nama;
  final int harga;
  int qty;

  MenuItem({required this.nama, required this.harga, this.qty = 0});
}

List<MenuItem> daftarMenu = [
  MenuItem(nama: "Nasi Goreng", harga: 12000),
  MenuItem(nama: "Mie Ayam", harga: 10000),
  MenuItem(nama: "Bakso", harga: 13000),
  MenuItem(nama: "Es Teh", harga: 5000),
  MenuItem(nama: "Pop Ice", harga: 5000),
];

List<MenuItem> keranjang = [];
String nomorWA = "6281234567890";
int ongkir = 2000;

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {

  int get total =>
      keranjang.fold(0, (sum, item) => sum + (item.harga * item.qty));

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Kantin SMKN 1 Banjar"),
        actions: [
          IconButton(
            icon: Icon(Icons.shopping_cart),
            onPressed: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(builder: (_) => CartScreen()));
            },
          )
        ],
      ),
      body: ListView.builder(
        itemCount: daftarMenu.length,
        itemBuilder: (context, index) {
          final item = daftarMenu[index];
          return Card(
            child: ListTile(
              title: Text(item.nama),
              subtitle: Text("Rp ${item.harga}"),
              trailing: item.qty == 0
                  ? ElevatedButton(
                      onPressed: () {
                        setState(() {
                          item.qty = 1;
                          keranjang.add(item);
                        });
                      },
                      child: Text("Tambah"),
                    )
                  : Row(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        IconButton(
                          icon: Icon(Icons.remove),
                          onPressed: () {
                            setState(() {
                              item.qty--;
                              if (item.qty == 0) {
                                keranjang.remove(item);
                              }
                            });
                          },
                        ),
                        Text(item.qty.toString()),
                        IconButton(
                          icon: Icon(Icons.add),
                          onPressed: () {
                            setState(() {
                              item.qty++;
                            });
                          },
                        ),
                      ],
                    ),
            ),
          );
        },
      ),
      floatingActionButton: keranjang.isEmpty
          ? null
          : FloatingActionButton.extended(
              label: Text("Rp $total"),
              icon: Icon(Icons.payment),
              onPressed: () {
                Navigator.push(
                    context,
                    MaterialPageRoute(builder: (_) => CheckoutScreen()));
              },
            ),
    );
  }
}

class CartScreen extends StatelessWidget {
  int get subtotal =>
      keranjang.fold(0, (sum, item) => sum + (item.harga * item.qty));

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Keranjang")),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: keranjang.length,
              itemBuilder: (context, index) {
                final item = keranjang[index];
                return ListTile(
                  title: Text("${item.nama} x${item.qty}"),
                  subtitle: Text("Rp ${item.harga * item.qty}"),
                );
              },
            ),
          ),
          Padding(
            padding: EdgeInsets.all(16),
            child: Column(
              children: [
                Text("Subtotal: Rp $subtotal"),
                Text("Ongkir: Rp $ongkir"),
                Text(
                  "Total: Rp ${subtotal + ongkir}",
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
              ],
            ),
          )
        ],
      ),
    );
  }
}

class CheckoutScreen extends StatelessWidget {

  void kirimWA() async {
    String pesan = "Pesanan Kantin SMKN 1 Banjar\n\n";
    for (var item in keranjang) {
      pesan += "- ${item.nama} x${item.qty} = Rp ${item.harga * item.qty}\n";
    }

    int total =
        keranjang.fold(0, (sum, item) => sum + (item.harga * item.qty));

    pesan += "\nOngkir: Rp $ongkir";
    pesan += "\nTotal: Rp ${total + ongkir}";

    final url =
        "https://wa.me/$nomorWA?text=${Uri.encodeComponent(pesan)}";

    await launchUrl(Uri.parse(url),
        mode: LaunchMode.externalApplication);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Checkout")),
      body: Center(
        child: ElevatedButton(
          child: Text("Kirim ke WhatsApp"),
          onPressed: kirimWA,
        ),
      ),
    );
  }
}

📦 Cara Build APK

flutter build apk --release

File APK ada di:

build/app/outputs/flutter-apk/app-release.apk

📝 Tugas Praktikum Siswa

  1. Tambahkan 3 menu baru.

  2. Ubah ongkir menjadi 3000.

  3. Tambahkan input nama dan kelas saat checkout.

  4. Tambahkan halaman pengaturan nomor WA.

  5. Ubah tema warna aplikasi.


📊 Refleksi Pembelajaran

Diskusikan dengan siswa:

  • Apa fungsi setState()?

  • Mengapa kita menggunakan List?

  • Bagaimana cara kerja pengiriman ke WhatsApp?

  • Bagaimana jika ingin menyimpan data ke database?


🚀 Pengembangan Lanjutan

Untuk level lanjut, aplikasi bisa dikembangkan menjadi:

  • Login siswa

  • Firebase database

  • Dashboard admin

  • Export PDF laporan

  • QRIS pembayaran

  • Teaching Factory Kantin Digital


Salam Redaksi.

Share:

Tidak ada komentar:

Posting Komentar

Blogger Tricks

Blogger Themes