Skip to content

Commit

Permalink
manifest stuff and install
Browse files Browse the repository at this point in the history
  • Loading branch information
Jared-Gross committed Aug 29, 2024
1 parent e5ffafe commit 042149b
Show file tree
Hide file tree
Showing 17 changed files with 213 additions and 36 deletions.
8 changes: 6 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import gzip
import json
import os
import re
from datetime import datetime, timedelta
from io import BytesIO
from typing import Literal, Union
Expand Down Expand Up @@ -42,7 +43,7 @@
]

INACTIVITY_TIMEOUT = timedelta(hours=5) # 5 hours
VERSION = '1.0.0'
VERSION = '0.0.1'


POSTGRES_USER = os.environ.get("POSTGRES_USER")
Expand All @@ -51,6 +52,7 @@
POSTGRES_HOST = os.environ.get("POSTGRES_HOST")
POSTGRES_PORT = os.environ.get("POSTGRES_PORT")


class SingAlong:
def __init__(self, host: tornado.websocket.WebSocketHandler):
self.host = host
Expand Down Expand Up @@ -94,7 +96,9 @@ class ServiceWorkerHandler(tornado.web.RequestHandler):
def get(self):
self.set_header('Content-Type', 'application/javascript')
with open("serviceWorker.js", "r") as file:
self.write(file.read())
script = file.read()
# script = re.sub(r"const VERSION = '.*?';", f"const VERSION = '{VERSION}';", script)
self.write(script)


class VersionHandler(tornado.web.RequestHandler):
Expand Down
35 changes: 23 additions & 12 deletions serviceWorker.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
const CACHE_NAME = 'my-cache-v2';
const CACHE_NAME = `cache`;
const urlsToCache = [
'/',
'/static/favicon.png',
'/static/icon.png',
'/serviceWorker.js',
'/dist/index.bundle.js',
'/dist/runtime.bundle.js',
'/dist/361.bundle.js',
'/dist/index.html',
];

// Install event: cache resources
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => {
Expand All @@ -33,8 +36,9 @@ self.addEventListener('install', event => {
);
});


// Fetch event: serve from cache, then network
self.addEventListener('fetch', event => {
const url = new URL(event.request.url);
if (event.request.method === 'GET') {
event.respondWith(
caches.match(event.request).then(cachedResponse => {
Expand All @@ -54,6 +58,7 @@ self.addEventListener('fetch', event => {
});
}).catch(error => {
console.error('Fetch failed:', error);
// Return a fallback page or message
return new Response("You are offline, and this resource is not cached.");
});
})
Expand All @@ -62,6 +67,7 @@ self.addEventListener('fetch', event => {
});


// Activate event: clear old caches
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(keys => {
Expand All @@ -80,18 +86,21 @@ self.addEventListener('activate', event => {
);
});


// Message event: update cache when version changes
self.addEventListener('message', event => {
if (event.data.action === 'newUpdateCache') {
updateCache(true);
}
if (event.data.action === 'updateCache') {
updateCache();
updateCache(false);
}
});

function updateCache() {
function updateCache(giveResponse) {
caches.keys().then(function (names) {
return Promise.all(names.map(name => caches.delete(name)));
}).then(function () {
caches.open(CACHE_NAME).then(cache => {
return caches.open(CACHE_NAME).then(cache => {
return Promise.all(
urlsToCache.map(url => {
return fetch(url, {
Expand All @@ -108,10 +117,12 @@ function updateCache() {
);
});
}).then(() => {
self.clients.matchAll().then(clients => {
clients.forEach(client => client.postMessage({
action: 'cacheUpdated'
}));
});
if (giveResponse) {
self.clients.matchAll().then(clients => {
clients.forEach(client => client.postMessage({
action: 'cacheUpdated'
}));
});
}
});
}
}
95 changes: 88 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,31 @@ let publicFolders: string[] = [];
const LONG_PRESS_DURATION = 500; // Duration in milliseconds to consider a long press
let longPressTimer: number | null = null;

interface BeforeInstallPromptEvent extends Event {
prompt: () => Promise<void>;
userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>;
}

let deferredPrompt: BeforeInstallPromptEvent | null = null;

window.addEventListener('beforeinstallprompt', (e: Event) => {
e.preventDefault();
deferredPrompt = e as BeforeInstallPromptEvent;
const installButton = document.getElementById('install-pwa');
if (installButton) {
installButton.style.display = 'block';
}
});


function escapeRegExp(string: string): string {
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
}

function isMobileDevice() {
return /Mobi|Android/i.test(navigator.userAgent);
}

function saveCustomFoldersToLocalStorage(folders: FolderData[]) {
localStorage.setItem('customFolders', JSON.stringify(folders));
}
Expand Down Expand Up @@ -336,7 +356,6 @@ function getFileButton(file: FileData): HTMLElement {
return fileContainer;
}


function getCustomFileButton(file: FileData, showText: boolean = true): HTMLElement {
const fileButton = document.createElement('a');
fileButton.className = 'custom-file-item padding surface-container no-round wave wrap';
Expand Down Expand Up @@ -664,13 +683,24 @@ function focusParagraph(index: number) {
function showSuccessSnackbar(message: string) {
const snackbar = document.getElementById('success-snackbar') as HTMLDivElement;
snackbar.textContent = message;
ui('#success-snackbar');
ui('#success-snackbar', 3000);
}

function showUpdateCompleteSnackbar(message: string) {
const snackbar = document.getElementById('update-snackbar') as HTMLDivElement;
const snackbarUpdate = snackbar.querySelector('#update-snackbar-update') as HTMLAnchorElement;
snackbarUpdate.onclick = () => {
window.location.reload();
};
const snackbarText = snackbar.querySelector('#update-snackbar-text') as HTMLDivElement;
snackbarText.textContent = message;
ui('#update-snackbar', 6000);
}

function showErrorSnackbar(message: string) {
const snackbar = document.getElementById('error-snackbar') as HTMLDivElement;
snackbar.textContent = message;
ui('#error-snackbar');
ui('#error-snackbar', 6000);
}

function initializeFileContent() {
Expand Down Expand Up @@ -863,7 +893,14 @@ document.addEventListener('DOMContentLoaded', async () => {
const selectSongsToggle = document.getElementById('select-songs-toggle') as HTMLInputElement;
const clearSelectionButton = document.getElementById('clear-selection') as HTMLButtonElement;
const customFolderList = document.getElementById('custom-folders-list') as HTMLDivElement;
const installPWA = document.getElementById('install-pwa') as HTMLButtonElement;
const installIcon = installPWA.querySelector('i') as HTMLElement;

if (isMobileDevice()) {
installIcon.textContent = `install_mobile`;
} else {
installIcon.textContent = `install_desktop`;
}
clearSelectionButton.style.display = 'none';

const currentHash = window.location.hash;
Expand Down Expand Up @@ -911,8 +948,19 @@ document.addEventListener('DOMContentLoaded', async () => {
}
});
});


installPWA.addEventListener('click', async () => {
if (deferredPrompt) {
await deferredPrompt.prompt();
const choiceResult = await deferredPrompt.userChoice;
if (choiceResult.outcome === 'accepted') {
console.log('User accepted the install prompt');
} else {
console.log('User dismissed the install prompt');
}
deferredPrompt = null;
installPWA.style.display = 'none';
}
});
document.querySelector('#text-increase')?.addEventListener('click', () => {
const newSize = getFontSize() + 1;
updateFontSize(newSize);
Expand Down Expand Up @@ -1176,13 +1224,46 @@ async function init() {
try {
if ('serviceWorker' in navigator) {
try {
navigator.serviceWorker.register('/serviceWorker.js', { scope: '/' })
const registration = await navigator.serviceWorker.register('/serviceWorker.js', { scope: '/' });
console.log('ServiceWorker registration successful with scope: /');

if (navigator.onLine) {
const response = await fetch('/version');
const data = await response.json();
const currentVersion = localStorage.getItem('latestVersion');

if (currentVersion !== data.version) {
navigator.serviceWorker.addEventListener('message', event => {
if (event.data.action === 'cacheUpdated') {
setTimeout(() => {
showUpdateCompleteSnackbar(`Update available: v${data.version}`);
}, 5000);
}
});

if (registration.active) {
registration.active.postMessage({ action: 'newUpdateCache' });
console.log('New version detected, updating cache...');
}
localStorage.setItem('latestVersion', data.version);
}else{
if (registration.active) {
registration.active.postMessage({ action: 'updateCache' });
console.log('Version check passed, updating cache...');
}
}
} else {
console.log('Offline: Skipping version check');
}
} catch (error) {
console.log('ServiceWorker registration failed: ', error);
}
}
const VERSION = localStorage.getItem('latestVersion') || '1.0.0';
const appNameVersion = document.getElementById('app-name-version') as HTMLHeadingElement;
appNameVersion.textContent = `Hutterite Bookshelf v${VERSION}`;

// Initialize databases and fetch data
const customFolders = getCustomFoldersFromLocalStorage();
const [globalDB, customDB] = await Promise.all([
initGlobalDB(),
Expand Down Expand Up @@ -1235,4 +1316,4 @@ async function initializeUIAndStartApp() {
}

window.addEventListener('load', initializeUIAndStartApp);
window.addEventListener('popstate', hashChanged);
window.addEventListener('popstate', hashChanged);
10 changes: 9 additions & 1 deletion static/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,12 @@ h6 .highlight {
padding-left: 1px;
padding-right: 1px;
display: inline-block !important;
}
}
#install-pwa {
display: none
}
@media (display-mode: browser) {
#install-pwa {
display: flex
}
}
75 changes: 67 additions & 8 deletions static/manifest.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,73 @@
{
"name": "Hutterite Bookshelf",
"short_name": "Hutterite Bookshelf",
"description": "Your own bookshelf",
"description": "A comprehensive app for accessing, managing, and sharing Hutterite literature.",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#000000",
"icons": [{
"src": "/static/icon.png",
"sizes": "1024x1024",
"type": "image/png"
}]
"background_color": "#161215",
"theme_color": "#161215",
"screenshots": [
{
"src": "screenshot1-wide.png",
"sizes": "1280x720",
"type": "image/png",
"form_factor": "wide"
},
{
"src": "screenshot2-mobile.png",
"sizes": "720x1280",
"type": "image/png",
"form_factor": "narrow"
}
],
"icons": [
{
"purpose": "maskable",
"sizes": "1204x1204",
"src": "maskable_icon.png",
"type": "image/png"
},
{
"purpose": "maskable",
"sizes": "48x48",
"src": "maskable_icon_x48.png",
"type": "image/png"
},
{
"purpose": "maskable",
"sizes": "72x72",
"src": "maskable_icon_x72.png",
"type": "image/png"
},
{
"purpose": "maskable",
"sizes": "96x96",
"src": "maskable_icon_x96.png",
"type": "image/png"
},
{
"purpose": "maskable",
"sizes": "128x128",
"src": "maskable_icon_x128.png",
"type": "image/png"
},
{
"purpose": "maskable",
"sizes": "192x192",
"src": "maskable_icon_x192.png",
"type": "image/png"
},
{
"purpose": "maskable",
"sizes": "384x384",
"src": "maskable_icon_x384.png",
"type": "image/png"
},
{
"purpose": "maskable",
"sizes": "512x512",
"src": "maskable_icon_x512.png",
"type": "image/png"
}
]
}
Binary file added static/maskable_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/maskable_icon_x128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/maskable_icon_x144.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/maskable_icon_x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/maskable_icon_x384.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/maskable_icon_x48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/maskable_icon_x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/maskable_icon_x72.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/maskable_icon_x96.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/screenshot1-wide.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/screenshot2-mobile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 042149b

Please sign in to comment.