feat: extended theme switching #87
This commit is contained in:
@@ -72,6 +72,11 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
li.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
button {
|
button {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
@@ -138,6 +143,9 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const registerReceiveEvents = () => {
|
const registerReceiveEvents = () => {
|
||||||
|
ipcRenderer.on("button-disabled", (e, button) => {
|
||||||
|
document.getElementById(button.id).parentNode.classList.toggle("disabled", button.disabled);
|
||||||
|
});
|
||||||
ipcRenderer.on("text-content", (e, text) => {
|
ipcRenderer.on("text-content", (e, text) => {
|
||||||
document.getElementById(text.id).textContent = text.content;
|
document.getElementById(text.id).textContent = text.content;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -78,6 +78,16 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<button id="theme">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
|
<title>compare</title>
|
||||||
|
<path
|
||||||
|
d="M19,3H14V5H19V18L14,12V21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M10,18H5L10,12M10,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H10V23H12V1H10V3Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<button id="keyboard">
|
<button id="keyboard">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
|
|||||||
+42
-2
@@ -48,12 +48,15 @@ const init = async () => {
|
|||||||
configuration_url: APP.homepage,
|
configuration_url: APP.homepage,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Connection settings
|
// Init options
|
||||||
const masked = password === null ? null : "*".repeat(password.length);
|
const masked = password === null ? null : "*".repeat(password.length);
|
||||||
const options = user === null || password === null ? {} : { username: user, password: password };
|
const options = user === null || password === null ? {} : { username: user, password: password };
|
||||||
options.rejectUnauthorized = !("ignore_certificate_errors" in ARGS);
|
options.rejectUnauthorized = !("ignore_certificate_errors" in ARGS);
|
||||||
|
|
||||||
|
// Client connect
|
||||||
console.log("MQTT Connecting:", `${user}:${masked}@${url.toString()}`);
|
console.log("MQTT Connecting:", `${user}:${masked}@${url.toString()}`);
|
||||||
INTEGRATION.client = mqtt.connect(url.toString(), options);
|
INTEGRATION.client = mqtt.connect(url.toString(), options);
|
||||||
|
INTEGRATION.client.setMaxListeners(20);
|
||||||
|
|
||||||
// Client connected
|
// Client connected
|
||||||
INTEGRATION.client
|
INTEGRATION.client
|
||||||
@@ -67,6 +70,7 @@ const init = async () => {
|
|||||||
initReboot();
|
initReboot();
|
||||||
initRefresh();
|
initRefresh();
|
||||||
initKiosk();
|
initKiosk();
|
||||||
|
initTheme();
|
||||||
initDisplay();
|
initDisplay();
|
||||||
initVolume();
|
initVolume();
|
||||||
initKeyboard();
|
initKeyboard();
|
||||||
@@ -97,6 +101,8 @@ const init = async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Update sensor states from events
|
// Update sensor states from events
|
||||||
|
EVENTS.on("updateStatus", updateKiosk);
|
||||||
|
EVENTS.on("updateTheme", updateTheme);
|
||||||
EVENTS.on("updateDisplay", updateDisplay);
|
EVENTS.on("updateDisplay", updateDisplay);
|
||||||
EVENTS.on("updateVolume", updateVolume);
|
EVENTS.on("updateVolume", updateVolume);
|
||||||
EVENTS.on("updateKeyboard", updateKeyboard);
|
EVENTS.on("updateKeyboard", updateKeyboard);
|
||||||
@@ -130,7 +136,6 @@ const update = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update client sensors
|
// Update client sensors
|
||||||
updateKiosk();
|
|
||||||
updatePageNumber();
|
updatePageNumber();
|
||||||
updatePageZoom();
|
updatePageZoom();
|
||||||
updatePageUrl();
|
updatePageUrl();
|
||||||
@@ -379,6 +384,41 @@ const updateKiosk = async () => {
|
|||||||
publishState("kiosk", kiosk);
|
publishState("kiosk", kiosk);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the application theme and handles the execute logic.
|
||||||
|
*/
|
||||||
|
const initTheme = () => {
|
||||||
|
const root = `${INTEGRATION.root}/theme`;
|
||||||
|
const config = {
|
||||||
|
name: "Theme",
|
||||||
|
unique_id: `${INTEGRATION.node}_theme`,
|
||||||
|
command_topic: `${root}/set`,
|
||||||
|
state_topic: `${root}/state`,
|
||||||
|
value_template: "{{ value }}",
|
||||||
|
options: ["Light", "Dark"],
|
||||||
|
icon: "mdi:compare",
|
||||||
|
device: INTEGRATION.device,
|
||||||
|
};
|
||||||
|
publishConfig("select", config)
|
||||||
|
.on("message", (topic, message) => {
|
||||||
|
if (topic === config.command_topic) {
|
||||||
|
const theme = message.toString();
|
||||||
|
console.log("Set Application Theme:", theme);
|
||||||
|
WEBVIEW.theme.set(theme);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.subscribe(config.command_topic);
|
||||||
|
updateTheme();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the application theme via the mqtt connection.
|
||||||
|
*/
|
||||||
|
const updateTheme = async () => {
|
||||||
|
const theme = WEBVIEW.theme.get();
|
||||||
|
publishState("theme", theme.charAt(0).toUpperCase() + theme.slice(1));
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the display status, brightness and handles the execute logic.
|
* Initializes the display status, brightness and handles the execute logic.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+63
-19
@@ -54,15 +54,37 @@ const init = async () => {
|
|||||||
WEBVIEW.viewActive = 0;
|
WEBVIEW.viewActive = 0;
|
||||||
WEBVIEW.viewUrls = urls;
|
WEBVIEW.viewUrls = urls;
|
||||||
WEBVIEW.viewZoom = zoom;
|
WEBVIEW.viewZoom = zoom;
|
||||||
WEBVIEW.viewTheme = theme;
|
|
||||||
WEBVIEW.pagerEnabled = widget;
|
|
||||||
WEBVIEW.widgetTheme = theme;
|
|
||||||
WEBVIEW.widgetEnabled = widget;
|
|
||||||
WEBVIEW.statusTheme = theme;
|
|
||||||
WEBVIEW.statusEnabled = true;
|
WEBVIEW.statusEnabled = true;
|
||||||
WEBVIEW.navigationTheme = theme;
|
WEBVIEW.pagerEnabled = widget;
|
||||||
|
WEBVIEW.widgetEnabled = widget;
|
||||||
WEBVIEW.navigationEnabled = widget;
|
WEBVIEW.navigationEnabled = widget;
|
||||||
nativeTheme.themeSource = WEBVIEW.viewTheme;
|
|
||||||
|
// Init global theme
|
||||||
|
WEBVIEW.theme = {
|
||||||
|
set: (name) => {
|
||||||
|
nativeTheme.themeSource = name.toLowerCase();
|
||||||
|
},
|
||||||
|
get: () => {
|
||||||
|
return nativeTheme.shouldUseDarkColors ? "dark" : "light";
|
||||||
|
},
|
||||||
|
toggle: () => {
|
||||||
|
nativeTheme.themeSource = nativeTheme.shouldUseDarkColors ? "light" : "dark";
|
||||||
|
},
|
||||||
|
register: () => {
|
||||||
|
nativeTheme.on("updated", () => {
|
||||||
|
const theme = WEBVIEW.theme.get();
|
||||||
|
WEBVIEW.statusTheme = theme;
|
||||||
|
WEBVIEW.widgetTheme = theme;
|
||||||
|
WEBVIEW.navigationTheme = theme;
|
||||||
|
if (WEBVIEW.initialized) {
|
||||||
|
resizeView();
|
||||||
|
}
|
||||||
|
EVENTS.emit("updateTheme");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
WEBVIEW.theme.register();
|
||||||
|
WEBVIEW.theme.set(theme);
|
||||||
|
|
||||||
// Init global root window
|
// Init global root window
|
||||||
WEBVIEW.display = screen.getPrimaryDisplay().workAreaSize;
|
WEBVIEW.display = screen.getPrimaryDisplay().workAreaSize;
|
||||||
@@ -190,10 +212,7 @@ const updateView = () => {
|
|||||||
|
|
||||||
// Update window title
|
// Update window title
|
||||||
console.log(`Update View: ${title}`);
|
console.log(`Update View: ${title}`);
|
||||||
WEBVIEW.status.webContents.send("text-content", {
|
WEBVIEW.status.webContents.send("text-content", { id: "title", content: title });
|
||||||
id: "title",
|
|
||||||
content: title,
|
|
||||||
});
|
|
||||||
WEBVIEW.window.setTitle(title);
|
WEBVIEW.window.setTitle(title);
|
||||||
|
|
||||||
// Hide all other webviews and show only the active one
|
// Hide all other webviews and show only the active one
|
||||||
@@ -628,7 +647,7 @@ const windowEvents = async () => {
|
|||||||
const delta = (now - then) / 1000;
|
const delta = (now - then) / 1000;
|
||||||
|
|
||||||
// Auto-hide navigation
|
// Auto-hide navigation
|
||||||
if (delta > 60) {
|
if (delta > 60 && WEBVIEW.tracker.status !== "Terminated") {
|
||||||
toggleNavigation("OFF");
|
toggleNavigation("OFF");
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
@@ -675,6 +694,9 @@ const widgetEvents = async () => {
|
|||||||
// Handle widget button click events
|
// Handle widget button click events
|
||||||
ipcMain.on("button-click", (e, button) => {
|
ipcMain.on("button-click", (e, button) => {
|
||||||
switch (button.id) {
|
switch (button.id) {
|
||||||
|
case "theme":
|
||||||
|
WEBVIEW.theme.toggle();
|
||||||
|
break;
|
||||||
case "keyboard":
|
case "keyboard":
|
||||||
const toggle = hardware.getKeyboardVisibility() === "ON" ? "OFF" : "ON";
|
const toggle = hardware.getKeyboardVisibility() === "ON" ? "OFF" : "ON";
|
||||||
hardware.setKeyboardVisibility(toggle, () => {
|
hardware.setKeyboardVisibility(toggle, () => {
|
||||||
@@ -711,14 +733,23 @@ const statusEvents = async () => {
|
|||||||
WEBVIEW.window.setStatus("Minimized");
|
WEBVIEW.window.setStatus("Minimized");
|
||||||
break;
|
break;
|
||||||
case "terminate":
|
case "terminate":
|
||||||
|
WEBVIEW.status.webContents.send("button-disabled", { id: "fullscreen", disabled: true });
|
||||||
|
WEBVIEW.status.webContents.send("button-disabled", { id: "minimize", disabled: true });
|
||||||
|
WEBVIEW.status.webContents.send("button-disabled", { id: "terminate", disabled: true });
|
||||||
const button = dialog.showMessageBoxSync(WEBVIEW.window, {
|
const button = dialog.showMessageBoxSync(WEBVIEW.window, {
|
||||||
type: "question",
|
type: "question",
|
||||||
title: "Confirm",
|
title: "Confirm",
|
||||||
message: `\nExit ${APP.title}?`,
|
message: `\nExit ${APP.title}?`,
|
||||||
buttons: ["No", "Yes"],
|
buttons: ["No", "Yes"],
|
||||||
});
|
});
|
||||||
if (button === 1) {
|
switch (button) {
|
||||||
|
case 1:
|
||||||
WEBVIEW.window.setStatus("Terminated");
|
WEBVIEW.window.setStatus("Terminated");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WEBVIEW.status.webContents.send("button-disabled", { id: "fullscreen", disabled: false });
|
||||||
|
WEBVIEW.status.webContents.send("button-disabled", { id: "minimize", disabled: false });
|
||||||
|
WEBVIEW.status.webContents.send("button-disabled", { id: "terminate", disabled: false });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -863,7 +894,7 @@ const viewEvents = async () => {
|
|||||||
if (WEBVIEW.viewActive === 0 && ready.length === WEBVIEW.views.length) {
|
if (WEBVIEW.viewActive === 0 && ready.length === WEBVIEW.views.length) {
|
||||||
nextView();
|
nextView();
|
||||||
}
|
}
|
||||||
view.webContents.loadURL(errorHtml(code, text, url));
|
view.webContents.loadURL(errorHtml(code, text, url, WEBVIEW.theme.get()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1089,9 +1120,14 @@ const loaderHtml = (size, speed, theme) => {
|
|||||||
* @param {number} code - The error code of the response.
|
* @param {number} code - The error code of the response.
|
||||||
* @param {string} text - The error text of the response.
|
* @param {string} text - The error text of the response.
|
||||||
* @param {string} url - The url of the requested page.
|
* @param {string} url - The url of the requested page.
|
||||||
|
* @param {string} theme - The theme used for text colors.
|
||||||
* @returns {string} A data string with the generated html.
|
* @returns {string} A data string with the generated html.
|
||||||
*/
|
*/
|
||||||
const errorHtml = (code, text, url) => {
|
const errorHtml = (code, text, url, theme) => {
|
||||||
|
const color = {
|
||||||
|
dark: { icon: "#FFA500", text: "#E5E5E5", background: "#111111" },
|
||||||
|
light: { icon: "#FFA500", text: "#1A1A1A", background: "#FAFAFA" },
|
||||||
|
}[theme];
|
||||||
const html = `
|
const html = `
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
@@ -1099,17 +1135,25 @@ const errorHtml = (code, text, url) => {
|
|||||||
body {
|
body {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
text-align: center;
|
background-color: ${color.background};
|
||||||
}
|
}
|
||||||
.icon {
|
.icon {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 5rem;
|
font-size: 5rem;
|
||||||
color: orange;
|
color: ${color.icon};
|
||||||
}
|
}
|
||||||
.title {
|
.title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
color: ${color.text};
|
||||||
|
}
|
||||||
|
.url {
|
||||||
|
color: ${color.text};
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
color: ${color.text};
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
@@ -1117,8 +1161,8 @@ const errorHtml = (code, text, url) => {
|
|||||||
<div>
|
<div>
|
||||||
<p class="icon">⚠</p>
|
<p class="icon">⚠</p>
|
||||||
<h1 class="title">Whoopsie!</h1>
|
<h1 class="title">Whoopsie!</h1>
|
||||||
<p><strong>Loading:</strong> ${url}</p>
|
<p class="url"><strong>Loading:</strong> ${url}</p>
|
||||||
<p><strong>Error:</strong> ${text} (${code})</p>
|
<p class="error"><strong>Error:</strong> ${text} (${code})</p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>`;
|
</html>`;
|
||||||
|
|||||||
Reference in New Issue
Block a user