talk2me/validate-pwa.html
Adolfo Delorenzo d818ec7d73 Major PWA and mobile UI improvements
- Fixed PWA installation on Android by correcting manifest.json icon configuration
- Made UI mobile-friendly with compact layout and sticky record button
- Implemented auto-translation after transcription stops
- Updated branding from 'Voice Translator' to 'Talk2Me' throughout
- Added reverse proxy support with ProxyFix middleware
- Created diagnostic tools for PWA troubleshooting
- Added proper HTTP headers for service worker and manifest
- Improved mobile CSS with responsive design
- Fixed JavaScript bundling with webpack configuration
- Updated service worker cache versioning
- Added comprehensive PWA documentation

These changes ensure the app works properly as a PWA on Android devices
and provides a better mobile user experience.
2025-06-03 12:28:09 -06:00

121 lines
5.1 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>PWA Validation - Talk2Me</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
.status { padding: 10px; margin: 10px 0; border-radius: 5px; }
.success { background: #d4edda; color: #155724; }
.error { background: #f8d7da; color: #721c24; }
.info { background: #d1ecf1; color: #0c5460; }
img { max-width: 100px; height: auto; margin: 10px; }
</style>
</head>
<body>
<h1>Talk2Me PWA Validation</h1>
<h2>Manifest Check</h2>
<div id="manifest-status"></div>
<h2>Icon Check</h2>
<div id="icon-status"></div>
<h2>Service Worker Check</h2>
<div id="sw-status"></div>
<h2>Installation Test</h2>
<button id="install-btn" style="display:none; padding: 10px 20px; font-size: 16px;">Install Talk2Me</button>
<div id="install-status"></div>
<script>
// Check manifest
fetch('/static/manifest.json')
.then(res => res.json())
.then(manifest => {
const status = document.getElementById('manifest-status');
status.innerHTML = `
<div class="status success">✓ Manifest loaded successfully</div>
<div class="status info">Name: ${manifest.name}</div>
<div class="status info">Short Name: ${manifest.short_name}</div>
<div class="status info">Icons: ${manifest.icons.length} defined</div>
`;
// Check icons
const iconStatus = document.getElementById('icon-status');
manifest.icons.forEach(icon => {
const img = new Image();
img.onload = () => {
const div = document.createElement('div');
div.className = 'status success';
div.innerHTML = `${icon.src} (${icon.sizes}) - ${icon.purpose}`;
iconStatus.appendChild(div);
iconStatus.appendChild(img);
};
img.onerror = () => {
const div = document.createElement('div');
div.className = 'status error';
div.innerHTML = `${icon.src} (${icon.sizes}) - Failed to load`;
iconStatus.appendChild(div);
};
img.src = icon.src;
img.style.maxWidth = '50px';
});
})
.catch(err => {
document.getElementById('manifest-status').innerHTML =
`<div class="status error">✗ Failed to load manifest: ${err.message}</div>`;
});
// Check service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistration()
.then(reg => {
const status = document.getElementById('sw-status');
if (reg) {
status.innerHTML = `
<div class="status success">✓ Service Worker is registered</div>
<div class="status info">Scope: ${reg.scope}</div>
<div class="status info">State: ${reg.active ? 'Active' : 'Not Active'}</div>
`;
} else {
status.innerHTML = '<div class="status error">✗ Service Worker not registered</div>';
}
})
.catch(err => {
document.getElementById('sw-status').innerHTML =
`<div class="status error">✗ Service Worker error: ${err.message}</div>`;
});
} else {
document.getElementById('sw-status').innerHTML =
'<div class="status error">✗ Service Workers not supported</div>';
}
// Check install prompt
let deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
deferredPrompt = e;
document.getElementById('install-btn').style.display = 'block';
document.getElementById('install-status').innerHTML =
'<div class="status success">✓ App is installable</div>';
});
document.getElementById('install-btn').addEventListener('click', async () => {
if (deferredPrompt) {
deferredPrompt.prompt();
const { outcome } = await deferredPrompt.userChoice;
document.getElementById('install-status').innerHTML +=
`<div class="status info">User ${outcome} the install</div>`;
deferredPrompt = null;
}
});
// Check if already installed
if (window.matchMedia('(display-mode: standalone)').matches) {
document.getElementById('install-status').innerHTML =
'<div class="status success">✓ App is already installed</div>';
}
</script>
</body>
</html>