Ya, kita bisa mengambil data JSON tanpa membuat model terlebih dahulu. Ini dapat dilakukan dengan mengurai JSON secara langsung ke dalam struktur data Dart seperti Map atau List. Perbandingan dengan Membuat Model: Membuat model khusus untuk data JSON biasanya lebih disarankan karena:
- Ketepatan Data: Model menjamin bahwa data yang diterima sesuai dengan struktur yang diharapkan.
- Pemeliharaan Kode: Model membuat kode lebih terorganisir dan mudah untuk dikelola.
- Keamanan Tipe: Dengan model, Anda memanfaatkan fitur keamanan tipe Dart, mengurangi kemungkinan kesalahan runtime.
Cookies biasanya digunakan untuk menyimpan informasi sesi seperti token autentikasi.
Pentingnya Bagi Aplikasi Flutter:
- Pemeliharaan Sesi: Cookies memungkinkan aplikasi Flutter untuk mempertahankan sesi pengguna, seperti tetap login meski aplikasi ditutup.
- Keamanan: Cookies sering digunakan untuk mengamankan komunikasi antara klien dan server, khususnya dalam autentikasi.
- HTTP Request: Aplikasi Flutter mengirim permintaan HTTP ke server (misalnya, Django).
- Penguraian Respons: Setelah menerima respons dari server, aplikasi mengurai respons JSON menggunakan json.decode.
- Konversi ke Objek: Data JSON yang diurai kemudian dikonversi ke dalam objek Dart atau model khusus.
- Tampilkan di UI: Data yang telah dikonversi ditampilkan dalam widget Flutter, seperti ListView atau Text.
- Input Data: Pengguna memasukkan data akun (username dan password) di aplikasi Flutter.
- Kirim ke Django: Data dikirim ke Django melalui permintaan HTTP.
- Proses di Django: Django memproses data, melakukan autentikasi, dan mengembalikan respons (biasanya berupa token jika berhasil).
- Terima dan Simpan Token: Aplikasi Flutter menerima token dan menyimpannya (biasanya dalam SharedPreferences).
- Navigasi Menu: Setelah autentikasi berhasil, aplikasi navigasi ke menu atau halaman utama.
- Scaffold: Membuat struktur dasar halaman aplikasi.
- AppBar: Menampilkan bar judul di atas layar.
- Drawer: Menyediakan menu samping yang dapat ditarik keluar.
- ListView: Menampilkan daftar item secara scrollable.
- ListTile: Menampilkan item dalam daftar dengan judul dan subjudul.
- TextFormField: Mengambil input teks dari pengguna. ElevatedButton: Menampilkan tombol yang menonjol untuk melakukan aksi.
- Padding: Menambahkan padding di sekitar widget lain.
- Column: Mengatur widget secara vertikal.
- Text: Menampilkan teks pada layar.
- Navigator.push() digunakan untuk menavigasi ke halaman baru di atas stack navigasi. Halaman sebelumnya tetap ada di stack, yang berarti jika pengguna menekan tombol kembali, mereka akan kembali ke halaman sebelumnya. Contoh Penggunaan: Navigasi dari daftar produk ke detail produk. Pengguna dapat kembali ke daftar produk dengan menekan tombol kembali.
- Navigator.pushReplacement() digunakan untuk mengganti halaman saat ini dengan halaman baru di stack navigasi. Halaman sebelumnya dihapus dari stack, sehingga ketika pengguna menekan tombol kembali, mereka tidak akan kembali ke halaman sebelumnya. Contoh Penggunaan: Navigasi dari layar login ke beranda setelah login berhasil. Pengguna tidak perlu kembali ke layar login jika menekan tombol kembali.
- Column dan Row: Untuk layout linear vertikal dan horizontal. Digunakan untuk menata widget dalam satu baris atau kolom.
- Stack: Untuk layout widget secara bertumpuk. Berguna untuk menempatkan widget di atas widget lain, seperti teks di atas gambar.
- Container: Widget serbaguna untuk styling, padding, margin, dan dimensi. Cocok untuk pembungkus widget lain dengan styling tertentu.
- GridView: Untuk membuat layout grid. Berguna untuk menampilkan item dalam bentuk grid seperti galeri foto.
- ListView: Untuk membuat daftar scrollable. Digunakan untuk menampilkan daftar item yang dapat di-scroll.
- Flex dan Expanded: Untuk layout yang fleksibel dan menyesuaikan ukuran widget anak berdasarkan ruang yang tersedia.
Elemen input yang digunakan dalam tugas 8 ini meliputi:
- TextFormField: Digunakan untuk mengumpulkan input teks dari pengguna, seperti nama item, deskripsi. Dipilih karena menyediakan validasi dan pengelolaan state input teks yang mudah.
- Numeric Input: Sebuah TextFormField dengan keyboardType: TextInputType.number untuk jumlah item. Digunakan untuk memastikan input adalah angka.
Clean Architecture melibatkan pemisahan kode menjadi lapisan dengan tanggung jawab tertentu:
- Presentation Layer: Berisi UI dan logic yang mengontrol apa yang ditampilkan di layar, misalnya widget Flutter dan state management.
- Domain Layer: Berisi bisnis logic aplikasi. Termasuk entitas (model data) dan use cases atau business rules.
- Data Layer: Berhubungan dengan penyimpanan data, seperti panggilan API, database lokal. Termasuk model data dari API atau database dan logic untuk mengambil/menyimpan data. Dalam Flutter, ini dapat diterapkan dengan memisahkan kode ke dalam paket atau folder terpisah seperti models, views, screens, controllers/viewmodels, dan services/repositories.
Pertama, saya mendesain tampilan dasar menggunakan widget Scaffold, AppBar, dan Column. Di MyHomePage, saya menampilkan beberapa ElevatedButton untuk navigasi.
class MyHomePage extends StatelessWidget {
// Constructor dan build method seperti biasa
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Shopping List'),
),
body: Column(
children: [
ElevatedButton.icon(
// ... Properties untuk button Lihat Item
),
ElevatedButton.icon(
// ... Properties untuk button Tambah Item
),
// ... Tombol lain jika ada
],
),
);
}
}
Di sini saya mengimplementasikan Navigator.push() untuk navigasi antarhalaman. Ketika tombol ditekan, pengguna akan dibawa ke halaman baru.
ElevatedButton.icon(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => AddItemPage()));
},
// ... Properties untuk button
),
Di AddItemPage, saya membuat Form dengan beberapa TextFormField dan logic validasi untuk mengumpulkan input dari pengguna.
class AddItemPage extends StatefulWidget {
// ... Constructor dan State
}
class _AddItemPageState extends State<AddItemPage> {
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
// ... Validator untuk 'name'
),
TextFormField(
// ... Validator untuk 'amount'
),
// ... TextFormField lain jika ada
],
),
),
);
}
}
Ketika pengguna menekan tombol 'Save', data dari form disimpan ke variabel lokal.
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
// Simpan data ke variabel atau kirim ke halaman lain
}
},
child: Text('Save'),
),
Di ItemListPage, saya menampilkan daftar item yang disimpan dengan ListView.
class ItemListPage extends StatelessWidget {
// ... Constructor dan variabel jika ada
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
// ... Properties untuk menampilkan item
);
},
),
);
}
}
Menambahkan Drawer di MyHomePage untuk memudahkan navigasi.
// Di dalam Scaffold dari MyHomePage
drawer: Drawer(
child: ListView(
children: [
// ... DrawerHeader dan ListTile untuk navigasi
],
),
),
menambahkan Snackbar untuk memberikan umpan balik kepada pengguna setelah aksi tertentu, seperti menekan tombol.
ElevatedButton.icon(
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Aksi dilakukan")),
);
// ... Aksi lain jika ada
},
// ... Properties untuk button
),
Melalui langkah-langkah ini, saya mendevelop aplikasi yang memungkinkan pengguna untuk memasukkan data melalui form, melihat daftar item, serta melakukan navigasi menggunakan drawer dan menerima umpan balik melalui snackbar.
Apa perbedaan utama antara stateless dan stateful widget dalam konteks pengembangan aplikasi Flutter?
- Stateless Widget: Ini adalah widget yang tidak memiliki perubahan internal. Dalam konteks pengembangan Flutter, stateless widget digunakan ketika Anda memiliki elemen antarmuka yang tidak akan berubah sepanjang siklus hidup widget tersebut. Misalnya, teks statis atau ikon.
- Stateful Widget: Widget ini dapat memiliki perubahan internal dan dapat diperbarui selama siklus hidupnya. Dalam konteks pengembangan Flutter, stateful widget digunakan ketika Anda perlu memperbarui elemen antarmuka, misalnya, saat pengguna berinteraksi dengan aplikasi dan data harus diperbarui secara dinamis.
Sebutkan seluruh widget yang kamu gunakan untuk menyelesaikan tugas ini dan jelaskan fungsinya masing-masing.
- MaterialApp: Ini adalah widget yang digunakan untuk menginisialisasi aplikasi Flutter dengan konfigurasi awal seperti judul, tema, dan layar awal.
- SingleChildScrollView: Ini adalah widget yang memungkinkan kontennya dapat di-scroll jika melebihi layar.
- ElevatedButton: Digunakan untuk membuat tombol yang menonjol dengan latar belakang warna tertentu.
Jelaskan bagaimana cara kamu mengimplementasikan checklist di atas secara step-by-step (bukan hanya sekadar mengikuti tutorial)
Pada main.dart, saya telah membuat program Flutter dengan tema "inventory" seperti tugas-tugas sebelumnya (dinamai dengan LiteraSync) dengan menggunakan MaterialApp:
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
useMaterial3: true,
),
home: const MyHomePage(),
);
}
}
Pada menu.dart, saya menggunakan Scaffold untuk mengatur struktur dasar aplikasi di dalam MyHomePage:
class MyHomePage extends StatelessWidget {
MyHomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Shopping List'),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
// Langkah selanjutnya...
),
),
),
);
}
}
Dalam Column, saya menambahkan elemen teks "LiteraSync" dengan:
Column(
children: [
const Padding(
padding: EdgeInsets.only(top: 10.0, bottom: 10.0),
child: Text(
'PBP Shop',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
),
),
),
// Langkah selanjutnya...
],
),
Menggunakan ElevatedButton untuk membuat tiga tombol dengan ikon dan teks:
Column(
children: [
// ...
ElevatedButton.icon(
onPressed: () {
// Menampilkan SnackBar dengan pesan "Kamu telah menekan tombol Lihat Item"
},
icon: Icon(Icons.checklist),
label: Text("Lihat Item"),
style: ElevatedButton.styleFrom(
primary: Colors.blue, // Warna latar belakang untuk "Lihat Item"
),
),
ElevatedButton.icon(
onPressed: () {
// Menampilkan SnackBar dengan pesan "Kamu telah menekan tombol Tambah Item"
},
icon: Icon(Icons.add_shopping_cart),
label: Text("Tambah Item"),
style: ElevatedButton.styleFrom(
primary: Colors.green, // Warna latar belakang untuk "Tambah Item"
),
),
ElevatedButton.icon(
onPressed: () {
// Menampilkan SnackBar dengan pesan "Kamu telah menekan tombol Logout"
},
icon: Icon(Icons.logout),
label: Text("Logout"),
style: ElevatedButton.styleFrom(
primary: Colors.red, // Warna latar belakang untuk "Logout"
),
),
],
),
Ketika tombol ditekan, saya menggunakan ScaffoldMessenger untuk menampilkan SnackBar dengan pesan yang sesuai.
Dengan langkah-langkah ini, seluruh checklist yang ada pada Tugas 7 PBP sudah berhasil diimplementasikan.