import React, { useState, useEffect, useCallback } from "react";
import {
View,
Text,
ScrollView,
StyleSheet,
TouchableOpacity,
TextInput,
Alert,
ActivityIndicator,
Keyboard,
} from "react-native";
import { useFocusEffect } from "@react-navigation/native";
import Slider from "@react-native-community/slider";
import CylinderSlider from "../components/CylinderSlinder";
import { setConveyorSpeed, getConveyorSpeed } from "../services/api";
// ─── Konstanta ────────────────────────────────────────────────────────────────
const SPEED_MODES = [
{ key: "pelan", label: "Pelan", value: 50, desc: "Cocok untuk telur rapuh" },
{ key: "sedang", label: "Sedang", value: 128, desc: "Mode normal" },
{ key: "cepat", label: "Cepat", value: 220, desc: "Throughput tinggi" },
];
function getSpeedLabel(v: number) {
if (v < 80) return "Pelan";
if (v < 170) return "Sedang";
return "Cepat";
}
function getSpeedColor(v: number) {
if (v < 80) return "#16a34a";
if (v < 170) return "#d97706";
return "#dc2626";
}
// ─── Komponen utama ───────────────────────────────────────────────────────────
export default function ControlScreen() {
const [speed, setSpeed] = useState(128);
const [speedMode, setSpeedMode] = useState("sedang");
const [speedInput, setSpeedInput] = useState("128");
const [saving, setSaving] = useState(false);
const [saved, setSaved] = useState(false);
const [loadingCurrent, setLoadingCurrent] = useState(true);
const [refreshing, setRefreshing] = useState(false);
// ── Fetch speed dari server ───────────────────────────────────────────────
const fetchSpeed = useCallback(async (isManual = false) => {
if (isManual) setRefreshing(true);
else setLoadingCurrent(true);
try {
const currentSpeed = await getConveyorSpeed();
setSpeed(currentSpeed);
setSpeedInput(String(currentSpeed));
const match = SPEED_MODES.find((m) => m.value === currentSpeed);
setSpeedMode(match ? match.key : "");
} catch {
if (isManual) {
Alert.alert("Gagal", "Tidak dapat mengambil data dari server.");
}
} finally {
setLoadingCurrent(false);
setRefreshing(false);
}
}, []);
// Fetch pertama kali saat app buka
useEffect(() => { fetchSpeed(); }, []);
// ✅ Fetch ulang SETIAP KALI tab Control difokuskan (balik dari tab lain)
// Ini memastikan data selalu sinkron dengan server, bukan dari state lama
useFocusEffect(
useCallback(() => {
fetchSpeed();
}, [fetchSpeed])
);
// ── Handler ───────────────────────────────────────────────────────────────
const applySpeedMode = (key: string, value: number) => {
setSpeedMode(key);
setSpeed(value);
setSpeedInput(String(value));
};
// Dipanggil dari cylinder atau slider — TIDAK dari input teks
const handleSpeedChange = (v: number) => {
const rounded = Math.round(v);
setSpeed(rounded);
setSpeedInput(String(rounded));
const match = SPEED_MODES.find((m) => m.value === rounded);
setSpeedMode(match ? match.key : "");
};
/**
* Terapkan nilai dari input teks.
* HANYA dipanggil saat tombol "Terapkan" diklik — BUKAN saat blur/dismiss keyboard.
*/
const handleApplyInput = () => {
Keyboard.dismiss();
const val = Math.max(0, Math.min(255, parseInt(speedInput, 10) || 0));
setSpeed(val);
setSpeedInput(String(val));
const match = SPEED_MODES.find((m) => m.value === val);
setSpeedMode(match ? match.key : "");
};
const handleSave = async () => {
try {
setSaving(true);
await setConveyorSpeed(speed);
setSaved(true);
setTimeout(() => setSaved(false), 2500);
} catch {
Alert.alert("Error", "Gagal mengirim data ke perangkat. Cek koneksi server.");
} finally {
setSaving(false);
}
};
const activeColor = getSpeedColor(speed);
// ── Loading state ─────────────────────────────────────────────────────────
if (loadingCurrent) {
return (
Memuat konfigurasi...
);
}
// ── Render ────────────────────────────────────────────────────────────────
return (
{/* Header */}
Kontrol Conveyor
Atur kecepatan laju conveyor
fetchSpeed(true)}
disabled={refreshing}
style={[styles.refreshBtn, refreshing && { opacity: 0.5 }]}
>
{refreshing
?
: ↺
}
{/* Cylinder */}
{Math.round((speed / 255) * 100)}%
Geser ke atas / bawah untuk adjust
{/* Control Card */}
{/* Header nilai */}
⚙️ Kecepatan Conveyor
{speed}
/ 255
{getSpeedLabel(speed)}
{/* Mode preset */}
Mode Cepat
{SPEED_MODES.map((m) => {
const active = speedMode === m.key;
const mColor = getSpeedColor(m.value);
return (
applySpeedMode(m.key, m.value)}
style={[
styles.modeButton,
{
borderColor: active ? mColor : "#e2e8f0",
backgroundColor: active ? mColor + "15" : "#f8fafc",
},
]}
>
{m.label}
{m.desc}
{active && (
)}
);
})}
{/* Slider */}
Slider Manual
0
255
{/* Input angka — onBlur DIHAPUS, hanya terapkan via tombol */}
Input Angka (0–255)
{/* Tombol Terapkan — SATU-SATUNYA cara nilai input diterapkan */}
Terapkan
{/* Speed bar indikator */}
{speed < 80
? "⚠️ Kecepatan rendah — pastikan conveyor bergerak"
: speed > 200
? "⚠️ Kecepatan tinggi — awasi kondisi telur"
: "✓ Kecepatan normal"}
{/* Tombol kirim */}
{saving ? "Mengirim..." : saved ? "✓ Kecepatan Tersimpan!" : "Kirim ke Perangkat"}
);
}
// ─── Styles ───────────────────────────────────────────────────────────────────
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: "#f8fafc" },
content: { padding: 16, paddingBottom: 32 },
loadingContainer: { flex: 1, justifyContent: "center", alignItems: "center", backgroundColor: "#f8fafc", gap: 12 },
loadingText: { fontSize: 13, color: "#94a3b8" },
header: { flexDirection: "row", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 20 },
title: { fontSize: 24, fontWeight: "800", color: "#0f172a", letterSpacing: -0.5 },
subtitle: { fontSize: 12, color: "#94a3b8", marginTop: 2 },
refreshBtn: {
width: 40, height: 40, borderRadius: 20,
backgroundColor: "#fff", borderWidth: 1, borderColor: "#e2e8f0",
alignItems: "center", justifyContent: "center",
shadowColor: "#000", shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.05, shadowRadius: 3, elevation: 2,
},
refreshIcon: { fontSize: 22, color: "#0284c7", fontWeight: "700", lineHeight: 26 },
// Cylinder card
cylinderCard: {
backgroundColor: "#fff", borderWidth: 1, borderColor: "#e2e8f0",
borderRadius: 16, paddingVertical: 28, paddingHorizontal: 16,
marginBottom: 16, alignItems: "center",
shadowColor: "#000", shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.05, shadowRadius: 4, elevation: 2,
},
cylinderWrapper: { alignItems: "center", gap: 16 },
cylinderInfo: { alignItems: "center" },
cylinderPct: { fontSize: 32, fontWeight: "800", color: "#0f172a", fontFamily: "monospace" },
cylinderHint: { fontSize: 11, color: "#94a3b8", marginTop: 2 },
// Control card
controlCard: {
backgroundColor: "#fff", borderWidth: 1, borderRadius: 16,
padding: 16, marginBottom: 12,
shadowColor: "#000", shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.04, shadowRadius: 3, elevation: 1,
},
controlHeaderRow: {
flexDirection: "row", justifyContent: "space-between",
alignItems: "flex-start", marginBottom: 16,
},
controlLabel: { fontSize: 12, fontWeight: "700", marginBottom: 4 },
valueRow: { flexDirection: "row", alignItems: "baseline" },
controlValueText: { fontSize: 32, fontWeight: "800", fontFamily: "monospace" },
controlValueUnit: { fontSize: 13, color: "#94a3b8" },
modeBadge: { paddingHorizontal: 12, paddingVertical: 5, borderRadius: 20, borderWidth: 1 },
modeBadgeText: { fontSize: 11, fontWeight: "600" },
sectionLabel: { fontSize: 10, color: "#94a3b8", fontWeight: "600", marginBottom: 8, marginTop: 4 },
// Mode buttons
modeRow: { flexDirection: "row", gap: 8, marginBottom: 16 },
modeButton: { flex: 1, paddingVertical: 10, paddingHorizontal: 6, borderRadius: 12, borderWidth: 1, alignItems: "center", gap: 3, position: "relative" },
modeButtonLabel:{ fontSize: 11, fontWeight: "700" },
modeButtonDesc: { fontSize: 9, color: "#94a3b8", textAlign: "center" },
activeIndicator:{ position: "absolute", top: 6, right: 6, width: 6, height: 6, borderRadius: 3 },
// Slider
sliderRow: { flexDirection: "row", alignItems: "center", gap: 8, marginBottom: 8 },
sliderMin: { fontSize: 10, color: "#94a3b8", width: 16, textAlign: "center" },
sliderMax: { fontSize: 10, color: "#94a3b8", width: 24, textAlign: "center" },
slider: { flex: 1, height: 40 },
// Input angka
inputRow: { flexDirection: "row", gap: 10, alignItems: "center" },
numberInput: {
width: 80, backgroundColor: "#f8fafc", borderWidth: 1.5,
borderRadius: 10, paddingHorizontal: 10, paddingVertical: 9,
color: "#0f172a", fontSize: 18, fontFamily: "monospace",
textAlign: "center", fontWeight: "700",
},
applyButton: { flex: 1, paddingVertical: 12, borderRadius: 10, borderWidth: 1, alignItems: "center" },
applyButtonText: { fontSize: 13, fontWeight: "700" },
inputHint: { fontSize: 10, color: "#cbd5e1", marginTop: 6, fontStyle: "italic" },
// Speed bar
speedBar: {
backgroundColor: "#f1f5f9", borderRadius: 12, overflow: "hidden",
marginBottom: 16, height: 40, justifyContent: "center",
borderWidth: 1, borderColor: "#e2e8f0",
},
speedBarFill: { position: "absolute", top: 0, left: 0, bottom: 0, opacity: 0.15, borderRadius: 12 },
speedBarLabel: { fontSize: 11, color: "#64748b", paddingHorizontal: 12 },
// Save button
saveButton: { borderRadius: 14, paddingVertical: 16, alignItems: "center" },
saveButtonText: { color: "#fff", fontSize: 15, fontWeight: "800", letterSpacing: 0.3 },
});