Merge pull request #5067 from LBreda/develop

Maskable icon and service worker
This commit is contained in:
James Cole 2021-09-14 06:19:58 +02:00 committed by GitHub
commit 34f9b38ea3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 339 additions and 11 deletions

2
.gitignore vendored
View File

@ -15,4 +15,4 @@ yarn-error.log
public/google*.html
report.html
composer.phar
app.js.map
app.js.map

58
frontend/src/serviceworker.js vendored Normal file
View File

@ -0,0 +1,58 @@
/*
* serviceworker.js
* Copyright (c) 2021 Lorenzo Breda (https://github.com/lbreda)
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
let staticCachePrefix = "firefly-III-"
let staticCacheName = staticCachePrefix + new Date().getTime();
let cachedFiles = [
'/offline',
'/v2/plugins/local-fonts/gf-source.css',
'/v2/css/app.css',
];
// Create cache on install
self.addEventListener("install", event => {
this.skipWaiting();
event.waitUntil(
caches.open(staticCacheName).then(cache => cache.addAll(cachedFiles))
)
});
// Clear cache on activate
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames
.filter(cacheName => (cacheName.startsWith(staticCachePrefix)))
.filter(cacheName => (cacheName !== staticCacheName))
.map(cacheName => caches.delete(cacheName))
);
})
);
});
// Serve from Cache or return the offline page
self.addEventListener("fetch", event => {
event.respondWith(
caches.match(event.request)
.then(response => (response || fetch(event.request)))
.catch(() => caches.match('offline'))
)
});

View File

@ -3,15 +3,83 @@
"short_name": "Firefly III",
"start_url": "/",
"icons": [
{
"src": "/maskable72.png",
"sizes": "72x72",
"type": "image/png",
"scope": "maskable"
},
{
"src": "/maskable76.png",
"sizes": "76x76",
"type": "image/png",
"scope": "maskable"
},
{
"src": "/maskable96.png",
"sizes": "96x96",
"type": "image/png",
"scope": "maskable"
},
{
"src": "/maskable120.png",
"sizes": "120x120",
"type": "image/png",
"scope": "maskable"
},
{
"src": "/maskable128.png",
"sizes": "128x128",
"type": "image/png",
"scope": "maskable"
},
{
"src": "/maskable144.png",
"sizes": "144x144",
"type": "image/png",
"scope": "maskable"
},
{
"src": "/maskable152.png",
"sizes": "152x152",
"type": "image/png",
"scope": "maskable"
},
{
"src": "/maskable180.png",
"sizes": "180x180",
"type": "image/png",
"scope": "maskable"
},
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
"type": "image/png",
"scope": "any"
},
{
"src": "/maskable192.png",
"sizes": "192x192",
"type": "image/png",
"scope": "maskable"
},
{
"src": "/maskable384.png",
"sizes": "384x384",
"type": "image/png",
"scope": "maskable"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
"type": "image/png",
"scope": "any"
},
{
"src": "/maskable512.png",
"sizes": "512x512",
"type": "image/png",
"scope": "maskable"
}
],
"theme_color": "#1e6581",

1
public/maskable-icon.svg Normal file
View File

@ -0,0 +1 @@
<svg height="377.95276" width="377.95276" xmlns="http://www.w3.org/2000/svg"><path d="m0 0h377.95276v377.95276h-377.95276z" fill="#cd5029" stroke-width="1.96129"/><g transform="matrix(.77452773 0 0 .77452773 21.636074 21.374655)"><path d="m140.49013 78.646381 2.249 53.017999s-40.103 29.566-45.538 68l-16.001 1.231s-11.539 2.564-11.539 14.103v37.18s3.846 11.538 12.82 11.538l16.487-.319s8 30.5 36.5 50.5v25.5s-2 8.5 15.5 11 40.75 2.25 44.5-1.5 3.75-4.5 3.75-9c0 0 21.25 5 60.25 0v5s3.5 7 29 7 33-3 37.5-12v-25s37.009-36.264 35.75-91.75c-1.083-47.75-15.901-64.299-35.806-82.96-22.67-21.254-69.944-31.165-117.944-25.353.001-.001-24.341-43.937999-67.478-36.187999z" fill="#fff"/><circle cx="135.46912" cy="214.39638" fill="#cd5029" r="9.5"/><path d="m360.08113 190.51238s-18.218-8.742-40.662 3.996c0 0-26.711-8.987-40.99 2.593-14.828 12.025-16.299 26.115-15.525 42.785 0 0 12.837-43.915 45.252-32.571 0 0-22.947 40.43 12.761 47.508 0 0 8.436-.05 15.401-4.256 6.644-4.011 11.842-11.433 9.711-24.814 0 0-4.348-13.336-15.569-21.42 0 0 11.042-7.806 31.988-2.209z" fill="#cd5029"/><path d="m320.19013 213.01938s-16.689 31.461 5.607 29.767c0 0 11.838-5.656 4.887-17.127-7.147-11.796-10.494-12.64-10.494-12.64z" fill="#fff"/></g><path d="m188.97638 175.70052s4.01698 13.60604-3.69586 21.52748c-7.713 7.92145-6.8792 16.6767-3.75227 20.84588 3.12692 4.16917 2.91831 7.29593.41674 9.58905-2.50141 2.29312-4.58608 3.96073-6.04523.20846-1.45916-3.75228-3.12676-3.75228-3.75228-5.62834-.62552-1.87605-1.87622-5.21142-1.87622-5.21142s-3.96072 6.25384-6.46229 10.00611c-2.50157 3.75228-2.50141 9.58922-.83381 12.71598 1.66761 3.12676 1.04226 6.87903-.20845 12.09046-1.2507 5.21143.4169 13.13288 6.25369 16.2598 5.83678 3.12692 12.92459 5.62833 16.05135 8.5468s10.42301 5.62833 19.80362 3.54382c9.3806-2.0845 21.26294-11.67355 23.34744-18.13585 0 0 5.41988-6.04523 4.37763-13.96668s-4.79469-7.71316-6.4623-13.75839c-1.6676-6.04523 3.60854-4.55469-.8338-14.93382 0 0-1.98012-4.94005-9.50352-8.49899-4.83404-2.28661-1.54469-12.63061-10.09149-23.05347s-16.73295-12.14688-16.73295-12.14688z" fill="#ffa284" stroke-width=".162598"/></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
public/maskable120.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
public/maskable128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
public/maskable144.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
public/maskable152.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
public/maskable180.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
public/maskable192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
public/maskable384.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/maskable512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/maskable72.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
public/maskable76.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
public/maskable96.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

58
public/serviceworker.js vendored Normal file
View File

@ -0,0 +1,58 @@
/*
* serviceworker.js
* Copyright (c) 2021 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
let staticCachePrefix = "firefly-III-"
let staticCacheName = staticCachePrefix + new Date().getTime();
let cachedFiles = [
'/offline',
'/v2/plugins/local-fonts/gf-source.css',
'/v2/css/app.css',
];
// Create cache on install
self.addEventListener("install", event => {
this.skipWaiting();
event.waitUntil(
caches.open(staticCacheName).then(cache => cache.addAll(cachedFiles))
)
});
// Clear cache on activate
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames
.filter(cacheName => (cacheName.startsWith(staticCachePrefix)))
.filter(cacheName => (cacheName !== staticCacheName))
.map(cacheName => caches.delete(cacheName))
);
})
);
});
// Serve from Cache or return the offline page
self.addEventListener("fetch", event => {
event.respondWith(
caches.match(event.request)
.then(response => (response || fetch(event.request)))
.catch(() => caches.match('offline'))
)
});

View File

@ -47,5 +47,4 @@ return [
'tell_more' => 'Tell us more than "it says Whoops!"',
'include_logs' => 'Include error logs (see above).',
'what_did_you_do' => 'Tell us what you were doing.',
];

View File

@ -47,5 +47,8 @@ return [
'tell_more' => 'Tell us more than "it says Whoops!"',
'include_logs' => 'Include error logs (see above).',
'what_did_you_do' => 'Tell us what you were doing.',
'offline_header' => 'You are probably offline',
'offline_unreachable' => 'Firefly III is unreachable. Your device is currently offline or the server is not working.',
'offline_github' => 'If you are sure both your device and the server are online, please open a ticket on <strong><a href="https://github.com/firefly-iii/firefly-iii/issues">GitHub</a></strong>.',
];

View File

@ -47,5 +47,4 @@ return [
'tell_more' => 'Dicci di più di "dice Oops!"',
'include_logs' => 'Includi i log degli errori (vedi sopra).',
'what_did_you_do' => 'Dicci cosa stavi facendo.',
];

View File

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<base href="{{ route('index') }}/">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Firefly III | Offline</title>
<!-- Tell the browser to be responsive to screen width -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="v2/plugins/local-fonts/gf-source.css" nonce="{{ JS_NONCE }}">
<link rel="stylesheet" href="v2/css/app.css" nonce="{{ JS_NONCE }}">
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div class="error-page">
<h2 class="headline text-danger"><span class="fas fa-unlink"></span></h2>
<div class="error-content">
<h3><span class="fas fa-exclamation-triangle text-danger"></span> Offline</h3>
<p>
{{ trans('errors.offline_header') }}
</p>
<p>
{{ trans('errors.offline_unreachable') }}
</p>
<p>
{{ trans('errors.offline_github')|raw }}
</p>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -228,5 +228,17 @@
<noscript><p><img src="//{{ config('firefly.tracker_url') }}/matomo.php?idsite={{ config('firefly.tracker_site_id') }}&amp;rec=1" style="border:0;" alt="" /></p></noscript>
{% endif %}
<script nonce="{{ JS_NONCE }}">
// Initialize the service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('serviceworker.js?v={{ FF_VERSION }}', {
scope: '{{ route('index') }}'
}).then(
() => console.log('ServiceWorker registration successful'),
(err) => console.log('ServiceWorker registration failed: ', err)
);
}
</script>
</body>
</html>

View File

@ -61,5 +61,17 @@
<noscript><p><img src="//{{ config('firefly.tracker_url') }}/matomo.php?idsite={{ config('firefly.tracker_site_id') }}&amp;rec=1" style="border:0;" alt="" /></p></noscript>
{% endif %}
<script nonce="{{ JS_NONCE }}">
// Initialize the service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('serviceworker.js?v={{ FF_VERSION }}', {
scope: '{{ route('index') }}'
}).then(
() => console.log('ServiceWorker registration successful'),
(err) => console.log('ServiceWorker registration failed: ', err)
);
}
</script>
</body>
</html>

View File

@ -76,5 +76,17 @@
<noscript><p><img src="//{{ config('firefly.tracker_url') }}/matomo.php?idsite={{ config('firefly.tracker_site_id') }}&amp;rec=1" style="border:0;" alt="" /></p></noscript>
{% endif %}
<script nonce="{{ JS_NONCE }}">
// Initialize the service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('serviceworker.js?v={{ FF_VERSION }}', {
scope: '{{ route('index') }}'
}).then(
() => console.log('ServiceWorker registration successful'),
(err) => console.log('ServiceWorker registration failed: ', err)
);
}
</script>
</body>
</html>

View File

@ -36,5 +36,17 @@
</div>
<script src="v1/js/app.js?v={{ FF_VERSION }}" type="text/javascript" nonce="{{ JS_NONCE }}"></script>
{% block scripts %}{% endblock %}
<script nonce="{{ JS_NONCE }}">
// Initialize the service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('serviceworker.js?v={{ FF_VERSION }}', {
scope: '{{ route('index') }}'
}).then(
() => console.log('ServiceWorker registration successful'),
(err) => console.log('ServiceWorker registration failed: ', err)
);
}
</script>
</body>
</html>

View File

@ -19,5 +19,17 @@
<body class="hold-transition login-page">
{% block content %}{% endblock %}
{% block scripts %}{% endblock %}
<script nonce="{{ JS_NONCE }}">
// Initialize the service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('serviceworker.js?v={{ FF_VERSION }}', {
scope: '{{ route('index') }}'
}).then(
() => console.log('ServiceWorker registration successful'),
(err) => console.log('ServiceWorker registration failed: ', err)
);
}
</script>
</body>
</html>

View File

@ -46,9 +46,11 @@
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark">
{% if mainTitleIcon|default(false) %}<span class="fa fas {{ mainTitleIcon }}"></span>{% endif %}
{% if mainTitleIcon|default(false) %}<span
class="fa fas {{ mainTitleIcon }}"></span>{% endif %}
{{ title }} <small class="text-muted">
{% if subTitleIcon|default(false) %}<span class="fa fas {{ subTitleIcon }}"></span>{% endif %}
{% if subTitleIcon|default(false) %}<span
class="fa fas {{ subTitleIcon }}"></span>{% endif %}
{{ subTitle|default('') }}</small></h1>
</div><!-- /.col -->
<div class="col-sm-6">
@ -91,6 +93,18 @@
<script src="v2/js/vendor.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script>
{% block scripts %}{% endblock %}
<script nonce="{{ JS_NONCE }}">
// Initialize the service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('serviceworker.js?v={{ FF_VERSION }}', {
scope: '{{ route('index') }}'
}).then(
() => console.log('ServiceWorker registration successful'),
(err) => console.log('ServiceWorker registration failed: ', err)
);
}
</script>
</body>
</html>

View File

@ -1,8 +1,28 @@
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">
{# main icons #}
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
<link rel="manifest" href="manifest.webmanifest">
{# iOS icons #}
<link rel="apple-touch-icon" sizes="76x76" href="maskable76.png">
<link rel="apple-touch-icon" sizes="120x120" href="maskable120.png">
<link rel="apple-touch-icon" sizes="152x152" href="maskable152.png">
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">
{# Pinned tab #}
<link rel="mask-icon" href="safari-pinned-tab.svg" color="#1e6581">
<meta name="msapplication-TileColor" content="#1e6581">
{# Android #}
<link href="maskable192.png" rel="icon" sizes="192x192">
<link href="maskable128.png" rel="icon" sizes="128x128">
{# Manifest #}
<link rel="manifest" href="/manifest.webmanifest">
{# Android colors #}
<meta name="theme-color" content="#1e6581">
{# Microsoft meta #}
<meta name="msapplication-TileColor" content="#1e6581">
<meta name="msapplication-TileImage" content="maskable.png">
<meta name="msapplication-tap-highlight" content="no">
<meta name="application-name" content="Firefly III">

View File

@ -37,6 +37,13 @@ Route::group(
}
);
Route::group(
['middleware' => 'binders-only'],
static function () {
Route::get('offline', fn () => view('errors.offline'));
}
);
/**
* These routes only work when the user is NOT logged in.
*/