From 8e660f403bfacfa90aa431f9917346c6935ac102 Mon Sep 17 00:00:00 2001 From: codex-bot Date: Sat, 12 Sep 2026 13:05:15 +0100 Subject: [PATCH] Salah 0.3: larger AMOLED UI with swipe-scrollable prayers --- README.md | 24 ++++---- preview-0.3.png | Bin 0 -> 19843 bytes src/manifest.json | 6 +- src/pages/index/index.ux | 115 +++++++++------------------------------ tests/amoled.cjs | 25 +++++++++ tests/page.cjs | 16 ++---- 6 files changed, 73 insertions(+), 113 deletions(-) create mode 100644 preview-0.3.png create mode 100644 tests/amoled.cjs diff --git a/README.md b/README.md index 975fc66..e7cf29e 100644 --- a/README.md +++ b/README.md @@ -13,21 +13,24 @@ Morocco (Ministry of Habous), matching AlAdhan `method=21`: - Fajr 19°, Isha 17° (twilight angles) - Standard Asr (shadow factor 1× — Maliki default in Morocco) - Dhuhr = solar noon + 5 min; Maghrib = sunset + 5 min (AlAdhan's baked offsets) -- Location hardcoded: Casablanca 33.5731, −7.5898 · TZ = UTC+1 year-round - (Morocco dropped DST in 2018) +- Location hardcoded: Casablanca 33.5731, −7.5898 · fixed TZ = UTC+1. + Ramadan clock changes are not handled by this version. All computation happens **on the watch** — no GPS, no network. Pure solar math (same Meeus approach as the sundial) lives in `src/common/prayer.js`. -## Screen +## Screen (v0.3) -- Header: CASABLANCA + current clock -- Purple banner: next prayer name + countdown (`1h 55m`, `+1d …` wraps past midnight) -- Six chord-tapered rows: widths [380, 412, 424, 406, 368, 304] px computed from - the circle chord at each row's position (fixed-width rows clipped off the disc - in the first layout — asserted numerically in tests now) -- Passed prayers dimmed (opacity 0.45); next row purple-highlighted -- 15s refresh +- Pure #000000 AMOLED background, including the list and prayer rows +- Larger 42px clock, 28px prayer names and 36px times +- Native vertically swipe-scrollable list: 80px rows in a 320×240px viewport +- Top/bottom spacers let the first and last prayers scroll to the center +- Fixed next-prayer countdown; lavender outline/text highlight the next prayer +- Normal system back button exits; no crown support assumed +- 15s refresh; no changes to prayer calculations + +Build and automated tests pass; v0.3 scrolling/rendering needs an on-watch check. +`preview-0.3.png` is a static layout mock with illustrative times, not a watch screenshot. ## Project layout @@ -52,6 +55,7 @@ npm ci npm run release node tests/prayer.cjs node tests/page.cjs +node tests/amoled.cjs ``` ## Install diff --git a/preview-0.3.png b/preview-0.3.png new file mode 100644 index 0000000000000000000000000000000000000000..bfe839d801e7dd12d78cbe5d4744cbbf3eca3ebc GIT binary patch literal 19843 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 ISn}n60DPC+Q~&?~ literal 0 HcmV?d00001 diff --git a/src/manifest.json b/src/manifest.json index 47c3a11..2b1e3a7 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -2,8 +2,8 @@ "package": "com.ilias.salah", "name": "SALAH", "icon": "/common/icon.png", - "versionName": "0.2", - "versionCode": 2, + "versionName": "0.3", + "versionCode": 3, "minAPILevel": 1, "deviceTypeList": [ "watch" @@ -22,7 +22,7 @@ } }, "display": { - "backgroundColor": "#0a0d18" + "backgroundColor": "#000000" }, "features": [ { diff --git a/src/pages/index/index.ux b/src/pages/index/index.ux index 278d240..ac22aee 100644 --- a/src/pages/index/index.ux +++ b/src/pages/index/index.ux @@ -1,19 +1,20 @@ diff --git a/tests/amoled.cjs b/tests/amoled.cjs new file mode 100644 index 0000000..4e6d946 --- /dev/null +++ b/tests/amoled.cjs @@ -0,0 +1,25 @@ +const assert = require('node:assert/strict') +const fs = require('node:fs') +const src = fs.readFileSync('src/pages/index/index.ux', 'utf8') +const manifest = JSON.parse(fs.readFileSync('src/manifest.json')) +function css(name, prop) { + const block = src.match(new RegExp('\\.' + name + '\\s*\\{([^}]+)'))[1] + return block.match(new RegExp(prop + ':\\s*([^;]+)'))[1].trim() +} +assert.equal(css('page', 'background-color'), '#000000', 'page must be AMOLED black') +assert.equal(manifest.display.backgroundColor, '#000000') +assert.match(src, /]*class="prayers"/, 'native swipe-scrollable list') +assert.match(src, /]*type="prayer"[^>]*for="\{\{ row in rows \}\}"/) +assert.ok(parseFloat(css('rowName', 'font-size')) >= 28) +assert.ok(parseFloat(css('rowTime', 'font-size')) >= 36) +const top = parseFloat(css('prayers', 'top')) +const height = parseFloat(css('prayers', 'height')) +const width = parseFloat(css('prayers', 'width')) +const dy = Math.max(Math.abs(top - 233), Math.abs(top + height - 233)) +assert.ok(width <= 2 * Math.sqrt(233 ** 2 - dy ** 2) - 20, 'whole scroll viewport fits circle') +const rowH = parseFloat(css('row', 'height')) +const pad = parseFloat(css('spacer', 'height')) +assert.equal(pad, (height - rowH) / 2, 'first/last rows can reach viewport center') +assert.ok(6 * rowH + 2 * pad > height, 'content actually scrolls') +assert.ok(!src.includes('onBackPress'), 'system back still exits') +console.log('AMOLED, large text, scroll wiring and circular viewport checks passed') diff --git a/tests/page.cjs b/tests/page.cjs index f763ea7..9ed462c 100644 --- a/tests/page.cjs +++ b/tests/page.cjs @@ -148,18 +148,10 @@ test('update() rows: six entries, key+label+time wired', () => { } }) -test('row widths taper with the chord and fit the 466 circle at every row position', () => { - // rows: 6 x 40px + 5 x 4px margins, block starts after header+banner (top=130) - const ROW_WIDTHS = spec.ROW_WIDTHS || sandbox.ROW_WIDTHS - assert.equal(ROW_WIDTHS.length, 6) - const H = 40, MARGIN = 4, BLOCK_TOP = 130, R = 233, INSET = 10 - for (let n = 0; n < 6; n++) { - const top = BLOCK_TOP + n * (H + MARGIN) - const dy = Math.max(Math.abs(233 - top), Math.abs(233 - (top + H))) - const chord = 2 * Math.sqrt(Math.max(0, R * R - dy * dy)) - const safe = chord - 2 * INSET - assert.ok(ROW_WIDTHS[n] <= safe, `row ${n} width ${ROW_WIDTHS[n]} exceeds safe chord ${safe.toFixed(0)} at top ${top}`) - } +test('all rows fit the scroll viewport', () => { + const widths = sandbox.ROW_WIDTHS + assert.equal(widths.length, 6) + widths.forEach(width => assert.equal(width, 320)) }) test('bound rowStyle width equals ROW_WIDTHS[i]', () => {