diff --git a/.github/workflows/badge-update.yml b/.github/workflows/badge-update.yml index 21d4c9f0..3926524b 100644 --- a/.github/workflows/badge-update.yml +++ b/.github/workflows/badge-update.yml @@ -66,7 +66,7 @@ jobs: # # -- Lint and parse Output # - pylint_output=$(PYTHONPATH=. pylint . --recursive=y --disable=W0511,R0903 --score=y) + pylint_output=$(PYTHONPATH=. pylint . --recursive=y --score=y) score=$(sed -n '$s/[^0-9]*\([0-9.]*\).*/\1/p' <<< "$pylint_output") # diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index 4fec8790..a59aeee9 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -136,7 +136,7 @@ jobs: # # -- Lint and parse Output # - pylint_output=$(PYTHONPATH=. pylint . --recursive=y --disable=W0511,R0903,R0801 --score=y) + pylint_output=$(PYTHONPATH=. pylint . --recursive=y --score=y) exitcode=$? score=$(sed -n '$s/[^0-9]*\([0-9.]*\).*/\1/p' <<< "$pylint_output") # diff --git a/.pylintrc b/.pylintrc index 8fcdd97d..532de186 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,2 +1,11 @@ [pylint] -disable=logging-fstring-interpolation, unspecified-encoding,attribute-defined-outside-init,wrong-import-position \ No newline at end of file +disable= + E0401, # import-error + W0511, # fixme + W1203, # logging-fstring-interpolation + R0903, # too-few-public-methods + R0915, # too-many-statements + R0913, # too-many-arguments + R0912, # too-many-branches + R0914, # too-many-locals + R0917 # too-many-positional-arguments \ No newline at end of file diff --git a/app/routes.py b/app/routes.py index 6f6c27de..9e4c974a 100644 --- a/app/routes.py +++ b/app/routes.py @@ -47,25 +47,29 @@ def require_login(): """ # Allow PyTest Client if current_app.config.get('TESTING', False): - return + return None - # Allow access to login route + # Allow access to login route or static content needed before login if request.endpoint == "login": - return + return None - # Allow access to CSS files - if request.endpoint == "static" and request.path.endswith(".css"): - return + if request.endpoint == "static" and ( + request.path.endswith('manifest.json') or + request.path.endswith('sw.js') + ): + return None - # Allow access to JS files - if request.endpoint == "static" and request.path.endswith(".js"): - return + if request.path.startswith('/static/css') or \ + request.path.startswith('/static/js') or \ + request.path.startswith('/static/icons'): + return None # Block everything else unless logged in if not session.get("logged_in"): return redirect('/login') - return + # Return no Redirection for logged-in users + return None @current_app.route("/login", methods=["GET", "POST"]) def login(): diff --git a/app/server.py b/app/server.py index b3645518..348de9b4 100755 --- a/app/server.py +++ b/app/server.py @@ -8,7 +8,9 @@ parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(os.path.join(parent_dir)) -from app.ui import UserInterface + +# Relative imports need to be after sys.path append +from app.ui import UserInterface #pylint: disable=wrong-import-position def create_app(config_path: str) -> Flask: diff --git a/app/static/css/grid.css b/app/static/css/grid.css index 5c6b3a80..c1697534 100644 --- a/app/static/css/grid.css +++ b/app/static/css/grid.css @@ -46,6 +46,8 @@ "gegen-val gegen-val" "tx-head tx-head" "tx-val tx-val" + "txt-head txt-head" + "txt-val txt-val" ". ."; } @@ -59,6 +61,8 @@ #dynamic-results tr:nth-child(4) td { grid-area: gegen-val;} #dynamic-results tr:nth-child(9) th { grid-area: tx-head;} #dynamic-results tr:nth-child(9) td { grid-area: tx-val;} + #dynamic-results tr:nth-child(10) th { grid-area: txt-head;} + #dynamic-results tr:nth-child(10) td { grid-area: txt-val;} /* Stack nav */ nav { display: block; } diff --git a/app/static/css/style.css b/app/static/css/style.css index e7439437..20f74d85 100644 --- a/app/static/css/style.css +++ b/app/static/css/style.css @@ -71,6 +71,11 @@ small.secondary, strong.secondary, i.secondary { .bottom-fixed > button { border-radius: 2em; } + +#pwa-install-btn { + margin-bottom: 6em; +} + /* Info TX button */ button.info { padding: 1em; @@ -159,7 +164,6 @@ button.info { background-color: var(--pico-code-kbd-background-color); border-radius: var(--pico-border-radius); color: var(--pico-code-kbd-color); - font-weight: bolder; font-size: .875em; font-family: var(--pico-font-family); line-height: initial; @@ -184,6 +188,7 @@ button.info { } .tag-chip.parsed {background-color: blueviolet; color:black;} + .tag-chip.parsed b {display: block;} .tag-chip:hover { filter: brightness(110%); } /* Generated Color Classes */ diff --git a/app/static/icons/apple-touch-icon.png b/app/static/icons/apple-touch-icon.png new file mode 100644 index 00000000..54e1aa18 Binary files /dev/null and b/app/static/icons/apple-touch-icon.png differ diff --git a/app/static/icons/favicon.ico b/app/static/icons/favicon.ico new file mode 100644 index 00000000..676e1900 Binary files /dev/null and b/app/static/icons/favicon.ico differ diff --git a/app/static/icons/icon-192.png b/app/static/icons/icon-192.png new file mode 100644 index 00000000..30a99dc3 Binary files /dev/null and b/app/static/icons/icon-192.png differ diff --git a/app/static/icons/icon-512.png b/app/static/icons/icon-512.png new file mode 100644 index 00000000..1ada1c44 Binary files /dev/null and b/app/static/icons/icon-512.png differ diff --git a/app/static/js/functions.js b/app/static/js/functions.js index aa51306f..d5e37cfa 100644 --- a/app/static/js/functions.js +++ b/app/static/js/functions.js @@ -3,6 +3,22 @@ let IBAN = window.location.pathname.split('/')[1]; let TAGS = []; +// ---------------------------------------------------------------------------- +// -- General Listeners ------------------------------------------------------- +// ---------------------------------------------------------------------------- + +document.addEventListener('DOMContentLoaded', function () { + + // Set PWA if used in PWA + if (sessionStorage.getItem('pwa_installed') != 'true'){ + if (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches || + window.navigator.standalone === true) { + sessionStorage.setItem('pwa_installed', 'true'); + } + } + +}); + // ---------------------------------------------------------------------------- // -- DOM Functions ---------------------------------------------------------- // ---------------------------------------------------------------------------- @@ -393,6 +409,19 @@ function createAjax(callback) { return ajax; } +// ----------------------------- +// PWA: Service Worker registration and Install prompt handling +// ----------------------------- +if ('serviceWorker' in navigator) { + window.addEventListener('load', function () { + navigator.serviceWorker.register('/static/sw.js').then(function (reg) { + console.log('Service worker registered.', reg); + }).catch(function (err) { + console.warn('Service worker registration failed:', err); + }); + }); +} + /** * Sends a GET request to the specified API endpoint with the given parameters. * diff --git a/app/static/js/iban.js b/app/static/js/iban.js index 9b5b5c9e..ba7e0726 100644 --- a/app/static/js/iban.js +++ b/app/static/js/iban.js @@ -43,6 +43,9 @@ document.addEventListener('DOMContentLoaded', function () { window.location.href = '/' + IBAN; }) + // Update Details Link ("_blank" for non-PWA) + updateDetailsLink(); + }); // ---------------------------------------------------------------------------- @@ -60,6 +63,19 @@ function set_all_checkboxes() { listTxElements(); } +/** + * Set "more" button to target "_blank" if not PWA + */ +function updateDetailsLink() { + var a = document.querySelector('#details-popup footer a.secondary'); + if (!a) return; + if (sessionStorage.getItem('pwa_installed') == 'true') { + a.removeAttribute('target'); + } else { + a.setAttribute('target', '_blank'); + } +} + /** * Set an eventlistener for every box and change the header when unselected * diff --git a/app/static/js/tx.js b/app/static/js/tx.js index 9a2f54d6..e78a1620 100644 --- a/app/static/js/tx.js +++ b/app/static/js/tx.js @@ -69,4 +69,15 @@ function manualTagTx(uuid) { */ function manualCatTx(uuid) { return manualCat([uuid], document.getElementById('cat-input').value); +} + +/** + * Close window when used as PWA, otherwise go back in browser history. + */ +function closeOrBack() { + if (sessionStorage.getItem('pwa_installed') != 'true') { + window.close(); + } else { + window.history.back(); + } } \ No newline at end of file diff --git a/app/static/manifest.json b/app/static/manifest.json new file mode 100644 index 00000000..f4e530c1 --- /dev/null +++ b/app/static/manifest.json @@ -0,0 +1,21 @@ +{ + "name": "PynanceParser", + "short_name": "PynanceParser", + "start_url": "/", + "display": "standalone", + "background_color": "#13171f", + "theme_color": "#00b478", + "description": "Get Insides into your Bank Account", + "icons": [ + { + "src": "/static/icons/icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/static/icons/icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/app/static/sw.js b/app/static/sw.js index 229dafce..84c9ab2f 100644 --- a/app/static/sw.js +++ b/app/static/sw.js @@ -1,11 +1,11 @@ self.addEventListener('install', function (event) { - event.waitUntil( - function(){ - console.log("SW: PWA installiert !"); - } - ); + self.skipWaiting(); +}); + +self.addEventListener('activate', function (event) { + event.waitUntil(self.clients.claim()); }); self.addEventListener('fetch', function (event) { - // Bisher kein Ressourcen Management nötig ! + // Not needed for now... }); \ No newline at end of file diff --git a/app/templates/layout.html b/app/templates/layout.html index 21c52ce2..08d41503 100644 --- a/app/templates/layout.html +++ b/app/templates/layout.html @@ -8,6 +8,9 @@ + + + diff --git a/app/templates/login.html b/app/templates/login.html index f868953c..c7dd3e32 100644 --- a/app/templates/login.html +++ b/app/templates/login.html @@ -33,5 +33,40 @@

Pynance Parser

+ {% endblock %} diff --git a/app/templates/tx.html b/app/templates/tx.html index 8068123e..f9e4664f 100644 --- a/app/templates/tx.html +++ b/app/templates/tx.html @@ -16,7 +16,7 @@