import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Peminjaman Mobil',
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.deepPurple,
),
home: const CarRentalApp(),
);
}
}
class Car {
String name;
String type;
String year;
String imageUrl;
String borrower;
String date; // YYYY-MM-DD
String time; // HH:MM
Car({
required this.name,
required this.type,
required this.year,
required this.imageUrl,
required this.borrower,
required this.date,
required this.time,
});
}
class CarRentalApp extends StatefulWidget {
const CarRentalApp({super.key});
@override
State<CarRentalApp> createState() => _CarRentalAppState();
}
class _CarRentalAppState extends State<CarRentalApp> {
final List<Car> ongoingRentals = [
Car(
name: "Avanza",
type: "MPV",
year: "2022",
imageUrl:
"https://img.hargamobil.com/2022/09/14/H41I0qrF/eksterior-toyota-avanza-2022-berubah-total-dari-se-de64.jpg",
borrower: "Budi",
date: "2025-08-14",
time: "09:00",
),
Car(
name: "Fortuner",
type: "SUV",
year: "2023",
imageUrl:
"https://assets.pikiran-rakyat.com/crop/2x544:718x1048/720x0/webp/photo/2023/06/04/394821350.jpg",
borrower: "Siti",
date: "2025-08-14",
time: "13:00",
),
];
final List<Car> historyRentals = [];
int _selectedIndex = 0;
// ---------- Helpers ----------
String _pad2(int v) => v.toString().padLeft(2, '0');
void _addRental(Car car) {
setState(() => ongoingRentals.add(car));
}
void _finishRental(Car car) {
setState(() {
ongoingRentals.remove(car);
historyRentals.add(car);
});
}
void _deleteRental(Car car, bool fromOngoing) {
setState(() {
if (fromOngoing) {
ongoingRentals.remove(car);
} else {
historyRentals.remove(car);
}
});
}
// ---------- Edit Dialog ----------
void _showEditRentalDialog(Car car) {
final nameController = TextEditingController(text: car.name);
final typeController = TextEditingController(text: car.type);
final yearController = TextEditingController(text: car.year);
final imageUrlController = TextEditingController(text: car.imageUrl);
final borrowerController = TextEditingController(text: car.borrower);
DateTime initialDate;
try {
initialDate = DateTime.parse(car.date);
} catch (_) {
initialDate = DateTime.now();
}
TimeOfDay initialTime;
try {
final parts = car.time.split(':');
initialTime =
TimeOfDay(hour: int.parse(parts[0]), minute: int.parse(parts[1]));
} catch (_) {
initialTime = TimeOfDay.now();
}
DateTime? selectedDate = initialDate;
TimeOfDay? selectedTime = initialTime;
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(builder: (context, setStateDialog) {
return AlertDialog(
title: const Text("Edit Peminjaman"),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: borrowerController,
decoration:
const InputDecoration(labelText: "Nama Peminjam"),
),
TextField(
controller: nameController,
decoration:
const InputDecoration(labelText: "Nama Mobil"),
),
TextField(
controller: typeController,
decoration: const InputDecoration(labelText: "Tipe"),
),
TextField(
controller: yearController,
decoration: const InputDecoration(labelText: "Tahun"),
keyboardType: TextInputType.number,
),
TextField(
controller: imageUrlController,
decoration: const InputDecoration(
labelText: "URL Gambar Mobil",
hintText: "https://....",
),
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: ElevatedButton.icon(
icon: const Icon(Icons.calendar_today),
label: Text(selectedDate == null
? "Pilih Tanggal"
: "${selectedDate!.year}-${_pad2(selectedDate!.month)}-${_pad2(selectedDate!.day)}"),
onPressed: () async {
final picked = await showDatePicker(
context: context,
initialDate: selectedDate ?? DateTime.now(),
firstDate: DateTime(2020),
lastDate: DateTime(2035),
);
if (picked != null) {
setStateDialog(() => selectedDate = picked);
}
},
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton.icon(
icon: const Icon(Icons.access_time),
label: Text(selectedTime == null
? "Pilih Waktu"
: "${_pad2(selectedTime!.hour)}:${_pad2(selectedTime!.minute)}"),
onPressed: () async {
final picked = await showTimePicker(
context: context,
initialTime: selectedTime ?? TimeOfDay.now(),
);
if (picked != null) {
setStateDialog(() => selectedTime = picked);
}
},
),
),
],
),
],
),
),
actions: [
TextButton(
child: const Text("Batal"),
onPressed: () => Navigator.pop(context),
),
ElevatedButton(
child: const Text("Simpan"),
onPressed: () {
if (nameController.text.isEmpty ||
typeController.text.isEmpty ||
yearController.text.isEmpty ||
imageUrlController.text.isEmpty ||
borrowerController.text.isEmpty ||
selectedDate == null ||
selectedTime == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content:
Text("Lengkapi semua field terlebih dahulu")),
);
return;
}
setState(() {
car.name = nameController.text;
car.type = typeController.text;
car.year = yearController.text;
car.imageUrl = imageUrlController.text;
car.borrower = borrowerController.text;
car.date =
"${selectedDate!.year}-${_pad2(selectedDate!.month)}-${_pad2(selectedDate!.day)}";
car.time =
"${_pad2(selectedTime!.hour)}:${_pad2(selectedTime!.minute)}";
});
Navigator.pop(context);
},
),
],
);
});
},
);
}
@override
Widget build(BuildContext context) {
final tabs = [
_buildRentalList(ongoingRentals, true),
_buildRentalList(historyRentals, false),
];
return Scaffold(
appBar: AppBar(
leading: const Padding(
padding: EdgeInsets.only(left: 12.0),
child: Icon(Icons.directions_car_filled, size: 28),
),
title: Text(
_selectedIndex == 0
? "Daftar Peminjaman Mobil"
: "Riwayat Peminjaman",
),
centerTitle: false,
elevation: 3,
),
body: tabs[_selectedIndex],
floatingActionButton: _selectedIndex == 0
? FloatingActionButton(
onPressed: () => _showAddRentalDialog(context),
child: const Icon(Icons.add),
)
: null,
bottomNavigationBar: NavigationBar(
selectedIndex: _selectedIndex,
onDestinationSelected: (index) {
setState(() => _selectedIndex = index);
},
destinations: const [
NavigationDestination(
icon: Icon(Icons.directions_car), label: "Peminjaman"),
NavigationDestination(icon: Icon(Icons.history), label: "Riwayat"),
],
),
);
}
Widget _buildRentalList(List<Car> list, bool isOngoing) {
if (list.isEmpty) {
return Center(
child: Padding(
padding: const EdgeInsets.all(28.0),
child: Text(
"Tidak ada data",
style: Theme.of(context).textTheme.titleMedium,
),
),
);
}
return ListView.builder(
padding: const EdgeInsets.all(12),
itemCount: list.length,
itemBuilder: (context, index) {
final car = list[index];
return Card(
elevation: 3,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
margin: const EdgeInsets.symmetric(vertical: 8),
child: ListTile(
contentPadding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
leading: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
car.imageUrl,
width: 72,
height: 72,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) {
return Container(
width: 72,
height: 72,
color: Theme.of(context).colorScheme.surfaceVariant,
child: const Icon(Icons.directions_car, size: 40),
);
},
),
),
title: Text("${car.name} (${car.year})",
style: const TextStyle(fontWeight: FontWeight.w600)),
subtitle: Text(
"${car.type} • Peminjam: ${car.borrower}\n${car.date} • ${car.time}"),
isThreeLine: true,
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (isOngoing)
IconButton(
tooltip: 'Edit',
icon: const Icon(Icons.edit, color: Colors.blue),
onPressed: () => _showEditRentalDialog(car),
),
if (isOngoing)
IconButton(
tooltip: 'Selesai (pindah ke riwayat)',
icon: const Icon(Icons.check_circle, color: Colors.green),
onPressed: () => _finishRental(car),
),
IconButton(
tooltip: 'Hapus',
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: () => _deleteRental(car, isOngoing),
),
],
),
),
);
},
);
}
// ---------- Add Dialog ----------
void _showAddRentalDialog(BuildContext context) {
final nameController = TextEditingController();
final typeController = TextEditingController();
final yearController = TextEditingController();
final imageUrlController = TextEditingController();
final borrowerController = TextEditingController();
DateTime? selectedDate;
TimeOfDay? selectedTime;
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(builder: (context, setStateDialog) {
return AlertDialog(
title: const Text("Tambah Peminjaman"),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: borrowerController,
decoration:
const InputDecoration(labelText: "Nama Peminjam"),
),
TextField(
controller: nameController,
decoration:
const InputDecoration(labelText: "Nama Mobil"),
),
TextField(
controller: typeController,
decoration: const InputDecoration(labelText: "Tipe"),
),
TextField(
controller: yearController,
decoration: const InputDecoration(labelText: "Tahun"),
keyboardType: TextInputType.number,
),
TextField(
controller: imageUrlController,
decoration: const InputDecoration(
labelText: "URL Gambar Mobil",
hintText: "https://....",
),
),
const SizedBox(height: 12),
Row(
children: {
Expanded(
child: ElevatedButton.icon(
icon: const Icon(Icons.calendar_today),
label: Text(selectedDate == null
? "Pilih Tanggal"
: "${selectedDate!.year}-${_pad2(selectedDate!.month)}-${_pad2(selectedDate!.day)}"),
onPressed: () async {
final picked = await showDatePicker(
context: context,
initialDate: selectedDate ?? DateTime.now(),
firstDate: DateTime(2020),
lastDate: DateTime(2035),
);
if (picked != null) {
setStateDialog(() => selectedDate = picked);
}
},
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton.icon(
icon: const Icon(Icons.access_time),
label: Text(selectedTime == null
? "Pilih Waktu"
: "${_pad2(selectedTime!.hour)}:${_pad2(selectedTime!.minute)}"),
onPressed: () async {
final picked = await showTimePicker(
context: context,
initialTime: selectedTime ?? TimeOfDay.now(),
);
if (picked != null) {
setStateDialog(() => selectedTime = picked);
}
},
),
),
}.toList(),
),
],
),
),
actions: [
TextButton(
child: const Text("Batal"),
onPressed: () => Navigator.pop(context),
),
ElevatedButton(
child: const Text("Simpan"),
onPressed: () {
if (nameController.text.isNotEmpty &&
typeController.text.isNotEmpty &&
yearController.text.isNotEmpty &&
imageUrlController.text.isNotEmpty &&
borrowerController.text.isNotEmpty &&
selectedDate != null &&
selectedTime != null) {
_addRental(Car(
name: nameController.text,
type: typeController.text,
year: yearController.text,
imageUrl: imageUrlController.text,
borrower: borrowerController.text,
date:
"${selectedDate!.year}-${_pad2(selectedDate!.month)}-${_pad2(selectedDate!.day)}",
time:
"${_pad2(selectedTime!.hour)}:${_pad2(selectedTime!.minute)}",
));
Navigator.pop(context);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content:
Text("Lengkapi semua field terlebih dahulu")),
);
}
},
),
],
);
});
},
);
}
}
Yoi gengs, itu dia tutorial santuy buat bikin app pinjam mobil. Loe udah punya kode lengkap — tinggal copy-paste main.dart yang udah aku kirim, lalu tweak warna / gambar sesuai selera.
Kalau lo mau aku bikin versi:
Jangan lupa: kalau kepake, share link blog/IG/Twitter lo. Tag aku biar aku bisa ngintip hasilnya. #MadeWithFlutter #GenZCode #Code#
Comments
Post a Comment