I need your help with the following content:
1. Jelaskan apa itu widget tree pada Flutter dan bagaimana hubungan parent-child (induk-anak) bekerja antar widget.
Widget tree adalah struktur hierarki yang menggambarkan bagaimana widget disusun dalam aplikasi Flutter.
Setiap elemen di layar (teks, tombol, kolom, dll) adalah widget, dan semua widget saling bersarang (nested).
- Parent (induk): Widget yang membungkus atau berisi widget lain.
- Child (anak): Widget yang berada di dalam parent.
Pada proyek ini contohnya Scaffold adalah parent yang memiliki child AppBar dan body.
Lalu body berisi Column → Row → InfoCard → Text.
2. Sebutkan semua widget yang kamu gunakan dalam proyek ini dan jelaskan fungsinya.
- MaterialApp: Widget root aplikasi. Mengatur tema, judul, dan halaman awal (
home). - Scaffold: Menyediakan struktur dasar halaman (
AppBar,Body,FloatingActionButton, dsb). - AppBar: Menampilkan header di bagian atas aplikasi dengan judul (“Offside Outlet”).
- Padding: Memberikan jarak di sekeliling konten (
EdgeInsets.all(16.0)). - Column: Menyusun widget secara vertikal (atas ke bawah).
- Row: Menyusun widget secara horizontal (samping).
- InfoCard: Widget kustom buatanmu untuk menampilkan info nama, NPM, kelas.
- Card: Memberi efek seperti kartu (elevasi/bayangan, border melengkung).
- GridView.count: Menyusun daftar tombol (
ItemCard) menjadi grid 3 kolom. - ItemCard / ProductCard: Widget kustom tombol berwarna untuk menampilkan aksi produk.
- Icon: Menampilkan ikon seperti inventory, person, add.
- Text: Menampilkan teks seperti “All Products” atau “Pilih aksi produk”.
- InkWell: Memberikan efek sentuhan dan menangani event
onTap(). - SnackBar: Muncul sementara di bawah layar untuk memberi notifikasi (“Kamu telah menekan tombol …”).
- ScaffoldMessenger: Menampilkan atau menyembunyikan
SnackBardi layar.
3. Apa fungsi dari widget MaterialApp? Jelaskan mengapa widget ini sering digunakan sebagai widget root.
MaterialApp adalah widget utama yang membungkus seluruh aplikasi Flutter berbasis Material Design.
Fungsinya:
- Mengatur tema warna aplikasi.
- Menyediakan navigasi antar halaman (
Navigator). - Menentukan halaman awal aplikasi melalui
home. - Menangani localization, routes, dan debug banner.
Widget MaterialApp sering jadi root karena menyediakan semua konfigurasi dasar yang dibutuhkan hampir setiap aplikasi Flutter modern. Tanpa MaterialApp, kita tidak bisa memakai widget seperti Scaffold, AppBar, atau SnackBar yang merupakan bagian dari Material Design system.
4. Jelaskan perbedaan antara StatelessWidget dan StatefulWidget. Kapan kamu memilih salah satunya?
- StatelessWidget: Bersifat tidak berubah (immutable) dan datanya tidak bisa berubah setelah dibuat.
Hanya mengimplementasikan metodebuild()untuk menampilkan UI yang statis (misalnyaTextatauIcon). - StatefulWidget: Dirancang untuk data yang bisa berubah (mutable) seiring berjalannya aplikasi.
Menggunakan metodecreateState()dan mengandalkansetState()untuk memicu pembangunan kembali widget secara selektif dan memperbarui tampilan menjadi dinamis dan interaktif (misalnyaFormatauCheckbox).
Dalam proyek ini saya memakai StatelessWidget karena tampilannya tidak berubah secara real-time.
5. Apa itu BuildContext dan mengapa penting di Flutter? Bagaimana penggunaannya di metode build?
BuildContext adalah objek yang menyimpan informasi lokasi widget di dalam widget tree.
Dengan BuildContext, Flutter mengetahui posisi widget berada dalam hierarki, tema atau ThemeData apa yang berlaku, dan akses ke widget induk seperti Scaffold atau Navigator.
6. Jelaskan konsep "hot reload" di Flutter dan bagaimana bedanya dengan "hot restart".
Hot Reload dan Hot Restart adalah dua fitur utama Flutter yang mempercepat proses pengembangan aplikasi.
- Hot Reload digunakan untuk menerapkan perubahan kecil secara cepat, seperti mengubah teks, warna, atau tata letak (layout), tanpa menghapus state atau data yang sedang aktif pada aplikasi. Artinya, jika sedang berada pada suatu halaman dengan data tertentu, data tersebut tetap dipertahankan setelah reload dilakukan. Prosesnya sangat cepat karena hanya memperbarui kode UI yang berubah.
- Hot Restart digunakan untuk memulai ulang seluruh aplikasi dari awal. Semua state widget akan dihapus dan aplikasi dijalankan kembali seperti saat pertama kali dijalankan. Fitur ini biasanya digunakan ketika terjadi perubahan besar pada struktur kode atau variabel global, karena memastikan aplikasi memuat ulang seluruh logika dan data dari awal.
1. Jelaskan perbedaan antara Navigator.push() dan Navigator.pushReplacement() pada Flutter. Dalam kasus apa sebaiknya masing-masing digunakan pada aplikasi Football Shop kamu?
Perbedaan utama:
Navigator.push()menambahkan halaman baru di atas navigation stack. Pengguna masih bisa kembali ke halaman sebelumnya dengan tombol Back.Navigator.pushReplacement()mengganti halaman yang aktif dengan halaman baru. Halaman lama dikeluarkan dari stack, jadi tidak bisa kembali ke sana.
Contoh:
- Pakai
Navigator.push()saat aksi yang memang perlu “jalan pulang”. Misalnya, dari drawer pilih Add Product → masuk ke form → setelah submit, pengguna bisa menekan Back untuk kembali ke halaman utama. - Pakai
Navigator.pushReplacement()untuk perpindahan antarmenu utama supaya stack tidak menumpuk. Misalnya, dari drawer pilih Home → halaman utama langsung menggantikan halaman sekarang, jadi tidak ada banyak “Home” berlapis di stack.
2. Bagaimana kamu memanfaatkan hierarchy widget seperti Scaffold, AppBar, dan Drawer untuk membangun struktur halaman yang konsisten di seluruh aplikasi?
Scaffoldjadi “tulang punggung” tiap halaman. tempat standar untuk AppBar, body, Drawer, dan komponen lain. Hasilnya, struktur UI konsisten di seluruh aplikasi.AppBardi bagian atas Scaffold yang menampilkan judul/branding dan aksi (icon search, add, dsb.).Drawersebagai navigasi utama yang berisi tautan antar‐halamanpushReplacementuntuk pindah antar halaman utama supaya stack tetap bersih.
Contoh:
Scaffold(
appBar: AppBar(
title: Text('Football Shop'),
backgroundColor: Theme.of(context).colorScheme.primary,
),
drawer: LeftDrawer(),
body: ...
)3. Dalam konteks desain antarmuka, apa kelebihan menggunakan layout widget seperti Padding, SingleChildScrollView, dan ListView saat menampilkan elemen-elemen form? Berikan contoh penggunaannya dari aplikasi kamu.
Paddingmemberikan jarak di sekitar widget, membuat tampilan lebih rapi dan nyaman untuk disentuh.SingleChildScrollViewmembuat form bisa di-scroll, sehingga semua field tetap bisa diakses meski layar kecil.ListViewcocok untuk menampilkan daftar widget yang dinamis, misal banyak field atau daftar produk.
Contoh:
SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: [
TextFormField(...),
SizedBox(height: 8),
TextFormField(...),
],
),
),
)4. Bagaimana kamu menyesuaikan warna tema agar aplikasi Football Shop memiliki identitas visual yang konsisten dengan brand toko?
- Warna utama dan properti tema diatur di
ThemeDatapadaMaterialApp. - Menggunakan warna utama brand untuk
primarySwatchdan background AppBar. - Terapkan skema warna ke tombol, ikon, dan highlight agar konsisten.
Contoh:
MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.blue),
appBarTheme: AppBarTheme(
backgroundColor: Color(0xFF2563EB),
foregroundColor: Colors.white,
),
),
home: MyHomePage(...),
)1. Jelaskan mengapa kita perlu membuat model Dart saat mengambil/mengirim data JSON? Apa konsekuensinya jika langsung memetakan Map<String, dynamic> tanpa model (terkait validasi tipe, null-safety, maintainability)?
Saat berkomunikasi dengan Django, data yang dikirim/diterima biasanya dalam bentuk JSON. Di Flutter, lebih aman dan rapi kalau JSON itu di-mapping dulu ke model Dart (class) daripada dibiarkan sebagai Map<String, dynamic>.
Alasannya:
-
Validasi tipe & type-safety
Dengan model, setiap field punya tipe jelas: String, int, bool, DateTime, dll. Kalau backend mengirim tipe yang salah atau kita salah pakai, error bisa cepat ketahuan saat compile / parse, bukan diam-diam di runtime. -
Null-safety
Dengan model, kita bisa menentukan mana field yang required dan mana yang boleh null. Ini mengurangi risiko error sepertiNull check operator used on a null value. -
Maintainability & readability
Aksesitem.name,item.pricejauh lebih jelas daripadamap['name'],map['price']. Kalau nama field di backend berubah, cukup perbaiki di satu file model, bukan di semua tempat yang pakaimap['...'].
Konsekuensi kalau langsung memakai Map<String, dynamic> tanpa model:
- Lebih rawan typo key ('naem' bukannya 'name') dan tetap lolos compile.
- Tidak ada jaminan tipe data, sehingga gampang muncul error aneh di runtime.
- Null-safety susah diawasi karena semua dianggap dynamic.
- Kode cepat berantakan dan susah di-maintain kalau aplikasi makin besar.
2. Apa fungsi package http dan CookieRequest dalam tugas ini? Jelaskan perbedaan peran http vs CookieRequest.
-
Package http
- Library umum untuk melakukan HTTP request (GET, POST, dll).
- Tidak otomatis mengatur cookie atau session.
- Cocok untuk: Mengakses endpoint publik dan kasus di mana kita sendiri yang urus header/token.
-
CookieRequest (dari pbp_django_auth)
- Wrapper khusus yang didesain untuk integrasi dengan Django.
- Menyimpan dan mengirim cookie session Django secara otomatis.
- Menyediakan method:
login(url, body)login ke Django dan simpan cookie.logout(url)logout dan hapus session.get(url)danpostJson(url, body)request dengan cookie yang sama.
Perbedaannya: http itu general, low-level, tidak tahu apa-apa soal session Django. Sedangkan CookieRequest lebih spesifik untuk autentikasi + session Django, mengelola cookie otomatis, dan sudah terintegrasi dengan pola tugas PBP.
3. Jelaskan mengapa instance CookieRequest perlu untuk dibagikan ke semua komponen di aplikasi Flutter.
Karena session user itu satu, bukan per-halaman. Aplikasi Flutter harus pakai satu instance CookieRequest yang sama di semua widget.
Untuk itu, MaterialApp di main.dart dibungkus dengan Provider:
-
Di main.dart:
Provider( create: (_) => CookieRequest(), child: MaterialApp(...), );
-
Di setiap widget yang butuh request:
final request = context.watch<CookieRequest>();
Alasannya:
-
Satu sumber truth untuk session
Login di halaman A harus otomatis membuat halaman B juga "tahu" bahwa user sudah login. Ini hanya bisa kalau semuanya pakai instanceCookieRequestyang sama. -
Cookie konsisten
Cookie session disimpan di dalamCookieRequest. Kalau tiap halaman punya objek sendiri, maka session bisa beda-beda dan backend akan menganggap kita belum login. -
Lebih rapi daripada global variable
Provider memberi cara yang bersih untuk mengaksesCookieRequestdi mana saja tanpa oper-oper variabel lewat constructor.
4. Jelaskan konfigurasi konektivitas yang diperlukan agar Flutter dapat berkomunikasi dengan Django. Mengapa kita perlu menambahkan 10.0.2.2 pada ALLOWED_HOSTS, mengaktifkan CORS dan pengaturan SameSite/cookie, dan menambahkan izin akses internet di Android? Apa yang akan terjadi jika konfigurasi tersebut tidak dilakukan dengan benar?
Supaya Flutter bisa terhubung dengan Django, ada beberapa konfigurasi penting:
- Di Android emulator, "localhost" = emulator itu sendiri, bukan laptop kita.
10.0.2.2adalah alamat khusus yang menunjuk ke localhost mesin host dari sudut pandang emulator.- Jadi di
settings.py:ALLOWED_HOSTS = [..., "10.0.2.2"]
Jika ini tidak dilakukan:
- Django akan memunculkan error
DisallowedHostdan menolak request dari10.0.2.2.
- Flutter app dan Django biasanya beda origin (beda port/domain).
django-cors-headersdigunakan untuk mengizinkan request dari Flutter.- Misalnya:
CORS_ALLOW_ALL_ORIGINS = True CORS_ALLOW_CREDENTIALS = True
Jika tidak diatur dengan benar:
- Browser/client bisa blok request dengan error CORS.
- Cookie (session) mungkin tidak akan dikirim jika
CORS_ALLOW_CREDENTIALSatau header terkait tidak tepat.
- Supaya cookie session Django bisa terkirim dalam konteks berbeda, diatur misalnya:
CSRF_COOKIE_SECURE = True SESSION_COOKIE_SECURE = True CSRF_COOKIE_SAMESITE = 'None' SESSION_COOKIE_SAMESITE = 'None'
Jika salah konfigurasi:
- Cookie session bisa tidak ikut terkirim, sehingga Django selalu menganggap user belum login meskipun user sudah login dari Flutter.
- Di
AndroidManifest.xml:<uses-permission android:name="android.permission.INTERNET" />
Kalau izin ini tidak ada:
- Aplikasi Android tidak bisa akses internet sama sekali, sehingga semua HTTP request ke Django akan gagal.
5. Jelaskan mekanisme pengiriman data mulai dari input hingga dapat ditampilkan pada Flutter.
Alur umumnya:
-
User melakukan input / aksi di Flutter
Contoh: membuka halaman daftar item atau submit form. -
Flutter mengirim request ke Django
- Untuk GET list item:
response = await request.get("http://[APP_URL]/json/");
- Untuk POST data (misalnya create item):
response = await request.postJson( "http://[APP_URL]/create-flutter/", jsonEncode({...}), );
- Untuk GET list item:
-
Django memproses request
- Untuk GET:
- Mengambil data dari database (misalnya
Item.objects.filter(user=request.user)). - Meng-serialize ke JSON dan mengembalikannya ke Flutter.
- Mengambil data dari database (misalnya
- Untuk POST:
- Parse
request.bodymenjadi JSON. - Validasi data dan membuat objek baru di database.
- Mengembalikan JSON yang berisi status sukses/gagal.
- Parse
- Untuk GET:
-
Flutter menerima JSON dan memetakan ke model Dart
- Data (list map) di-loop dan dikonversi ke
List<Model>denganfromJson:List<Item> items = []; for (var d in response) { items.add(Item.fromJson(d)); }
- Data (list map) di-loop dan dikonversi ke
-
UI menampilkan data
- Menggunakan
FutureBuilder:- Saat future masih jalan → tampil
CircularProgressIndicator. - Saat future selesai → build
ListView.builderdengan data model.
- Saat future masih jalan → tampil
- Tiap item di-render dalam
CardatauListTileyang menampilkan field seperti name, price, description, thumbnail, category, is_featured.
- Menggunakan
6. Jelaskan mekanisme autentikasi dari login, register, hingga logout. Mulai dari input data akun pada Flutter ke Django hingga selesainya proses autentikasi oleh Django dan tampilnya menu pada Flutter.
- User mengisi form register di Flutter (username, password, confirm password).
- Flutter mengirim request ke Django:
response = await request.postJson( "http://[APP_URL]/auth/register/", jsonEncode({ "username": username, "password1": password1, "password2": password2, }), );
- Django:
- Parse JSON dari
request.body. - Cek apakah
password1 == password2. - Cek apakah username sudah ada di database.
- Jika valid, membuat user baru dengan
User.objects.create_user. - Mengembalikan JSON dengan status success atau error.
- Parse JSON dari
- Flutter:
- Jika
status == "success"tampilkan pesan "Successfully registered!" lalu redirect ke halaman login. - Jika gagal menampilkan pesan error via SnackBar/AlertDialog.
- Jika
-
User mengisi username dan password di form login Flutter.
-
Flutter memanggil:
response = await request.login( "http://[APP_URL]/auth/login/", { "username": username, "password": password, }, );
-
Django:
- Mengambil username dan password dari
request.POST. - Memanggil
authenticate(username=..., password=...). - Jika user valid dan aktif:
auth_login(request, user)→ membuat session di server.- Mengembalikan JSON:
{ "username": user.username, "status": True, "message": "Login successful!" }
- Jika gagal, mengembalikan status False dengan pesan error.
- Mengambil username dan password dari
-
CookieRequest:
- Menyimpan cookie session dari Django.
- Menandai
request.loggedIn = true.
-
Flutter:
- Jika
request.loggedIn == true, melakukanNavigator.pushReplacementke halaman utama (misalnyaMyHomePage()). - Menampilkan pesan sambutan misalnya "Login successful! Welcome, ".
- Jika
- User menekan tombol Logout di Flutter.
- Flutter memanggil:
response = await request.logout("http://[APP_URL]/auth/logout/");
- Django:
- Mengambil username dari
request.user.username. - Memanggil
auth_logout(request)untuk menghapus session. - Mengembalikan JSON dengan status True/False dan message.
- Mengambil username dari
- CookieRequest:
- Menghapus cookie/session yang tersimpan.
- Flutter:
- Jika logout sukses ada SnackBar "Logged out successfully! See you again, ." dan melakukan
Navigator.pushReplacementkeLoginPage(). - Jika gagal akan menampilkan pesan error.
- Jika logout sukses ada SnackBar "Logged out successfully! See you again, ." dan melakukan
7. Cara mengimplementasikan checklist secara step-by-step (bukan hanya mengikuti tutorial) 1. Menyiapkan backend Django tugas
- Memastikan proyek Django dari tugas sebelumnya berjalan (runserver atau deployment).
- Menambahkan
django-cors-headers, mengaturCORS_ALLOW_ALL_ORIGINS,CORS_ALLOW_CREDENTIALS, dan pengaturan cookie (CSRF_COOKIE_SAMESITE,SESSION_COOKIE_SAMESITE). - Menambahkan
10.0.2.2dan domain deployment keALLOWED_HOSTS.
2. Membuat dan mengonfigurasi app authentication di Django
- Menjalankan
python manage.py startapp authentication. - Menambahkan
"authentication"keINSTALLED_APPS. - Membuat view login, register, dan logout di
authentication/views.py. - Menambahkan urls authentication (login, register, logout) dan meng-include-nya di
urls.pyutama dengan prefix/auth/.
3. Menyiapkan endpoint JSON untuk item
- Membuat view yang meng-serialize daftar item ke JSON.
- Memastikan queryset difilter berdasarkan user yang login (
filter(user=request.user)) sehingga hanya item milik user yang tampil. - Menambahkan path
/json/(atau nama lain) diurls.py.
4. Menyiapkan endpoint untuk create item dari Flutter
- Membuat view
create_<model>_flutterdengan@csrf_exempt. - Mem-parse
request.body, memvalidasi data, menghapus tag HTML jika perlu (strip_tags), dan membuat objek baru di database denganuser=request.user. - Mengembalikan
JsonResponse({"status": "success"})jika berhasil. - Menambahkan path
/create-flutter/diurls.py.
5. Konfigurasi aplikasi Flutter
- Menambahkan dependency
provider,pbp_django_auth, danhttpdipubspec.yaml. - Menambahkan izin internet di
AndroidManifest.xml. - Mengubah
main.dartsupaya membungkusMaterialAppdenganProvideryang menyediakan satu instanceCookieRequest. - Mengganti
home: MyHomePage()menjadihome: const LoginPage().
6. Membuat halaman Login di Flutter
- Membuat
screens/login.dartdenganLoginPage(StatefulWidget). - Menambahkan
TextEditingControlleruntuk username dan password. - Mengambil
CookieRequestviacontext.watch<CookieRequest>(). - Di tombol login, memanggil
request.login("http://[APP_URL]/auth/login/", {...}). - Jika berhasil, menampilkan SnackBar dan melakukan
Navigator.pushReplacementke halaman utama.
7. Membuat halaman Register di Flutter
- Membuat
screens/register.dartdengan form username, password, dan confirm password. - Mengirim data ke Django menggunakan
request.postJson("http://[APP_URL]/auth/register/", jsonEncode({...})). - Menambahkan
GestureDetector/ tombol diLoginPageyang menavigasi keRegisterPage. - Menangani response: jika
status == 'success', tampilkan pesan dan kembali keLoginPage.
8. Membuat model Dart custom dari endpoint JSON
- Membuka endpoint JSON Django di browser (misal
/json/). - Menyalin data JSON ke Quicktype dan meng-generate model Dart.
- Menyalin model tersebut ke
lib/models/<model>.dartdan menyesuaikan nama field / tipe sesuai kebutuhan.
9. Membuat halaman daftar item di Flutter
- Membuat
screens/item_list.dart. - Menulis fungsi
Future<List<Item>> fetchItems(CookieRequest request)yang melakukanrequest.get("http://[APP_URL]/json/")dan mapping keList<Item>. - Menggunakan
FutureBuilderuntuk memanggilfetchItemsdan menampilkan:CircularProgressIndicatorsaat loading.ListView.builderyang berisi card item saat data sudah ada.
- Di card item, menampilkan name, price, description, thumbnail, category, dan is_featured.
10. Membuat card item dan halaman detail item
- Membuat widget
ItemCarddilib/widgets/item_card.dart. - Memberikan
onTapyang memanggilNavigator.pushkeItemDetailPage(item: item). - Membuat
ItemDetailPagediscreens/item_detail.dartyang menampilkan seluruh atribut model item. - Menambahkan tombol kembali (
Navigator.pop) diAppBaratau di dalam body.
11. Memastikan filter item hanya milik user yang login
- Di Django, memastikan view JSON hanya mengembalikan item dengan
filter(user=request.user). - Menguji dengan login dua user berbeda dan memastikan item yang tampil di Flutter sesuai pemiliknya.
12. Menambahkan fitur logout di Flutter
- Menambahkan opsi Logout di menu / drawer / card pada halaman utama.
- Mengambil
CookieRequestviacontext.watch<CookieRequest>()di widget tersebut. - Di
onTap, memanggilrequest.logout("http://[APP_URL]/auth/logout/"). - Menangani response: jika status
True, tampilkan pesan "Logged out successfully!" danNavigator.pushReplacementkeLoginPage.
13. Testing end-to-end
- Register akun baru → login → tambah item dari Django/Flutter → cek apakah muncul di daftar item di Flutter → buka detail item → kembali → logout.
- Memastikan URL
[APP_URL]di Flutter sudah diganti ke URL backend yang benar (10.0.2.2:8000,localhost:8000, atau URL deployment).