TKK_E32230206/lib/features/iot/providers/control_state.dart

225 lines
7.3 KiB
Dart

import 'package:flutter/material.dart';
// ── Model: WateringSchedule ────────────────────────────────────
/// Model data untuk jadwal penyiraman otomatis yang tersimpan di sistem.
class WateringSchedule {
/// ID unik jadwal yang digenerate oleh database.
final String id;
/// Jam penyiraman (WIB).
final TimeOfDay time;
/// Teks deskripsi pengulangan jadwal (misal: "Setiap Hari" atau "Sen, Rab, Jum").
final String repeat;
/// Menandakan apakah jadwal ini sedang aktif atau dinonaktifkan oleh pengguna.
final bool isEnabled;
/// Format string Cron asli yang disimpan di database (dalam zona waktu UTC).
final String? cron;
/// Durasi penyiraman dalam satuan detik. Default: 30 detik.
final int durationS;
const WateringSchedule({
required this.id,
required this.time,
this.repeat = 'Setiap Hari',
this.isEnabled = true,
this.cron,
this.durationS = 30,
});
/// Mengembalikan format jam dalam string 'HH.MM' untuk kebutuhan UI.
String get formattedTime {
final h = time.hour.toString().padLeft(2, '0');
final m = time.minute.toString().padLeft(2, '0');
return '$h.$m';
}
/// Menggandakan objek [WateringSchedule] dengan nilai baru secara immutable.
WateringSchedule copyWith({
String? id,
TimeOfDay? time,
String? repeat,
bool? isEnabled,
String? cron,
int? durationS,
}) {
return WateringSchedule(
id: id ?? this.id,
time: time ?? this.time,
repeat: repeat ?? this.repeat,
isEnabled: isEnabled ?? this.isEnabled,
cron: cron ?? this.cron,
durationS: durationS ?? this.durationS,
);
}
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is WateringSchedule &&
runtimeType == other.runtimeType &&
id == other.id);
@override
int get hashCode => id.hashCode;
}
// ── Enum: DeviceMode ─────────────────────────────────────────────────
/// Mode operasional dari modul IoT penyiram jamur:
/// - [auto_] : Pompa menyala otomatis jika sensor mendeteksi nilai melewati threshold atau sesuai jadwal.
/// - [manual] : Pompa hanya menyala saat dikendalikan langsung oleh pengguna dari aplikasi.
/// - [offline] : Status perangkat sedang tidak terhubung ke jaringan internet.
enum DeviceMode { auto_, manual, offline }
/// Ekstensi pendukung untuk mempermudah manipulasi nilai enum [DeviceMode].
extension DeviceModeX on DeviceMode {
/// Nilai string yang digunakan dalam pertukaran data API dengan backend.
String get apiValue {
switch (this) {
case DeviceMode.auto_: return 'auto';
case DeviceMode.manual: return 'manual';
case DeviceMode.offline: return 'offline';
}
}
/// Teks berformat rapi untuk ditampilkan di UI label status.
String get label {
switch (this) {
case DeviceMode.auto_: return 'AUTO';
case DeviceMode.manual: return 'MANUAL';
case DeviceMode.offline: return 'OFFLINE';
}
}
/// Memparsing string dari backend menjadi tipe [DeviceMode].
static DeviceMode fromString(String s) {
final str = s.toLowerCase();
if (str.startsWith('manual')) {
return DeviceMode.manual;
} else if (str.startsWith('offline')) {
return DeviceMode.offline;
} else {
return DeviceMode.auto_;
}
}
}
// ── State: ControlState ────────────────────────────────────────────
/// State yang menampung seluruh konfigurasi kendali modul IoT (Pompa/Watering).
class ControlState {
/// Status loading pemuatan data konfigurasi dari API.
final bool isLoading;
/// Status relay pompa saat ini (true = menyala, false = mati).
final bool isPumpOn;
/// Nilai threshold suhu maksimal (°C).
final double suhuLimit;
/// Nilai threshold kelembapan minimal (%).
final double kelembapanLimit;
/// Daftar jadwal penyiraman otomatis yang telah diatur pengguna.
final List<WateringSchedule> schedules;
/// Pesan error dari server (jika ada).
final String? errorMessage;
/// Pesan sukses aksi (jika ada).
final String? successMessage;
/// Berapa lama pompa manual diset menyala (detik).
final int? activePumpDuration;
/// Timestamp waktu ketika pompa dinyalakan (untuk kalkulasi countdown sisa durasi).
final DateTime? pumpTurnedOnAt;
/// Mode alat saat ini (Auto / Manual / Offline).
final DeviceMode deviceMode;
/// Status loading khusus saat mengubah mode alat.
final bool isModeLoading;
const ControlState({
this.isLoading = false,
this.isPumpOn = false,
this.suhuLimit = 30,
this.kelembapanLimit = 75,
this.schedules = const [],
this.errorMessage,
this.successMessage,
this.activePumpDuration,
this.pumpTurnedOnAt,
this.deviceMode = DeviceMode.auto_,
this.isModeLoading = false,
});
/// State awal saat pertama kali dimuat di memori.
factory ControlState.initial() => const ControlState(
isLoading: true, // Data sedang dimuat dari API pada awal jalannya screen
schedules: [],
);
/// Menggandakan [ControlState] secara immutable.
/// Menyediakan fitur pembersihan pesan sukses/error atau countdown timer.
ControlState copyWith({
bool? isLoading,
bool? isPumpOn,
double? suhuLimit,
double? kelembapanLimit,
List<WateringSchedule>? schedules,
String? errorMessage,
String? successMessage,
int? activePumpDuration,
DateTime? pumpTurnedOnAt,
DeviceMode? deviceMode,
bool? isModeLoading,
bool clearError = false,
bool clearSuccess = false,
bool clearTimer = false,
}) {
return ControlState(
isLoading: isLoading ?? this.isLoading,
isPumpOn: isPumpOn ?? this.isPumpOn,
suhuLimit: suhuLimit ?? this.suhuLimit,
kelembapanLimit: kelembapanLimit ?? this.kelembapanLimit,
schedules: schedules ?? this.schedules,
errorMessage: clearError ? null : (errorMessage ?? this.errorMessage),
successMessage: clearSuccess ? null : (successMessage ?? this.successMessage),
activePumpDuration: clearTimer ? null : (activePumpDuration ?? this.activePumpDuration),
pumpTurnedOnAt: clearTimer ? null : (pumpTurnedOnAt ?? this.pumpTurnedOnAt),
deviceMode: deviceMode ?? this.deviceMode,
isModeLoading: isModeLoading ?? this.isModeLoading,
);
}
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is ControlState &&
isLoading == other.isLoading &&
isPumpOn == other.isPumpOn &&
suhuLimit == other.suhuLimit &&
kelembapanLimit == other.kelembapanLimit &&
errorMessage == other.errorMessage &&
successMessage == other.successMessage &&
activePumpDuration == other.activePumpDuration &&
pumpTurnedOnAt == other.pumpTurnedOnAt &&
schedules == other.schedules);
@override
int get hashCode =>
isLoading.hashCode ^
isPumpOn.hashCode ^
suhuLimit.hashCode ^
kelembapanLimit.hashCode ^
errorMessage.hashCode ^
successMessage.hashCode ^
activePumpDuration.hashCode ^
pumpTurnedOnAt.hashCode ^
schedules.hashCode;
}