From c0a645b4e552ee6e6837b6cc033c4cd2b7014f8b Mon Sep 17 00:00:00 2001 From: olcxja Date: Sat, 22 Aug 2026 09:22:22 +0200 Subject: [PATCH 1/2] added style for select --- android/app/src/main/assets/public/main.js | 38 ++++++-- android/app/src/main/assets/public/screens.js | 13 ++- android/app/src/main/assets/public/style.css | 95 +++++++++++++++++++ webroot/main.js | 38 ++++++-- webroot/screens.js | 13 ++- webroot/style.css | 95 +++++++++++++++++++ 6 files changed, 268 insertions(+), 24 deletions(-) diff --git a/android/app/src/main/assets/public/main.js b/android/app/src/main/assets/public/main.js index c00574ed..2c1d5d29 100644 --- a/android/app/src/main/assets/public/main.js +++ b/android/app/src/main/assets/public/main.js @@ -4364,19 +4364,41 @@ async function switchSettingsTab(tabName) { } async function populateLanguageDropdown() { - let sel = document.getElementById("settings-language"); - if (!sel) return; + let container = document.getElementById("settings-language"); + let optionsContainer = document.getElementById("settings-language-options"); + let display = document.getElementById("settings-language-display"); + if (!container || !optionsContainer || !display) return; try { let path = window.location.pathname.replace("/login/index.html", "/").replace("index.html", ""); let res = await fetchAsync(`${path}blah/index.json`); let json = JSON.parse(res); - sel.innerHTML = ""; + optionsContainer.innerHTML = ""; + + window._langDropdownListener = window._langDropdownListener || ((e) => { + let cont = document.getElementById("settings-language"); + if (cont && !cont.contains(e.target)) { + cont.classList.remove('open'); + } + }); + document.removeEventListener('click', window._langDropdownListener); + document.addEventListener('click', window._langDropdownListener); + for (let code in json) { - let opt = document.createElement("option"); - opt.value = code; - opt.textContent = json[code].native + " (" + json[code].english + ")"; - if (code === lang) opt.selected = true; - sel.appendChild(opt); + let opt = document.createElement("div"); + opt.className = "custom-select-option"; + let text = json[code].native + " (" + json[code].english + ")"; + opt.textContent = text; + if (code === lang) { + opt.classList.add("selected"); + display.textContent = text; + display.classList.remove("blah"); + } + opt.onclick = () => { + display.textContent = text; + container.classList.remove("open"); + changeLanguage(code); + }; + optionsContainer.appendChild(opt); } } catch (e) { console.error("Failed to load languages", e); diff --git a/android/app/src/main/assets/public/screens.js b/android/app/src/main/assets/public/screens.js index d0b90b22..bdbcad05 100644 --- a/android/app/src/main/assets/public/screens.js +++ b/android/app/src/main/assets/public/screens.js @@ -415,10 +415,15 @@ var appearanceSettings = ` title.appearance
- - + +
+
+ title.loading + ${ICONS.chevronDown({ className: "chevron", style: "width: 1.2rem; height: 1.2rem; opacity: 0.7;" })} +
+
+
+
`; diff --git a/android/app/src/main/assets/public/style.css b/android/app/src/main/assets/public/style.css index af2ff9c7..723ecf4b 100644 --- a/android/app/src/main/assets/public/style.css +++ b/android/app/src/main/assets/public/style.css @@ -1181,3 +1181,98 @@ input:checked + .toggle-slider:before { 0% { transform: scale(0); } 100% { transform: scale(1); } } + +/* Custom Select */ +.custom-select { + position: relative; + border-radius: 0.8rem; + background-color: rgba(255, 255, 255, 0.05); + margin: var(--button-margin); + height: var(--button-height); + display: flex; + cursor: pointer; + align-items: center; + border: var(--border-width) solid var(--light-border-color); + color: var(--text-color); + width: calc(100% - (var(--button-margin) * 2)); + outline: none; + user-select: none; + z-index: 2; /* to appear above other elements if necessary */ +} + +.custom-select-value { + padding: var(--button-margin); + padding-left: calc(var(--button-margin) * 2); + padding-right: 1.5rem; + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; +} + +.custom-select-value span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.custom-select .chevron { + transition: transform 0.2s ease; +} + +.custom-select.open .chevron { + transform: rotate(180deg); +} + +.custom-select-options { + position: absolute; + top: calc(100% + 0.4rem); + left: 0; + width: 100%; + background-color: var(--main-bg-color); + border: var(--border-width) solid var(--light-border-color); + border-radius: 0.8rem; + max-height: 15rem; + overflow-y: auto; + z-index: 100; + opacity: 0; + visibility: hidden; + transform: translateY(-10px); + transition: all 0.2s ease; + box-shadow: 0 4px 12px rgba(0,0,0,0.5); + padding: 0.4rem; + pointer-events: none; +} + +.custom-select.open .custom-select-options { + opacity: 1; + visibility: visible; + transform: translateY(0); + pointer-events: auto; +} + +.custom-select-option { + padding: var(--button-margin) calc(var(--button-margin) * 2); + height: var(--button-height); + display: flex; + align-items: center; + border-radius: 0.8rem; + background-color: transparent; + cursor: pointer; + transition: background-color 0.2s; + text-align: left; + margin-bottom: 0.2rem; +} + +.custom-select-option:last-child { + margin-bottom: 0; +} + +.custom-select-option:hover { + background-color: rgba(255, 255, 255, 0.1); +} + +.custom-select-option.selected { + background-color: rgba(255, 255, 255, 0.15); + font-weight: bold; +} diff --git a/webroot/main.js b/webroot/main.js index c00574ed..2c1d5d29 100644 --- a/webroot/main.js +++ b/webroot/main.js @@ -4364,19 +4364,41 @@ async function switchSettingsTab(tabName) { } async function populateLanguageDropdown() { - let sel = document.getElementById("settings-language"); - if (!sel) return; + let container = document.getElementById("settings-language"); + let optionsContainer = document.getElementById("settings-language-options"); + let display = document.getElementById("settings-language-display"); + if (!container || !optionsContainer || !display) return; try { let path = window.location.pathname.replace("/login/index.html", "/").replace("index.html", ""); let res = await fetchAsync(`${path}blah/index.json`); let json = JSON.parse(res); - sel.innerHTML = ""; + optionsContainer.innerHTML = ""; + + window._langDropdownListener = window._langDropdownListener || ((e) => { + let cont = document.getElementById("settings-language"); + if (cont && !cont.contains(e.target)) { + cont.classList.remove('open'); + } + }); + document.removeEventListener('click', window._langDropdownListener); + document.addEventListener('click', window._langDropdownListener); + for (let code in json) { - let opt = document.createElement("option"); - opt.value = code; - opt.textContent = json[code].native + " (" + json[code].english + ")"; - if (code === lang) opt.selected = true; - sel.appendChild(opt); + let opt = document.createElement("div"); + opt.className = "custom-select-option"; + let text = json[code].native + " (" + json[code].english + ")"; + opt.textContent = text; + if (code === lang) { + opt.classList.add("selected"); + display.textContent = text; + display.classList.remove("blah"); + } + opt.onclick = () => { + display.textContent = text; + container.classList.remove("open"); + changeLanguage(code); + }; + optionsContainer.appendChild(opt); } } catch (e) { console.error("Failed to load languages", e); diff --git a/webroot/screens.js b/webroot/screens.js index d0b90b22..bdbcad05 100644 --- a/webroot/screens.js +++ b/webroot/screens.js @@ -415,10 +415,15 @@ var appearanceSettings = ` title.appearance
- - + +
+
+ title.loading + ${ICONS.chevronDown({ className: "chevron", style: "width: 1.2rem; height: 1.2rem; opacity: 0.7;" })} +
+
+
+
`; diff --git a/webroot/style.css b/webroot/style.css index af2ff9c7..723ecf4b 100644 --- a/webroot/style.css +++ b/webroot/style.css @@ -1181,3 +1181,98 @@ input:checked + .toggle-slider:before { 0% { transform: scale(0); } 100% { transform: scale(1); } } + +/* Custom Select */ +.custom-select { + position: relative; + border-radius: 0.8rem; + background-color: rgba(255, 255, 255, 0.05); + margin: var(--button-margin); + height: var(--button-height); + display: flex; + cursor: pointer; + align-items: center; + border: var(--border-width) solid var(--light-border-color); + color: var(--text-color); + width: calc(100% - (var(--button-margin) * 2)); + outline: none; + user-select: none; + z-index: 2; /* to appear above other elements if necessary */ +} + +.custom-select-value { + padding: var(--button-margin); + padding-left: calc(var(--button-margin) * 2); + padding-right: 1.5rem; + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; +} + +.custom-select-value span { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.custom-select .chevron { + transition: transform 0.2s ease; +} + +.custom-select.open .chevron { + transform: rotate(180deg); +} + +.custom-select-options { + position: absolute; + top: calc(100% + 0.4rem); + left: 0; + width: 100%; + background-color: var(--main-bg-color); + border: var(--border-width) solid var(--light-border-color); + border-radius: 0.8rem; + max-height: 15rem; + overflow-y: auto; + z-index: 100; + opacity: 0; + visibility: hidden; + transform: translateY(-10px); + transition: all 0.2s ease; + box-shadow: 0 4px 12px rgba(0,0,0,0.5); + padding: 0.4rem; + pointer-events: none; +} + +.custom-select.open .custom-select-options { + opacity: 1; + visibility: visible; + transform: translateY(0); + pointer-events: auto; +} + +.custom-select-option { + padding: var(--button-margin) calc(var(--button-margin) * 2); + height: var(--button-height); + display: flex; + align-items: center; + border-radius: 0.8rem; + background-color: transparent; + cursor: pointer; + transition: background-color 0.2s; + text-align: left; + margin-bottom: 0.2rem; +} + +.custom-select-option:last-child { + margin-bottom: 0; +} + +.custom-select-option:hover { + background-color: rgba(255, 255, 255, 0.1); +} + +.custom-select-option.selected { + background-color: rgba(255, 255, 255, 0.15); + font-weight: bold; +} From 5a04288e961b95da4131bdefb7d6b7d16e684384 Mon Sep 17 00:00:00 2001 From: olcxja Date: Sat, 22 Aug 2026 09:33:12 +0200 Subject: [PATCH 2/2] update deps & add version sync --- android/app/build.gradle | 2 +- android/app/src/main/assets/public/index.html | 1 + android/app/src/main/assets/public/screens.js | 2 +- android/app/src/main/assets/public/version.js | 1 + electron/assets/icon.png | Bin 14827 -> 14827 bytes electron/package.json | 2 +- icons/icon.png | Bin 14827 -> 14827 bytes .../com/getcapacitor/Bridge.dex | Bin 35340 -> 35340 bytes .../getcapacitor/BridgeWebChromeClient.dex | Bin 18456 -> 18464 bytes .../com/getcapacitor/MessageHandler.dex | Bin 6888 -> 6888 bytes .../com/getcapacitor/WebViewLocalServer$1.dex | Bin 2848 -> 2848 bytes .../cordova/MockCordovaWebViewImpl.dex | Bin 7604 -> 7604 bytes .../getcapacitor/plugin/CapacitorHttp$1.dex | Bin 2104 -> 2104 bytes .../com/getcapacitor/plugin/SystemBars.dex | Bin 13248 -> 13248 bytes .../classes/classes_dex/classes.dex | Bin 179708 -> 179732 bytes .../release/syncReleaseLibJars/classes.jar | Bin 179708 -> 179682 bytes .../bundleLibCompileToJarRelease/classes.jar | Bin 387543 -> 387458 bytes .../release/createFullJarRelease/full.jar | Bin 383872 -> 383787 bytes .../classes/com/getcapacitor/Bridge.class | Bin 47562 -> 47562 bytes .../getcapacitor/BridgeWebChromeClient.class | Bin 22758 -> 22726 bytes .../com/getcapacitor/MessageHandler.class | Bin 8232 -> 8232 bytes .../getcapacitor/WebViewLocalServer$1.class | Bin 2733 -> 2733 bytes .../cordova/MockCordovaWebViewImpl.class | Bin 9905 -> 9905 bytes .../plugin/CapacitorCookies.class | Bin 6020 -> 5967 bytes .../getcapacitor/plugin/CapacitorHttp$1.class | Bin 1952 -> 1952 bytes .../com/getcapacitor/plugin/SystemBars.class | Bin 14133 -> 14133 bytes .../androidx/appcompat/group-index.xml | 4 +-- .../androidx/core/group-index.xml | 10 +++--- .../androidx/fragment/group-index.xml | 10 +++--- .../androidx/webkit/group-index.xml | 2 +- .../com/android/tools/build/group-index.xml | 30 +++++++++--------- .../maven.google/master-index.xml | 5 +++ .../sdk_index/snapshot.gz | Bin 94559 -> 105914 bytes .../local_aar_for_lint/release/out.aar | Bin 241074 -> 241048 bytes .../com/getcapacitor/Bridge.class | Bin 47562 -> 47562 bytes .../getcapacitor/BridgeWebChromeClient.class | Bin 22758 -> 22726 bytes .../com/getcapacitor/MessageHandler.class | Bin 8232 -> 8232 bytes .../getcapacitor/WebViewLocalServer$1.class | Bin 2733 -> 2733 bytes .../cordova/MockCordovaWebViewImpl.class | Bin 9905 -> 9905 bytes .../plugin/CapacitorCookies.class | Bin 6020 -> 5967 bytes .../getcapacitor/plugin/CapacitorHttp$1.class | Bin 1952 -> 1952 bytes .../com/getcapacitor/plugin/SystemBars.class | Bin 14133 -> 14133 bytes .../bundleLibRuntimeToJarRelease/classes.jar | Bin 384702 -> 384617 bytes .../outputs/aar/capacitor-android-release.aar | Bin 182967 -> 182934 bytes .../previous-compilation-data.bin | Bin 90371 -> 90371 bytes .../release/syncReleaseLibJars/classes.jar | Bin 5797 -> 5796 bytes .../bundleLibCompileToJarRelease/classes.jar | Bin 12436 -> 12436 bytes .../release/createFullJarRelease/full.jar | Bin 11698 -> 11698 bytes .../release-artifact-libraries.xml | 4 +-- .../capacitorjs/plugins/app/AppPlugin.class | Bin 9667 -> 9667 bytes .../androidx/appcompat/group-index.xml | 4 +-- .../com/android/tools/build/group-index.xml | 30 +++++++++--------- .../maven.google/master-index.xml | 5 +++ .../sdk_index/snapshot.gz | Bin 94559 -> 105914 bytes .../local_aar_for_lint/release/out.aar | Bin 7166 -> 7165 bytes .../capacitorjs/plugins/app/AppPlugin.class | Bin 9667 -> 9667 bytes .../bundleLibRuntimeToJarRelease/classes.jar | Bin 12146 -> 12146 bytes .../outputs/aar/capacitor-app-release.aar | Bin 6054 -> 6058 bytes .../previous-compilation-data.bin | Bin 61585 -> 61585 bytes .../plugins/statusbar/StatusBarPlugin.dex | Bin 7788 -> 7788 bytes .../classes/classes_dex/classes.dex | Bin 14116 -> 14116 bytes .../release/syncReleaseLibJars/classes.jar | Bin 10074 -> 10081 bytes .../bundleLibCompileToJarRelease/classes.jar | Bin 21530 -> 21530 bytes .../release/createFullJarRelease/full.jar | Bin 20762 -> 20762 bytes .../release-artifact-libraries.xml | 4 +-- .../plugins/statusbar/StatusBarPlugin.class | Bin 7778 -> 7778 bytes .../androidx/appcompat/group-index.xml | 4 +-- .../androidx/core/group-index.xml | 10 +++--- .../com/android/tools/build/group-index.xml | 30 +++++++++--------- .../maven.google/master-index.xml | 5 +++ .../sdk_index/snapshot.gz | Bin 94559 -> 105914 bytes .../local_aar_for_lint/release/out.aar | Bin 11467 -> 11474 bytes .../plugins/statusbar/StatusBarPlugin.class | Bin 7778 -> 7778 bytes .../bundleLibRuntimeToJarRelease/classes.jar | Bin 21222 -> 21222 bytes .../aar/capacitor-status-bar-release.aar | Bin 9860 -> 9867 bytes .../previous-compilation-data.bin | Bin 70357 -> 70357 bytes package.json | 2 +- sync-project.sh | 21 ++++++++++++ version.json | 5 +++ webroot/index.html | 1 + webroot/screens.js | 2 +- webroot/version.js | 1 + 82 files changed, 121 insertions(+), 76 deletions(-) create mode 100644 android/app/src/main/assets/public/version.js create mode 100644 version.json create mode 100644 webroot/version.js diff --git a/android/app/build.gradle b/android/app/build.gradle index dfa78d5c..18033c55 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -8,7 +8,7 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 - versionName "1.0" + versionName "0.1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/android/app/src/main/assets/public/index.html b/android/app/src/main/assets/public/index.html index 27ac622f..013bd422 100644 --- a/android/app/src/main/assets/public/index.html +++ b/android/app/src/main/assets/public/index.html @@ -133,6 +133,7 @@ +