code cleanup

Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
2026-04-09 22:16:35 +02:00
parent 2460fb32d6
commit bc1b75beeb
5 changed files with 102 additions and 187 deletions
+61
View File
@@ -0,0 +1,61 @@
class ActionBase {
constructor($UD, context) {
this.$UD = $UD;
this.context = context;
this.refreshTimer = null;
this.debounceTimer = 0;
}
onClear() {
if (this.refreshTimer) {
clearInterval(this.refreshTimer);
this.refreshTimer = null;
}
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
this.debounceTimer = 0;
}
}
startTimer(fetchFn, refreshRate) {
this.onClear();
fetchFn();
const duration = this.getRefreshDuration(refreshRate);
if (duration > 0) {
this.refreshTimer = setInterval(() => fetchFn(), duration * 60 * 1000);
}
}
debounce(fn, delay = 300) {
if (this.debounceTimer) clearTimeout(this.debounceTimer);
this.debounceTimer = setTimeout(() => fn(), delay);
}
getRefreshDuration(refreshRate) {
switch (refreshRate) {
case '1': return 1;
case '2': return 2;
case '3': return 5;
case '4': return 10;
case '5': return 30;
case '6': return 60;
default: return 0;
}
}
createCanvas() {
const canvas = document.createElement('canvas');
canvas.width = 196;
canvas.height = 196;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, 196, 196);
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
return { canvas, ctx };
}
setIcon(canvas) {
this.$UD.setBaseDataIcon(this.context, canvas.toDataURL('image/png'));
}
}
+21 -71
View File
@@ -1,62 +1,42 @@
class CopilotAction {
class CopilotAction extends ActionBase {
constructor($UD, context) {
this.$UD = $UD;
this.context = context;
super($UD, context);
this.config = {
url: '',
refreshRate: '4',
};
this.refreshTimer = null;
this.debounceTimer = 0;
}
setActive() {}
onClear() {
if (this.refreshTimer) {
clearInterval(this.refreshTimer);
this.refreshTimer = null;
}
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
this.debounceTimer = 0;
}
}
setParams(jsn) {
this.config = Object.assign(this.config, (jsn && jsn.param) || {});
this.start();
this.startTimer(() => this.fetchData(), this.config.refreshRate);
}
onRun() {
this.fetchData();
}
start() {
this.onClear();
this.fetchData();
const duration = this.getRefreshDuration();
if (duration > 0) {
this.refreshTimer = setInterval(() => this.fetchData(), duration * 60 * 1000);
}
}
async fetchData() {
if (this.debounceTimer) clearTimeout(this.debounceTimer);
this.debounceTimer = setTimeout(async () => {
fetchData() {
this.debounce(async () => {
if (!this.config.url) {
this.renderGauge(null);
this.renderGauge(null, false);
return;
}
try {
const response = await fetch(this.config.url);
if (!response.ok) {
this.renderGauge(null, true);
return;
}
const text = await response.text();
const value = this.parsePrometheus(text);
this.renderGauge(value !== null ? parseFloat(value) : null);
this.renderGauge(value !== null ? parseFloat(value) : null, false);
} catch (e) {
this.renderGauge(null);
this.renderGauge(null, true);
}
}, 300);
});
}
parsePrometheus(text) {
@@ -66,7 +46,6 @@ class CopilotAction {
if (trimmed.startsWith('github_copilot_usage_percentage')) {
const closingBrace = trimmed.indexOf('}');
if (closingBrace !== -1) return trimmed.slice(closingBrace + 1).trim();
// no labels
const parts = trimmed.split(/\s+/);
if (parts.length >= 2) return parts[1];
}
@@ -74,25 +53,18 @@ class CopilotAction {
return null;
}
renderGauge(value) {
const canvas = document.createElement('canvas');
canvas.width = 196;
canvas.height = 196;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, 196, 196);
renderGauge(value, isError) {
const { canvas, ctx } = this.createCanvas();
const cx = 98, cy = 100;
const r = 68;
const lineWidth = 14;
// Gauge runs from 225° to 315° clockwise (270° sweep)
const startAngle = 135 * Math.PI / 180;
const totalSweep = 270 * Math.PI / 180;
const greenEnd = startAngle + 0.50 * totalSweep; // 50%
const yellowEnd = startAngle + 0.80 * totalSweep; // 80%
const endAngle = startAngle + totalSweep; // 100%
const greenEnd = startAngle + 0.50 * totalSweep;
const yellowEnd = startAngle + 0.80 * totalSweep;
const endAngle = startAngle + totalSweep;
// Background track
ctx.beginPath();
@@ -106,7 +78,6 @@ class CopilotAction {
const pct = Math.max(0, Math.min(100, value)) / 100;
const valueAngle = startAngle + pct * totalSweep;
// Green segment (050%)
if (pct > 0) {
ctx.beginPath();
ctx.arc(cx, cy, r, startAngle, Math.min(valueAngle, greenEnd), false);
@@ -115,8 +86,6 @@ class CopilotAction {
ctx.lineCap = 'round';
ctx.stroke();
}
// Yellow segment (5080%)
if (pct > 0.5) {
ctx.beginPath();
ctx.arc(cx, cy, r, greenEnd, Math.min(valueAngle, yellowEnd), false);
@@ -125,8 +94,6 @@ class CopilotAction {
ctx.lineCap = 'butt';
ctx.stroke();
}
// Red segment (80100%)
if (pct > 0.8) {
ctx.beginPath();
ctx.arc(cx, cy, r, yellowEnd, valueAngle, false);
@@ -136,21 +103,16 @@ class CopilotAction {
ctx.stroke();
}
// Value text — centered, colored
const color = pct <= 0.5 ? '#4caf50' : pct <= 0.8 ? '#ffeb3b' : '#f44336';
const displayText = value.toFixed(1) + '%';
const fSize = displayText.length > 6 ? 28 : 34;
ctx.fillStyle = color;
ctx.font = `bold ${fSize}px "Source Han Sans SC"`;
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.fillText(displayText, cx, cy + 8);
} else {
ctx.fillStyle = '#666666';
ctx.fillStyle = isError ? '#ff6b6b' : '#666666';
ctx.font = 'bold 28px "Source Han Sans SC"';
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.fillText('N/A', cx, cy + 8);
ctx.fillText(isError ? 'ERR' : 'N/A', cx, cy + 8);
}
// Label — bottom
@@ -158,18 +120,6 @@ class CopilotAction {
ctx.font = 'bold 20px "Source Han Sans SC"';
ctx.fillText('Copilot', cx, 165);
this.$UD.setBaseDataIcon(this.context, canvas.toDataURL('image/png'));
}
getRefreshDuration() {
switch (this.config.refreshRate) {
case '1': return 1;
case '2': return 2;
case '3': return 5;
case '4': return 10;
case '5': return 30;
case '6': return 60;
default: return 0;
}
this.setIcon(canvas);
}
}
+8 -53
View File
@@ -1,7 +1,6 @@
class GiteaAction {
class GiteaAction extends ActionBase {
constructor($UD, context) {
this.$UD = $UD;
this.context = context;
super($UD, context);
this.config = {
url: '',
owner: '',
@@ -9,26 +8,13 @@ class GiteaAction {
token: '',
refreshRate: '4',
};
this.refreshTimer = null;
this.debounceTimer = 0;
}
setActive() {}
onClear() {
if (this.refreshTimer) {
clearInterval(this.refreshTimer);
this.refreshTimer = null;
}
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
this.debounceTimer = 0;
}
}
setParams(jsn) {
this.config = Object.assign(this.config, (jsn && jsn.param) || {});
this.start();
this.startTimer(() => this.fetchRun(), this.config.refreshRate);
}
onRun() {
@@ -37,18 +23,8 @@ class GiteaAction {
}
}
start() {
this.onClear();
this.fetchRun();
const duration = this.getRefreshDuration();
if (duration > 0) {
this.refreshTimer = setInterval(() => this.fetchRun(), duration * 60 * 1000);
}
}
async fetchRun() {
if (this.debounceTimer) clearTimeout(this.debounceTimer);
this.debounceTimer = setTimeout(async () => {
fetchRun() {
this.debounce(async () => {
if (!this.config.url || !this.config.owner || !this.config.repo) {
this.renderButton(null);
return;
@@ -69,20 +45,11 @@ class GiteaAction {
} catch (e) {
this.renderButton({ error: 'ERR' });
}
}, 300);
});
}
renderButton(run) {
const canvas = document.createElement('canvas');
canvas.width = 196;
canvas.height = 196;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, 196, 196);
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
const { canvas, ctx } = this.createCanvas();
// Owner — top
const ownerLabel = this.config.owner || '?';
@@ -135,18 +102,6 @@ class GiteaAction {
ctx.fillText(info.length > 16 ? info.slice(0, 15) + '…' : info, 98, 172);
}
this.$UD.setBaseDataIcon(this.context, canvas.toDataURL('image/png'));
}
getRefreshDuration() {
switch (this.config.refreshRate) {
case '1': return 1;
case '2': return 2;
case '3': return 5;
case '4': return 10;
case '5': return 30;
case '6': return 60;
default: return 0;
}
this.setIcon(canvas);
}
}
+11 -63
View File
@@ -1,15 +1,12 @@
class PetrolAction {
class PetrolAction extends ActionBase {
constructor($UD, context) {
this.$UD = $UD;
this.context = context;
super($UD, context);
this.config = {
url: '',
stationUuid: '',
fuelType: '',
refreshRate: '1',
};
this.refreshTimer = null;
this.debounceTimer = 0;
this.previousPrice = null;
this.lastDelta = null;
@@ -24,40 +21,18 @@ class PetrolAction {
setActive() {}
onClear() {
if (this.refreshTimer) {
clearInterval(this.refreshTimer);
this.refreshTimer = null;
}
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
this.debounceTimer = 0;
}
}
setParams(jsn) {
const params = (jsn && jsn.param) || {};
this.config = Object.assign(this.config, params);
this.config = Object.assign(this.config, (jsn && jsn.param) || {});
this.$UD.getSettings(this.context);
this.start();
this.startTimer(() => this.fetchPrice(), this.config.refreshRate);
}
onRun() {
this.fetchPrice();
}
start() {
this.onClear();
this.fetchPrice();
const duration = this.getRefreshDuration();
if (duration > 0) {
this.refreshTimer = setInterval(() => this.fetchPrice(), duration * 60 * 1000);
}
}
async fetchPrice() {
if (this.debounceTimer) clearTimeout(this.debounceTimer);
this.debounceTimer = setTimeout(async () => {
fetchPrice() {
this.debounce(async () => {
if (!this.config.url || !this.config.stationUuid || !this.config.fuelType) {
this.renderButton('?', null);
return;
@@ -73,7 +48,7 @@ class PetrolAction {
if (delta !== 0) this.lastDelta = delta;
}
this.previousPrice = current;
this.renderButton(`${raw}`, this.lastDelta);
this.renderButton(`${parseFloat(raw).toFixed(3)}`, this.lastDelta);
this.$UD.setSettings({ ...this.config, previousPrice: this.previousPrice, lastDelta: this.lastDelta }, this.context);
} else {
this.renderButton('N/A', null);
@@ -81,7 +56,7 @@ class PetrolAction {
} catch (e) {
this.renderButton('ERR', null);
}
}, 300);
});
}
parsePrometheus(text) {
@@ -97,55 +72,28 @@ class PetrolAction {
}
renderButton(priceText, delta) {
const canvas = document.createElement('canvas');
canvas.width = 196;
canvas.height = 196;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, 196, 196);
ctx.strokeStyle = '#000';
ctx.lineWidth = 3;
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
const { canvas, ctx } = this.createCanvas();
// Fuel type — top, light blue
ctx.fillStyle = '#7ec8e3';
ctx.font = 'bold 28px "Source Han Sans SC"';
ctx.strokeText(this.config.fuelType, 98, 45);
ctx.fillText(this.config.fuelType, 98, 45);
// Price — middle, yellow
const fSize = priceText.length > 6 ? 34 - priceText.length : 40;
ctx.fillStyle = '#f0c040';
ctx.font = `bold ${fSize}px "Source Han Sans SC"`;
ctx.strokeText(priceText, 98, 105);
ctx.fillText(priceText, 98, 105);
// Delta — bottom
if (delta !== null) {
const arrow = delta > 0 ? '▲' : '▼';
const color = delta > 0 ? '#ff6b6b' : '#6bff6b';
const deltaText = `${arrow} ${Math.abs(delta).toFixed(3)}`;
ctx.fillStyle = color;
ctx.font = '18px "Source Han Sans SC"';
ctx.strokeText(deltaText, 98, 142);
ctx.fillText(deltaText, 98, 142);
ctx.fillText(`${arrow} ${Math.abs(delta).toFixed(3)}`, 98, 142);
}
this.$UD.setBaseDataIcon(this.context, canvas.toDataURL('image/png'));
}
getRefreshDuration() {
switch (this.config.refreshRate) {
case '1': return 1;
case '2': return 2;
case '3': return 5;
case '4': return 10;
case '5': return 30;
case '6': return 60;
default: return 0;
}
this.setIcon(canvas);
}
}
+1
View File
@@ -11,6 +11,7 @@
<script src="../libs/js/utils.js"></script>
<script src="../libs/js/ulanzideckApi.js"></script>
<script src="./ActionBase.js"></script>
<script src="./actions/PetrolAction.js"></script>
<script src="./actions/CopilotAction.js"></script>
<script src="./actions/GiteaAction.js"></script>