diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index a8ecd8d..9ccbca1 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -2,7 +2,7 @@
package="com.example.coffee_iot_flutter">
-
-
-
-
-
+ -
+
+
diff --git a/android/app/src/main/res/drawable/background.png b/android/app/src/main/res/drawable/background.png
new file mode 100644
index 0000000..22a1c6b
Binary files /dev/null and b/android/app/src/main/res/drawable/background.png differ
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
index 304732f..f88598c 100644
--- a/android/app/src/main/res/drawable/launch_background.xml
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -1,12 +1,6 @@
-
-
-
-
-
+ -
+
+
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
index db77bb4..1c71fcc 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
index 17987b7..9b9c3de 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index 09d4391..54ca34a 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index d5f1c8d..06de0f2 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index 4d6372e..075a42b 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/values-night-v31/styles.xml b/android/app/src/main/res/values-night-v31/styles.xml
new file mode 100644
index 0000000..5fef228
--- /dev/null
+++ b/android/app/src/main/res/values-night-v31/styles.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml
index 06952be..dbc9ea9 100644
--- a/android/app/src/main/res/values-night/styles.xml
+++ b/android/app/src/main/res/values-night/styles.xml
@@ -5,6 +5,10 @@
- @drawable/launch_background
+ - false
+ - false
+ - false
+ - shortEdges
+
+
+
+
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index cb1ef88..86a149a 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -1,18 +1,13 @@
-
-
-
-
diff --git a/assets/icon/kopibaru.png b/assets/icon/kopibaru.png
new file mode 100644
index 0000000..6eaa5b4
Binary files /dev/null and b/assets/icon/kopibaru.png differ
diff --git a/assets/icon/kopibaru_removebg.png b/assets/icon/kopibaru_removebg.png
new file mode 100644
index 0000000..88642cc
Binary files /dev/null and b/assets/icon/kopibaru_removebg.png differ
diff --git a/lib/constants/app_colors.dart b/lib/constants/app_colors.dart
new file mode 100644
index 0000000..f2491f5
--- /dev/null
+++ b/lib/constants/app_colors.dart
@@ -0,0 +1,28 @@
+import 'package:flutter/material.dart';
+
+class AppColors {
+ // Latar Belakang (Mint Ice yang lembut)
+ static const Color background = Color(0xFFF4F7F6);
+ static const Color cardBg = Colors.white;
+
+ // Warna Utama (Earth Tone Premium - Olive Sage)
+ static const Color primary = Color(0xFF627254);
+ static const Color primaryLight = Color(0xFF76885B);
+
+ // Teks (Menggunakan pilihan barumu: Charcoal & Cool Grey)
+ static const Color textMain = Color(0xFF3D3D3B); // Charcoal Dark Grey (Tegas)
+ static const Color textSecondary = Color(0xFF8B949E); // Cool Grey (Elegan)
+
+ // Warna Status & Peringatan
+ static const Color success = Color(0xFF7DA78C);
+ static const Color error = Color(0xFFE74C3C);
+ static const Color warning = Color(0xFFE67E22);
+ static const Color info = Color(0xFF3498DB);
+ static const Color light = Color(0xFFF1C40F);
+
+ // Latar belakang transparan untuk elemen status (Update .withValues untuk Flutter terbaru)
+ static Color get successBg => success.withValues(alpha: 0.15);
+ static Color get errorBg => error.withValues(alpha: 0.15);
+ static Color get warningBg => warning.withValues(alpha: 0.15);
+ static Color get infoBg => info.withValues(alpha: 0.15);
+}
\ No newline at end of file
diff --git a/lib/main.dart b/lib/main.dart
index f644ba0..a7c2860 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -2,6 +2,12 @@ import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:provider/provider.dart';
import 'package:app_links/app_links.dart';
+import 'package:google_fonts/google_fonts.dart';
+
+// --- IMPORT APP COLORS ---
+import 'constants/app_colors.dart';
+// -------------------------
+
import 'services/mqtt_service.dart';
import 'screens/login_screen.dart';
import 'screens/register_screen.dart';
@@ -10,6 +16,7 @@ import 'screens/analytics_screen.dart';
import 'screens/image_result_screen.dart';
import 'screens/change_password_screen.dart';
import 'screens/forgot_password_screen.dart';
+import 'screens/splash_screen.dart';
final GlobalKey navigatorKey = GlobalKey();
@@ -61,13 +68,72 @@ class MyApp extends StatelessWidget {
navigatorKey: navigatorKey,
title: 'Coffee IoT',
debugShowCheckedModeBanner: false,
+
+ // --- KONFIGURASI TEMA LIGHT MODE (TERPUSAT) ---
theme: ThemeData(
- brightness: Brightness.dark,
- primarySwatch: Colors.green,
- scaffoldBackgroundColor: Colors.black,
+ useMaterial3: true,
+ brightness: Brightness.light,
+ scaffoldBackgroundColor: AppColors.background,
+ primaryColor: AppColors.primary,
+
+ // ColorScheme untuk warna dasar komponen Material (Tombol, Dialog, dll)
+ colorScheme: const ColorScheme.light(
+ primary: AppColors.primary,
+ secondary: AppColors.primary,
+ surface: AppColors.cardBg,
+ error: AppColors.error,
+ onPrimary: Colors.white,
+ onSurface: AppColors.textMain,
+ ),
+
+ // Menerapkan Google Fonts (Poppins) dengan pewarnaan dari AppColors
+ textTheme: GoogleFonts.poppinsTextTheme(
+ ThemeData.light().textTheme,
+ ).copyWith(
+ displayLarge: GoogleFonts.poppins(color: AppColors.textMain, fontWeight: FontWeight.bold),
+ displayMedium: GoogleFonts.poppins(color: AppColors.textMain, fontWeight: FontWeight.bold),
+ headlineLarge: GoogleFonts.poppins(color: AppColors.textMain, fontWeight: FontWeight.bold),
+ headlineMedium: GoogleFonts.poppins(color: AppColors.textMain, fontWeight: FontWeight.w600),
+ titleLarge: GoogleFonts.poppins(color: AppColors.textMain, fontWeight: FontWeight.w600),
+ bodyLarge: GoogleFonts.poppins(color: AppColors.textMain),
+ bodyMedium: GoogleFonts.poppins(color: AppColors.textMain),
+ bodySmall: GoogleFonts.poppins(color: AppColors.textSecondary),
+ labelLarge: GoogleFonts.poppins(color: AppColors.textMain, fontWeight: FontWeight.w500),
+ ),
+
+ // Tema AppBar Global (Biar transparan dan tulisannya otomatis ikut tema)
+ appBarTheme: AppBarTheme(
+ backgroundColor: AppColors.background,
+ elevation: 0,
+ centerTitle: true,
+ iconTheme: const IconThemeData(color: AppColors.textMain),
+ titleTextStyle: GoogleFonts.poppins(
+ color: AppColors.textMain,
+ fontSize: 18,
+ fontWeight: FontWeight.w600,
+ ),
+ ),
+
+ // Tema Card Global (Otomatis membulat dan punya bayangan halus)
+ cardTheme: CardThemeData(
+ color: AppColors.cardBg,
+ elevation: 2,
+ shadowColor: Colors.black.withValues(alpha: 0.05),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(16),
+ ),
+ ),
+
+ // Tema Ikon Global
+ iconTheme: const IconThemeData(
+ color: AppColors.textMain,
+ ),
),
- initialRoute: '/login',
+ // ----------------------------------------------
+
+ initialRoute: '/',
routes: {
+ '/': (context) => const SplashScreen(),
'/login': (context) => const LoginScreen(),
'/register': (context) => const RegisterScreen(),
'/home': (context) => const HomeScreen(),
diff --git a/lib/screens/analytics_screen.dart b/lib/screens/analytics_screen.dart
index 7032e2d..577c623 100644
--- a/lib/screens/analytics_screen.dart
+++ b/lib/screens/analytics_screen.dart
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
import '../services/supabase_service.dart';
+import '../constants/app_colors.dart'; // <-- IMPORT APP COLORS DITAMBAHKAN
class AnalyticsScreen extends StatefulWidget {
const AnalyticsScreen({super.key});
@@ -36,21 +37,27 @@ class _AnalyticsScreenState extends State {
Widget build(BuildContext context) {
final args = (ModalRoute.of(context)?.settings.arguments as Map?) ?? {};
final String title = args['title'] ?? 'Grafik';
- final Color color = args['color'] ?? Colors.green;
+ final Color color = args['color'] ?? AppColors.primary; // --- BERUBAH: Fallback color ---
final String sensorKey = title.contains('Suhu') ? 'suhu' : title.contains('Kelembaban') ? 'kelembapan' : 'intensitas';
return Scaffold(
- backgroundColor: Colors.black,
+ // --- BERUBAH: Background Scaffold Utama ---
+ backgroundColor: AppColors.background,
appBar: AppBar(
- backgroundColor: Colors.black,
- title: Text(title, style: const TextStyle(color: Colors.white)),
+ // --- BERUBAH: Dibuat transparan agar menyatu dengan background ---
+ backgroundColor: Colors.transparent,
+ elevation: 0,
+ // --- BERUBAH: Warna Teks Judul ---
+ title: Text(title, style: const TextStyle(color: AppColors.textMain)),
leading: IconButton(
- icon: const Icon(Icons.arrow_back, color: Colors.grey),
+ // --- BERUBAH: Warna Ikon Back ---
+ icon: const Icon(Icons.arrow_back, color: AppColors.primary),
onPressed: () => Navigator.pop(context),
),
),
body: _isLoading
- ? const Center(child: CircularProgressIndicator(color: Colors.green))
+ // --- BERUBAH: Warna Loading Indicator ---
+ ? const Center(child: CircularProgressIndicator(color: AppColors.primary))
: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
@@ -60,21 +67,27 @@ class _AnalyticsScreenState extends State {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- const Text('Riwayat Data', style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)),
- IconButton(icon: const Icon(Icons.refresh, color: Colors.green), onPressed: _fetchLogs),
+ // --- BERUBAH: Warna Teks Judul Riwayat ---
+ const Text('Riwayat Data', style: TextStyle(color: AppColors.textMain, fontSize: 18, fontWeight: FontWeight.bold)),
+ // --- BERUBAH: Warna Ikon Refresh ---
+ IconButton(icon: const Icon(Icons.refresh, color: AppColors.primary), onPressed: _fetchLogs),
],
),
const SizedBox(height: 10),
Expanded(
child: Container(
decoration: BoxDecoration(
- color: const Color(0xFF1A1A1A),
+ // --- BERUBAH: Warna Latar Daftar Riwayat ---
+ color: AppColors.cardBg,
borderRadius: BorderRadius.circular(20),
+ // --- BERUBAH: Menambahkan border halus agar serasi dengan kartu lain ---
+ border: Border.all(color: AppColors.textSecondary.withValues(alpha: 0.15)),
),
child: ListView.separated(
padding: const EdgeInsets.all(15),
itemCount: _logs.length,
- separatorBuilder: (context, index) => const Divider(color: Colors.grey),
+ // --- BERUBAH: Warna Garis Pemisah (Divider) antar item ---
+ separatorBuilder: (context, index) => Divider(color: AppColors.textSecondary.withValues(alpha: 0.3)),
itemBuilder: (context, index) {
final log = _logs[index];
return Padding(
@@ -85,10 +98,13 @@ class _AnalyticsScreenState extends State {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Text(log['timestamp'] ?? '', style: const TextStyle(color: Colors.grey, fontSize: 10)),
- Text('Fans: ${log['kipas1']}/${log['kipas2']}', style: const TextStyle(color: Colors.green, fontSize: 10)),
+ // --- BERUBAH: Warna Teks Tanggal/Waktu ---
+ Text(log['timestamp'] ?? '', style: const TextStyle(color: AppColors.textSecondary, fontSize: 10)),
+ // --- BERUBAH: Warna Teks Status Kipas ---
+ Text('Kipas 1: ${log['kipas1']} | Kipas 2: ${log['kipas2']}', style: const TextStyle(color: AppColors.primary, fontSize: 10)),
],
),
+ // Warna nilai sensor tetap mengikuti `color` dinamis (Merah/Cyan/Orange)
Text('${log[sensorKey]}', style: TextStyle(color: color, fontWeight: FontWeight.bold)),
],
),
@@ -116,14 +132,15 @@ class _AnalyticsScreenState extends State {
height: 250,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
- color: const Color(0xFF1A1A1A),
+ // --- BERUBAH: Warna Latar Kartu Grafik ---
+ color: AppColors.cardBg,
borderRadius: BorderRadius.circular(20),
+ // --- BERUBAH: Menambahkan border halus agar serasi dengan kartu lain ---
+ border: Border.all(color: AppColors.textSecondary.withValues(alpha: 0.15)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Text(title, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold)),
- const SizedBox(height: 20),
Expanded(
child: LineChart(
LineChartData(
@@ -134,10 +151,12 @@ class _AnalyticsScreenState extends State {
LineChartBarData(
spots: spots.isEmpty ? [const FlSpot(0, 0)] : spots,
isCurved: true,
+ // Warna garis grafik tetap mengikuti `color` dinamis
color: color,
barWidth: 4,
dotData: FlDotData(show: false),
- belowBarData: BarAreaData(show: true, color: color.withOpacity(0.1)),
+ // --- BERUBAH: Gunakan withValues untuk transparansi area bawah grafik ---
+ belowBarData: BarAreaData(show: true, color: color.withValues(alpha: 0.1)),
),
],
),
@@ -147,6 +166,7 @@ class _AnalyticsScreenState extends State {
alignment: Alignment.bottomRight,
child: Text(
'Terakhir: ${logs.isNotEmpty ? logs.first[key] : "-"}',
+ // Warna teks terakhir tetap mengikuti `color` dinamis
style: TextStyle(color: color, fontSize: 12)
),
),
@@ -154,4 +174,4 @@ class _AnalyticsScreenState extends State {
),
);
}
-}
+}
\ No newline at end of file
diff --git a/lib/screens/change_password_screen.dart b/lib/screens/change_password_screen.dart
index 092f3b9..9f847b4 100644
--- a/lib/screens/change_password_screen.dart
+++ b/lib/screens/change_password_screen.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import '../services/supabase_service.dart';
+import '../constants/app_colors.dart'; // <-- IMPORT APP COLORS DITAMBAHKAN
class ChangePasswordScreen extends StatefulWidget {
const ChangePasswordScreen({super.key});
@@ -118,17 +119,18 @@ class _ChangePasswordScreenState extends State {
content: Row(
children: [
Icon(isError ? Icons.error_outline : Icons.check_circle_outline,
- color: Colors.white),
+ color: Colors.white), // Tetap putih agar kontras
const SizedBox(width: 10),
Expanded(
child: Text(pesan,
style: const TextStyle(
- color: Colors.white, fontWeight: FontWeight.bold)),
+ color: Colors.white, fontWeight: FontWeight.bold)), // Tetap putih
),
],
),
+ // --- BERUBAH: Warna Notifikasi ---
backgroundColor:
- isError ? Colors.red.shade700 : Colors.green.shade700,
+ isError ? AppColors.error : AppColors.success,
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
margin: const EdgeInsets.all(16),
@@ -140,11 +142,15 @@ class _ChangePasswordScreenState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
- backgroundColor: Colors.black,
+ // --- BERUBAH: Background Utama ---
+ backgroundColor: AppColors.background,
appBar: AppBar(
- backgroundColor: Colors.black,
+ // --- BERUBAH: AppBar Transparan ---
+ backgroundColor: Colors.transparent,
+ elevation: 0,
leading: IconButton(
- icon: const Icon(Icons.arrow_back, color: Colors.white),
+ // --- BERUBAH: Warna Ikon Kembali ---
+ icon: const Icon(Icons.arrow_back, color: AppColors.primary),
onPressed: () => _dariResetLink
? Navigator.pushReplacementNamed(context, '/login')
: Navigator.pop(context),
@@ -152,7 +158,8 @@ class _ChangePasswordScreenState extends State {
title: Text(
_dariResetLink ? 'Reset Password' : 'Ganti Password',
style: const TextStyle(
- color: Colors.white,
+ // --- BERUBAH: Warna Judul ---
+ color: AppColors.textMain,
fontSize: 20,
fontWeight: FontWeight.bold),
),
@@ -167,16 +174,19 @@ class _ChangePasswordScreenState extends State {
_dariResetLink
? 'Masukkan password baru untuk akun kamu.'
: 'Ubah password akun kamu.\nPastikan password baru minimal 6 karakter.',
- style: const TextStyle(color: Colors.grey, fontSize: 14),
+ // --- BERUBAH: Warna Sub-judul ---
+ style: const TextStyle(color: AppColors.textSecondary, fontSize: 14),
),
const SizedBox(height: 30),
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
- color: const Color(0xFF1A1A1A),
+ // --- BERUBAH: Latar Belakang Kotak Form ---
+ color: AppColors.cardBg,
borderRadius: BorderRadius.circular(20),
- border: Border.all(color: Colors.grey.withOpacity(0.3)),
+ // --- BERUBAH: Garis Pinggir Halus ---
+ border: Border.all(color: AppColors.textSecondary.withValues(alpha: 0.15)),
),
child: Column(
children: [
@@ -189,7 +199,8 @@ class _ChangePasswordScreenState extends State {
onToggle: () => setState(
() => _obscurePassLama = !_obscurePassLama),
),
- const Divider(color: Colors.grey),
+ // --- BERUBAH: Warna Divider ---
+ Divider(color: AppColors.textSecondary.withValues(alpha: 0.3)),
],
_buildPasswordField(
@@ -199,7 +210,8 @@ class _ChangePasswordScreenState extends State {
onToggle: () => setState(
() => _obscurePassBaru = !_obscurePassBaru),
),
- const Divider(color: Colors.grey),
+ // --- BERUBAH: Warna Divider ---
+ Divider(color: AppColors.textSecondary.withValues(alpha: 0.3)),
_buildPasswordField(
controller: _konfirmasiController,
@@ -220,20 +232,22 @@ class _ChangePasswordScreenState extends State {
child: ElevatedButton(
onPressed: _isLoading ? null : _handleGantiPassword,
style: ElevatedButton.styleFrom(
- backgroundColor: Colors.green,
- disabledBackgroundColor: Colors.green.withOpacity(0.3),
+ // --- BERUBAH: Warna Tombol ---
+ backgroundColor: AppColors.primary,
+ disabledBackgroundColor: AppColors.primary.withValues(alpha: 0.3),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
child: _isLoading
- ? const CircularProgressIndicator(color: Colors.white)
+ // Tetap putih agar kontras dengan tombol primer
+ ? const CircularProgressIndicator(color: Colors.white)
: const Text(
'Simpan Password Baru',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
- color: Colors.white),
+ color: Colors.white), // Tetap putih
),
),
),
@@ -253,16 +267,20 @@ class _ChangePasswordScreenState extends State {
return TextField(
controller: controller,
obscureText: obscure,
- style: const TextStyle(color: Colors.white),
+ // --- BERUBAH: Warna Teks Inputan ---
+ style: const TextStyle(color: AppColors.textMain),
decoration: InputDecoration(
- prefixIcon: const Icon(Icons.lock, color: Colors.green),
+ // --- BERUBAH: Warna Ikon Kunci ---
+ prefixIcon: const Icon(Icons.lock, color: AppColors.primary),
suffixIcon: IconButton(
icon: Icon(obscure ? Icons.visibility : Icons.visibility_off,
- color: Colors.grey),
+ // --- BERUBAH: Warna Ikon Mata ---
+ color: AppColors.textSecondary),
onPressed: onToggle,
),
hintText: label,
- hintStyle: const TextStyle(color: Colors.grey),
+ // --- BERUBAH: Warna Placeholder/Hint ---
+ hintStyle: const TextStyle(color: AppColors.textSecondary),
border: InputBorder.none,
),
);
diff --git a/lib/screens/control_settings_screen.dart b/lib/screens/control_settings_screen.dart
index 5bdcf86..ac3ae6d 100644
--- a/lib/screens/control_settings_screen.dart
+++ b/lib/screens/control_settings_screen.dart
@@ -3,6 +3,7 @@ import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../services/mqtt_service.dart';
import '../services/supabase_service.dart';
+import '../constants/app_colors.dart'; // <-- IMPORT APP COLORS DITAMBAHKAN
class ControlSettingsScreen extends StatefulWidget {
const ControlSettingsScreen({super.key});
@@ -60,9 +61,10 @@ class _ControlSettingsScreenState extends State {
_humMinController.text.isEmpty ||
_humMaxController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
- const SnackBar(
- content: Text('Semua kolom batas harus diisi!'),
- backgroundColor: Colors.orange,
+ SnackBar(
+ content: const Text('Semua kolom batas harus diisi!'),
+ // --- BERUBAH: Warna Notifikasi Peringatan ---
+ backgroundColor: AppColors.warning,
),
);
return;
@@ -76,18 +78,20 @@ class _ControlSettingsScreenState extends State {
// Validasi logika
if (suhuMin >= suhuMax) {
ScaffoldMessenger.of(context).showSnackBar(
- const SnackBar(
- content: Text('Suhu min harus lebih kecil dari suhu max!'),
- backgroundColor: Colors.orange,
+ SnackBar(
+ content: const Text('Suhu min harus lebih kecil dari suhu max!'),
+ // --- BERUBAH: Warna Notifikasi Peringatan ---
+ backgroundColor: AppColors.warning,
),
);
return;
}
if (rhMin >= rhMax) {
ScaffoldMessenger.of(context).showSnackBar(
- const SnackBar(
- content: Text('RH min harus lebih kecil dari RH max!'),
- backgroundColor: Colors.orange,
+ SnackBar(
+ content: const Text('RH min harus lebih kecil dari RH max!'),
+ // --- BERUBAH: Warna Notifikasi Peringatan ---
+ backgroundColor: AppColors.warning,
),
);
return;
@@ -113,9 +117,10 @@ class _ControlSettingsScreenState extends State {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
- const SnackBar(
- content: Text('✅ Pengaturan Tersimpan & Terkirim ke ESP32'),
- backgroundColor: Colors.green,
+ SnackBar(
+ content: const Text('✅ Pengaturan Tersimpan & Terkirim ke ESP32'),
+ // --- BERUBAH: Warna Notifikasi Sukses ---
+ backgroundColor: AppColors.success,
),
);
}
@@ -124,7 +129,8 @@ class _ControlSettingsScreenState extends State {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('❌ Gagal: $e'),
- backgroundColor: Colors.red,
+ // --- BERUBAH: Warna Notifikasi Error ---
+ backgroundColor: AppColors.error,
),
);
}
@@ -136,11 +142,13 @@ class _ControlSettingsScreenState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
- backgroundColor: Colors.black,
+ // --- BERUBAH: Background Scaffold Utama ---
+ backgroundColor: AppColors.background,
body: SafeArea(
child: _isLoading
? const Center(
- child: CircularProgressIndicator(color: Colors.green))
+ // --- BERUBAH: Warna Loading Indicator ---
+ child: CircularProgressIndicator(color: AppColors.primary))
: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
@@ -150,13 +158,15 @@ class _ControlSettingsScreenState extends State {
const Text(
'Pengaturan',
style: TextStyle(
- color: Colors.white,
+ // --- BERUBAH: Warna Judul Utama ---
+ color: AppColors.textMain,
fontSize: 32,
fontWeight: FontWeight.bold),
),
const Text(
'Batas Sensor & Mode Operasi',
- style: TextStyle(color: Colors.grey, fontSize: 16),
+ // --- BERUBAH: Warna Sub-judul ---
+ style: TextStyle(color: AppColors.textSecondary, fontSize: 16),
),
const SizedBox(height: 30),
@@ -188,15 +198,19 @@ class _ControlSettingsScreenState extends State {
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
- color: const Color(0xFF1A1A1A),
+ // --- BERUBAH: Background Kartu Mode Operasi ---
+ color: AppColors.cardBg,
borderRadius: BorderRadius.circular(20),
+ // --- BERUBAH: Menambahkan border halus agar serasi ---
+ border: Border.all(color: AppColors.textSecondary.withValues(alpha: 0.15)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Mode Operasi',
style: TextStyle(
- color: Colors.white,
+ // --- BERUBAH: Warna Judul Kartu Mode ---
+ color: AppColors.textMain,
fontWeight: FontWeight.bold,
fontSize: 16)),
const SizedBox(height: 10),
@@ -206,12 +220,15 @@ class _ControlSettingsScreenState extends State {
onChanged: (val) =>
setState(() => _operatingMode = val!),
title: const Text('Mode Otomatis',
- style: TextStyle(color: Colors.white)),
- activeColor: Colors.green,
+ // --- BERUBAH: Warna Teks Radio Button ---
+ style: TextStyle(color: AppColors.textMain)),
+ // --- BERUBAH: Warna Lingkaran Radio Button (Aktif) ---
+ activeColor: AppColors.primary,
subtitle: const Text(
'Kipas bekerja otomatis berdasarkan sensor',
+ // --- BERUBAH: Warna Sub-teks Radio Button ---
style: TextStyle(
- color: Colors.grey, fontSize: 10),
+ color: AppColors.textSecondary, fontSize: 10),
),
),
RadioListTile(
@@ -220,12 +237,15 @@ class _ControlSettingsScreenState extends State {
onChanged: (val) =>
setState(() => _operatingMode = val!),
title: const Text('Mode Manual',
- style: TextStyle(color: Colors.white)),
- activeColor: Colors.green,
+ // --- BERUBAH: Warna Teks Radio Button ---
+ style: TextStyle(color: AppColors.textMain)),
+ // --- BERUBAH: Warna Lingkaran Radio Button (Aktif) ---
+ activeColor: AppColors.primary,
subtitle: const Text(
'Kontrol penuh kipas melalui dashboard HP',
+ // --- BERUBAH: Warna Sub-teks Radio Button ---
style: TextStyle(
- color: Colors.grey, fontSize: 10),
+ color: AppColors.textSecondary, fontSize: 10),
),
),
],
@@ -240,7 +260,8 @@ class _ControlSettingsScreenState extends State {
child: ElevatedButton(
onPressed: _saveSettings,
style: ElevatedButton.styleFrom(
- backgroundColor: Colors.green,
+ // --- BERUBAH: Warna Latar Tombol Simpan ---
+ backgroundColor: AppColors.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
@@ -250,7 +271,8 @@ class _ControlSettingsScreenState extends State {
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
- color: Colors.white),
+ // Tetap putih agar tulisan dalam tombol kontras
+ color: Colors.white),
),
),
),
@@ -268,31 +290,44 @@ class _ControlSettingsScreenState extends State {
return Container(
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(
- color: const Color(0xFF1A1A1A),
+ // --- BERUBAH: Latar Belakang Kartu Input Sensor ---
+ color: AppColors.cardBg,
borderRadius: BorderRadius.circular(20),
+ // --- BERUBAH: Menambahkan border halus agar serasi ---
+ border: Border.all(color: AppColors.textSecondary.withValues(alpha: 0.15)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title,
style: const TextStyle(
- color: Colors.white,
+ // --- BERUBAH: Warna Judul Input Sensor ---
+ color: AppColors.textMain,
fontSize: 12,
fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
TextField(
controller: controller,
keyboardType: TextInputType.number,
- style: const TextStyle(color: Colors.white),
+ // --- BERUBAH: Warna Angka/Nilai Input Sensor ---
+ style: const TextStyle(color: AppColors.textMain),
decoration: InputDecoration(
hintText: hint,
- hintStyle: const TextStyle(color: Colors.grey),
+ // --- BERUBAH: Warna Teks Placeholder/Hint ---
+ hintStyle: const TextStyle(color: AppColors.textSecondary),
filled: true,
- fillColor: Colors.black,
+ // --- BERUBAH: Warna Kolom Input Sensor ---
+ fillColor: AppColors.background,
isDense: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
- borderSide: const BorderSide(color: Colors.grey),
+ // --- BERUBAH: Warna Garis Pinggir Input Sensor ---
+ borderSide: BorderSide(color: AppColors.textSecondary.withValues(alpha: 0.3)),
+ ),
+ // Menambahkan fokus border agar saat diklik terlihat jelas warnanya
+ focusedBorder: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(15),
+ borderSide: const BorderSide(color: AppColors.primary),
),
),
),
diff --git a/lib/screens/forgot_password_screen.dart b/lib/screens/forgot_password_screen.dart
index 68f9b7c..7f077c4 100644
--- a/lib/screens/forgot_password_screen.dart
+++ b/lib/screens/forgot_password_screen.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import '../services/supabase_service.dart';
+import '../constants/app_colors.dart'; // <-- IMPORT APP COLORS DITAMBAHKAN
class ForgotPasswordScreen extends StatefulWidget {
const ForgotPasswordScreen({super.key});
@@ -104,7 +105,7 @@ class _ForgotPasswordScreenState extends State {
content: Row(children: [
Icon(
isError ? Icons.error_outline : Icons.check_circle_outline,
- color: Colors.white,
+ color: Colors.white, // Tetap putih untuk kontras
),
const SizedBox(width: 10),
Expanded(
@@ -113,8 +114,9 @@ class _ForgotPasswordScreenState extends State {
color: Colors.white, fontWeight: FontWeight.bold)),
),
]),
+ // --- BERUBAH: Menggunakan warna notifikasi dari AppColors ---
backgroundColor:
- isError ? Colors.red.shade700 : Colors.green.shade700,
+ isError ? AppColors.error : AppColors.success,
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
margin: const EdgeInsets.all(16),
@@ -126,12 +128,14 @@ class _ForgotPasswordScreenState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
- backgroundColor: Colors.black,
+ // --- BERUBAH: Background Utama ---
+ backgroundColor: AppColors.background,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
- icon: const Icon(Icons.arrow_back, color: Colors.green),
+ // --- BERUBAH: Warna Ikon Back ---
+ icon: const Icon(Icons.arrow_back, color: AppColors.primary),
onPressed: () => Navigator.pop(context),
),
),
@@ -152,12 +156,14 @@ class _ForgotPasswordScreenState extends State {
const Text(
'Lupa Password?',
style: TextStyle(
- color: Colors.green, fontSize: 32, fontWeight: FontWeight.bold),
+ // --- BERUBAH: Warna Judul ---
+ color: AppColors.primary, fontSize: 32, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text(
'Masukkan email akun kamu. Kami akan kirim kode verifikasi 6 angka ke inbox kamu.',
- style: TextStyle(color: Colors.grey, fontSize: 14),
+ // --- BERUBAH: Warna Sub-judul ---
+ style: TextStyle(color: AppColors.textSecondary, fontSize: 14),
),
const SizedBox(height: 50),
@@ -165,18 +171,23 @@ class _ForgotPasswordScreenState extends State {
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
- color: const Color(0xFF1A1A1A),
+ // --- BERUBAH: Latar Belakang Form ---
+ color: AppColors.cardBg,
borderRadius: BorderRadius.circular(25),
- border: Border.all(color: Colors.grey.withOpacity(0.3)),
+ // --- BERUBAH: Garis Pinggir Form ---
+ border: Border.all(color: AppColors.textSecondary.withValues(alpha: 0.3)),
),
child: TextField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
- style: const TextStyle(color: Colors.white),
+ // --- BERUBAH: Warna Teks Inputan ---
+ style: const TextStyle(color: AppColors.textMain),
decoration: const InputDecoration(
- prefixIcon: Icon(Icons.email, color: Colors.green),
+ // --- BERUBAH: Warna Ikon ---
+ prefixIcon: Icon(Icons.email, color: AppColors.primary),
hintText: 'Email',
- hintStyle: TextStyle(color: Colors.grey),
+ // --- BERUBAH: Warna Placeholder/Hint ---
+ hintStyle: TextStyle(color: AppColors.textSecondary),
border: InputBorder.none,
),
),
@@ -190,8 +201,10 @@ class _ForgotPasswordScreenState extends State {
child: ElevatedButton(
onPressed: _isLoading ? null : _handleKirimOTP,
style: ElevatedButton.styleFrom(
- backgroundColor: Colors.green,
- disabledBackgroundColor: Colors.green.withOpacity(0.3),
+ // --- BERUBAH: Warna Tombol ---
+ backgroundColor: AppColors.primary,
+ // --- BERUBAH: Warna Tombol saat Loading ---
+ disabledBackgroundColor: AppColors.primary.withValues(alpha: 0.3),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)),
),
@@ -211,7 +224,8 @@ class _ForgotPasswordScreenState extends State {
child: TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Kembali ke Login',
- style: TextStyle(color: Colors.green)),
+ // --- BERUBAH: Warna Teks Bawah ---
+ style: TextStyle(color: AppColors.primary)),
),
),
],
@@ -225,19 +239,23 @@ class _ForgotPasswordScreenState extends State {
children: [
const CircleAvatar(
radius: 40,
- backgroundColor: Color(0xFF1A1A1A),
- child: Icon(Icons.mark_email_read, size: 40, color: Colors.green),
+ // --- BERUBAH: Latar Belakang Ikon ---
+ backgroundColor: AppColors.cardBg,
+ // --- BERUBAH: Warna Ikon ---
+ child: Icon(Icons.mark_email_read, size: 40, color: AppColors.primary),
),
const SizedBox(height: 24),
const Text(
'Cek Email Kamu',
style: TextStyle(
- color: Colors.green, fontSize: 28, fontWeight: FontWeight.bold),
+ // --- BERUBAH: Warna Judul ---
+ color: AppColors.primary, fontSize: 28, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(
'Kode verifikasi 6 angka sudah dikirim ke:\n$_email\n\nMasukkan kode tersebut di bawah ini.',
- style: const TextStyle(color: Colors.grey, fontSize: 14),
+ // --- BERUBAH: Warna Subteks ---
+ style: const TextStyle(color: AppColors.textSecondary, fontSize: 14),
),
const SizedBox(height: 40),
@@ -245,9 +263,11 @@ class _ForgotPasswordScreenState extends State {
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
- color: const Color(0xFF1A1A1A),
+ // --- BERUBAH: Latar Belakang Kotak OTP ---
+ color: AppColors.cardBg,
borderRadius: BorderRadius.circular(25),
- border: Border.all(color: Colors.green.withOpacity(0.5)),
+ // --- BERUBAH: Garis Pinggir Kotak OTP ---
+ border: Border.all(color: AppColors.primary.withValues(alpha: 0.5)),
),
child: TextField(
controller: _otpController,
@@ -255,11 +275,14 @@ class _ForgotPasswordScreenState extends State {
maxLength: 6,
textAlign: TextAlign.center,
style: const TextStyle(
- color: Colors.white, fontSize: 28, letterSpacing: 12),
+ // --- BERUBAH: Warna Teks Inputan ---
+ color: AppColors.textMain, fontSize: 28, letterSpacing: 12),
decoration: const InputDecoration(
- prefixIcon: Icon(Icons.lock_open, color: Colors.green),
+ // --- BERUBAH: Warna Ikon ---
+ prefixIcon: Icon(Icons.lock_open, color: AppColors.primary),
hintText: '000000',
- hintStyle: TextStyle(color: Colors.grey, letterSpacing: 8),
+ // --- BERUBAH: Warna Placeholder/Hint ---
+ hintStyle: TextStyle(color: AppColors.textSecondary, letterSpacing: 8),
border: InputBorder.none,
counterText: '', // sembunyikan counter maxLength
),
@@ -274,8 +297,10 @@ class _ForgotPasswordScreenState extends State {
child: ElevatedButton(
onPressed: _isLoading ? null : _handleVerifikasiOTP,
style: ElevatedButton.styleFrom(
- backgroundColor: Colors.green,
- disabledBackgroundColor: Colors.green.withOpacity(0.3),
+ // --- BERUBAH: Warna Tombol ---
+ backgroundColor: AppColors.primary,
+ // --- BERUBAH: Warna Tombol saat Loading ---
+ disabledBackgroundColor: AppColors.primary.withValues(alpha: 0.3),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)),
),
@@ -303,7 +328,8 @@ class _ForgotPasswordScreenState extends State {
}),
child: const Text(
'Kirim ulang kode',
- style: TextStyle(color: Colors.green),
+ // --- BERUBAH: Warna Teks Bawah ---
+ style: TextStyle(color: AppColors.primary),
),
),
),
diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart
index 5af2375..e70b1e2 100644
--- a/lib/screens/home_screen.dart
+++ b/lib/screens/home_screen.dart
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../services/mqtt_service.dart';
+import '../constants/app_colors.dart'; // <-- IMPORT APP COLORS DITAMBAHKAN
import 'monitoring_screen.dart';
import 'control_settings_screen.dart';
import 'recording_screen.dart';
@@ -26,8 +27,15 @@ class _HomeScreenState extends State {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
- content: Text(message),
- backgroundColor: isSuccess ? Colors.green.withOpacity(0.8) : Colors.redAccent,
+ content: Text(
+ message,
+ // Opsional: Teks putih agar selalu kontras dengan warna notifikasi
+ style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold)
+ ),
+ // --- BERUBAH: Warna Notifikasi Berhasil / Gagal ---
+ backgroundColor: isSuccess
+ ? AppColors.success.withValues(alpha: 0.9)
+ : AppColors.error,
duration: const Duration(seconds: 3),
),
);
@@ -51,11 +59,15 @@ class _HomeScreenState extends State {
currentIndex: _currentIndex,
onTap: (index) => setState(() => _currentIndex = index),
type: BottomNavigationBarType.fixed,
- backgroundColor: Colors.black,
- selectedItemColor: Colors.green,
- unselectedItemColor: Colors.grey,
+ // --- BERUBAH: Latar Belakang Menu Navigasi Bawah ---
+ backgroundColor: AppColors.cardBg,
+ // --- BERUBAH: Warna Ikon yang Sedang Dipilih ---
+ selectedItemColor: AppColors.primary,
+ // --- BERUBAH: Warna Ikon yang Tidak Dipilih ---
+ unselectedItemColor: AppColors.textSecondary,
showSelectedLabels: false,
showUnselectedLabels: false,
+ elevation: 10, // Menambahkan sedikit bayangan agar terpisah dari body
items: const [
BottomNavigationBarItem(icon: Icon(Icons.grid_view), label: 'Monitoring'),
BottomNavigationBarItem(icon: Icon(Icons.tune), label: 'Control'),
@@ -65,4 +77,4 @@ class _HomeScreenState extends State {
),
);
}
-}
+}
\ No newline at end of file
diff --git a/lib/screens/image_result_screen.dart b/lib/screens/image_result_screen.dart
index b98a84c..aede919 100644
--- a/lib/screens/image_result_screen.dart
+++ b/lib/screens/image_result_screen.dart
@@ -4,6 +4,7 @@ import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
import 'package:http/http.dart' as http;
+import '../constants/app_colors.dart';
class ImageResultScreen extends StatelessWidget {
const ImageResultScreen({super.key});
@@ -14,19 +15,17 @@ class ImageResultScreen extends StatelessWidget {
Future _exportPDF(
BuildContext context, Map args) async {
- // Tampilkan loading
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => const Center(
- child: CircularProgressIndicator(color: Colors.green),
+ child: CircularProgressIndicator(color: AppColors.primary),
),
);
try {
final pdf = pw.Document();
- // Download foto dari URL untuk dimasukkan ke PDF
pw.MemoryImage? fotoImage;
final urlFoto = args['url_foto']?.toString() ?? '';
if (urlFoto.isNotEmpty) {
@@ -40,7 +39,6 @@ class ImageResultScreen extends StatelessWidget {
}
}
- // Buat halaman PDF
pdf.addPage(
pw.Page(
pageFormat: PdfPageFormat.a4,
@@ -49,7 +47,6 @@ class ImageResultScreen extends StatelessWidget {
return pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
- // ── Header ──
pw.Container(
width: double.infinity,
padding: const pw.EdgeInsets.all(16),
@@ -82,7 +79,6 @@ class ImageResultScreen extends StatelessWidget {
pw.SizedBox(height: 20),
- // ── Info Waktu ──
pw.Text(
'Tanggal & Waktu: ${args['date']} - ${args['time']}',
style: pw.TextStyle(
@@ -95,7 +91,6 @@ class ImageResultScreen extends StatelessWidget {
pw.Divider(),
pw.SizedBox(height: 16),
- // ── Foto ──
if (fotoImage != null) ...[
pw.Center(
child: pw.Container(
@@ -122,7 +117,6 @@ class ImageResultScreen extends StatelessWidget {
pw.SizedBox(height: 16),
],
- // ── Data Sensor ──
pw.Text(
'Data Sensor',
style: pw.TextStyle(
@@ -151,7 +145,6 @@ class ImageResultScreen extends StatelessWidget {
pw.Divider(),
pw.SizedBox(height: 8),
- // ── Footer ──
pw.Text(
'Diekspor dari Aplikasi Monitoring Kopi',
style: const pw.TextStyle(
@@ -165,10 +158,8 @@ class ImageResultScreen extends StatelessWidget {
),
);
- // Tutup loading
if (context.mounted) Navigator.pop(context);
- // Tampilkan preview PDF + opsi simpan/share
await Printing.layoutPdf(
onLayout: (PdfPageFormat format) async => pdf.save(),
name:
@@ -176,11 +167,11 @@ class ImageResultScreen extends StatelessWidget {
);
} catch (e) {
if (context.mounted) {
- Navigator.pop(context); // tutup loading
+ Navigator.pop(context);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Gagal membuat PDF: $e'),
- backgroundColor: Colors.red.shade700,
+ backgroundColor: AppColors.error,
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
@@ -231,18 +222,18 @@ class ImageResultScreen extends StatelessWidget {
};
return Scaffold(
- backgroundColor: Colors.black,
+ backgroundColor: AppColors.background,
appBar: AppBar(
- backgroundColor: Colors.black,
+ backgroundColor: Colors.transparent,
+ elevation: 0,
title: const Text(
'Detail Data Citra',
- style: TextStyle(color: Colors.white),
+ style: TextStyle(color: AppColors.textMain),
),
leading: IconButton(
- icon: const Icon(Icons.arrow_back, color: Colors.grey),
+ icon: const Icon(Icons.arrow_back, color: AppColors.primary),
onPressed: () => Navigator.pop(context),
),
- // Icon download dihapus
),
body: Padding(
padding: const EdgeInsets.all(20.0),
@@ -253,8 +244,9 @@ class ImageResultScreen extends StatelessWidget {
height: 250,
width: double.infinity,
decoration: BoxDecoration(
- color: const Color(0xFF1A1A1A),
+ color: AppColors.cardBg,
borderRadius: BorderRadius.circular(20),
+ border: Border.all(color: AppColors.textSecondary.withValues(alpha: 0.15)),
),
clipBehavior: Clip.hardEdge,
child: args['url_foto'] != null &&
@@ -265,26 +257,26 @@ class ImageResultScreen extends StatelessWidget {
loadingBuilder: (context, child, progress) {
if (progress == null) return child;
return const Center(
- child:
- CircularProgressIndicator(color: Colors.green),
+ child: CircularProgressIndicator(color: AppColors.primary),
);
},
errorBuilder: (context, error, stack) => Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.broken_image,
- size: 80, color: Colors.grey),
+ size: 80, color: AppColors.textSecondary),
Text('Citra #${args['id']}',
- style: const TextStyle(color: Colors.grey)),
+ style: const TextStyle(color: AppColors.textSecondary)),
],
),
)
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
- const Icon(Icons.image, size: 80, color: Colors.grey),
+ const Icon(Icons.image,
+ size: 80, color: AppColors.textSecondary),
Text('Citra #${args['id']}',
- style: const TextStyle(color: Colors.grey)),
+ style: const TextStyle(color: AppColors.textSecondary)),
],
),
),
@@ -294,41 +286,43 @@ class ImageResultScreen extends StatelessWidget {
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
- color: const Color(0xFF1A1A1A),
+ color: AppColors.cardBg,
borderRadius: BorderRadius.circular(20),
+ border: Border.all(color: AppColors.textSecondary.withValues(alpha: 0.15)),
),
child: Column(
children: [
- // Tanggal & waktu
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.calendar_today,
- color: Colors.green, size: 16),
+ color: AppColors.primary, size: 16),
const SizedBox(width: 8),
Text(
'${args['date']} - ${args['time']}',
style: const TextStyle(
- color: Colors.green,
+ color: AppColors.primary,
fontWeight: FontWeight.bold,
fontSize: 16),
),
],
),
- // Lokasi dihapus
- const Divider(color: Colors.grey, height: 30),
+ Divider(color: AppColors.textSecondary.withValues(alpha: 0.3), height: 30),
_buildDataRow(
'Suhu', args['temp'], 'Kelembaban', args['humidity']),
const SizedBox(height: 15),
+
+ // --- BERUBAH: Mengirimkan string kosong ('') untuk menghapus kolom Mode ---
_buildDataRow(
- 'Cahaya', args['light'], 'Mode', 'Terjadwal'),
- const Divider(color: Colors.grey, height: 30),
+ 'Cahaya', args['light'], '', ''),
+
+ Divider(color: AppColors.textSecondary.withValues(alpha: 0.3), height: 30),
_buildDataRow(
'Kipas 1 (Intake)', args['intake'],
'Kipas 2 (Exhaust)', args['exhaust'],
- valueColor: Colors.green,
+ valueColor: AppColors.primary,
),
],
),
@@ -342,7 +336,7 @@ class ImageResultScreen extends StatelessWidget {
child: ElevatedButton.icon(
onPressed: () => _exportPDF(context, args),
style: ElevatedButton.styleFrom(
- backgroundColor: Colors.green,
+ backgroundColor: AppColors.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
@@ -361,12 +355,13 @@ class ImageResultScreen extends StatelessWidget {
);
}
+ // --- BERUBAH: Menambahkan logika untuk menyembunyikan kolom kanan jika string kosong ---
Widget _buildDataRow(
String label1,
String value1,
String label2,
String value2, {
- Color valueColor = Colors.white,
+ Color? valueColor,
}) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -376,30 +371,32 @@ class ImageResultScreen extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label1,
- style: const TextStyle(color: Colors.grey, fontSize: 12)),
+ style: const TextStyle(color: AppColors.textSecondary, fontSize: 12)),
const SizedBox(height: 4),
Text(': $value1',
style: TextStyle(
- color: valueColor,
+ color: valueColor ?? AppColors.textMain,
fontWeight: FontWeight.bold,
fontSize: 15)),
],
),
),
Expanded(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(label2,
- style: const TextStyle(color: Colors.grey, fontSize: 12)),
- const SizedBox(height: 4),
- Text(': $value2',
- style: TextStyle(
- color: valueColor,
- fontWeight: FontWeight.bold,
- fontSize: 15)),
- ],
- ),
+ child: label2.isEmpty
+ ? const SizedBox.shrink() // Jika kosong, sembunyikan sepenuhnya
+ : Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(label2,
+ style: const TextStyle(color: AppColors.textSecondary, fontSize: 12)),
+ const SizedBox(height: 4),
+ Text(': $value2',
+ style: TextStyle(
+ color: valueColor ?? AppColors.textMain,
+ fontWeight: FontWeight.bold,
+ fontSize: 15)),
+ ],
+ ),
),
],
);
diff --git a/lib/screens/login_screen.dart b/lib/screens/login_screen.dart
index 94ed567..386fbdd 100644
--- a/lib/screens/login_screen.dart
+++ b/lib/screens/login_screen.dart
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import '../services/supabase_service.dart';
+import '../constants/app_colors.dart'; // <-- IMPORT APP COLORS DITAMBAHKAN
class LoginScreen extends StatefulWidget {
const LoginScreen({super.key});
@@ -64,20 +65,21 @@ class _LoginScreenState extends State {
SnackBar(
content: Row(
children: [
- const Icon(Icons.error_outline, color: Colors.white),
+ const Icon(Icons.error_outline, color: Colors.white), // Tetap putih agar kontras di atas merah
const SizedBox(width: 10),
Expanded(
child: Text(
pesan,
style: const TextStyle(
- color: Colors.white,
+ color: Colors.white, // Tetap putih
fontWeight: FontWeight.bold,
),
),
),
],
),
- backgroundColor: Colors.red.shade700,
+ // --- BERUBAH: Background SnackBar Error ---
+ backgroundColor: AppColors.error,
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
@@ -91,70 +93,93 @@ class _LoginScreenState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
- backgroundColor: Colors.black,
+ // --- BERUBAH: Background Scaffold Utama ---
+ backgroundColor: AppColors.background,
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 80.0),
child: Column(
children: [
- const CircleAvatar(
+ CircleAvatar(
radius: 60,
- backgroundColor: Color(0xFF1A1A1A),
- child: Icon(Icons.coffee, size: 60, color: Colors.orange),
+ // --- BERUBAH: Latar belakang logo ---
+ backgroundColor: AppColors.primary,
+ child: ClipOval(
+ child: Padding(
+ padding: const EdgeInsets.all(8),
+ child: Image.asset(
+ 'assets/icon/kopibaru_removebg.png',
+ width: 120,
+ height: 120,
+ fit: BoxFit.contain,
+ ),
+ ),
+ ),
),
const SizedBox(height: 30),
const Text(
'Selamat Datang',
style: TextStyle(
- color: Colors.green,
+ // --- BERUBAH: Warna Judul ---
+ color: AppColors.primary,
fontSize: 32,
fontWeight: FontWeight.bold),
),
const Text(
'Sistem Kendali Pengering Kopi',
- style: TextStyle(color: Colors.grey, fontSize: 16),
+ // --- BERUBAH: Warna Sub-judul ---
+ style: TextStyle(color: AppColors.textSecondary, fontSize: 16),
),
const SizedBox(height: 50),
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
- color: const Color(0xFF1A1A1A),
+ // --- BERUBAH: Warna Kotak Form ---
+ color: AppColors.cardBg,
borderRadius: BorderRadius.circular(25),
- border: Border.all(color: Colors.grey.withOpacity(0.3)),
+ // --- BERUBAH: Warna Garis Pinggir Form ---
+ border: Border.all(color: AppColors.textSecondary.withValues(alpha: 0.3)),
),
child: Column(
children: [
TextField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
- style: const TextStyle(color: Colors.white),
+ // --- BERUBAH: Warna Teks Inputan ---
+ style: const TextStyle(color: AppColors.textMain),
decoration: const InputDecoration(
- prefixIcon: Icon(Icons.email, color: Colors.green),
+ // --- BERUBAH: Warna Ikon ---
+ prefixIcon: Icon(Icons.email, color: AppColors.primary),
hintText: 'Email',
- hintStyle: TextStyle(color: Colors.grey),
+ // --- BERUBAH: Warna Placeholder/Hint ---
+ hintStyle: TextStyle(color: AppColors.textSecondary),
border: InputBorder.none,
),
),
- const Divider(color: Colors.grey),
+ // --- BERUBAH: Garis Pemisah (Divider) ---
+ Divider(color: AppColors.textSecondary.withValues(alpha: 0.3)),
TextField(
controller: _passwordController,
obscureText: _obscurePassword,
- style: const TextStyle(color: Colors.white),
+ // --- BERUBAH: Warna Teks Inputan ---
+ style: const TextStyle(color: AppColors.textMain),
decoration: InputDecoration(
- prefixIcon:
- const Icon(Icons.lock, color: Colors.green),
+ // --- BERUBAH: Warna Ikon ---
+ prefixIcon: const Icon(Icons.lock, color: AppColors.primary),
suffixIcon: IconButton(
icon: Icon(
_obscurePassword
? Icons.visibility
: Icons.visibility_off,
- color: Colors.grey,
+ // --- BERUBAH: Warna Ikon Mata ---
+ color: AppColors.textSecondary,
),
onPressed: () => setState(
() => _obscurePassword = !_obscurePassword),
),
hintText: 'Password',
- hintStyle: const TextStyle(color: Colors.grey),
+ // --- BERUBAH: Warna Placeholder/Hint ---
+ hintStyle: const TextStyle(color: AppColors.textSecondary),
border: InputBorder.none,
),
),
@@ -165,42 +190,64 @@ class _LoginScreenState extends State {
child: ElevatedButton(
onPressed: _isLoading ? null : _handleLogin,
style: ElevatedButton.styleFrom(
- backgroundColor: Colors.green,
+ // --- BERUBAH: Latar Belakang Tombol ---
+ backgroundColor: AppColors.primary,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
child: _isLoading
? const CircularProgressIndicator(
- color: Colors.white)
+ color: Colors.white) // Tetap putih untuk kontras
: const Text(
'Masuk ke Akun',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
- color: Colors.white),
+ color: Colors.white), // Tetap putih
),
),
),
],
),
),
-
- // Lupa Password dan Daftar — rapat tanpa jarak besar, warna sama hijau
- const SizedBox(height: 10),
+ const SizedBox(height: 16),
+
+ // ── 1. TOMBOL LUPA PASSWORD ──
TextButton(
- onPressed: () =>
- Navigator.pushNamed(context, '/forgot_password'),
+ onPressed: () => Navigator.pushNamed(context, '/forgot_password'),
+ style: TextButton.styleFrom(
+ padding: EdgeInsets.zero,
+ minimumSize: Size.zero,
+ tapTargetSize: MaterialTapTargetSize.shrinkWrap,
+ ),
child: const Text(
'Lupa Password?',
- style: TextStyle(color: Colors.green),
+ style: TextStyle(
+ // --- BERUBAH: Warna Teks ---
+ color: AppColors.primary,
+ fontSize: 14,
+ ),
),
),
+
+ const SizedBox(height: 12),
+
+ // ── 2. TOMBOL DAFTAR AKUN ──
TextButton(
onPressed: () => Navigator.pushNamed(context, '/register'),
+ style: TextButton.styleFrom(
+ padding: EdgeInsets.zero,
+ minimumSize: Size.zero,
+ tapTargetSize: MaterialTapTargetSize.shrinkWrap,
+ ),
child: const Text(
'Belum punya akun? Daftar Sekarang',
- style: TextStyle(color: Colors.green),
+ style: TextStyle(
+ // --- BERUBAH: Warna Teks ---
+ color: AppColors.primary,
+ fontSize: 14,
+ ),
),
),
],
diff --git a/lib/screens/monitoring_screen.dart b/lib/screens/monitoring_screen.dart
index 87c350a..5174b7d 100644
--- a/lib/screens/monitoring_screen.dart
+++ b/lib/screens/monitoring_screen.dart
@@ -3,6 +3,7 @@ import 'package:provider/provider.dart';
import 'package:mqtt_client/mqtt_client.dart';
import '../services/mqtt_service.dart';
import '../services/supabase_service.dart';
+import '../constants/app_colors.dart'; // <-- IMPORT APP COLORS DITAMBAHKAN
class MonitoringScreen extends StatefulWidget {
final VoidCallback? onProfileTap;
@@ -60,19 +61,21 @@ class _MonitoringScreenState extends State {
});
return Scaffold(
- backgroundColor: Colors.black,
+ // --- BERUBAH: Background Utama ---
+ backgroundColor: AppColors.background,
body: SafeArea(
child: _isInitialLoading
- ? const Center(child: CircularProgressIndicator(color: Colors.green))
+ // --- BERUBAH: Warna Loading Indicator ---
+ ? const Center(child: CircularProgressIndicator(color: AppColors.primary))
: RefreshIndicator(
onRefresh: _initData,
- color: Colors.green,
+ // --- BERUBAH: Warna Refresh Indicator ---
+ color: AppColors.primary,
child: LayoutBuilder(
builder: (context, constraints) {
- // Tinggi tersedia = tinggi layar dikurangi header
- const headerHeight = 175.0; // header + timestamp + mode badge + padding
- const gaps = 15.0 * 2; // 2 gap antar 3 baris
- const padding = 20.0 * 2; // padding atas bawah
+ const headerHeight = 175.0;
+ const gaps = 15.0 * 2;
+ const padding = 20.0 * 2;
final available = constraints.maxHeight - headerHeight - gaps - padding;
final cardH = (available / 3).clamp(100.0, 180.0);
@@ -94,11 +97,13 @@ class _MonitoringScreenState extends State {
children: [
const Text('Monitoring',
style: TextStyle(
- color: Colors.white,
+ // --- BERUBAH: Warna Judul ---
+ color: AppColors.textMain,
fontSize: 32,
fontWeight: FontWeight.bold)),
const Text('Sistem Pengeringan Kopi',
- style: TextStyle(color: Colors.grey, fontSize: 16)),
+ // --- BERUBAH: Warna Sub-judul ---
+ style: TextStyle(color: AppColors.textSecondary, fontSize: 16)),
const SizedBox(height: 5),
Row(
children: [
@@ -106,10 +111,11 @@ class _MonitoringScreenState extends State {
width: 8, height: 8,
decoration: BoxDecoration(
shape: BoxShape.circle,
+ // --- BERUBAH: Indikator Titik Koneksi ---
color: mqtt.client?.connectionStatus?.state ==
MqttConnectionState.connected
- ? Colors.green
- : Colors.red,
+ ? AppColors.success
+ : AppColors.error,
),
),
const SizedBox(width: 8),
@@ -119,11 +125,13 @@ class _MonitoringScreenState extends State {
? 'Connected'
: 'Disconnected',
style: TextStyle(
+ // --- BERUBAH: Warna Teks Koneksi ---
color: mqtt.client?.connectionStatus?.state ==
MqttConnectionState.connected
- ? Colors.green
- : Colors.red,
+ ? AppColors.success
+ : AppColors.error,
fontSize: 12,
+ fontWeight: FontWeight.bold,
),
),
],
@@ -133,9 +141,11 @@ class _MonitoringScreenState extends State {
GestureDetector(
onTap: widget.onProfileTap,
child: const CircleAvatar(
- backgroundColor: Color(0xFF1A1A1A),
+ // --- BERUBAH: Latar Belakang Avatar Profil ---
+ backgroundColor: AppColors.cardBg,
radius: 25,
- child: Icon(Icons.person, color: Colors.green),
+ // --- BERUBAH: Warna Ikon Avatar ---
+ child: Icon(Icons.person, color: AppColors.primary),
),
),
],
@@ -144,25 +154,29 @@ class _MonitoringScreenState extends State {
// ── Timestamp ──
Text('Update: ${mqtt.timestamp}',
- style: const TextStyle(color: Colors.grey, fontSize: 11)),
+ // --- BERUBAH: Warna Teks Timestamp ---
+ style: const TextStyle(color: AppColors.textSecondary, fontSize: 11)),
const SizedBox(height: 10),
// ── Mode Badge ──
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
+ // --- BERUBAH: Latar Belakang Transparan Badge ---
color: mqtt.mode == 'manual'
- ? Colors.orange.withOpacity(0.2)
- : Colors.green.withOpacity(0.2),
+ ? AppColors.warning.withValues(alpha: 0.2)
+ : AppColors.success.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(20),
border: Border.all(
- color: mqtt.mode == 'manual' ? Colors.orange : Colors.green,
+ // --- BERUBAH: Warna Garis Pinggir Badge ---
+ color: mqtt.mode == 'manual' ? AppColors.warning : AppColors.success,
),
),
child: Text(
'Mode: ${mqtt.mode.toUpperCase()}',
style: TextStyle(
- color: mqtt.mode == 'manual' ? Colors.orange : Colors.green,
+ // --- BERUBAH: Warna Teks Badge ---
+ color: mqtt.mode == 'manual' ? AppColors.warning : AppColors.success,
fontSize: 12,
fontWeight: FontWeight.bold,
),
@@ -183,11 +197,12 @@ class _MonitoringScreenState extends State {
suffix: '°C',
dec: 1,
icon: Icons.thermostat,
- color: curSuhu > mqtt.maxSuhu ? Colors.red : Colors.redAccent,
+ // --- BERUBAH: Warna Tema Kartu Suhu ---
+ color: curSuhu > mqtt.maxSuhu ? AppColors.error : AppColors.warning,
isAlert: curSuhu > mqtt.maxSuhu,
isLow: curSuhu < mqtt.minSuhu,
onTap: () => Navigator.pushNamed(context, '/analytics',
- arguments: {'title': 'Grafik Suhu (°C)', 'color': Colors.redAccent, 'value': '${mqtt.suhu}°C'}),
+ arguments: {'title': 'Grafik Suhu (°C)', 'color': AppColors.error, 'value': '${mqtt.suhu}°C'}),
),
),
const SizedBox(width: 15),
@@ -199,11 +214,12 @@ class _MonitoringScreenState extends State {
suffix: '%',
dec: 1,
icon: Icons.water_drop,
- color: curHum > mqtt.maxRh ? Colors.red : Colors.cyan,
+ // --- BERUBAH: Warna Tema Kartu Kelembaban ---
+ color: curHum > mqtt.maxRh ? AppColors.error : AppColors.info,
isAlert: curHum > mqtt.maxRh,
isLow: curHum < mqtt.minRh,
onTap: () => Navigator.pushNamed(context, '/analytics',
- arguments: {'title': 'Grafik Kelembaban (%)', 'color': Colors.cyan, 'value': '${mqtt.kelembapan}%'}),
+ arguments: {'title': 'Grafik Kelembaban (%)', 'color': AppColors.info, 'value': '${mqtt.kelembapan}%'}),
),
),
],
@@ -222,9 +238,10 @@ class _MonitoringScreenState extends State {
suffix: ' Lux',
dec: 1,
icon: Icons.wb_sunny,
- color: Colors.orange,
+ // --- BERUBAH: Warna Tema Kartu Cahaya ---
+ color: AppColors.warning,
onTap: () => Navigator.pushNamed(context, '/analytics',
- arguments: {'title': 'Grafik Cahaya (Lux)', 'color': Colors.orange, 'value': '${mqtt.intensitas} Lux'}),
+ arguments: {'title': 'Grafik Cahaya (Lux)', 'color': AppColors.light, 'value': '${mqtt.intensitas} Lux'}),
),
),
const SizedBox(height: 15),
@@ -261,19 +278,23 @@ class _MonitoringScreenState extends State {
margin: const EdgeInsets.only(top: 15),
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(
- color: Colors.red.withOpacity(0.2),
+ // --- BERUBAH: Background Peringatan ---
+ color: AppColors.error.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(15),
- border: Border.all(color: Colors.red),
+ // --- BERUBAH: Garis Pinggir Peringatan ---
+ border: Border.all(color: AppColors.error),
),
child: const Row(
children: [
- Icon(Icons.warning_amber_rounded, color: Colors.red),
+ // --- BERUBAH: Ikon Peringatan ---
+ Icon(Icons.warning_amber_rounded, color: AppColors.error),
SizedBox(width: 10),
Expanded(
child: Text(
'Peringatan: Parameter pengeringan melewati batas aman!',
style: TextStyle(
- color: Colors.red,
+ // --- BERUBAH: Teks Peringatan ---
+ color: AppColors.error,
fontWeight: FontWeight.bold,
fontSize: 12),
),
@@ -286,19 +307,23 @@ class _MonitoringScreenState extends State {
margin: const EdgeInsets.only(top: 15),
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(
- color: Colors.blue.withOpacity(0.2),
+ // --- BERUBAH: Background Info/Low ---
+ color: AppColors.info.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(15),
- border: Border.all(color: Colors.blue),
+ // --- BERUBAH: Garis Pinggir Info/Low ---
+ border: Border.all(color: AppColors.info),
),
child: const Row(
children: [
- Icon(Icons.info_outline, color: Colors.blue),
+ // --- BERUBAH: Ikon Info/Low ---
+ Icon(Icons.info_outline, color: AppColors.info),
SizedBox(width: 10),
Expanded(
child: Text(
'Info: Parameter pengeringan di bawah batas minimum!',
style: TextStyle(
- color: Colors.blue,
+ // --- BERUBAH: Teks Info/Low ---
+ color: AppColors.info,
fontWeight: FontWeight.bold,
fontSize: 12),
),
@@ -337,16 +362,23 @@ class _MonitoringScreenState extends State {
height: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
- color: isAlert ? Colors.red.withOpacity(0.1) : isLow ? Colors.blue.withOpacity(0.1) : const Color(0xFF1A1A1A),
+ // --- BERUBAH: Kartu Latar Putih Bersih atau Transparan Merah/Biru ---
+ color: isAlert ? AppColors.error.withValues(alpha: 0.1) : isLow ? AppColors.info.withValues(alpha: 0.1) : AppColors.cardBg,
borderRadius: BorderRadius.circular(20),
- border: isAlert ? Border.all(color: Colors.red, width: 2) : isLow ? Border.all(color: Colors.blue, width: 2) : null,
+ // --- BERUBAH: Memberi garis halus agar kartu terlihat pop up di latar terang ---
+ border: isAlert
+ ? Border.all(color: AppColors.error, width: 2)
+ : isLow
+ ? Border.all(color: AppColors.info, width: 2)
+ : Border.all(color: AppColors.textSecondary.withValues(alpha: 0.15)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, color: color, size: 32),
const SizedBox(height: 6),
- Text(title, style: const TextStyle(color: Colors.grey, fontSize: 12)),
+ // --- BERUBAH: Warna Judul Sensor ---
+ Text(title, style: const TextStyle(color: AppColors.textSecondary, fontSize: 12)),
const SizedBox(height: 4),
TweenAnimationBuilder(
tween: Tween(begin: prev, end: cur),
@@ -357,7 +389,8 @@ class _MonitoringScreenState extends State {
child: Text(
'${value.toStringAsFixed(dec)}$suffix',
style: const TextStyle(
- color: Colors.white,
+ // --- BERUBAH: Warna Angka/Nilai Sensor ---
+ color: AppColors.textMain,
fontSize: 22,
fontWeight: FontWeight.bold),
),
@@ -380,8 +413,10 @@ class _MonitoringScreenState extends State {
height: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
- color: const Color(0xFF1A1A1A),
+ // --- BERUBAH: Kartu Latar Putih Bersih & Garis Halus ---
+ color: AppColors.cardBg,
borderRadius: BorderRadius.circular(20),
+ border: Border.all(color: AppColors.textSecondary.withValues(alpha: 0.15)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -389,13 +424,15 @@ class _MonitoringScreenState extends State {
children: [
Row(
children: [
+ // --- BERUBAH: Warna Ikon Kontroler ---
Icon(Icons.settings_input_component,
- color: isOn ? Colors.green : Colors.grey, size: 16),
+ color: isOn ? AppColors.primary : AppColors.textSecondary, size: 16),
const SizedBox(width: 6),
Expanded(
+ // --- BERUBAH: Warna Judul Kartu Kontrol ---
child: Text(title,
style: const TextStyle(
- color: Colors.white,
+ color: AppColors.textMain,
fontSize: 11,
fontWeight: FontWeight.bold)),
),
@@ -404,16 +441,18 @@ class _MonitoringScreenState extends State {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
+ // --- BERUBAH: Warna Status Mode ---
Text('Mode: ${mqtt.mode.toUpperCase()}',
style: const TextStyle(
- color: Colors.green, fontSize: 9, fontWeight: FontWeight.bold)),
+ color: AppColors.primary, fontSize: 9, fontWeight: FontWeight.bold)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
isOn ? 'ON' : 'OFF',
style: TextStyle(
- color: isOn ? Colors.green : Colors.grey,
+ // --- BERUBAH: Warna Status ON/OFF ---
+ color: isOn ? AppColors.primary : AppColors.textSecondary,
fontSize: 12,
fontWeight: FontWeight.bold),
),
@@ -422,7 +461,8 @@ class _MonitoringScreenState extends State {
child: Switch(
value: isOn,
onChanged: mqtt.mode == 'manual' ? onChanged : null,
- activeColor: Colors.green,
+ // --- BERUBAH: Warna Switch ---
+ activeColor: AppColors.primary,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
),
diff --git a/lib/screens/recording_screen.dart b/lib/screens/recording_screen.dart
index 7c64fcd..11258ce 100644
--- a/lib/screens/recording_screen.dart
+++ b/lib/screens/recording_screen.dart
@@ -3,6 +3,8 @@ import 'package:provider/provider.dart';
import '../services/mqtt_service.dart';
import '../services/supabase_service.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
+import '../constants/app_colors.dart';
+import '../services/recording_service.dart'; // Memori Abadi Timer Tetap Dipakai
class RecordingScreen extends StatefulWidget {
const RecordingScreen({super.key});
@@ -15,8 +17,8 @@ class _RecordingScreenState extends State {
final TextEditingController _intervalController = TextEditingController();
List