Native improvements: - Add haptic feedback on recording start (heavy) and stop (medium) - Add keep-screen-awake during recording (nativeKeepAwake) - Add isNativeApp() detection helper - Android: deep linking (pedscribe:// + https://app.pedshub.com) - Android: share intent for text/plain and application/pdf - iOS: deep linking (pedscribe:// URL scheme) - iOS: remote-notification background mode - Add Capacitor plugins: haptics, keyboard, push-notifications, screen-orientation, share Updated README with complete build/deploy instructions, App Store listing suggestions, and icon generation guide.
118 lines
3.6 KiB
JavaScript
118 lines
3.6 KiB
JavaScript
// PedScribe Mobile Launcher
|
|
// Handles configurable server URL, auto-redirect, and native features
|
|
|
|
(function() {
|
|
var STORAGE_KEY = 'pedscribe_server_url';
|
|
var DEFAULT_URL = 'https://app.pedshub.com';
|
|
|
|
var setupScreen = document.getElementById('setup-screen');
|
|
var connectingScreen = document.getElementById('connecting-screen');
|
|
var urlInput = document.getElementById('server-url');
|
|
var connectBtn = document.getElementById('btn-connect');
|
|
var changeBtn = document.getElementById('btn-change-server');
|
|
|
|
// Check for saved server URL
|
|
var savedUrl = localStorage.getItem(STORAGE_KEY);
|
|
|
|
if (savedUrl) {
|
|
showConnecting(savedUrl);
|
|
} else {
|
|
urlInput.value = DEFAULT_URL;
|
|
setupScreen.style.display = '';
|
|
connectingScreen.style.display = 'none';
|
|
}
|
|
|
|
// Connect button
|
|
connectBtn.addEventListener('click', function() {
|
|
var url = (urlInput.value || DEFAULT_URL).trim().replace(/\/+$/, '');
|
|
if (!url.startsWith('http')) url = 'https://' + url;
|
|
|
|
connectBtn.disabled = true;
|
|
connectBtn.textContent = 'Connecting...';
|
|
hapticFeedback();
|
|
|
|
testServer(url, function(ok) {
|
|
if (ok) {
|
|
localStorage.setItem(STORAGE_KEY, url);
|
|
navigateToServer(url);
|
|
} else {
|
|
connectBtn.disabled = false;
|
|
connectBtn.textContent = 'Connect';
|
|
showError('Could not reach server. Check the URL and try again.');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Enter key
|
|
urlInput.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Enter') connectBtn.click();
|
|
});
|
|
|
|
// Change server button
|
|
changeBtn.addEventListener('click', function() {
|
|
localStorage.removeItem(STORAGE_KEY);
|
|
setupScreen.style.display = '';
|
|
connectingScreen.style.display = 'none';
|
|
urlInput.value = savedUrl || DEFAULT_URL;
|
|
urlInput.focus();
|
|
});
|
|
|
|
function showConnecting(url) {
|
|
setupScreen.style.display = 'none';
|
|
connectingScreen.style.display = '';
|
|
|
|
setTimeout(function() {
|
|
testServer(url, function(ok) {
|
|
if (ok) {
|
|
navigateToServer(url);
|
|
} else {
|
|
setupScreen.style.display = '';
|
|
connectingScreen.style.display = 'none';
|
|
urlInput.value = url;
|
|
showError('Server not reachable. Check your connection or change the URL.');
|
|
}
|
|
});
|
|
}, 500);
|
|
}
|
|
|
|
function testServer(url, callback) {
|
|
var done = false;
|
|
function respond(ok) {
|
|
if (done) return;
|
|
done = true;
|
|
callback(ok);
|
|
}
|
|
|
|
fetch(url + '/api/health', { mode: 'no-cors', signal: AbortSignal.timeout(8000) })
|
|
.then(function() { respond(true); })
|
|
.catch(function() {
|
|
var fallbackTimer = setTimeout(function() { respond(false); }, 5000);
|
|
var img = new Image();
|
|
img.onload = function() { clearTimeout(fallbackTimer); respond(true); };
|
|
img.onerror = function() { clearTimeout(fallbackTimer); respond(false); };
|
|
img.src = url + '/favicon.ico?t=' + Date.now();
|
|
});
|
|
}
|
|
|
|
function navigateToServer(url) {
|
|
window.location.href = url;
|
|
}
|
|
|
|
function showError(msg) {
|
|
var existing = document.querySelector('.error-msg');
|
|
if (existing) existing.remove();
|
|
var div = document.createElement('div');
|
|
div.className = 'error-msg';
|
|
div.style.display = 'block';
|
|
div.textContent = msg;
|
|
connectBtn.parentNode.insertBefore(div, connectBtn.nextSibling);
|
|
setTimeout(function() { if (div.parentNode) div.remove(); }, 8000);
|
|
}
|
|
|
|
// Haptic feedback (Capacitor native)
|
|
function hapticFeedback() {
|
|
if (window.Capacitor && window.Capacitor.Plugins && window.Capacitor.Plugins.Haptics) {
|
|
window.Capacitor.Plugins.Haptics.impact({ style: 'medium' });
|
|
}
|
|
}
|
|
})();
|