- Dashboard (/dashboard): configurable widget system with 6 widget types (current_tasks, category_time, today_progress, next_task, motivace, calendar_mini) stored in localStorage widget_config - Lock screen (/lockscreen): fullscreen with clock, active group badge, up to 4 current tasks, gradient from group color, swipe/tap to unlock - InactivityMonitor: auto-redirect to lockscreen after configurable timeout (only in PWA standalone/fullscreen mode) - Settings: widget toggle switches, inactivity timeout slider, lockscreen preview - manifest.json: added display_override ["fullscreen","standalone"] + orientation portrait Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
55 lines
1.8 KiB
TypeScript
55 lines
1.8 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useRef } from "react";
|
|
import { useRouter, usePathname } from "next/navigation";
|
|
|
|
export default function InactivityMonitor() {
|
|
const router = useRouter();
|
|
const pathname = usePathname();
|
|
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (typeof window === "undefined") return;
|
|
|
|
// Only activate in PWA standalone mode
|
|
const isStandalone =
|
|
window.matchMedia("(display-mode: standalone)").matches ||
|
|
window.matchMedia("(display-mode: fullscreen)").matches ||
|
|
(window.navigator as unknown as { standalone?: boolean }).standalone === true;
|
|
if (!isStandalone) return;
|
|
|
|
// Skip on lockscreen/login pages
|
|
if (pathname?.startsWith("/lockscreen") || pathname?.startsWith("/login") || pathname?.startsWith("/register")) return;
|
|
|
|
// Read timeout from localStorage
|
|
let timeoutMinutes = 5;
|
|
try {
|
|
const stored = localStorage.getItem("widget_config");
|
|
if (stored) {
|
|
const cfg = JSON.parse(stored);
|
|
if (cfg.inactivityTimeout > 0) timeoutMinutes = cfg.inactivityTimeout;
|
|
}
|
|
} catch { /* ignore */ }
|
|
|
|
const timeoutMs = timeoutMinutes * 60 * 1000;
|
|
|
|
function resetTimer() {
|
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
timerRef.current = setTimeout(() => {
|
|
router.push("/lockscreen");
|
|
}, timeoutMs);
|
|
}
|
|
|
|
const events = ["mousedown", "mousemove", "keydown", "touchstart", "scroll", "click"];
|
|
events.forEach(e => window.addEventListener(e, resetTimer, { passive: true }));
|
|
resetTimer();
|
|
|
|
return () => {
|
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
events.forEach(e => window.removeEventListener(e, resetTimer));
|
|
};
|
|
}, [pathname, router]);
|
|
|
|
return null;
|
|
}
|