Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
- sayso's tests: `PYTHONPATH=lib python -m unittest discover -s tests/sayso` from the root. The offline tests need no credentials; `test_live.py` skips without a `sayso.local.json`. Never commit `sayso.local.json`, `tokens.json` or `lib/sayso/examples/write_examples.json`.
- To test sayso without a network, replace `sayso.transport.requests` with a mock that has `get`/`post` (and `put`/`delete` for writes) before you build `SpotifyClient`.
- Spotify's Dev Mode removed `GET /users/{id}` and the legacy playlist track endpoints ([PORTABILITY.md](lib/sayso/PORTABILITY.md)). Don't add `fetch_method` on `User`.
- tests/ has an `appkit` folder, which hides the real `appkit` when `tests/` is first on the path: put `lib/` before it.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pip install ./audiodsp numpy
pip install --no-deps ./audioinstruments ./audioeffects/lib/audioeffects
```

The libraries the apps share (`appkit`, `controlkit`, `sayso`,
The libraries the apps share (`appkit`, `controlkit`, `deskkit`, `sayso`,
`songmodel`, `soundmodule`, `spectrum` and `touchkit`) also install as a package, under
their own names. Each is imported directly, as in `import controlkit`:

Expand Down
5 changes: 5 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ It grows one part at a time, on the desktop interpreters first.
- Stompbox (`apps/stompbox`) plays a guitar through one airwindows effect. A
meter and clip light, a tuner, several slots and presets come next.

## Clock and Weather

- More faces on the clock, and a way to pick a face that's saved.
- Weather searches by place name, for anywhere outside the US.

## Libraries

- sayso's own list is in [lib/sayso/ROADMAP.md](lib/sayso/ROADMAP.md).
Expand Down
37 changes: 37 additions & 0 deletions apps/clock/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# SPDX-FileCopyrightText: 2026 Brad Barnett
#
# SPDX-License-Identifier: MIT
"""Clock: an analog clock that fills the screen, on the time at your chosen place."""

import lvgl as lv
from deskkit import forecast, localtime

from .face import AnalogClock

FACE = "Grand Classic"
_TICK_MS = 200 # the second hand is at most this late


def main(scope):
root = scope.root
root.remove_flag(lv.obj.FLAG.SCROLLABLE)
clock = AnalogClock(root, scope.size, localtime.clock_time, FACE)

# A clock showing a wrong time looks right, so say so until it's been set.
waiting = lv.label(root)
waiting.set_text("Setting the time")
waiting.set_style_text_color(lv.color_hex(clock.skin["second"]), 0)
waiting.set_style_text_font(lv.font_montserrat_16, 0)
waiting.align(lv.ALIGN.CENTER, 0, 70)

def tick(_timer=None):
clock.update_time()
if localtime.is_set():
waiting.add_flag(lv.obj.FLAG.HIDDEN)
else:
waiting.remove_flag(lv.obj.FLAG.HIDDEN)

scope.every(_TICK_MS, tick)
tick()
# Here all day: the forecast's reply is what keeps the offset and the clock right.
forecast.keep_fresh(scope)
1 change: 1 addition & 0 deletions apps/clock/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name": "clock", "title": "Clock", "category": "Desk", "symbol": "BELL", "color": "#8A651E"}
Loading
Loading