TKK_E32220565/newata2/README.md

122 lines
6.7 KiB
Markdown

# newata2
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
----------------------------------------------------------------------------------------------------------------------------------------------------------
Penjelasan Detail per Bagian Kode
1. main.dart
Ini adalah titik masuk (entry point) dari aplikasi Anda.
Future<void> main() async: Fungsi main dibuat async karena kita perlu menunggu proses inisialisasi selesai sebelum aplikasi berjalan.
WidgetsFlutterBinding.ensureInitialized(): Baris ini wajib ada ketika Anda ingin menjalankan kode sebelum runApp(), memastikan semua binding Flutter siap.
await dotenv.load(...): Memuat semua variabel dari file .env Anda (seperti URL dan Kunci Supabase) ke dalam memori.
await Supabase.initialize(...): Menginisialisasi koneksi ke proyek Supabase Anda. Ini adalah langkah krusial.
ChangeNotifierProvider(...): Ini berasal dari library provider. Ini "membungkus" seluruh aplikasi Anda dengan AppState, sehingga semua halaman di bawahnya dapat "mendengarkan" dan bereaksi terhadap perubahan data di AppState.
MyApp: Widget utama yang mengatur tema global aplikasi dan mendefinisikan halaman awal.
2. AppState (lib/provider/app_state.dart)
Ini adalah "otak" dari aplikasi Anda. Kelas ini mengelola semua data dan logika bisnis aplikasi (state management).
class AppState extends ChangeNotifier: ChangeNotifier adalah kelas dari Flutter yang memungkinkan AppState untuk "memberi tahu" para pendengarnya (widget) ketika ada data yang berubah, menggunakan notifyListeners().
Variabel State (_): Variabel yang diawali dengan _ (contoh: _isLoading) bersifat private. Data ini hanya bisa diubah dari dalam kelas AppState itu sendiri. Widget lain hanya bisa membacanya melalui getters (contoh: isLoading).
Constructor AppState(): Di sini kita mengatur pendengar onAuthStateChange. Ini adalah pendengar realtime dari Supabase yang aktif setiap kali ada perubahan status login (login, logout). Jika pengguna logout (_currentUser == null), kita memanggil clearState() untuk membersihkan semua data sesi sebelumnya.
_setLoading(bool value): Fungsi internal untuk mengontrol tampilan CircularProgressIndicator di seluruh aplikasi.
setDeviceIdAndFetchData(...): Fungsi ini dipanggil setelah login berhasil. Ia menyimpan deviceId, kemudian memanggil fungsi lain untuk mengambil data awal dan mulai mendengarkan perubahan realtime.
fetchEvents() & fetchDeviceStatus(): Fungsi ini mengambil data dari tabel Supabase (sensor_events dan device_status) menggunakan select(). Data ini kemudian disimpan dalam variabel state.
_listenToRealtimeChanges() (PERBAIKAN ERROR):
Fungsi ini sekarang menggunakan sintaks baru dari supabase_flutter v2.
supabase.channel(...): Membuat channel komunikasi realtime.
.onPostgresChanges(...): Ini adalah fungsi spesifik untuk mendengarkan perubahan pada database PostgreSQL Anda.
event: PostgresChangeEvent.insert: Hanya mendengarkan event INSERT (ketika ada data baru masuk).
schema: 'public', table: '...': Menentukan tabel mana yang ingin dipantau.
filter: ...: Filter tambahan agar kita hanya mendapatkan notifikasi untuk deviceId yang sedang dipantau.
.listen((payload) { ... }): Callback yang akan dieksekusi ketika ada data baru. payload.new berisi data baris yang baru saja ditambahkan.
setSleepSchedule(...): Fungsi ini dipanggil saat pengguna menekan tombol "Set Timer". Ia melakukan update() pada tabel device_status, mengisi kolom schedule_duration_microseconds dan setter_user_id dengan nilai yang baru.
3. Halaman SplashScreen (Baru)
StatefulWidget: Diperlukan karena kita perlu mengelola state selama proses navigasi.
initState(): Metode ini dipanggil sekali saat widget pertama kali dibuat. Di sinilah kita memulai timer.
Future.delayed(const Duration(seconds: 3), ...): Menjalankan kode di dalamnya setelah jeda 3 detik.
Navigator.pushReplacement(...): Setelah 3 detik, kita pindah ke AuthWrapper. pushReplacement digunakan agar pengguna tidak bisa kembali ke splash screen dengan menekan tombol "back".
4. AuthWrapper
Seperti yang dijelaskan, ini adalah widget tanpa tampilan yang berfungsi sebagai router cerdas.
Consumer<AppState>: Widget ini secara otomatis "mendengarkan" AppState. Setiap kali notifyListeners() dipanggil di AppState, bagian builder dari Consumer ini akan dieksekusi ulang.
if (appState.currentUser != null && appState.deviceId != null): Logika inti. Jika ada pengguna yang login DAN deviceId sudah diatur, tampilkan DashboardPage. Jika tidak, tampilkan LoginPage.
5. LoginPage
StatefulWidget & TextEditingController: Digunakan untuk mengelola input teks dari pengguna.
_formKey: Digunakan untuk validasi form (memastikan kolom tidak kosong).
_signIn():
Memeriksa validasi form.
Memanggil supabase.auth.signInWithPassword(...).
Jika berhasil, ia memanggil Provider.of<AppState>(context, listen: false).setDeviceIdAndFetchData(...) untuk memberi tahu AppState bahwa pengguna telah login dengan deviceId tertentu, sehingga AppState bisa mulai mengambil data.
Menangani AuthException jika login gagal (misalnya, password salah).
6. RegisterPage
Mirip dengan LoginPage, tetapi memanggil supabase.auth.signUp(...).
data: {'full_name': ...}: Ini adalah bagian penting. Di sinilah kita menyimpan data tambahan (nama lengkap) ke dalam kolom raw_user_meta_data di tabel auth.users Supabase.
7. DashboardPage & Komponen-komponennya
DashboardPage: Menggunakan CustomScrollView dan Sliver untuk layout yang efisien dan memungkinkan adanya refresh indicator.
ProfileBar: Mengambil data pengguna (fullName, email) dari AppState dan menampilkannya. Tombol logout memanggil appState.signOut().
SettingsBar:
Menampilkan status online/offline berdasarkan data dari _deviceStatus di AppState.
Tombol "Set Timer" hanya aktif jika isOnline == true.
_showSetTimerDialog(): Memunculkan TimePicker bawaan Flutter. Logikanya menghitung selisih antara waktu sekarang dan waktu yang dipilih pengguna, mengonversinya ke mikrodetik, lalu memanggil appState.setSleepSchedule() untuk mengirim data ke Supabase.
FootageGallery & FootageCard:
FootageGallery menampilkan SliverList dari FootageCard berdasarkan data _events di AppState.
FootageCard adalah kartu individu yang menampilkan gambar (Image.network), lokasi, tipe event, dan waktu kejadian. Desain kartu dibuat dengan BoxDecoration untuk memberikan efek bayangan (mirip 3D) dan sudut yang tumpul (borderRadius).