diff --git a/README.md b/README.md
index 3111bfe..09687d7 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,7 @@ Game enthusiasts who play turn-based games (board games, tabletop RPGs, card gam
* **JavaScript:** For application logic, timer functionality, and event handling.
* **Web Audio API:** For audio feedback (ticking sounds, alerts).
* **Browser API:** For capturing Players' photo.
+* **Screen Wake Lock API:** For preventing of the screen lock in a PWA.
* **Local Storage/IndexedDB:** For persistent storage of player data, timer states, and settings.
* **Service Worker:** Essential for PWA functionality (offline access, push notifications - potential future feature).
* **Manifest File:** Defines the PWA's metadata (name, icons, theme color).
@@ -125,7 +126,7 @@ For an enhanced tactile experience, Nexus Timer supports Smart Buttons based on
}
```
## Building for the production
-Navigate to your project directory on the server
+Navigate to the projects' directory on the server
```bash
cd /virt
```
@@ -154,7 +155,7 @@ Use the editor to create or overwrite the service:
```bash
sudo systemctl edit --force --full virt-nexus-timer.service
```
-Paste the contents from virt-nexus-timer.service, then save and exit.
+Paste the content from `systemd/virt-nexus-timer.service`, then save and exit.
Enable on system boot and start the service
```bash
diff --git a/src/components/PlayerForm.vue b/src/components/PlayerForm.vue
index c44d71d..5a71357 100644
--- a/src/components/PlayerForm.vue
+++ b/src/components/PlayerForm.vue
@@ -41,14 +41,13 @@
"Pass Turn / My Pause" Hotkey:
-
- {{ editablePlayer.hotkey ? editablePlayer.hotkey.toUpperCase() : '-' }}
+ {{ editablePlayer.hotkey ? editablePlayer.hotkey.toUpperCase() : '-' }}
{
+ if ('wakeLock' in navigator && !wakeLockActive) {
+ try {
+ wakeLock = await navigator.wakeLock.request('screen');
+ wakeLockActive = true;
+ console.log('Screen Wake Lock activated.');
+
+ wakeLock.addEventListener('release', () => {
+ console.log('Screen Wake Lock was released.');
+ wakeLockActive = false;
+ wakeLock = null; // Clear the reference
+ // Optionally, re-request if it was released unexpectedly and should be active
+ // For now, we'll let it be re-requested manually by the app logic
+ });
+ } catch (err) {
+ console.error(`Failed to acquire Screen Wake Lock: ${err.name}, ${err.message}`);
+ wakeLock = null;
+ wakeLockActive = false;
+ }
+ } else {
+ console.warn('Screen Wake Lock API not supported or already active.');
+ }
+};
+
+const releaseWakeLock = async () => {
+ if (wakeLock && wakeLockActive) {
+ try {
+ await wakeLock.release();
+ // The 'release' event listener on wakeLock itself will set wakeLockActive = false and wakeLock = null
+ } catch (err) {
+ console.error(`Failed to release Screen Wake Lock: ${err.name}, ${err.message}`);
+ // Even if release fails, mark as inactive to allow re-request
+ wakeLock = null;
+ wakeLockActive = false;
+ }
+ } else {
+ // console.log('No active Screen Wake Lock to release or already released.');
+ }
+};
+
+// Handle visibility changes to re-acquire lock if necessary
+const handleVisibilityChange = () => {
+ if (wakeLock !== null && document.visibilityState === 'visible') {
+ // If we had a wake lock and the page became visible again,
+ // it might have been released by the browser. Try to re-acquire.
+ // This behavior is usually handled automatically by the browser with the 'release' event
+ // but can be a fallback. For now, we rely on manual re-request.
+ // console.log('Page visible, checking wake lock status.');
+ } else if (document.visibilityState === 'hidden' && wakeLockActive) {
+ // The browser usually releases the wake lock when tab is hidden.
+ // Our 'release' event listener should handle this.
+ }
+};
+
+document.addEventListener('visibilitychange', handleVisibilityChange);
+// document.addEventListener('fullscreenchange', handleVisibilityChange); // Also useful for fullscreen
+
+export const WakeLockService = {
+ request: requestWakeLock,
+ release: releaseWakeLock,
+ isActive: () => wakeLockActive,
+};
\ No newline at end of file
diff --git a/src/views/GameView.vue b/src/views/GameView.vue
index 52eb459..123f219 100644
--- a/src/views/GameView.vue
+++ b/src/views/GameView.vue
@@ -83,6 +83,7 @@ import { useRouter } from 'vue-router';
import PlayerDisplay from '../components/PlayerDisplay.vue';
import PlayerListItem from '../components/PlayerListItem.vue';
import { AudioService } from '../services/AudioService';
+import { WakeLockService } from '../services/WakeLockService';
const store = useStore();
const router = useRouter();
@@ -93,7 +94,7 @@ const currentPlayer = computed(() => store.getters.currentPlayer);
const nextPlayer = computed(() => store.getters.nextPlayer);
const gameMode = computed(() => store.getters.gameMode);
const isMuted = computed(() => store.getters.isMuted);
-// const gameRunning = computed(() => store.getters.gameRunning);
+const gameRunning = computed(() => store.getters.gameRunning);
let timerInterval = null;
@@ -130,12 +131,42 @@ onMounted(() => {
timerInterval = setInterval(() => {
store.dispatch('tick');
}, 1000);
+
+ // Attempt to acquire wake lock if game is already running (e.g., page refresh)
+ if (gameRunning.value) {
+ WakeLockService.request();
+ }
});
-onUnmounted(() => {
+onUnmounted(async () => {
clearInterval(timerInterval);
AudioService.stopContinuousTick();
AudioService.cancelPassTurnSound();
+ await WakeLockService.release(); // Release wake lock when leaving the game view
+});
+
+// Watch gameRunning state to acquire/release wake lock
+watch(gameRunning, async (isRunning) => {
+ if (isRunning) {
+ await WakeLockService.request();
+ } else {
+ // Don't release immediately on pause, only if all timers stop and stay stopped.
+ // For simplicity, we'll rely on onUnmounted for now or if explicitly navigating away.
+ // If you want to release on extended pause, you'd need more logic here.
+ // Perhaps only release if gameMode is normal and current player is paused,
+ // or if allTimers mode and ALL are paused.
+ // For now, aggressive release on any gameRunning=false might be too much.
+ // Let's only release it when navigating away or explicitly stopped.
+ // The browser will also release it if the tab is hidden.
+ // Let's make it simpler: release if game isn't running
+ if (!WakeLockService.isActive()) return; // Avoid releasing if not active
+ // A short delay before releasing to avoid flickering if quickly pausing/resuming
+ setTimeout(async () => {
+ if (!store.getters.gameRunning && WakeLockService.isActive()) { // Check again before releasing
+ await WakeLockService.release();
+ }
+ }, 3000); // e.g., release after 3 seconds of no activity
+ }
});
watch(gameMode, (newMode) => {
@@ -180,7 +211,8 @@ watch(() => currentPlayer.value?.isTimerRunning, (isRunning, wasRunning) => {
});
-const navigateToSetup = () => {
+const navigateToSetup = async () => {
+ await WakeLockService.release(); // Release before navigating
const isAnyTimerActive = store.getters.gameRunning;
if (isAnyTimerActive) {
if (window.confirm('Game is active. Going to Setup will pause all timers. Continue?')) {
@@ -192,9 +224,10 @@ const navigateToSetup = () => {
}
};
-const navigateToInfo = () => {
+const navigateToInfo = async () => {
+ await WakeLockService.release(); // Release before navigating
if (store.getters.gameRunning) {
- store.commit('PAUSE_ALL_TIMERS');
+ store.commit('PAUSE_ALL_TIMERS'); // Good practice to pause if navigating away
}
router.push({ name: 'Info' });
};
diff --git a/src/views/SetupView.vue b/src/views/SetupView.vue
index 54d2f38..8f61fd8 100644
--- a/src/views/SetupView.vue
+++ b/src/views/SetupView.vue
@@ -72,9 +72,9 @@
type="button"
id="globalHotkeyStopPauseDisplay"
@click="startCaptureGlobalHotkey('stopPause')"
- class="input-base w-12 h-8 text-center font-mono text-lg p-0 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700"
+ class="input-base w-12 h-8 font-mono text-lg p-0 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700 flex items-center justify-center"
>
- {{ globalHotkeyStopPauseDisplay || '-' }}
+ {{ globalHotkeyStopPauseDisplay || '-' }}
Clear
@@ -91,9 +91,9 @@
type="button"
id="globalHotkeyRunAllDisplay"
@click="startCaptureGlobalHotkey('runAll')"
- class="input-base w-12 h-8 text-center font-mono text-lg p-0 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700"
+ class="input-base w-12 h-8 font-mono text-lg p-0 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700 flex items-center justify-center"
>
- {{ globalHotkeyRunAllDisplay || '-' }}
+ {{ globalHotkeyRunAllDisplay || '-' }}
Clear