Membuat aplikasi Jastip/Kantin
🛒 APLIKASI KANTIN/JASTIP BERBASIS FLUTTER
1. Identitas
Nama: Nabil Rega Mulyadi
Kelas: XI RPL
Mata Pelajaran: Pemrograman Mobile
Teknologi: Flutter & Dart
2. Judul Projek
KantinJastip — Aplikasi Pemesanan Makanan dan Jasa Titip
3. Pengertian Aplikasi
Aplikasi Kantin/Jastip adalah aplikasi yang dibuat untuk memudahkan pengguna dalam melakukan pemesanan makanan dan minuman dari kantin. Selain menyediakan daftar menu kantin, aplikasi ini juga memiliki fitur jasa titip (jastip) untuk membantu pengguna yang tidak dapat datang langsung ke kantin.
Pengguna dapat melihat menu, mengetahui harga, memilih makanan atau minuman, memasukkannya ke dalam keranjang, kemudian melakukan pemesanan. Pada fitur jastip, pengguna dapat menuliskan makanan yang ingin dibeli dan lokasi pengantaran.
Aplikasi ini dikembangkan menggunakan Flutter dan bahasa pemrograman Dart.
4. Latar Belakang
Kantin merupakan salah satu tempat yang banyak digunakan oleh siswa untuk membeli makanan dan minuman. Namun, pada saat jam istirahat, kantin biasanya ramai sehingga siswa harus mengantre dan membutuhkan waktu untuk mendapatkan makanan.
Oleh karena itu, dibuatlah aplikasi KantinJastip untuk membantu mempermudah proses pemesanan makanan. Dengan adanya aplikasi ini, pengguna dapat melihat menu dan melakukan pemesanan tanpa harus datang langsung ke kantin.
Selain itu, fitur jastip dapat membantu siswa yang sedang berada di kelas atau memiliki kegiatan lain sehingga tidak sempat pergi ke kantin.
5. Tujuan Aplikasi
Tujuan dibuatnya aplikasi KantinJastip adalah:
Mempermudah pengguna dalam memesan makanan dan minuman.
Mengurangi waktu yang digunakan untuk mengantre di kantin.
Menyediakan informasi menu dan harga.
Menyediakan layanan jasa titip makanan.
Menerapkan pembelajaran Flutter dan Dart dalam sebuah projek.
Membuat aplikasi sederhana yang dapat digunakan di lingkungan sekolah.
6. Fitur Aplikasi
🏠 Home
Halaman utama menampilkan informasi aplikasi dan daftar makanan serta minuman yang tersedia di kantin.
🍔 Menu Kantin
Pengguna dapat melihat berbagai menu seperti nasi goreng, ayam geprek, mie goreng, es teh, es jeruk, dan air mineral.
🛒 Keranjang
Menu yang dipilih akan masuk ke dalam keranjang. Pengguna dapat melihat jumlah pesanan dan total harga.
📦 Jastip
Fitur jastip digunakan ketika pengguna ingin menitipkan pembelian kepada orang lain. Pengguna dapat menuliskan pesanan dan lokasi pengantaran.
👤 Profil
Halaman profil menampilkan informasi pengguna.
7. Teknologi yang Digunakan
Aplikasi ini dibuat menggunakan:
Flutter
Framework untuk membuat aplikasi menggunakan bahasa Dart.
Dart
Bahasa pemrograman yang digunakan dalam pengembangan aplikasi Flutter.
DartPad / FlutLab / VS Code
Digunakan sebagai tempat untuk menulis dan menjalankan kode Flutter.
8. Alur Penggunaan Aplikasi
Alur penggunaan aplikasi KantinJastip:
Home → Pilih Menu → Tambahkan ke Keranjang → Periksa Pesanan → Pesan
Sedangkan untuk jastip:
Home → Jastip → Masukkan Pesanan → Masukkan Lokasi → Kirim Pesanan
9. Tampilan Aplikasi
Halaman Home
Pada halaman Home, pengguna dapat melihat banner aplikasi dan daftar makanan serta minuman yang tersedia.
Screenshot:
Masukkan screenshot halaman Home di sini.
Halaman Keranjang
Halaman keranjang menampilkan makanan yang telah dipilih, jumlah pesanan, dan total harga.
Screenshot:
Masukkan screenshot halaman Keranjang di sini.
Halaman Jastip
Halaman Jastip digunakan untuk memasukkan makanan yang ingin dititipkan dan lokasi pengantaran.
Screenshot:
Masukkan screenshot halaman Jastip di sini.
Halaman Profil
Halaman profil berisi informasi pengguna.
Screenshot:
Masukkan screenshot halaman Profil di sini.
10. Source Code
Kode aplikasi dibuat menggunakan Flutter dan Dart. Struktur utama aplikasi menggunakan MaterialApp, Scaffold, NavigationBar, Card, GridView, ListView, dan beberapa widget Flutter lainnya.
Screenshot kode:
Masukkan screenshot kode Flutter di sini.
11. Kelebihan Aplikasi
Beberapa kelebihan aplikasi KantinJastip adalah:
Tampilan sederhana dan mudah digunakan.
Pengguna dapat melihat menu dan harga.
Terdapat fitur keranjang.
Terdapat fitur jasa titip.
Dapat digunakan sebagai dasar pengembangan aplikasi kantin yang lebih lengkap.
Dibuat menggunakan Flutter sehingga dapat dikembangkan untuk berbagai platform.
12. Kekurangan Aplikasi
Aplikasi ini masih merupakan versi sederhana sehingga masih memiliki beberapa kekurangan, seperti:
Belum menggunakan database online.
Belum memiliki sistem login.
Pembayaran masih berupa simulasi.
Belum terhubung dengan sistem kasir kantin.
Belum memiliki fitur pelacakan pesanan secara real-time.
13. Pengembangan Selanjutnya
Aplikasi KantinJastip dapat dikembangkan dengan menambahkan:
🔐 Login dan registrasi pengguna.
💳 Pembayaran digital.
🗄️ Database Firebase.
🔔 Notifikasi pesanan.
📍 Pelacakan pengantaran.
⭐ Rating dan ulasan makanan.
👨🍳 Halaman khusus penjual/kantin.
📊 Dashboard admin.
14. Kesimpulan
Aplikasi KantinJastip merupakan aplikasi berbasis Flutter yang dibuat untuk membantu pengguna dalam melakukan pemesanan makanan dan minuman di kantin serta menggunakan layanan jasa titip.
Dengan adanya aplikasi ini, proses pemesanan diharapkan menjadi lebih praktis dan menghemat waktu. Projek ini juga menjadi sarana untuk menerapkan pembelajaran bahasa pemrograman Dart dan framework Flutter dalam pembuatan aplikasi mobile.
KantinJastip — Pesan mudah, tidak perlu antre! 🛒🍔📦
CODE
import 'package:flutter/material.dart';
void main() {
runApp(const KantinJastipApp());
}
class KantinJastipApp extends StatelessWidget {
const KantinJastipApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'KantinJastip',
theme: ThemeData(
primarySwatch: Colors.orange,
scaffoldBackgroundColor: const Color(0xFFF7F7F7),
useMaterial3: true,
),
home: const MainPage(),
);
}
}
// ================= DATA MENU =================
class MenuItem {
final String nama;
final int harga;
final String emoji;
const MenuItem({
required this.nama,
required this.harga,
required this.emoji,
});
}
const List<MenuItem> daftarMenu = [
MenuItem(
nama: 'Nasi Goreng',
harga: 10000,
emoji: '🍳',
),
MenuItem(
nama: 'Ayam Geprek',
harga: 12000,
emoji: '🍗',
),
MenuItem(
nama: 'Mie Goreng',
harga: 8000,
emoji: '🍜',
),
MenuItem(
nama: 'Bakso',
harga: 10000,
emoji: '🍲',
),
MenuItem(
nama: 'Es Teh',
harga: 4000,
emoji: '🥤',
),
MenuItem(
nama: 'Es Jeruk',
harga: 5000,
emoji: '🍊',
),
MenuItem(
nama: 'Air Mineral',
harga: 3000,
emoji: '💧',
),
MenuItem(
nama: 'Kopi Susu',
harga: 7000,
emoji: '☕',
),
];
// ================= MAIN PAGE =================
class MainPage extends StatefulWidget {
const MainPage({super.key});
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
int selectedIndex = 0;
final Map<MenuItem, int> keranjang = {};
// ================= FORMAT RUPIAH =================
String formatRupiah(int harga) {
String angka = harga.toString();
return 'Rp ${angka.replaceAllMapped(
RegExp(r'(\d)(?=(\d{3})+(?!\d))'),
(match) => '${match[1]}.',
)}';
}
// ================= TAMBAH MENU =================
void tambahMenu(MenuItem item) {
setState(() {
keranjang[item] = (keranjang[item] ?? 0) + 1;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('${item.nama} ditambahkan ke keranjang'),
duration: const Duration(seconds: 1),
),
);
}
// ================= KURANG MENU =================
void kurangiMenu(MenuItem item) {
setState(() {
if (keranjang[item] != null) {
if (keranjang[item]! > 1) {
keranjang[item] = keranjang[item]! - 1;
} else {
keranjang.remove(item);
}
}
});
}
// ================= TOTAL ITEM =================
int get totalItem {
int total = 0;
for (final jumlah in keranjang.values) {
total += jumlah;
}
return total;
}
// ================= TOTAL HARGA =================
int get totalHarga {
int total = 0;
keranjang.forEach((item, jumlah) {
total += item.harga * jumlah;
});
return total;
}
@override
Widget build(BuildContext context) {
final pages = [
buildHome(),
buildKeranjang(),
buildJastip(),
buildProfil(),
];
return Scaffold(
body: pages[selectedIndex],
bottomNavigationBar: NavigationBar(
selectedIndex: selectedIndex,
onDestinationSelected: (index) {
setState(() {
selectedIndex = index;
});
},
destinations: [
const NavigationDestination(
icon: Icon(Icons.home_outlined),
selectedIcon: Icon(Icons.home),
label: 'Home',
),
NavigationDestination(
icon: Badge(
isLabelVisible: totalItem > 0,
label: Text('$totalItem'),
child: const Icon(Icons.shopping_cart_outlined),
),
selectedIcon: Badge(
isLabelVisible: totalItem > 0,
label: Text('$totalItem'),
child: const Icon(Icons.shopping_cart),
),
label: 'Keranjang',
),
const NavigationDestination(
icon: Icon(Icons.delivery_dining_outlined),
selectedIcon: Icon(Icons.delivery_dining),
label: 'Jastip',
),
const NavigationDestination(
icon: Icon(Icons.person_outline),
selectedIcon: Icon(Icons.person),
label: 'Profil',
),
],
),
);
}
// ==================================================
// HOME
// ==================================================
Widget buildHome() {
return SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(18),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
const Text(
'Halo 👋',
style: TextStyle(
fontSize: 17,
color: Colors.grey,
),
),
const SizedBox(height: 5),
const Text(
'Mau makan apa hari ini?',
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 20),
// ================= BANNER =================
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [
Colors.orange,
Colors.deepOrange,
],
),
borderRadius: BorderRadius.circular(22),
),
child: Row(
children: [
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'KantinJastip',
style: TextStyle(
color: Colors.white,
fontSize: 25,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text(
'Pesan makanan tanpa perlu antre!',
style: TextStyle(
color: Colors.white,
fontSize: 14,
),
),
],
),
),
const Text(
'🍔',
style: TextStyle(fontSize: 55),
),
],
),
),
const SizedBox(height: 25),
const Text(
'Menu Kantin',
style: TextStyle(
fontSize: 21,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 15),
// ================= GRID MENU =================
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: daftarMenu.length,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 0.78,
),
itemBuilder: (context, index) {
final item = daftarMenu[index];
return Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18),
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
item.emoji,
style: const TextStyle(
fontSize: 48,
),
),
const SizedBox(height: 8),
Text(
item.nama,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 5),
Text(
formatRupiah(item.harga),
style: const TextStyle(
color: Colors.orange,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
tambahMenu(item);
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange,
foregroundColor: Colors.white,
),
child: const Text('Tambah'),
),
),
],
),
),
);
},
),
],
),
),
);
}
// ==================================================
// KERANJANG
// ==================================================
Widget buildKeranjang() {
return SafeArea(
child: Padding(
padding: const EdgeInsets.all(18),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'🛒 Keranjang',
style: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 20),
if (keranjang.isEmpty)
const Expanded(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'🛒',
style: TextStyle(fontSize: 70),
),
SizedBox(height: 15),
Text(
'Keranjang masih kosong',
style: TextStyle(
fontSize: 18,
color: Colors.grey,
),
),
],
),
),
)
else
Expanded(
child: Column(
children: [
Expanded(
child: ListView(
children: keranjang.entries.map((entry) {
final item = entry.key;
final jumlah = entry.value;
return Card(
margin: const EdgeInsets.only(
bottom: 10,
),
child: ListTile(
leading: Text(
item.emoji,
style: const TextStyle(
fontSize: 35,
),
),
title: Text(
item.nama,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
subtitle: Text(
'${jumlah} x ${formatRupiah(item.harga)}',
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
onPressed: () {
kurangiMenu(item);
},
icon: const Icon(
Icons.remove_circle_outline,
),
),
Text(
'$jumlah',
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
IconButton(
onPressed: () {
tambahMenu(item);
},
icon: const Icon(
Icons.add_circle_outline,
color: Colors.orange,
),
),
],
),
),
);
}).toList(),
),
),
// ================= TOTAL =================
Container(
padding: const EdgeInsets.all(18),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(18),
),
child: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const Text(
'Total Pesanan',
style: TextStyle(
fontSize: 17,
),
),
Text(
formatRupiah(totalHarga),
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.orange,
),
),
],
),
const SizedBox(height: 15),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: pesanSekarang,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange,
foregroundColor: Colors.white,
padding:
const EdgeInsets.all(15),
),
child: const Text(
'Pesan Sekarang',
),
),
),
],
),
),
],
),
),
],
),
),
);
}
// ==================================================
// PESAN SEKARANG
// ==================================================
void pesanSekarang() {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text(
'Pesanan Berhasil 🎉',
),
content: Text(
'Total pesanan kamu '
'${formatRupiah(totalHarga)}.\n\n'
'Pesanan sedang diproses.',
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
setState(() {
keranjang.clear();
});
},
child: const Text('OK'),
),
],
);
},
);
}
// ==================================================
// JASTIP
// ==================================================
Widget buildJastip() {
final pesananController = TextEditingController();
final lokasiController = TextEditingController();
return SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(18),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'📦 Jasa Titip',
style: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const Text(
'Tidak sempat ke kantin? Titip saja!',
style: TextStyle(
color: Colors.grey,
),
),
const SizedBox(height: 25),
Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
const Text(
'🚶',
style: TextStyle(
fontSize: 65,
),
),
const SizedBox(height: 10),
const Text(
'Pesan Jastip',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const Text(
'Tuliskan makanan yang ingin '
'kamu titipkan.',
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
TextField(
controller: pesananController,
decoration: InputDecoration(
labelText: 'Pesanan',
hintText: 'Contoh: Nasi goreng 1',
prefixIcon: const Icon(
Icons.fastfood,
),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(12),
),
),
),
const SizedBox(height: 15),
TextField(
controller: lokasiController,
decoration: InputDecoration(
labelText: 'Lokasi Pengantaran',
hintText: 'Contoh: Kelas XI

Komentar
Posting Komentar