Add NextSnap PWA with photo gallery viewer and continuous capture
Offline-first photo capture app for Nextcloud with: - Camera capture with continuous mode (auto-reopens after each photo) - File browser with fullscreen image gallery, swipe navigation, and rename - Upload queue with background sync engine - Admin panel for Nextcloud user management - Service worker for offline-first caching (v13) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
111
app/static/js/app.js
Normal file
111
app/static/js/app.js
Normal file
@@ -0,0 +1,111 @@
|
||||
// NextSnap - Main application logic
|
||||
'use strict';
|
||||
|
||||
const NextSnap = {
|
||||
version: '1.0.0',
|
||||
isOnline: navigator.onLine,
|
||||
|
||||
init() {
|
||||
console.log(`NextSnap v${this.version} initializing...`);
|
||||
this.setupConnectivityMonitoring();
|
||||
this.setupServiceWorkerMessaging();
|
||||
this.checkHealth();
|
||||
},
|
||||
|
||||
setupConnectivityMonitoring() {
|
||||
// Update online status on events
|
||||
window.addEventListener('online', () => {
|
||||
console.log('Network: Online');
|
||||
this.isOnline = true;
|
||||
this.updateConnectivityIndicator();
|
||||
// Sync is handled by SyncEngine's own online listener in sync.js
|
||||
});
|
||||
|
||||
window.addEventListener('offline', () => {
|
||||
console.log('Network: Offline');
|
||||
this.isOnline = false;
|
||||
this.updateConnectivityIndicator();
|
||||
});
|
||||
|
||||
// Initial status
|
||||
this.updateConnectivityIndicator();
|
||||
},
|
||||
|
||||
updateConnectivityIndicator() {
|
||||
const indicator = document.querySelector('.connectivity-indicator');
|
||||
if (!indicator) return;
|
||||
|
||||
indicator.classList.remove('online', 'offline', 'syncing');
|
||||
|
||||
if (this.isOnline) {
|
||||
indicator.classList.add('online');
|
||||
indicator.title = 'Online';
|
||||
} else {
|
||||
indicator.classList.add('offline');
|
||||
indicator.title = 'Offline';
|
||||
}
|
||||
},
|
||||
|
||||
setSyncingStatus(isSyncing) {
|
||||
const indicator = document.querySelector('.connectivity-indicator');
|
||||
if (!indicator) return;
|
||||
|
||||
if (isSyncing) {
|
||||
indicator.classList.add('syncing');
|
||||
indicator.title = 'Syncing...';
|
||||
} else {
|
||||
indicator.classList.remove('syncing');
|
||||
indicator.title = this.isOnline ? 'Online' : 'Offline';
|
||||
}
|
||||
},
|
||||
|
||||
setupServiceWorkerMessaging() {
|
||||
if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
|
||||
// Listen for messages from service worker
|
||||
navigator.serviceWorker.addEventListener('message', (event) => {
|
||||
console.log('Message from SW:', event.data);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Force service worker update
|
||||
async updateServiceWorker() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
const registration = await navigator.serviceWorker.getRegistration();
|
||||
if (registration) {
|
||||
await registration.update();
|
||||
console.log('Service worker update check triggered');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Clear all caches (for debugging)
|
||||
async clearCache() {
|
||||
if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
|
||||
navigator.serviceWorker.controller.postMessage({
|
||||
type: 'CLEAR_CACHE'
|
||||
});
|
||||
console.log('Cache clear requested');
|
||||
}
|
||||
},
|
||||
|
||||
async checkHealth() {
|
||||
try {
|
||||
const response = await fetch('/api/health');
|
||||
const data = await response.json();
|
||||
console.log('Health check:', data);
|
||||
} catch (error) {
|
||||
console.error('Health check failed:', error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize when DOM is ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', () => NextSnap.init());
|
||||
} else {
|
||||
NextSnap.init();
|
||||
}
|
||||
|
||||
// Make NextSnap globally available
|
||||
window.NextSnap = NextSnap;
|
||||
Reference in New Issue
Block a user