diff --git a/css/styles.css b/css/styles.css index 53c4ded..d0772d7 100644 --- a/css/styles.css +++ b/css/styles.css @@ -453,7 +453,7 @@ input[type="file"] { } .action-button { - background-color: #6c757d; + background-color: #3498db; color: white; border: none; padding: 0.5rem 1rem; @@ -463,7 +463,20 @@ input[type="file"] { } .action-button:hover { - background-color: #5a6268; + background-color: #2980b9; +} + +button:disabled { + background-color: #cccccc !important; /* Gray background */ + color: #888888 !important; /* Darker gray text */ + cursor: not-allowed !important; /* Change cursor */ + opacity: 0.7 !important; /* Reduce opacity */ +} + +.cancel-button:disabled { + background-color: #e0e0e0 !important; /* Light gray */ + color: #999999 !important; + border: 1px solid #cccccc !important; } .message-output { diff --git a/index.html b/index.html index bc22c89..f20efe9 100644 --- a/index.html +++ b/index.html @@ -137,7 +137,7 @@
- +
@@ -147,8 +147,7 @@
- - +
Monitoring for service worker messages...
@@ -221,7 +220,7 @@ } const webhookUrl = `${backendUrl}/webhook/${action}`; - output.textContent = `Sending request to: ${webhookUrl}\n\nHeaders:\n`; + output.textContent = `Sending request to: ${webhookUrl}\n`; output.textContent += `Authorization: Basic ****\n`; output.textContent += `Button-Name: ${buttonName}\n`; output.textContent += `Timestamp: ${timestamp}\n`; diff --git a/js b/js deleted file mode 120000 index 1fb06d7..0000000 --- a/js +++ /dev/null @@ -1 +0,0 @@ -src/js \ No newline at end of file diff --git a/src/js/app.js b/js/app.js similarity index 100% rename from src/js/app.js rename to js/app.js diff --git a/src/js/config.js b/js/config.js similarity index 100% rename from src/js/config.js rename to js/config.js diff --git a/src/js/core/eventHandlers.js b/js/core/eventHandlers.js similarity index 100% rename from src/js/core/eventHandlers.js rename to js/core/eventHandlers.js diff --git a/src/js/core/gameActions.js b/js/core/gameActions.js similarity index 100% rename from src/js/core/gameActions.js rename to js/core/gameActions.js diff --git a/src/js/core/playerManager.js b/js/core/playerManager.js similarity index 100% rename from src/js/core/playerManager.js rename to js/core/playerManager.js diff --git a/src/js/core/state.js b/js/core/state.js similarity index 100% rename from src/js/core/state.js rename to js/core/state.js diff --git a/src/js/core/timer.js b/js/core/timer.js similarity index 100% rename from src/js/core/timer.js rename to js/core/timer.js diff --git a/src/js/env-loader.js b/js/env-loader.js similarity index 100% rename from src/js/env-loader.js rename to js/env-loader.js diff --git a/src/js/services/pushFlicIntegration.js b/js/services/pushFlicIntegration.js similarity index 82% rename from src/js/services/pushFlicIntegration.js rename to js/services/pushFlicIntegration.js index a46aba2..d2c5074 100644 --- a/src/js/services/pushFlicIntegration.js +++ b/js/services/pushFlicIntegration.js @@ -90,26 +90,16 @@ async function subscribeToPush() { console.log('Notification permission granted.'); - // IMPORTANT: Force checking for credentials - even with an existing subscription - // Always allow the user to set/update credentials + // Get stored credentials but don't prompt let credentials = getBasicAuthCredentials(); const hasExistingCreds = !!credentials; console.log('Has existing credentials:', hasExistingCreds); - // Ask for credentials every time unless one exists + // No prompting for credentials - user must enter them manually in the UI if (!credentials) { - const confirmAuth = confirm('Do you want to set up credentials for push notifications now?'); - if (!confirmAuth) { - console.log('User declined to provide auth credentials.'); - return; - } - - credentials = promptForCredentials(); - if (!credentials) { - console.log('User canceled credential input.'); - alert('Authentication required to set up push notifications.'); - return; - } + console.log('No credentials found. User needs to enter them manually.'); + // Just return if no credentials are available + return; } const registration = await navigator.serviceWorker.ready; @@ -167,20 +157,8 @@ async function sendSubscriptionToServer(subscription, buttonId) { console.log(`Sending subscription for button "${buttonId}" to backend...`); const credentials = getBasicAuthCredentials(); if (!credentials) { - // One more chance to enter credentials if needed - const confirmAuth = confirm('Authentication required to complete setup. Provide credentials now?'); - if (!confirmAuth) { - alert('Authentication required to save button link.'); - return; - } - - const newCredentials = promptForCredentials(); - if (!newCredentials) { - alert('Authentication required to save button link.'); - return; - } - - credentials = newCredentials; + console.log('No credentials found. User needs to enter them manually.'); + return; } const headers = { 'Content-Type': 'application/json' }; @@ -199,7 +177,7 @@ async function sendSubscriptionToServer(subscription, buttonId) { if (response.ok) { const result = await response.json(); console.log('Subscription sent successfully:', result.message); - alert('Push notification setup completed successfully!'); + // Success alert removed as requested } else { let errorMsg = `Server error: ${response.status}`; if (response.status === 401 || response.status === 403) { @@ -289,9 +267,48 @@ export function setupPushNotifications() { // Function to force re-authentication even if credentials exist export function forceCredentialsPrompt() { - // Remove existing credentials to force new ones - localStorage.removeItem('basicAuthCredentials'); - console.log('[PushFlic] Removed stored credentials, will prompt on next subscription attempt'); - // Trigger the subscription process again + // Get credentials from the form fields if available + const usernameField = document.getElementById('pushUsername'); + const passwordField = document.getElementById('pushPassword'); + + let credentialsUpdated = false; + + if (usernameField && passwordField && usernameField.value.trim() && passwordField.value.trim()) { + // Save the entered credentials to localStorage + const credentials = { + username: usernameField.value.trim(), + password: passwordField.value.trim() + }; + localStorage.setItem('basicAuthCredentials', JSON.stringify(credentials)); + console.log('[PushFlic] Saved credentials from form fields'); + credentialsUpdated = true; + } else { + // Check if we have stored credentials + try { + const storedAuth = localStorage.getItem('basicAuthCredentials'); + if (storedAuth) { + const credentials = JSON.parse(storedAuth); + if (credentials.username && credentials.password) { + // We have stored credentials, no need to update + console.log('[PushFlic] Using stored credentials'); + credentialsUpdated = true; + + // Update the form fields if they exist + if (usernameField && passwordField) { + usernameField.value = credentials.username; + passwordField.value = credentials.password; + } + } + } + } catch (error) { + console.error('[PushFlic] Error accessing stored credentials:', error); + } + } + + if (!credentialsUpdated) { + console.log('[PushFlic] No valid credentials available'); + } + + // Trigger the subscription process setupPushNotifications(); } \ No newline at end of file diff --git a/src/js/services/serviceWorkerManager.js b/js/services/serviceWorkerManager.js similarity index 96% rename from src/js/services/serviceWorkerManager.js rename to js/services/serviceWorkerManager.js index 7b9b549..0eb30b5 100644 --- a/src/js/services/serviceWorkerManager.js +++ b/js/services/serviceWorkerManager.js @@ -10,10 +10,8 @@ export function setFlicActionHandlers(handlers) { flicActionHandlers = handlers; console.log('[ServiceWorkerManager] Stored action handlers:', Object.keys(flicActionHandlers)); - // If pushFlic is already initialized, update its handlers directly - if (navigator.serviceWorker.controller) { - pushFlic.initPushFlic(flicActionHandlers); - } + // Always pass handlers to pushFlic, regardless of service worker state + pushFlic.initPushFlic(flicActionHandlers); } else { console.warn('[ServiceWorkerManager] No action handlers provided to setFlicActionHandlers!'); } diff --git a/src/js/ui/audio.js b/js/ui/audio.js similarity index 100% rename from src/js/ui/audio.js rename to js/ui/audio.js diff --git a/src/js/ui/camera.js b/js/ui/camera.js similarity index 100% rename from src/js/ui/camera.js rename to js/ui/camera.js diff --git a/src/js/ui/pushSettingsUI.js b/js/ui/pushSettingsUI.js similarity index 59% rename from src/js/ui/pushSettingsUI.js rename to js/ui/pushSettingsUI.js index b50de67..e131f6c 100644 --- a/src/js/ui/pushSettingsUI.js +++ b/js/ui/pushSettingsUI.js @@ -15,8 +15,8 @@ const elements = { pushUnsubscribeButton: null, pushResubscribeButton: null, // Message monitor elements - clearMessagesButton: null, - swMessagesOutput: null + swMessagesOutput: null, + simulateClickButton: null }; // --- State --- @@ -39,8 +39,8 @@ export function initPushSettingsUI() { elements.pushResubscribeButton = document.getElementById('pushResubscribeButton'); // Message Monitor elements - elements.clearMessagesButton = document.getElementById('clearMessagesButton'); elements.swMessagesOutput = document.getElementById('swMessagesOutput'); + elements.simulateClickButton = document.getElementById('simulateClickButton'); // Set up event listeners elements.pushSettingsButton.addEventListener('click', openPushSettingsModal); @@ -48,9 +48,6 @@ export function initPushSettingsUI() { elements.pushSaveButton.addEventListener('click', saveCredentialsAndSubscribe); elements.pushUnsubscribeButton.addEventListener('click', unsubscribeFromPush); elements.pushResubscribeButton.addEventListener('click', resubscribeToPush); - - // Message Monitor event listeners - elements.clearMessagesButton.addEventListener('click', clearMessages); // Initial status check updateNotificationStatus(); @@ -122,18 +119,14 @@ function stopMessageMonitoring() { } } -// Clear the messages output -function clearMessages() { - if (elements.swMessagesOutput) { - elements.swMessagesOutput.textContent = 'Monitoring for service worker messages...'; - } -} - // Update the notification permission status display function updateNotificationStatus() { if (!('Notification' in window)) { elements.notificationPermissionStatus.textContent = 'Not Supported'; elements.notificationPermissionStatus.className = 'status-denied'; + // Disable subscribe button when notifications are not supported + elements.pushResubscribeButton.disabled = true; + elements.pushResubscribeButton.classList.add('disabled'); return; } @@ -143,12 +136,21 @@ function updateNotificationStatus() { switch (permission) { case 'granted': elements.notificationPermissionStatus.className = 'status-granted'; + // Enable subscribe button when permission is granted + elements.pushResubscribeButton.disabled = false; + elements.pushResubscribeButton.classList.remove('disabled'); break; case 'denied': elements.notificationPermissionStatus.className = 'status-denied'; + // Disable subscribe button when permission is denied + elements.pushResubscribeButton.disabled = true; + elements.pushResubscribeButton.classList.add('disabled'); break; default: elements.notificationPermissionStatus.className = 'status-default'; + // Enable subscribe button for default state (prompt) + elements.pushResubscribeButton.disabled = false; + elements.pushResubscribeButton.classList.remove('disabled'); } } @@ -157,6 +159,14 @@ async function updateSubscriptionStatus() { if (!('serviceWorker' in navigator) || !('PushManager' in window)) { elements.subscriptionStatus.textContent = 'Not Supported'; elements.subscriptionStatus.className = 'status-denied'; + // Disable unsubscribe button when not supported + elements.pushUnsubscribeButton.disabled = true; + // Set subscribe button text + elements.pushResubscribeButton.textContent = 'Subscribe'; + // Disable simulate button when not supported + if (elements.simulateClickButton) { + elements.simulateClickButton.disabled = true; + } return; } @@ -167,14 +177,38 @@ async function updateSubscriptionStatus() { if (currentSubscription) { elements.subscriptionStatus.textContent = 'active'; elements.subscriptionStatus.className = 'status-active'; + // Enable unsubscribe button when subscription is active + elements.pushUnsubscribeButton.disabled = false; + // Change subscribe button text to "Re-subscribe" + elements.pushResubscribeButton.textContent = 'Re-subscribe'; + // Enable simulate button when subscription is active + if (elements.simulateClickButton) { + elements.simulateClickButton.disabled = false; + } } else { elements.subscriptionStatus.textContent = 'Not Subscribed'; elements.subscriptionStatus.className = 'status-inactive'; + // Disable unsubscribe button when not subscribed + elements.pushUnsubscribeButton.disabled = true; + // Set subscribe button text + elements.pushResubscribeButton.textContent = 'Subscribe'; + // Disable simulate button when not subscribed + if (elements.simulateClickButton) { + elements.simulateClickButton.disabled = true; + } } } catch (error) { console.error('Error checking subscription status:', error); elements.subscriptionStatus.textContent = 'Error'; elements.subscriptionStatus.className = 'status-denied'; + // Disable unsubscribe button on error + elements.pushUnsubscribeButton.disabled = true; + // Set subscribe button text + elements.pushResubscribeButton.textContent = 'Subscribe'; + // Disable simulate button on error + if (elements.simulateClickButton) { + elements.simulateClickButton.disabled = true; + } } } @@ -196,7 +230,7 @@ function loadSavedCredentials() { // --- Action Functions --- -// Save credentials and subscribe to push notifications +// Save credentials and close the modal async function saveCredentialsAndSubscribe() { const username = elements.pushUsername.value.trim(); const password = elements.pushPassword.value.trim(); @@ -210,26 +244,6 @@ async function saveCredentialsAndSubscribe() { const credentials = { username, password }; localStorage.setItem('basicAuthCredentials', JSON.stringify(credentials)); - // Request notification permission if needed - if (Notification.permission !== 'granted') { - const permission = await Notification.requestPermission(); - if (permission !== 'granted') { - alert('Notification permission is required for push notifications'); - updateNotificationStatus(); - return; - } - } - - // Subscribe using the service worker - try { - await setupPushNotifications(); - await updateSubscriptionStatus(); - alert('Subscription successful!'); - } catch (error) { - console.error('Subscription error:', error); - alert(`Error subscribing: ${error.message}`); - } - // Close the modal closePushSettingsModal(); } @@ -244,22 +258,78 @@ async function unsubscribeFromPush() { try { await currentSubscription.unsubscribe(); await updateSubscriptionStatus(); - alert('Successfully unsubscribed from push notifications'); + // No success alert } catch (error) { console.error('Error unsubscribing:', error); alert(`Error unsubscribing: ${error.message}`); } } -// Force resubscription to push notifications +// Force subscription to push notifications async function resubscribeToPush() { try { - // Force credential prompt and resubscribe + let username = elements.pushUsername.value.trim(); + let password = elements.pushPassword.value.trim(); + + // If fields are empty, try to use stored credentials + if (!username || !password) { + try { + const storedAuth = localStorage.getItem('basicAuthCredentials'); + if (storedAuth) { + const credentials = JSON.parse(storedAuth); + if (credentials.username && credentials.password) { + username = credentials.username; + password = credentials.password; + + // Update the form fields with stored values + elements.pushUsername.value = username; + elements.pushPassword.value = password; + } + } + } catch (error) { + console.error('Error loading stored credentials:', error); + } + } + + // Use the credentials to subscribe await forceCredentialsPrompt(); - await updateSubscriptionStatus(); + + // Wait a moment for the subscription to complete + await new Promise(resolve => setTimeout(resolve, 500)); + + // Get the updated subscription + const registration = await navigator.serviceWorker.ready; + currentSubscription = await registration.pushManager.getSubscription(); + + // Update the UI directly + if (currentSubscription && elements.subscriptionStatus) { + elements.subscriptionStatus.textContent = 'active'; + elements.subscriptionStatus.className = 'status-active'; + // Enable unsubscribe button when subscription is active + elements.pushUnsubscribeButton.disabled = false; + // Change subscribe button text to "Re-subscribe" + elements.pushResubscribeButton.textContent = 'Re-subscribe'; + // Enable simulate button when subscription is active + if (elements.simulateClickButton) { + elements.simulateClickButton.disabled = false; + } + } else { + // Disable unsubscribe button when not subscribed + elements.pushUnsubscribeButton.disabled = true; + // Set subscribe button text + elements.pushResubscribeButton.textContent = 'Subscribe'; + // Disable simulate button when not subscribed + if (elements.simulateClickButton) { + elements.simulateClickButton.disabled = true; + } + // Fall back to the standard update function + await updateSubscriptionStatus(); + + alert('Subscription failed. Please check your credentials and try again.'); + } } catch (error) { - console.error('Error resubscribing:', error); - alert(`Error resubscribing: ${error.message}`); + console.error('Error subscribing:', error); + alert(`Error subscribing: ${error.message}`); } } @@ -268,7 +338,7 @@ export async function sendSubscriptionToServer() { if (!currentSubscription) { await updateSubscriptionStatus(); if (!currentSubscription) { - alert('No active subscription available. Please subscribe first.'); + // No alert, just return silently return; } } @@ -286,7 +356,7 @@ export async function sendSubscriptionToServer() { throw new Error('No stored credentials'); } } catch (error) { - alert('No valid credentials found. Please set them up first.'); + // No alert, just open the modal to let the user set credentials openPushSettingsModal(); return; } @@ -307,7 +377,8 @@ export async function sendSubscriptionToServer() { const configModule = await import('../config.js'); backendUrl = configModule.BACKEND_URL; } catch (error) { - alert('Could not get backend URL from config.'); + // No alert, just log the error and return + console.error('Could not get backend URL from config:', error); return; } @@ -325,7 +396,25 @@ export async function sendSubscriptionToServer() { if (response.ok) { const result = await response.json(); - alert(`Subscription sent successfully: ${result.message || 'OK'}`); + // No success alert + + // Update the currentSubscription variable + const registration = await navigator.serviceWorker.ready; + currentSubscription = await registration.pushManager.getSubscription(); + + // Directly update the subscription status element in the DOM + if (currentSubscription && elements.subscriptionStatus) { + elements.subscriptionStatus.textContent = 'active'; + elements.subscriptionStatus.className = 'status-active'; + // Enable unsubscribe button when subscription is active + elements.pushUnsubscribeButton.disabled = false; + // Change subscribe button text to "Re-subscribe" + elements.pushResubscribeButton.textContent = 'Re-subscribe'; + // Enable simulate button when subscription is active + if (elements.simulateClickButton) { + elements.simulateClickButton.disabled = false; + } + } } else { let errorMsg = `Server error: ${response.status}`; if (response.status === 401 || response.status === 403) { @@ -337,14 +426,11 @@ export async function sendSubscriptionToServer() { errorMsg = errorData.message || errorMsg; } catch (e) { /* use default */ } } - alert(`Failed to send subscription: ${errorMsg}`); + // No error alert, just log the error + console.error(`Failed to send subscription: ${errorMsg}`); } } catch (error) { - alert(`Network error: ${error.message}`); + // No error alert, just log the error + console.error(`Network error: ${error.message}`); } } - -// --- Cleanup on page unload --- -window.addEventListener('unload', function() { - stopMessageMonitoring(); -}); \ No newline at end of file diff --git a/src/js/ui/ui.js b/js/ui/ui.js similarity index 100% rename from src/js/ui/ui.js rename to js/ui/ui.js diff --git a/sw.js b/sw.js index 0ae5458..959b49e 100644 --- a/sw.js +++ b/sw.js @@ -163,7 +163,7 @@ self.addEventListener('push', event => { }); return Promise.all(sendPromises).then(() => { - // Remove battery notification logic - don't show any notifications + // No notifications will be shown for any action, including low battery return Promise.resolve(); }); }) @@ -178,7 +178,7 @@ self.addEventListener('message', event => { return; } - // Remove the battery timestamp handling + // No battery-related handling }); // This helps with navigation after app is installed