271 lines
6.3 KiB
JavaScript
271 lines
6.3 KiB
JavaScript
import { ApiService } from "./ApiService.js";
|
||
import { DialogManager } from "./DialogManager.js";
|
||
import { throttle, createStyledElement } from "./utils.js";
|
||
|
||
export class BarControlSystem {
|
||
constructor() {
|
||
this.settings = {};
|
||
this.websockets = {};
|
||
this.init();
|
||
}
|
||
|
||
async init() {
|
||
await this.loadSettings();
|
||
this.createControlPanel();
|
||
this.renderColorPickers();
|
||
}
|
||
|
||
async loadSettings() {
|
||
this.settings = await ApiService.loadSettings();
|
||
}
|
||
|
||
createControlPanel() {
|
||
const panel = createStyledElement("div", {
|
||
position: "fixed",
|
||
top: "10px",
|
||
right: "10px",
|
||
padding: "15px",
|
||
border: "2px solid #333",
|
||
borderRadius: "8px",
|
||
backgroundColor: "#f0f0f0",
|
||
zIndex: "1000",
|
||
});
|
||
panel.id = "control-panel";
|
||
|
||
const title = createStyledElement(
|
||
"h3",
|
||
{
|
||
margin: "0 0 10px 0",
|
||
fontFamily: "Arial, sans-serif",
|
||
},
|
||
{ textContent: "Control Panel" },
|
||
);
|
||
|
||
const buttonStyles = {
|
||
padding: "8px 12px",
|
||
border: "none",
|
||
borderRadius: "4px",
|
||
cursor: "pointer",
|
||
color: "white",
|
||
};
|
||
|
||
const createButton = createStyledElement(
|
||
"button",
|
||
{
|
||
...buttonStyles,
|
||
marginRight: "10px",
|
||
backgroundColor: "#4CAF50",
|
||
},
|
||
{ textContent: "Create New Bar" },
|
||
);
|
||
|
||
const refreshButton = createStyledElement(
|
||
"button",
|
||
{
|
||
...buttonStyles,
|
||
backgroundColor: "#2196F3",
|
||
},
|
||
{ textContent: "Refresh" },
|
||
);
|
||
|
||
createButton.onclick = () => this.showCreateDialog();
|
||
refreshButton.onclick = () => this.refresh();
|
||
|
||
panel.append(title, createButton, refreshButton);
|
||
document.body.appendChild(panel);
|
||
}
|
||
|
||
showCreateDialog() {
|
||
DialogManager.showCreateDialog((barData) => this.createBar(barData));
|
||
}
|
||
|
||
async createBar(barData) {
|
||
if (!barData.barId) {
|
||
alert("Bar ID is required");
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await ApiService.createBar(barData);
|
||
console.log(`Bar created: ${barData.barId}`);
|
||
await this.refresh();
|
||
} catch (error) {
|
||
console.error("Failed to create bar:", error);
|
||
alert(error.message || "Failed to create bar");
|
||
}
|
||
}
|
||
|
||
async deleteBar(barId) {
|
||
if (!confirm(`Are you sure you want to delete bar ${barId}?`)) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await ApiService.deleteBar(barId);
|
||
console.log(`Bar deleted: ${barId}`);
|
||
await this.refresh();
|
||
} catch (error) {
|
||
console.error("Failed to delete bar:", error);
|
||
alert(error.message || "Failed to delete bar");
|
||
}
|
||
}
|
||
|
||
async refresh() {
|
||
// Close existing websockets
|
||
Object.values(this.websockets).forEach((ws) => {
|
||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||
ws.close();
|
||
}
|
||
});
|
||
|
||
// Remove existing color pickers
|
||
Object.keys(this.settings).forEach((barId) => {
|
||
const form = document.getElementById("color_form_" + barId);
|
||
if (form) {
|
||
form.remove();
|
||
}
|
||
});
|
||
|
||
this.websockets = {};
|
||
await this.loadSettings();
|
||
this.renderColorPickers();
|
||
}
|
||
|
||
renderColorPickers() {
|
||
Object.keys(this.settings).forEach((barId) => {
|
||
const config = this.settings[barId];
|
||
this.createColorPicker(barId, config);
|
||
});
|
||
}
|
||
|
||
makeDraggable(element, barId) {
|
||
let isDragging = false;
|
||
let startX, startY, initialX, initialY;
|
||
|
||
element.addEventListener("mousedown", (e) => {
|
||
if (e.target.tagName === "BUTTON") return;
|
||
|
||
isDragging = true;
|
||
startX = e.clientX;
|
||
startY = e.clientY;
|
||
|
||
const rect = element.getBoundingClientRect();
|
||
initialX = rect.left;
|
||
initialY = rect.top;
|
||
|
||
element.style.cursor = "move";
|
||
e.preventDefault();
|
||
});
|
||
|
||
document.addEventListener("mousemove", (e) => {
|
||
if (!isDragging) return;
|
||
|
||
const deltaX = e.clientX - startX;
|
||
const deltaY = e.clientY - startY;
|
||
|
||
const newX = initialX + deltaX;
|
||
const newY = initialY + deltaY;
|
||
|
||
element.style.left = newX + "px";
|
||
element.style.top = newY + "px";
|
||
});
|
||
|
||
document.addEventListener("mouseup", () => {
|
||
if (isDragging) {
|
||
const rect = element.getBoundingClientRect();
|
||
ApiService.savePosition(barId, rect.left, rect.top);
|
||
element.style.cursor = "default";
|
||
}
|
||
isDragging = false;
|
||
});
|
||
}
|
||
|
||
createColorPicker(barId, config) {
|
||
const ws = new WebSocket(config["url"]);
|
||
this.websockets[barId] = ws;
|
||
|
||
const form = createStyledElement("form", {
|
||
position: "absolute",
|
||
left: config["x"] + "px",
|
||
top: config["y"] + "px",
|
||
padding: "10px",
|
||
border: "1px solid #ccc",
|
||
borderRadius: "5px",
|
||
backgroundColor: "white",
|
||
});
|
||
form.id = "color_form_" + barId;
|
||
|
||
const label = createStyledElement(
|
||
"label",
|
||
{
|
||
display: "block",
|
||
marginBottom: "5px",
|
||
fontFamily: "Arial, sans-serif",
|
||
fontSize: "14px",
|
||
},
|
||
{
|
||
htmlFor: "color_input_" + barId,
|
||
textContent: barId,
|
||
},
|
||
);
|
||
|
||
const colorInput = createStyledElement(
|
||
"input",
|
||
{},
|
||
{
|
||
type: "color",
|
||
id: "color_input_" + barId,
|
||
name: barId,
|
||
value: config["color"],
|
||
},
|
||
);
|
||
|
||
const deleteButton = createStyledElement(
|
||
"button",
|
||
{
|
||
position: "absolute",
|
||
top: "2px",
|
||
right: "2px",
|
||
width: "20px",
|
||
height: "20px",
|
||
backgroundColor: "#f44336",
|
||
color: "white",
|
||
border: "none",
|
||
borderRadius: "50%",
|
||
cursor: "pointer",
|
||
fontSize: "12px",
|
||
lineHeight: "1",
|
||
},
|
||
{
|
||
type: "button",
|
||
textContent: "×",
|
||
},
|
||
);
|
||
|
||
deleteButton.onclick = () => this.deleteBar(barId);
|
||
|
||
const throttledColorHandler = throttle((event) => {
|
||
const color = event.target.value;
|
||
console.log(`Color selected for ${barId}: ${color}`);
|
||
|
||
ApiService.saveColor(barId, color);
|
||
|
||
if (ws.readyState === WebSocket.OPEN) {
|
||
const message = { color1: color };
|
||
ws.send(JSON.stringify(message));
|
||
} else {
|
||
console.warn(
|
||
`WebSocket not ready for ${barId}. ReadyState: ${ws.readyState}`,
|
||
);
|
||
}
|
||
}, 500);
|
||
|
||
colorInput.addEventListener("input", throttledColorHandler);
|
||
|
||
form.append(label, colorInput, deleteButton);
|
||
document.body.appendChild(form);
|
||
|
||
this.makeDraggable(form, barId);
|
||
}
|
||
}
|