@hawsen-the-first/interactiv 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +326 -0
- package/dist/animations.css +160 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/src/animationBus.d.ts +30 -0
- package/dist/src/animationBus.d.ts.map +1 -0
- package/dist/src/animationBus.js +125 -0
- package/dist/src/appBuilder.d.ts +173 -0
- package/dist/src/appBuilder.d.ts.map +1 -0
- package/dist/src/appBuilder.js +957 -0
- package/dist/src/eventBus.d.ts +100 -0
- package/dist/src/eventBus.d.ts.map +1 -0
- package/dist/src/eventBus.js +326 -0
- package/dist/src/eventManager.d.ts +87 -0
- package/dist/src/eventManager.d.ts.map +1 -0
- package/dist/src/eventManager.js +455 -0
- package/dist/src/garbageCollector.d.ts +68 -0
- package/dist/src/garbageCollector.d.ts.map +1 -0
- package/dist/src/garbageCollector.js +169 -0
- package/dist/src/logger.d.ts +11 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +15 -0
- package/dist/src/navigationManager.d.ts +105 -0
- package/dist/src/navigationManager.d.ts.map +1 -0
- package/dist/src/navigationManager.js +533 -0
- package/dist/src/screensaverManager.d.ts +66 -0
- package/dist/src/screensaverManager.d.ts.map +1 -0
- package/dist/src/screensaverManager.js +417 -0
- package/dist/src/settingsManager.d.ts +48 -0
- package/dist/src/settingsManager.d.ts.map +1 -0
- package/dist/src/settingsManager.js +317 -0
- package/dist/src/stateManager.d.ts +58 -0
- package/dist/src/stateManager.d.ts.map +1 -0
- package/dist/src/stateManager.js +278 -0
- package/dist/src/types.d.ts +32 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +1 -0
- package/dist/utils/generateGuid.d.ts +2 -0
- package/dist/utils/generateGuid.d.ts.map +1 -0
- package/dist/utils/generateGuid.js +19 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +42 -0
- package/dist/utils/template-helpers.d.ts +32 -0
- package/dist/utils/template-helpers.d.ts.map +1 -0
- package/dist/utils/template-helpers.js +24 -0
- package/package.json +59 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { EventOrchestrator } from "./eventBus";
|
|
2
|
+
import { Page } from "./appBuilder";
|
|
3
|
+
import { NavigationManager, type TransitionConfig } from "./navigationManager";
|
|
4
|
+
export interface ScreensaverConfig {
|
|
5
|
+
timeoutSeconds: number;
|
|
6
|
+
page: Page;
|
|
7
|
+
defaultViewId?: string;
|
|
8
|
+
screensaverViewBehavior?: "default" | "specific" | "return";
|
|
9
|
+
specificViewId?: string;
|
|
10
|
+
transitionConfig?: TransitionConfig;
|
|
11
|
+
exitBehavior?: "reset" | "return";
|
|
12
|
+
startingPageId?: string;
|
|
13
|
+
startingViewId?: string;
|
|
14
|
+
activityEvents?: string[];
|
|
15
|
+
excludeSelectors?: string[];
|
|
16
|
+
activateCallback?: () => void;
|
|
17
|
+
deactivateCallback?: () => void;
|
|
18
|
+
blockerCallback?: () => boolean;
|
|
19
|
+
rebootTimeout?: number | null;
|
|
20
|
+
rebootCallback?: () => void;
|
|
21
|
+
}
|
|
22
|
+
export declare class ScreensaverManager {
|
|
23
|
+
private eventBus;
|
|
24
|
+
private orchestrator;
|
|
25
|
+
private navigationManager;
|
|
26
|
+
private config;
|
|
27
|
+
private activityTimer;
|
|
28
|
+
private rebootCheckInterval;
|
|
29
|
+
private isScreensaverActive;
|
|
30
|
+
private lastActivePageId;
|
|
31
|
+
private lastActiveViewId;
|
|
32
|
+
private lastScreensaverViewId;
|
|
33
|
+
private lastActivityResetTime;
|
|
34
|
+
private globalListeners;
|
|
35
|
+
private readonly DEBOUNCE_INTERVAL;
|
|
36
|
+
private readonly DEFAULT_ACTIVITY_EVENTS;
|
|
37
|
+
constructor(orchestrator: EventOrchestrator, navigationManager: NavigationManager);
|
|
38
|
+
private initializeGlobalState;
|
|
39
|
+
private setupEventListeners;
|
|
40
|
+
registerScreensaver(config: ScreensaverConfig): void;
|
|
41
|
+
private validateConfig;
|
|
42
|
+
private setupGlobalActivityListeners;
|
|
43
|
+
private shouldIgnoreActivity;
|
|
44
|
+
private resetActivityTimer;
|
|
45
|
+
private pauseActivityTimer;
|
|
46
|
+
private clearActivityTimer;
|
|
47
|
+
private activateScreensaver;
|
|
48
|
+
private determineScreensaverView;
|
|
49
|
+
private handleScreensaverExit;
|
|
50
|
+
private deactivateScreensaver;
|
|
51
|
+
isActive(): boolean;
|
|
52
|
+
getCurrentConfig(): ScreensaverConfig | null;
|
|
53
|
+
getLastActivePageId(): string | null;
|
|
54
|
+
getLastActiveViewId(): string | null;
|
|
55
|
+
getLastScreensaverViewId(): string | null;
|
|
56
|
+
forceActivate(): void;
|
|
57
|
+
forceDeactivate(): void;
|
|
58
|
+
resetTimer(): void;
|
|
59
|
+
private cleanup;
|
|
60
|
+
destroy(): void;
|
|
61
|
+
private hasRebootTimeoutElapsed;
|
|
62
|
+
private checkAndPerformReboot;
|
|
63
|
+
private startRebootCheckInterval;
|
|
64
|
+
private stopRebootCheckInterval;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=screensaverManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screensaverManager.d.ts","sourceRoot":"","sources":["../../src/screensaverManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAM/E,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,IAAI,CAAC;IACX,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uBAAuB,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,qBAAqB,CAAuB;IACpD,OAAO,CAAC,eAAe,CAIf;IAGR,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAQ;IAG1C,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAStC;gBAEU,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB;IASjF,OAAO,CAAC,qBAAqB;IAkB7B,OAAO,CAAC,mBAAmB;IAwCpB,mBAAmB,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAiC3D,OAAO,CAAC,cAAc;IA0BtB,OAAO,CAAC,4BAA4B;IAmDpC,OAAO,CAAC,oBAAoB;IAgB5B,OAAO,CAAC,kBAAkB;IAe1B,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,kBAAkB;YAOZ,mBAAmB;IAkDjC,OAAO,CAAC,wBAAwB;YAclB,qBAAqB;YAmDrB,qBAAqB;IAI5B,QAAQ,IAAI,OAAO;IAInB,gBAAgB,IAAI,iBAAiB,GAAG,IAAI;IAI5C,mBAAmB,IAAI,MAAM,GAAG,IAAI;IAIpC,mBAAmB,IAAI,MAAM,GAAG,IAAI;IAIpC,wBAAwB,IAAI,MAAM,GAAG,IAAI;IAKzC,aAAa,IAAI,IAAI;IAKrB,eAAe,IAAI,IAAI;IAIvB,UAAU,IAAI,IAAI;IAMzB,OAAO,CAAC,OAAO;IAcR,OAAO,IAAI,IAAI;IAUtB,OAAO,CAAC,uBAAuB;IAc/B,OAAO,CAAC,qBAAqB;IAc7B,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,uBAAuB;CAOhC"}
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import { stateManager } from "./stateManager";
|
|
2
|
+
import { logger } from "./logger";
|
|
3
|
+
const log = logger;
|
|
4
|
+
export class ScreensaverManager {
|
|
5
|
+
eventBus;
|
|
6
|
+
orchestrator;
|
|
7
|
+
navigationManager;
|
|
8
|
+
config = null;
|
|
9
|
+
activityTimer = null;
|
|
10
|
+
rebootCheckInterval = null;
|
|
11
|
+
isScreensaverActive = false;
|
|
12
|
+
lastActivePageId = null;
|
|
13
|
+
lastActiveViewId = null;
|
|
14
|
+
lastScreensaverViewId = null;
|
|
15
|
+
lastActivityResetTime = null;
|
|
16
|
+
globalListeners = [];
|
|
17
|
+
// Debounce interval for activity timer resets (in milliseconds)
|
|
18
|
+
DEBOUNCE_INTERVAL = 1000;
|
|
19
|
+
// Default activity events to monitor
|
|
20
|
+
DEFAULT_ACTIVITY_EVENTS = [
|
|
21
|
+
"mousemove",
|
|
22
|
+
"click",
|
|
23
|
+
"keydown",
|
|
24
|
+
"keypress",
|
|
25
|
+
"touchstart",
|
|
26
|
+
"touchmove",
|
|
27
|
+
"wheel",
|
|
28
|
+
"scroll",
|
|
29
|
+
];
|
|
30
|
+
constructor(orchestrator, navigationManager) {
|
|
31
|
+
this.orchestrator = orchestrator;
|
|
32
|
+
this.navigationManager = navigationManager;
|
|
33
|
+
this.eventBus = orchestrator.registerEventBus("screensaver-manager");
|
|
34
|
+
this.setupEventListeners();
|
|
35
|
+
this.initializeGlobalState();
|
|
36
|
+
}
|
|
37
|
+
initializeGlobalState() {
|
|
38
|
+
if (!stateManager.has("screensaver.isActive")) {
|
|
39
|
+
stateManager.set("screensaver.isActive", false);
|
|
40
|
+
}
|
|
41
|
+
if (!stateManager.has("screensaver.lastActivePageId")) {
|
|
42
|
+
stateManager.set("screensaver.lastActivePageId", null);
|
|
43
|
+
}
|
|
44
|
+
if (!stateManager.has("screensaver.lastActiveViewId")) {
|
|
45
|
+
stateManager.set("screensaver.lastActiveViewId", null);
|
|
46
|
+
}
|
|
47
|
+
if (!stateManager.has("screensaver.lastScreensaverViewId")) {
|
|
48
|
+
stateManager.set("screensaver.lastScreensaverViewId", null);
|
|
49
|
+
}
|
|
50
|
+
if (!stateManager.has("lastReboot")) {
|
|
51
|
+
stateManager.set("lastReboot", Date.now());
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
setupEventListeners() {
|
|
55
|
+
this.eventBus.on("register-screensaver", (e) => {
|
|
56
|
+
const { config } = e.detail;
|
|
57
|
+
this.registerScreensaver(config);
|
|
58
|
+
});
|
|
59
|
+
this.eventBus.on("activate-screensaver", () => {
|
|
60
|
+
this.activateScreensaver();
|
|
61
|
+
});
|
|
62
|
+
this.eventBus.on("deactivate-screensaver", () => {
|
|
63
|
+
this.deactivateScreensaver();
|
|
64
|
+
});
|
|
65
|
+
// Listen for navigation changes to track active pages and views
|
|
66
|
+
const navBus = this.orchestrator.getEventBus("navigation-manager");
|
|
67
|
+
if (navBus) {
|
|
68
|
+
navBus.on("page-changed", (e) => {
|
|
69
|
+
const { newPageId } = e.detail;
|
|
70
|
+
if (!this.isScreensaverActive && newPageId !== this.config?.page.componentId) {
|
|
71
|
+
this.lastActivePageId = newPageId;
|
|
72
|
+
stateManager.set("screensaver.lastActivePageId", newPageId);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
navBus.on("view-changed", (e) => {
|
|
76
|
+
const { newViewId } = e.detail;
|
|
77
|
+
if (this.isScreensaverActive) {
|
|
78
|
+
// Track view changes within screensaver for "return" behavior
|
|
79
|
+
this.lastScreensaverViewId = newViewId;
|
|
80
|
+
stateManager.set("screensaver.lastScreensaverViewId", newViewId);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
this.lastActiveViewId = newViewId;
|
|
84
|
+
stateManager.set("screensaver.lastActiveViewId", newViewId);
|
|
85
|
+
// Timer reset is handled by activity event listeners, not navigation events
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
registerScreensaver(config) {
|
|
91
|
+
this.validateConfig(config);
|
|
92
|
+
// Clean up existing screensaver if any
|
|
93
|
+
if (this.config) {
|
|
94
|
+
this.cleanup();
|
|
95
|
+
}
|
|
96
|
+
this.config = {
|
|
97
|
+
...config,
|
|
98
|
+
exitBehavior: config.exitBehavior || "reset",
|
|
99
|
+
screensaverViewBehavior: config.screensaverViewBehavior || "default",
|
|
100
|
+
activityEvents: config.activityEvents || this.DEFAULT_ACTIVITY_EVENTS,
|
|
101
|
+
excludeSelectors: config.excludeSelectors || [],
|
|
102
|
+
transitionConfig: config.transitionConfig || {
|
|
103
|
+
type: "snap",
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
// Register the screensaver page with navigation manager
|
|
107
|
+
const navBus = this.orchestrator.getEventBus("navigation-manager");
|
|
108
|
+
if (navBus) {
|
|
109
|
+
navBus.emit("register-page", { page: this.config.page });
|
|
110
|
+
}
|
|
111
|
+
this.setupGlobalActivityListeners();
|
|
112
|
+
this.resetActivityTimer();
|
|
113
|
+
log.trace(`Screensaver registered with ${config.timeoutSeconds}s timeout and '${this.config.exitBehavior}' exit behavior`);
|
|
114
|
+
}
|
|
115
|
+
validateConfig(config) {
|
|
116
|
+
if (!config.page) {
|
|
117
|
+
throw new Error("Screensaver page is required");
|
|
118
|
+
}
|
|
119
|
+
if (config.timeoutSeconds <= 0) {
|
|
120
|
+
throw new Error("timeoutSeconds must be greater than 0");
|
|
121
|
+
}
|
|
122
|
+
if (config.exitBehavior === "reset" && !config.startingPageId) {
|
|
123
|
+
throw new Error('startingPageId is required when exitBehavior is "reset"');
|
|
124
|
+
}
|
|
125
|
+
if (config.exitBehavior && !["reset", "return"].includes(config.exitBehavior)) {
|
|
126
|
+
throw new Error('exitBehavior must be either "reset" or "return"');
|
|
127
|
+
}
|
|
128
|
+
if (config.screensaverViewBehavior === "specific" && !config.specificViewId) {
|
|
129
|
+
throw new Error('specificViewId is required when screensaverViewBehavior is "specific"');
|
|
130
|
+
}
|
|
131
|
+
if (config.screensaverViewBehavior && !["default", "specific", "return"].includes(config.screensaverViewBehavior)) {
|
|
132
|
+
throw new Error('screensaverViewBehavior must be "default", "specific", or "return"');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
setupGlobalActivityListeners() {
|
|
136
|
+
if (!this.config)
|
|
137
|
+
return;
|
|
138
|
+
const activityHandler = (event) => {
|
|
139
|
+
// Check if event should be ignored based on excludeSelectors
|
|
140
|
+
if (this.shouldIgnoreActivity(event)) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (this.isScreensaverActive) {
|
|
144
|
+
// If screensaver is active, any activity should exit it
|
|
145
|
+
this.handleScreensaverExit();
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
// If screensaver is not active, check debounce before resetting the timer
|
|
149
|
+
const now = Date.now();
|
|
150
|
+
if (this.lastActivityResetTime === null ||
|
|
151
|
+
now - this.lastActivityResetTime >= this.DEBOUNCE_INTERVAL) {
|
|
152
|
+
this.resetActivityTimer();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
// Add listeners to document for global coverage
|
|
157
|
+
this.config.activityEvents.forEach((eventType) => {
|
|
158
|
+
const listener = activityHandler.bind(this);
|
|
159
|
+
document.addEventListener(eventType, listener, { passive: true });
|
|
160
|
+
this.globalListeners.push({
|
|
161
|
+
element: document,
|
|
162
|
+
type: eventType,
|
|
163
|
+
listener,
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
// Also listen for visibility changes (tab switching, etc.)
|
|
167
|
+
const visibilityHandler = () => {
|
|
168
|
+
if (document.hidden) {
|
|
169
|
+
this.pauseActivityTimer();
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
this.resetActivityTimer();
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
document.addEventListener("visibilitychange", visibilityHandler);
|
|
176
|
+
this.globalListeners.push({
|
|
177
|
+
element: document,
|
|
178
|
+
type: "visibilitychange",
|
|
179
|
+
listener: visibilityHandler,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
shouldIgnoreActivity(event) {
|
|
183
|
+
if (!this.config?.excludeSelectors?.length)
|
|
184
|
+
return false;
|
|
185
|
+
const target = event.target;
|
|
186
|
+
if (!target)
|
|
187
|
+
return false;
|
|
188
|
+
return this.config.excludeSelectors.some((selector) => {
|
|
189
|
+
try {
|
|
190
|
+
return target.matches(selector) || target.closest(selector);
|
|
191
|
+
}
|
|
192
|
+
catch (e) {
|
|
193
|
+
log.warn(`Invalid exclude selector: ${selector} ${e.message}`);
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
resetActivityTimer() {
|
|
199
|
+
if (!this.config)
|
|
200
|
+
return;
|
|
201
|
+
this.clearActivityTimer();
|
|
202
|
+
this.activityTimer = window.setTimeout(() => {
|
|
203
|
+
this.activateScreensaver();
|
|
204
|
+
}, this.config.timeoutSeconds * 1000);
|
|
205
|
+
// Record the timestamp for debouncing
|
|
206
|
+
this.lastActivityResetTime = Date.now();
|
|
207
|
+
log.trace(`Activity timer reset for ${this.config.timeoutSeconds} seconds`);
|
|
208
|
+
}
|
|
209
|
+
pauseActivityTimer() {
|
|
210
|
+
this.clearActivityTimer();
|
|
211
|
+
// Reset the debounce timestamp when pausing
|
|
212
|
+
this.lastActivityResetTime = null;
|
|
213
|
+
log.trace("Activity timer paused");
|
|
214
|
+
}
|
|
215
|
+
clearActivityTimer() {
|
|
216
|
+
if (this.activityTimer !== null) {
|
|
217
|
+
clearTimeout(this.activityTimer);
|
|
218
|
+
this.activityTimer = null;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async activateScreensaver() {
|
|
222
|
+
if (!this.config || this.isScreensaverActive)
|
|
223
|
+
return;
|
|
224
|
+
if (this.config.blockerCallback && this.config.blockerCallback()) {
|
|
225
|
+
this.resetActivityTimer();
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
log.trace("Activating screensaver");
|
|
229
|
+
// Store the current page and view before switching to screensaver
|
|
230
|
+
const currentPageId = this.navigationManager.getCurrentPageId();
|
|
231
|
+
const currentViewId = this.navigationManager.getCurrentViewId();
|
|
232
|
+
if (currentPageId && currentPageId !== this.config.page.componentId) {
|
|
233
|
+
this.lastActivePageId = currentPageId;
|
|
234
|
+
this.lastActiveViewId = currentViewId;
|
|
235
|
+
stateManager.set("screensaver.lastActivePageId", currentPageId);
|
|
236
|
+
stateManager.set("screensaver.lastActiveViewId", currentViewId);
|
|
237
|
+
}
|
|
238
|
+
this.isScreensaverActive = true;
|
|
239
|
+
stateManager.set("screensaver.isActive", true);
|
|
240
|
+
try {
|
|
241
|
+
// Navigate to screensaver page
|
|
242
|
+
await this.navigationManager.navigateToPage(this.config.page.componentId, this.config.transitionConfig);
|
|
243
|
+
// Determine which view to show based on screensaverViewBehavior
|
|
244
|
+
const targetViewId = this.determineScreensaverView();
|
|
245
|
+
if (targetViewId) {
|
|
246
|
+
await this.navigationManager.navigateToView(targetViewId, { type: "snap" });
|
|
247
|
+
}
|
|
248
|
+
this.eventBus.emit("screensaver-activated", {
|
|
249
|
+
pageId: this.config.page.componentId,
|
|
250
|
+
viewId: targetViewId,
|
|
251
|
+
previousPageId: this.lastActivePageId,
|
|
252
|
+
previousViewId: this.lastActiveViewId,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
log.error("Failed to activate screensaver:", error);
|
|
257
|
+
this.isScreensaverActive = false;
|
|
258
|
+
stateManager.set("screensaver.isActive", false);
|
|
259
|
+
}
|
|
260
|
+
if (this.config.activateCallback)
|
|
261
|
+
this.config.activateCallback();
|
|
262
|
+
// Start periodic reboot check and check immediately
|
|
263
|
+
this.startRebootCheckInterval();
|
|
264
|
+
this.checkAndPerformReboot();
|
|
265
|
+
}
|
|
266
|
+
determineScreensaverView() {
|
|
267
|
+
if (!this.config)
|
|
268
|
+
return null;
|
|
269
|
+
switch (this.config.screensaverViewBehavior) {
|
|
270
|
+
case "return":
|
|
271
|
+
return this.lastScreensaverViewId || this.config.defaultViewId || null;
|
|
272
|
+
case "specific":
|
|
273
|
+
return this.config.specificViewId || null;
|
|
274
|
+
case "default":
|
|
275
|
+
default:
|
|
276
|
+
return this.config.defaultViewId || null;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
async handleScreensaverExit() {
|
|
280
|
+
if (!this.config || !this.isScreensaverActive)
|
|
281
|
+
return;
|
|
282
|
+
log.trace(`Exiting screensaver with '${this.config.exitBehavior}' behavior`);
|
|
283
|
+
// Stop the reboot check interval
|
|
284
|
+
this.stopRebootCheckInterval();
|
|
285
|
+
if (this.config.deactivateCallback)
|
|
286
|
+
this.config.deactivateCallback();
|
|
287
|
+
this.isScreensaverActive = false;
|
|
288
|
+
stateManager.set("screensaver.isActive", false);
|
|
289
|
+
let targetPageId = null;
|
|
290
|
+
let targetViewId = null;
|
|
291
|
+
if (this.config.exitBehavior === "return") {
|
|
292
|
+
targetPageId = this.lastActivePageId;
|
|
293
|
+
targetViewId = this.lastActiveViewId;
|
|
294
|
+
}
|
|
295
|
+
else if (this.config.exitBehavior === "reset") {
|
|
296
|
+
targetPageId = this.config.startingPageId || null;
|
|
297
|
+
targetViewId = this.config.startingViewId || null;
|
|
298
|
+
}
|
|
299
|
+
if (targetPageId) {
|
|
300
|
+
try {
|
|
301
|
+
await this.navigationManager.navigateToPage(targetPageId, this.config.transitionConfig);
|
|
302
|
+
if (targetViewId) {
|
|
303
|
+
await this.navigationManager.navigateToView(targetViewId, { type: "snap" });
|
|
304
|
+
}
|
|
305
|
+
this.eventBus.emit("screensaver-deactivated", {
|
|
306
|
+
targetPageId,
|
|
307
|
+
targetViewId,
|
|
308
|
+
exitBehavior: this.config.exitBehavior,
|
|
309
|
+
});
|
|
310
|
+
// Reset timer for next cycle
|
|
311
|
+
this.resetActivityTimer();
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
log.error("Failed to exit screensaver:", error);
|
|
315
|
+
// Reset state on error
|
|
316
|
+
this.isScreensaverActive = true;
|
|
317
|
+
stateManager.set("screensaver.isActive", true);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
log.warn("No target page available for screensaver exit");
|
|
322
|
+
this.resetActivityTimer();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
async deactivateScreensaver() {
|
|
326
|
+
await this.handleScreensaverExit();
|
|
327
|
+
}
|
|
328
|
+
isActive() {
|
|
329
|
+
return this.isScreensaverActive;
|
|
330
|
+
}
|
|
331
|
+
getCurrentConfig() {
|
|
332
|
+
return this.config;
|
|
333
|
+
}
|
|
334
|
+
getLastActivePageId() {
|
|
335
|
+
return this.lastActivePageId;
|
|
336
|
+
}
|
|
337
|
+
getLastActiveViewId() {
|
|
338
|
+
return this.lastActiveViewId;
|
|
339
|
+
}
|
|
340
|
+
getLastScreensaverViewId() {
|
|
341
|
+
return this.lastScreensaverViewId;
|
|
342
|
+
}
|
|
343
|
+
// Manual control methods
|
|
344
|
+
forceActivate() {
|
|
345
|
+
this.clearActivityTimer();
|
|
346
|
+
this.activateScreensaver();
|
|
347
|
+
}
|
|
348
|
+
forceDeactivate() {
|
|
349
|
+
this.deactivateScreensaver();
|
|
350
|
+
}
|
|
351
|
+
resetTimer() {
|
|
352
|
+
if (!this.isScreensaverActive) {
|
|
353
|
+
this.resetActivityTimer();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
cleanup() {
|
|
357
|
+
this.clearActivityTimer();
|
|
358
|
+
this.stopRebootCheckInterval();
|
|
359
|
+
// Remove all global event listeners
|
|
360
|
+
this.globalListeners.forEach(({ element, type, listener }) => {
|
|
361
|
+
element.removeEventListener(type, listener);
|
|
362
|
+
});
|
|
363
|
+
this.globalListeners.length = 0;
|
|
364
|
+
this.isScreensaverActive = false;
|
|
365
|
+
stateManager.set("screensaver.isActive", false);
|
|
366
|
+
}
|
|
367
|
+
destroy() {
|
|
368
|
+
this.cleanup();
|
|
369
|
+
this.config = null;
|
|
370
|
+
this.lastActivePageId = null;
|
|
371
|
+
this.lastActiveViewId = null;
|
|
372
|
+
this.lastScreensaverViewId = null;
|
|
373
|
+
log.trace("ScreensaverManager destroyed");
|
|
374
|
+
}
|
|
375
|
+
// Reboot timeout checking methods
|
|
376
|
+
hasRebootTimeoutElapsed() {
|
|
377
|
+
if (!this.config?.rebootTimeout)
|
|
378
|
+
return false;
|
|
379
|
+
const lastReboot = stateManager.get("lastReboot");
|
|
380
|
+
if (!lastReboot) {
|
|
381
|
+
// Initialize timestamp on first check
|
|
382
|
+
stateManager.set("lastReboot", Date.now());
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
const elapsedMinutes = (Date.now() - lastReboot) / (1000 * 60);
|
|
386
|
+
return elapsedMinutes >= this.config.rebootTimeout;
|
|
387
|
+
}
|
|
388
|
+
checkAndPerformReboot() {
|
|
389
|
+
if (!this.hasRebootTimeoutElapsed())
|
|
390
|
+
return;
|
|
391
|
+
log.trace("Reboot timeout elapsed, performing reboot");
|
|
392
|
+
// Call the reboot callback function
|
|
393
|
+
if (this.config?.rebootCallback) {
|
|
394
|
+
this.config.rebootCallback();
|
|
395
|
+
}
|
|
396
|
+
// Reset the timestamp after reboot is triggered
|
|
397
|
+
stateManager.set("lastReboot", Date.now());
|
|
398
|
+
}
|
|
399
|
+
startRebootCheckInterval() {
|
|
400
|
+
if (!this.config?.rebootTimeout)
|
|
401
|
+
return;
|
|
402
|
+
// Clear any existing interval
|
|
403
|
+
this.stopRebootCheckInterval();
|
|
404
|
+
// Check every 10 minutes (600000 ms)
|
|
405
|
+
this.rebootCheckInterval = window.setInterval(() => {
|
|
406
|
+
this.checkAndPerformReboot();
|
|
407
|
+
}, 600000);
|
|
408
|
+
log.trace("Reboot check interval started (10 minute intervals)");
|
|
409
|
+
}
|
|
410
|
+
stopRebootCheckInterval() {
|
|
411
|
+
if (this.rebootCheckInterval !== null) {
|
|
412
|
+
clearInterval(this.rebootCheckInterval);
|
|
413
|
+
this.rebootCheckInterval = null;
|
|
414
|
+
log.trace("Reboot check interval stopped");
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { EventOrchestrator } from "./eventBus";
|
|
2
|
+
import { View } from "./appBuilder";
|
|
3
|
+
import { NavigationManager, type TransitionConfig } from "./navigationManager";
|
|
4
|
+
export interface SettingsConfig {
|
|
5
|
+
view: View;
|
|
6
|
+
transitionConfig?: TransitionConfig;
|
|
7
|
+
exitBehavior?: "reset" | "return";
|
|
8
|
+
startingViewId?: string;
|
|
9
|
+
cornerTouchRadius?: number;
|
|
10
|
+
touchTimeout?: number;
|
|
11
|
+
debugMode?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare class SettingsManager {
|
|
14
|
+
private eventBus;
|
|
15
|
+
private orchestrator;
|
|
16
|
+
private navigationManager;
|
|
17
|
+
private config;
|
|
18
|
+
private isSettingsActive;
|
|
19
|
+
private lastActiveViewId;
|
|
20
|
+
private touchSequenceState;
|
|
21
|
+
private lastEventTime;
|
|
22
|
+
private touchListeners;
|
|
23
|
+
private readonly DEFAULT_CORNER_RADIUS;
|
|
24
|
+
private readonly DEFAULT_TOUCH_TIMEOUT;
|
|
25
|
+
private readonly EVENT_DEBOUNCE_MS;
|
|
26
|
+
constructor(orchestrator: EventOrchestrator, navigationManager: NavigationManager);
|
|
27
|
+
private initializeGlobalState;
|
|
28
|
+
private setupEventListeners;
|
|
29
|
+
registerSettings(config: SettingsConfig): void;
|
|
30
|
+
private validateConfig;
|
|
31
|
+
private setupCornerTouchListeners;
|
|
32
|
+
private handleTouchAttempt;
|
|
33
|
+
private detectCornerTouch;
|
|
34
|
+
private getExpectedCorner;
|
|
35
|
+
private resetTouchSequence;
|
|
36
|
+
private activateSettings;
|
|
37
|
+
private handleSettingsExit;
|
|
38
|
+
private deactivateSettings;
|
|
39
|
+
isActive(): boolean;
|
|
40
|
+
getCurrentConfig(): SettingsConfig | null;
|
|
41
|
+
getLastActiveViewId(): string | null;
|
|
42
|
+
forceActivate(): void;
|
|
43
|
+
forceDeactivate(): void;
|
|
44
|
+
resetSequence(): void;
|
|
45
|
+
private cleanup;
|
|
46
|
+
destroy(): void;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=settingsManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settingsManager.d.ts","sourceRoot":"","sources":["../../src/settingsManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAM/E,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,IAAI,CAAC;IACX,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAOD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,kBAAkB,CAGxB;IACF,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,cAAc,CAId;IAGR,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAO;IAC7C,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAQ;IAC9C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAM;gBAE5B,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,iBAAiB;IASjF,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,mBAAmB;IA2BpB,gBAAgB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAkCrD,OAAO,CAAC,cAAc;IAsBtB,OAAO,CAAC,yBAAyB;IAwBjC,OAAO,CAAC,kBAAkB;IA+D1B,OAAO,CAAC,iBAAiB;IA4BzB,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,kBAAkB;YAQZ,gBAAgB;YA6BhB,kBAAkB;YAmClB,kBAAkB;IAIzB,QAAQ,IAAI,OAAO;IAInB,gBAAgB,IAAI,cAAc,GAAG,IAAI;IAIzC,mBAAmB,IAAI,MAAM,GAAG,IAAI;IAKpC,aAAa,IAAI,IAAI;IAKrB,eAAe,IAAI,IAAI;IAIvB,aAAa,IAAI,IAAI;IAI5B,OAAO,CAAC,OAAO;IAYR,OAAO,IAAI,IAAI;CAMvB"}
|