📱 Praktikum Membuat Aplikasi Jasa Titip Kantin Menggunakan Flutte

 


✨ Pendahuluan

Pada praktikum kali ini, saya membuat sebuah aplikasi Jasa Titip Kantin menggunakan Flutter. Aplikasi ini dirancang untuk memudahkan siswa dalam memesan makanan atau minuman dari kantin tanpa harus datang langsung ke tempat penjual.

Melalui aplikasi ini, pengguna dapat melihat daftar menu, memilih makanan atau minuman yang diinginkan, serta melakukan pemesanan dengan tampilan yang sederhana dan menarik.

🎯 Tujuan Praktikum

Tujuan dari pembuatan aplikasi ini adalah:

  • Mempelajari dasar-dasar penggunaan Flutter.

  • Memahami struktur project Flutter.

  • Membuat tampilan aplikasi menggunakan widget Flutter.

  • Menerapkan navigasi dan interaksi sederhana.

  • Mengembangkan aplikasi yang dapat digunakan untuk kebutuhan jasa titip makanan di lingkungan sekolah.

🛠️ Teknologi yang Digunakan

Dalam pembuatan aplikasi ini, beberapa teknologi yang digunakan yaitu:

Flutter
Framework yang digunakan untuk membangun aplikasi.

Dart
Bahasa pemrograman yang digunakan oleh Flutter.

Visual Studio Code
Digunakan sebagai code editor untuk menulis dan mengembangkan program.

📂 Struktur Project

Struktur dasar project Flutter yang digunakan dalam praktikum ini terdiri dari beberapa bagian penting, seperti:

jastip_kantin/
├── android/
├── ios/
├── lib/
│   └── main.dart
├── test/
├── pubspec.yaml
└── README.md

File utama yang digunakan untuk menjalankan aplikasi adalah:

lib/main.dart

Pada file tersebut, kode program utama aplikasi dibuat dan dijalankan.

💻 Kode Program

Berikut merupakan kode program Flutter yang digunakan untuk membuat tampilan aplikasi Jasa Titip Kantin:

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Jastip Kantin',
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        scaffoldBackgroundColor: const Color(0xffF7F9FC),
      ),
      home: const HomePage(),
    );
  }
}

// ================= HOME PAGE =================

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int selectedIndex = 0;

  final List<Map<String, dynamic>> makanan = [
    {'nama': 'Nasi Goreng', 'harga': 12000, 'icon': Icons.rice_bowl},
    {'nama': 'Bakso', 'harga': 10000, 'icon': Icons.ramen_dining},
    {'nama': 'Mie Ayam', 'harga': 11000, 'icon': Icons.lunch_dining},
    {'nama': 'Es Teh', 'harga': 5000, 'icon': Icons.local_drink},
  ];

  final List<Map<String, dynamic>> keranjang = [];

  void tambahKeranjang(Map<String, dynamic> makanan) {
    setState(() {
      keranjang.add(makanan);
    });

    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text('${makanan['nama']} ditambahkan ke keranjang'),
        duration: const Duration(seconds: 1),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0,
        title: const Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Jastip Kantin',
              style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
            ),
            Text(
              'Pesan makanan tanpa antre',
              style: TextStyle(fontSize: 12, color: Colors.grey),
            ),
          ],
        ),
        actions: [
          IconButton(
            onPressed: () {},
            icon: const Icon(Icons.notifications_none),
          ),
        ],
      ),

      // ================= BODY =================
      body: IndexedStack(
        index: selectedIndex,
        children: [
          buildHome(),
          buildPesanan(),
          buildKeranjang(),
          buildProfil(),
        ],
      ),

      // ================= BOTTOM NAVIGATION =================
      bottomNavigationBar: NavigationBar(
        selectedIndex: selectedIndex,
        onDestinationSelected: (index) {
          setState(() {
            selectedIndex = index;
          });
        },
        destinations: const [
          NavigationDestination(
            icon: Icon(Icons.home_outlined),
            selectedIcon: Icon(Icons.home),
            label: 'Beranda',
          ),
          NavigationDestination(
            icon: Icon(Icons.receipt_long_outlined),
            selectedIcon: Icon(Icons.receipt_long),
            label: 'Pesanan',
          ),
          NavigationDestination(
            icon: Icon(Icons.shopping_cart_outlined),
            selectedIcon: Icon(Icons.shopping_cart),
            label: 'Keranjang',
          ),
          NavigationDestination(
            icon: Icon(Icons.person_outline),
            selectedIcon: Icon(Icons.person),
            label: 'Profil',
          ),
        ],
      ),
    );
  }

  // ================= BERANDA =================

  Widget buildHome() {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // Greeting
          const Text(
            'Halo, Soni 👋',
            style: TextStyle(fontSize: 26, fontWeight: FontWeight.bold),
          ),

          const SizedBox(height: 5),

          const Text(
            'Mau pesan apa hari ini?',
            style: TextStyle(color: Colors.grey),
          ),

          const SizedBox(height: 20),

          // Search
          TextField(
            decoration: InputDecoration(
              hintText: 'Cari makanan atau minuman...',
              prefixIcon: const Icon(Icons.search),
              filled: true,
              fillColor: Colors.white,
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(15),
                borderSide: BorderSide.none,
              ),
            ),
          ),

          const SizedBox(height: 20),

          // Banner
          Container(
            width: double.infinity,
            padding: const EdgeInsets.all(20),
            decoration: BoxDecoration(
              gradient: const LinearGradient(
                colors: [Color(0xff1976D2), Color(0xff42A5F5)],
              ),
              borderRadius: BorderRadius.circular(22),
            ),
            child: const Row(
              children: [
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Jajanan Enak\nDi Kantin!',
                        style: TextStyle(
                          color: Colors.white,
                          fontSize: 22,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      SizedBox(height: 8),
                      Text(
                        'Pesan sekarang,\ntinggal tunggu di tempat.',
                        style: TextStyle(color: Colors.white70),
                      ),
                    ],
                  ),
                ),
                Icon(Icons.fastfood, color: Colors.white, size: 65),
              ],
            ),
          ),

          const SizedBox(height: 25),

          const Text(
            'Kategori',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),

          const SizedBox(height: 15),

          Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              kategori(Icons.restaurant, 'Makanan'),
              kategori(Icons.local_drink, 'Minuman'),
              kategori(Icons.fastfood, 'Snack'),
              kategori(Icons.grid_view, 'Lainnya'),
            ],
          ),

          const SizedBox(height: 25),

          const Text(
            'Menu Populer',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),

          const SizedBox(height: 15),

          GridView.builder(
            shrinkWrap: true,
            physics: const NeverScrollableScrollPhysics(),
            itemCount: makanan.length,
            gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 2,
              crossAxisSpacing: 12,
              mainAxisSpacing: 12,
              childAspectRatio: 0.85,
            ),
            itemBuilder: (context, index) {
              final item = makanan[index];

              return Card(
                elevation: 1,
                color: Colors.white,
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(18),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(12),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Expanded(
                        child: Container(
                          width: double.infinity,
                          decoration: BoxDecoration(
                            color: Colors.blue.shade50,
                            borderRadius: BorderRadius.circular(15),
                          ),
                          child: Icon(
                            item['icon'],
                            size: 65,
                            color: Colors.blue,
                          ),
                        ),
                      ),

                      const SizedBox(height: 10),

                      Text(
                        item['nama'],
                        style: const TextStyle(
                          fontWeight: FontWeight.bold,
                          fontSize: 16,
                        ),
                      ),

                      const SizedBox(height: 5),

                      Text(
                        'Rp ${item['harga']}',
                        style: const TextStyle(
                          color: Colors.blue,
                          fontWeight: FontWeight.bold,
                        ),
                      ),

                      const SizedBox(height: 8),

                      SizedBox(
                        width: double.infinity,
                        child: ElevatedButton(
                          onPressed: () {
                            tambahKeranjang(item);
                          },
                          child: const Text('Tambah'),
                        ),
                      ),
                    ],
                  ),
                ),
              );
            },
          ),
        ],
      ),
    );
  }

  // ================= KATEGORI =================

  Widget kategori(IconData icon, String nama) {
    return Column(
      children: [
        Container(
          padding: const EdgeInsets.all(14),
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(15),
          ),
          child: Icon(icon, color: Colors.blue, size: 28),
        ),
        const SizedBox(height: 6),
        Text(nama, style: const TextStyle(fontSize: 12)),
      ],
    );
  }

  // ================= PESANAN =================

  Widget buildPesanan() {
    return const Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(Icons.receipt_long, size: 80, color: Colors.blue),
          SizedBox(height: 15),
          Text(
            'Belum ada pesanan',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
          SizedBox(height: 5),
          Text(
            'Pesanan kamu akan muncul di sini',
            style: TextStyle(color: Colors.grey),
          ),
        ],
      ),
    );
  }

  // ================= KERANJANG =================

  Widget buildKeranjang() {
    if (keranjang.isEmpty) {
      return const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.shopping_cart_outlined, size: 80, color: Colors.grey),
            SizedBox(height: 15),
            Text(
              'Keranjang masih kosong',
              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
            ),
          ],
        ),
      );
    }

    int total = keranjang.fold(0, (sum, item) => sum + item['harga'] as int);

    return Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: keranjang.length,
              itemBuilder: (context, index) {
                final item = keranjang[index];

                return Card(
                  child: ListTile(
                    leading: CircleAvatar(child: Icon(item['icon'])),
                    title: Text(item['nama']),
                    subtitle: Text('Rp ${item['harga']}'),
                    trailing: IconButton(
                      icon: const Icon(Icons.delete_outline, color: Colors.red),
                      onPressed: () {
                        setState(() {
                          keranjang.removeAt(index);
                        });
                      },
                    ),
                  ),
                );
              },
            ),
          ),

          Container(
            padding: const EdgeInsets.all(18),
            decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(18),
            ),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text('Total'),
                    Text(
                      'Rp $total',
                      style: const TextStyle(
                        fontSize: 20,
                        fontWeight: FontWeight.bold,
                        color: Colors.blue,
                      ),
                    ),
                  ],
                ),

                ElevatedButton(
                  onPressed: () {},
                  child: const Text('Pesan Sekarang'),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  // ================= PROFIL =================

  Widget buildProfil() {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const CircleAvatar(radius: 45, child: Icon(Icons.person, size: 50)),

          const SizedBox(height: 15),

          const Text(
            'Soni',
            style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
          ),

          const Text(
            'Pengguna Jastip Kantin',
            style: TextStyle(color: Colors.grey),
          ),

          const SizedBox(height: 25),

          SizedBox(
            width: 220,
            child: OutlinedButton.icon(
              onPressed: () {},
              icon: const Icon(Icons.settings),
              label: const Text('Pengaturan'),
            ),
          ),
        ],
      ),
    );
  }
}

🚀 Langkah-Langkah Pembuatan

  1. Membuat project Flutter baru.

  2. Membuka project menggunakan Visual Studio Code.

  3. Membuka folder lib.

  4. Membuat atau mengedit file main.dart.

  5. Menuliskan kode program aplikasi.

  6. Menjalankan aplikasi menggunakan emulator atau perangkat yang terhubung.

  7. Melakukan pengecekan tampilan dan fungsi aplikasi.

  8. Memperbaiki kode apabila terdapat error.

  9. Mengambil screenshot hasil aplikasi sebagai dokumentasi praktikum.

🖥️ Hasil Praktikum

Setelah program berhasil dijalankan, aplikasi menampilkan halaman utama Jastip Kantin dengan daftar makanan dan minuman yang dapat dipesan.

Tampilan aplikasi dibuat sederhana agar mudah dipahami dan digunakan oleh siswa.

Dokumentasi hasil aplikasi:



📝 Kesimpulan

Dari praktikum ini, saya dapat memahami dasar pembuatan aplikasi menggunakan Flutter dan bahasa pemrograman Dart. Saya juga mempelajari bagaimana membuat struktur project, menggunakan berbagai widget, membuat tampilan aplikasi, serta menjalankan aplikasi Flutter.

Pembuatan aplikasi Jasa Titip Kantin menjadi salah satu latihan untuk meningkatkan kemampuan dalam pengembangan aplikasi mobile dan memahami proses pembuatan aplikasi dari kode hingga menghasilkan tampilan yang dapat digunakan.

Komentar

Postingan populer dari blog ini

Praktikum Flutter Seri 2 — Struktur Project dan main.dart

💻 MEMBUAT "APLIKASI DATA SISWA" MENGGUNAKAN FLUTTER

"Dari Pengguna HP Menjadi Pembuat Aplikasi"