Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ddbee199b | ||
|
|
9d63e00632 | ||
|
|
94ec22d466 | ||
|
|
e7709e8756 |
+1
-1
@@ -10,7 +10,7 @@ showing, so it is ready the moment it is opened. Built for It Is Written
|
||||
| Do this | What happens |
|
||||
|---|---|
|
||||
| Drag a finger | The page scrolls. |
|
||||
| Tap a text box on the page | The app's own keyboard (the Prayer tab's) comes up and types into it. Enter submits; the keyboard puts itself away when the page moves on (e.g. after a search). × closes it; tap the box again to bring it back. |
|
||||
| Tap a text box on the page | The app's own keyboard (the Prayer tab's) comes up right under the box (above it if the box is near the bottom of the screen — the stage TV is portrait) and types into it. Enter submits and puts the keyboard away; it also goes away when the page moves on. × closes it; tap the box again to bring it back. |
|
||||
| Tap a scripture reference (e.g. "Isaiah 41:10") | It opens in a new Bible tab, at that verse, in the translation printed beside it (NIV, ESV…) when that translation is switched on. |
|
||||
| Tap anything else | Works on the page as normal. |
|
||||
| Leave the tab and come back | The page is exactly as it was: same search, same place, same typing. |
|
||||
|
||||
@@ -70,6 +70,12 @@ Notes:
|
||||
for you. The TV's updater compares versions numerically and only offers a HIGHER version.
|
||||
- If `WIN_CSC_LINK` / `CSC_LINK` / `CSC_KEY_PASSWORD` / `CSC_KEYCHAIN` exist in your environment,
|
||||
`build-win.cjs` removes them for the build (electron-builder aborts on an EMPTY `WIN_CSC_LINK`).
|
||||
- **Keep `build/installerIcon.ico`.** On macOS electron-builder rebuilds the uninstaller in JavaScript
|
||||
and leaves out NSIS's icon patch; if the installer and uninstaller icons differ, the uninstaller fails
|
||||
NSIS's integrity check, and that version can then never be updated or uninstalled. This file makes
|
||||
both use one icon (NSIS's own default, so nothing looks different). `build-win.cjs` refuses to build
|
||||
without it. Versions 1.4.35–1.4.37 shipped without it; `build/installer.nsh` installs over their
|
||||
damaged uninstallers instead of running them.
|
||||
- On Windows, if the build fails while extracting `winCodeSign` (symlink / permission errors), run the
|
||||
terminal as administrator or turn on Developer Mode, delete
|
||||
`%LOCALAPPDATA%\electron-builder\Cache\winCodeSign`, and build again.
|
||||
|
||||
@@ -127,6 +127,19 @@ function restoreOsKeyboard(el) {
|
||||
if (v === null) el.removeAttribute('inputmode'); else el.setAttribute('inputmode', v);
|
||||
}
|
||||
|
||||
/*
|
||||
* Where the field is, so the app can open its keyboard right under it: the stage TV is portrait, and a
|
||||
* keyboard parked at the bottom of a 75" screen is a reach to the floor. `field` tells one field from
|
||||
* another, so focus moving to a different one (Tab, the next memorize blank) can move the keyboard too.
|
||||
*/
|
||||
let fieldSeq = 0;
|
||||
const fieldIds = new WeakMap();
|
||||
function fieldInfo(el) {
|
||||
if (!fieldIds.has(el)) fieldIds.set(el, ++fieldSeq);
|
||||
const r = el.getBoundingClientRect();
|
||||
return { field: fieldIds.get(el), rect: { x: Math.round(r.left), y: Math.round(r.top), w: Math.round(r.width), h: Math.round(r.height) } };
|
||||
}
|
||||
|
||||
/*
|
||||
* Only a TAP raises the keyboard. A page that focuses its own search box as it loads must not throw a
|
||||
* keyboard over the stage while nobody is touching it; focus moving between fields (Tab, the next
|
||||
@@ -137,10 +150,13 @@ window.addEventListener('pointerdown', (e) => {
|
||||
const el = editableFrom(e.target);
|
||||
if (!el) return;
|
||||
quietOsKeyboard(el);
|
||||
send('bibleapp:editable', { on: true, tap: true });
|
||||
send('bibleapp:editable', Object.assign({ on: true, tap: true }, fieldInfo(el)));
|
||||
}, true);
|
||||
document.addEventListener('focusin', (e) => {
|
||||
send('bibleapp:editable', { on: isEditable(e.target), tap: false });
|
||||
const el = e.target;
|
||||
if (!isEditable(el)) { send('bibleapp:editable', { on: false, tap: false }); return; }
|
||||
// Measured a frame later: focusing can scroll the field into view first.
|
||||
requestAnimationFrame(() => send('bibleapp:editable', Object.assign({ on: true, tap: false }, fieldInfo(el))));
|
||||
}, true);
|
||||
document.addEventListener('focusout', (e) => {
|
||||
restoreOsKeyboard(e.target);
|
||||
|
||||
+39
-10
@@ -360,7 +360,9 @@
|
||||
// Only the page on screen may raise or drop the keyboard; a background page focusing its own
|
||||
// search box as it loads must not.
|
||||
if (!d || !isShown(v)) return;
|
||||
if (d.on && d.tap) showKeyboard();
|
||||
if (d.on && d.tap) showKeyboard(v, d);
|
||||
// Focus moved on to a DIFFERENT field while typing (Tab, the next memorize blank): follow it.
|
||||
else if (d.on && kb && kb.el.style.display === 'block' && d.field && d.field !== kb.field) placeKeyboard(v, d);
|
||||
else if (!d.on) hideKeyboard();
|
||||
return;
|
||||
case 'bibleapp:activity':
|
||||
@@ -600,6 +602,9 @@
|
||||
if (name === 'Enter') v.el.sendInputEvent({ type: 'char', keyCode: '\r' });
|
||||
v.el.sendInputEvent({ type: 'keyUp', keyCode: code });
|
||||
} catch (_) {}
|
||||
// Enter is "done": the search runs and the keyboard gets out of the way of the results. A tap on a
|
||||
// field brings it back.
|
||||
if (name === 'Enter') hideKeyboard();
|
||||
},
|
||||
focus: function () {
|
||||
var v = activeView();
|
||||
@@ -616,20 +621,44 @@
|
||||
el.style.display = 'none';
|
||||
document.body.appendChild(el);
|
||||
a.createPrayerKeyboard(el, null, 'browser', sink);
|
||||
kb = { el: el, placed: false };
|
||||
kb = { el: el, field: null };
|
||||
return kb;
|
||||
}
|
||||
function showKeyboard() {
|
||||
/*
|
||||
* The keyboard opens directly under the field being typed into. The stage TV is portrait: anything at
|
||||
* the bottom of the screen is a reach to the floor, and the page's search box is near the top. If the
|
||||
* field is too low for the keyboard to fit under it, it goes just above instead. Re-tapping the same
|
||||
* field while the keyboard is up leaves it wherever it was dragged.
|
||||
*/
|
||||
function placeKeyboard(v, d) {
|
||||
var k = kb;
|
||||
if (!k || !d || !d.rect || !v || !v.el) return;
|
||||
var W = v.el.getBoundingClientRect(), z = v.zoom || 1;
|
||||
var fieldTop = W.top + d.rect.y * z;
|
||||
var fieldBottom = W.top + (d.rect.y + d.rect.h) * z;
|
||||
var fieldMid = W.left + (d.rect.x + d.rect.w / 2) * z;
|
||||
var w = k.el.offsetWidth || 760, h = k.el.offsetHeight || 340, gap = 14;
|
||||
var y = fieldBottom + gap;
|
||||
if (y + h > window.innerHeight - 8) {
|
||||
var above = fieldTop - gap - h;
|
||||
y = above >= 0 ? above : Math.max(0, window.innerHeight - h - 8);
|
||||
}
|
||||
var x = Math.max(0, Math.min(window.innerWidth - w, Math.round(fieldMid - w / 2)));
|
||||
k.el.style.left = x + 'px';
|
||||
k.el.style.top = Math.round(y) + 'px';
|
||||
k.field = d.field || null;
|
||||
}
|
||||
function showKeyboard(v, d) {
|
||||
if (ROLE !== 'stage') return;
|
||||
var k = keyboard();
|
||||
if (!k) return;
|
||||
k.el.style.display = 'block';
|
||||
// First time: bottom centre, clear of the page's search box at the top. After that, wherever it was dragged.
|
||||
if (!k.placed) {
|
||||
k.placed = true;
|
||||
var w = k.el.offsetWidth || 760, hgt = k.el.offsetHeight || 340;
|
||||
k.el.style.left = Math.max(0, Math.round((window.innerWidth - w) / 2)) + 'px';
|
||||
k.el.style.top = Math.max(0, Math.round(window.innerHeight - hgt - Math.max(24, window.innerHeight * 0.04))) + 'px';
|
||||
var wasHidden = k.el.style.display !== 'block';
|
||||
k.el.style.display = 'block'; // shown before measuring: a hidden element has no size
|
||||
if (d && d.rect && (wasHidden || d.field !== k.field)) placeKeyboard(v, d);
|
||||
else if (wasHidden && !k.field) {
|
||||
// No position from the page (should not happen): centre it rather than leave it anywhere odd.
|
||||
k.el.style.left = Math.max(0, Math.round((window.innerWidth - (k.el.offsetWidth || 760)) / 2)) + 'px';
|
||||
k.el.style.top = Math.max(0, Math.round((window.innerHeight - (k.el.offsetHeight || 340)) / 3)) + 'px';
|
||||
}
|
||||
}
|
||||
function hideKeyboard() { if (kb) kb.el.style.display = 'none'; }
|
||||
|
||||
@@ -42,4 +42,33 @@
|
||||
nsExec::Exec $2
|
||||
Pop $0
|
||||
Sleep 1000
|
||||
!insertmacro bibleAppSkipDamagedUninstaller SHELL_CONTEXT
|
||||
!insertmacro bibleAppSkipDamagedUninstaller HKCU
|
||||
!macroend
|
||||
|
||||
; ---------------------------------------------------------------------------------------------------
|
||||
; Versions 1.4.35 - 1.4.37 were built on macOS before build/installerIcon.ico existed, and their
|
||||
; uninstallers are damaged: they fail NSIS's own integrity check ("Installer integrity check has
|
||||
; failed"). electron-builder rebuilds the uninstaller in JavaScript on macOS and leaves out NSIS's
|
||||
; icon patch, so whenever the installer and uninstaller icons differ (NSIS's two defaults do), the
|
||||
; checksum is wrong. An update runs the PREVIOUS version's uninstaller first, so those versions could
|
||||
; never be updated: the damaged uninstaller fails, and the installer reports "Bible App cannot be
|
||||
; closed" (it also cannot be uninstalled from Windows Settings).
|
||||
;
|
||||
; For exactly those versions, the old uninstaller is not run: its UninstallString is cleared, so
|
||||
; electron-builder's uninstallOldVersion finds nothing to run, and the new files are copied over the
|
||||
; old ones. This installer then writes a fresh, valid uninstaller and registry entry. Every other
|
||||
; version still goes through the normal uninstall-then-install path.
|
||||
; ---------------------------------------------------------------------------------------------------
|
||||
!macro bibleAppSkipDamagedUninstaller ROOT
|
||||
ReadRegStr $3 ${ROOT} "${UNINSTALL_REGISTRY_KEY}" DisplayVersion
|
||||
${If} $3 == "1.4.35"
|
||||
${OrIf} $3 == "1.4.36"
|
||||
${OrIf} $3 == "1.4.37"
|
||||
DetailPrint `Version $3's uninstaller is damaged; installing over it instead.`
|
||||
DeleteRegValue ${ROOT} "${UNINSTALL_REGISTRY_KEY}" UninstallString
|
||||
!ifdef UNINSTALL_REGISTRY_KEY_2
|
||||
DeleteRegValue ${ROOT} "${UNINSTALL_REGISTRY_KEY_2}" UninstallString
|
||||
!endif
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bible-app",
|
||||
"version": "1.4.37",
|
||||
"version": "1.4.39",
|
||||
"description": "Minimalist Bible App for Portrait-Oriented Touchscreen TV",
|
||||
"type": "module",
|
||||
"main": "main.cjs",
|
||||
|
||||
@@ -12,8 +12,14 @@
|
||||
* - a clean signing environment. There is no code-signing certificate. electron-builder aborts on
|
||||
* an EMPTY WIN_CSC_LINK ("Env WIN_CSC_LINK is not correct"), so those variables are removed
|
||||
* rather than blanked, and identity auto-discovery is turned off.
|
||||
* - a working uninstaller. On macOS electron-builder rebuilds the NSIS uninstaller in JavaScript and
|
||||
* skips NSIS's icon patch, so unless the installer and uninstaller use the SAME icon the uninstaller
|
||||
* fails NSIS's integrity check — and then that version can never be updated or uninstalled
|
||||
* (1.4.35-1.4.37 shipped like that). build/installerIcon.ico makes electron-builder use one icon for
|
||||
* both, so this refuses to build without it.
|
||||
*/
|
||||
const { spawnSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const env = { ...process.env, CSC_IDENTITY_AUTO_DISCOVERY: 'false' };
|
||||
@@ -21,6 +27,13 @@ for (const key of ['CSC_LINK', 'WIN_CSC_LINK', 'CSC_KEY_PASSWORD', 'WIN_CSC_KEY_
|
||||
delete env[key];
|
||||
}
|
||||
|
||||
const ICON = path.join(__dirname, '..', 'build', 'installerIcon.ico');
|
||||
if (!fs.existsSync(ICON)) {
|
||||
console.error('build/installerIcon.ico is missing. Without it the uninstaller built on macOS is damaged');
|
||||
console.error('("Installer integrity check has failed") and the version could never be updated. See tools/build-win.cjs.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const extra = process.argv.slice(2);
|
||||
const args = ['electron-builder', '--win', '--x64', ...extra];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user