fix(applauncher): throttle inactivity timer resets in menus, optimize sound slider updates, and adjust keyboard layout/keys
This commit is contained in:
@@ -1,5 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-01-06 - 3.34.2 - fix(applauncher)
|
||||||
|
throttle inactivity timer resets in menus, optimize sound slider updates, and adjust keyboard layout/keys
|
||||||
|
|
||||||
|
- Add lastActivityTime and throttle resetInactivityTimer to only reset if 5+ seconds have passed in battery, sound, and wifi menus to reduce frequent resets from continuous input.
|
||||||
|
- Remove @mousemove listener in menu containers and rely on mousedown + throttled resets to lower event noise.
|
||||||
|
- Debounce slider mousemove handling in sound menu using requestAnimationFrame and pendingPercentage to batch setVolume calls and cancel RAF on mouseup, preventing excessive volume updates.
|
||||||
|
- Add up/down arrow keys to virtual keyboard, reduce space key width from 4 to 3, and add .key.wide-3 CSS class to support the new sizing.
|
||||||
|
|
||||||
## 2026-01-06 - 3.34.1 - fix(elements/applauncher)
|
## 2026-01-06 - 3.34.1 - fix(elements/applauncher)
|
||||||
add eco app launcher components, wifi/sound/battery menus, demos and new eco-screensaver; replace dees-screensaver (breaking API change)
|
add eco app launcher components, wifi/sound/battery menus, demos and new eco-screensaver; replace dees-screensaver (breaking API change)
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@ecobridge.xyz/catalog',
|
name: '@ecobridge.xyz/catalog',
|
||||||
version: '3.34.1',
|
version: '3.34.2',
|
||||||
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
|
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,6 +248,7 @@ export class EcoApplauncherBatterymenu extends DeesElement {
|
|||||||
private boundHandleClickOutside = this.handleClickOutside.bind(this);
|
private boundHandleClickOutside = this.handleClickOutside.bind(this);
|
||||||
private inactivityTimeout: ReturnType<typeof setTimeout> | null = null;
|
private inactivityTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
private readonly INACTIVITY_TIMEOUT = 60000; // 1 minute
|
private readonly INACTIVITY_TIMEOUT = 60000; // 1 minute
|
||||||
|
private lastActivityTime = 0;
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
const fillClass = this.getFillClass();
|
const fillClass = this.getFillClass();
|
||||||
@@ -255,7 +256,6 @@ export class EcoApplauncherBatterymenu extends DeesElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="menu-container"
|
<div class="menu-container"
|
||||||
@click=${(e: MouseEvent) => e.stopPropagation()}
|
@click=${(e: MouseEvent) => e.stopPropagation()}
|
||||||
@mousemove=${this.resetInactivityTimer}
|
|
||||||
@mousedown=${this.resetInactivityTimer}
|
@mousedown=${this.resetInactivityTimer}
|
||||||
>
|
>
|
||||||
<div class="battery-display">
|
<div class="battery-display">
|
||||||
@@ -340,6 +340,12 @@ export class EcoApplauncherBatterymenu extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private resetInactivityTimer(): void {
|
private resetInactivityTimer(): void {
|
||||||
|
const now = Date.now();
|
||||||
|
// Throttle: only reset if 5+ seconds since last reset
|
||||||
|
if (now - this.lastActivityTime < 5000) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.lastActivityTime = now;
|
||||||
this.clearInactivityTimer();
|
this.clearInactivityTimer();
|
||||||
if (this.open) {
|
if (this.open) {
|
||||||
this.inactivityTimeout = setTimeout(() => {
|
this.inactivityTimeout = setTimeout(() => {
|
||||||
|
|||||||
@@ -78,8 +78,10 @@ const qwertyLayout: IKeyConfig[][] = [
|
|||||||
[
|
[
|
||||||
{ key: '123', display: '123', width: 1.5, type: 'layout', action: 'numbers' },
|
{ key: '123', display: '123', width: 1.5, type: 'layout', action: 'numbers' },
|
||||||
{ key: 'globe', display: '🌐', type: 'special' },
|
{ key: 'globe', display: '🌐', type: 'special' },
|
||||||
{ key: 'space', display: '', width: 4, type: 'space' },
|
{ key: 'space', display: '', width: 3, type: 'space' },
|
||||||
{ key: 'left', display: '←', type: 'special', action: 'arrow-left' },
|
{ key: 'left', display: '←', type: 'special', action: 'arrow-left' },
|
||||||
|
{ key: 'up', display: '↑', type: 'special', action: 'arrow-up' },
|
||||||
|
{ key: 'down', display: '↓', type: 'special', action: 'arrow-down' },
|
||||||
{ key: 'right', display: '→', type: 'special', action: 'arrow-right' },
|
{ key: 'right', display: '→', type: 'special', action: 'arrow-right' },
|
||||||
{ key: 'enter', display: '↵', width: 1.5, type: 'special' },
|
{ key: 'enter', display: '↵', width: 1.5, type: 'special' },
|
||||||
],
|
],
|
||||||
@@ -102,8 +104,10 @@ const numbersLayout: IKeyConfig[][] = [
|
|||||||
[
|
[
|
||||||
{ key: 'ABC', display: 'ABC', width: 1.5, type: 'layout', action: 'qwerty' },
|
{ key: 'ABC', display: 'ABC', width: 1.5, type: 'layout', action: 'qwerty' },
|
||||||
{ key: 'globe', display: '🌐', type: 'special' },
|
{ key: 'globe', display: '🌐', type: 'special' },
|
||||||
{ key: 'space', display: '', width: 4, type: 'space' },
|
{ key: 'space', display: '', width: 3, type: 'space' },
|
||||||
{ key: 'left', display: '←', type: 'special', action: 'arrow-left' },
|
{ key: 'left', display: '←', type: 'special', action: 'arrow-left' },
|
||||||
|
{ key: 'up', display: '↑', type: 'special', action: 'arrow-up' },
|
||||||
|
{ key: 'down', display: '↓', type: 'special', action: 'arrow-down' },
|
||||||
{ key: 'right', display: '→', type: 'special', action: 'arrow-right' },
|
{ key: 'right', display: '→', type: 'special', action: 'arrow-right' },
|
||||||
{ key: 'enter', display: '↵', width: 1.5, type: 'special' },
|
{ key: 'enter', display: '↵', width: 1.5, type: 'special' },
|
||||||
],
|
],
|
||||||
@@ -126,8 +130,10 @@ const symbolsLayout: IKeyConfig[][] = [
|
|||||||
[
|
[
|
||||||
{ key: 'ABC', display: 'ABC', width: 1.5, type: 'layout', action: 'qwerty' },
|
{ key: 'ABC', display: 'ABC', width: 1.5, type: 'layout', action: 'qwerty' },
|
||||||
{ key: 'globe', display: '🌐', type: 'special' },
|
{ key: 'globe', display: '🌐', type: 'special' },
|
||||||
{ key: 'space', display: '', width: 4, type: 'space' },
|
{ key: 'space', display: '', width: 3, type: 'space' },
|
||||||
{ key: 'left', display: '←', type: 'special', action: 'arrow-left' },
|
{ key: 'left', display: '←', type: 'special', action: 'arrow-left' },
|
||||||
|
{ key: 'up', display: '↑', type: 'special', action: 'arrow-up' },
|
||||||
|
{ key: 'down', display: '↓', type: 'special', action: 'arrow-down' },
|
||||||
{ key: 'right', display: '→', type: 'special', action: 'arrow-right' },
|
{ key: 'right', display: '→', type: 'special', action: 'arrow-right' },
|
||||||
{ key: 'enter', display: '↵', width: 1.5, type: 'special' },
|
{ key: 'enter', display: '↵', width: 1.5, type: 'special' },
|
||||||
],
|
],
|
||||||
@@ -245,6 +251,11 @@ export class EcoApplauncherKeyboard extends DeesElement {
|
|||||||
max-width: 100px;
|
max-width: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.key.wide-3 {
|
||||||
|
flex: 3;
|
||||||
|
max-width: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
.key.wide-4 {
|
.key.wide-4 {
|
||||||
flex: 4;
|
flex: 4;
|
||||||
max-width: 180px;
|
max-width: 180px;
|
||||||
|
|||||||
@@ -249,6 +249,7 @@ export class EcoApplauncherSoundmenu extends DeesElement {
|
|||||||
private isDragging = false;
|
private isDragging = false;
|
||||||
private inactivityTimeout: ReturnType<typeof setTimeout> | null = null;
|
private inactivityTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
private readonly INACTIVITY_TIMEOUT = 60000; // 1 minute
|
private readonly INACTIVITY_TIMEOUT = 60000; // 1 minute
|
||||||
|
private lastActivityTime = 0;
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
const volumeIcon = this.getVolumeIcon();
|
const volumeIcon = this.getVolumeIcon();
|
||||||
@@ -256,7 +257,6 @@ export class EcoApplauncherSoundmenu extends DeesElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="menu-container"
|
<div class="menu-container"
|
||||||
@click=${(e: MouseEvent) => e.stopPropagation()}
|
@click=${(e: MouseEvent) => e.stopPropagation()}
|
||||||
@mousemove=${this.resetInactivityTimer}
|
|
||||||
@mousedown=${this.resetInactivityTimer}
|
@mousedown=${this.resetInactivityTimer}
|
||||||
>
|
>
|
||||||
<div class="menu-header">
|
<div class="menu-header">
|
||||||
@@ -368,16 +368,34 @@ export class EcoApplauncherSoundmenu extends DeesElement {
|
|||||||
private handleSliderMouseDown(e: MouseEvent): void {
|
private handleSliderMouseDown(e: MouseEvent): void {
|
||||||
this.isDragging = true;
|
this.isDragging = true;
|
||||||
const slider = e.currentTarget as HTMLElement;
|
const slider = e.currentTarget as HTMLElement;
|
||||||
|
let rafId: number | null = null;
|
||||||
|
let pendingPercentage: number | null = null;
|
||||||
|
|
||||||
|
const updateVolume = () => {
|
||||||
|
if (pendingPercentage !== null) {
|
||||||
|
this.setVolume(pendingPercentage);
|
||||||
|
pendingPercentage = null;
|
||||||
|
}
|
||||||
|
rafId = null;
|
||||||
|
};
|
||||||
|
|
||||||
const handleMouseMove = (moveEvent: MouseEvent) => {
|
const handleMouseMove = (moveEvent: MouseEvent) => {
|
||||||
if (!this.isDragging) return;
|
if (!this.isDragging) return;
|
||||||
const rect = slider.getBoundingClientRect();
|
const rect = slider.getBoundingClientRect();
|
||||||
const percentage = Math.round(((moveEvent.clientX - rect.left) / rect.width) * 100);
|
pendingPercentage = Math.max(0, Math.min(100, Math.round(((moveEvent.clientX - rect.left) / rect.width) * 100)));
|
||||||
this.setVolume(Math.max(0, Math.min(100, percentage)));
|
if (!rafId) {
|
||||||
|
rafId = requestAnimationFrame(updateVolume);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseUp = () => {
|
const handleMouseUp = () => {
|
||||||
this.isDragging = false;
|
this.isDragging = false;
|
||||||
|
if (rafId) {
|
||||||
|
cancelAnimationFrame(rafId);
|
||||||
|
}
|
||||||
|
if (pendingPercentage !== null) {
|
||||||
|
this.setVolume(pendingPercentage);
|
||||||
|
}
|
||||||
document.removeEventListener('mousemove', handleMouseMove);
|
document.removeEventListener('mousemove', handleMouseMove);
|
||||||
document.removeEventListener('mouseup', handleMouseUp);
|
document.removeEventListener('mouseup', handleMouseUp);
|
||||||
};
|
};
|
||||||
@@ -421,6 +439,12 @@ export class EcoApplauncherSoundmenu extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private resetInactivityTimer(): void {
|
private resetInactivityTimer(): void {
|
||||||
|
const now = Date.now();
|
||||||
|
// Throttle: only reset if 5+ seconds since last reset
|
||||||
|
if (now - this.lastActivityTime < 5000) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.lastActivityTime = now;
|
||||||
this.clearInactivityTimer();
|
this.clearInactivityTimer();
|
||||||
if (this.open) {
|
if (this.open) {
|
||||||
this.inactivityTimeout = setTimeout(() => {
|
this.inactivityTimeout = setTimeout(() => {
|
||||||
|
|||||||
@@ -231,12 +231,12 @@ export class EcoApplauncherWifimenu extends DeesElement {
|
|||||||
private boundHandleClickOutside = this.handleClickOutside.bind(this);
|
private boundHandleClickOutside = this.handleClickOutside.bind(this);
|
||||||
private inactivityTimeout: ReturnType<typeof setTimeout> | null = null;
|
private inactivityTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
private readonly INACTIVITY_TIMEOUT = 60000; // 1 minute
|
private readonly INACTIVITY_TIMEOUT = 60000; // 1 minute
|
||||||
|
private lastActivityTime = 0;
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="menu-container"
|
<div class="menu-container"
|
||||||
@click=${(e: MouseEvent) => e.stopPropagation()}
|
@click=${(e: MouseEvent) => e.stopPropagation()}
|
||||||
@mousemove=${this.resetInactivityTimer}
|
|
||||||
@mousedown=${this.resetInactivityTimer}
|
@mousedown=${this.resetInactivityTimer}
|
||||||
>
|
>
|
||||||
<div class="menu-header">
|
<div class="menu-header">
|
||||||
@@ -348,6 +348,12 @@ export class EcoApplauncherWifimenu extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private resetInactivityTimer(): void {
|
private resetInactivityTimer(): void {
|
||||||
|
const now = Date.now();
|
||||||
|
// Throttle: only reset if 5+ seconds since last reset
|
||||||
|
if (now - this.lastActivityTime < 5000) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.lastActivityTime = now;
|
||||||
this.clearInactivityTimer();
|
this.clearInactivityTimer();
|
||||||
if (this.open) {
|
if (this.open) {
|
||||||
this.inactivityTimeout = setTimeout(() => {
|
this.inactivityTimeout = setTimeout(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user