Skip to content

Add iOS Daily Puzzle widget#2965

Merged
veloce merged 41 commits into
lichess-org:mainfrom
r3econ:ios-lichess-daily-puzzle-widget
Apr 14, 2026
Merged

Add iOS Daily Puzzle widget#2965
veloce merged 41 commits into
lichess-org:mainfrom
r3econ:ios-lichess-daily-puzzle-widget

Conversation

@r3econ

@r3econ r3econ commented Apr 12, 2026

Copy link
Copy Markdown
Contributor

Adds a new iOS home screen widget that displays today's chess puzzle from lichess.org. Scroll down for demos.

Features

  • Large widget — board + header with the Lichess logo, title, side-to-move indicator, update time, and an optional rating (toggled via a widget configuration intent)

Board rendering:

  • Parses the puzzle FEN and renders the full 8×8 position with piece images
  • Highlights the last move square
  • Flips the board to always show the side to move at the bottom
  • Reads the board theme and piece set from the shared App Group, so the widget automatically matches whatever the user has configured in the app
  • Supports all board themes — both solid-colour (brown, blue, green, etc) and image-backed (wood, marble, etc.)

Data & refresh:

  • Fetches from /api/puzzle/daily; uses the host configured in the main app (supports local dev server)
  • Refreshes every 6 hours
  • Tapping the widget opens the puzzle natively via a universal link

Notes for reviewers

  • Board texture and piece images are sourced from the ChessgroundAssets swift package from flutter-chessground

  • EXTENSIONS.md documents how external contributors can build and test the widget locally using their own Apple Developer account, and what a Lichess org member needs to do when merging a new extension.

Showcase

Theme support

themes1

themes_2

Error state

errors

Configuration

config

Videos

  • Opening puzzle screen from the widget + widget config
demo_config.mov
  • Changing app and widget chessboard theme and piece set
theme_change.mov

r3econ added 30 commits April 11, 2026 09:25
All eight fixes applied cleanly. Here's a concise account of each change:

| # | File | Fix |
|---|------|-----|
| 1 | `app.dart` | Chained both `saveWidgetData` calls inside `Future.wait([…]).then((_) { updateWidget })`, matching the `kidMode` pattern |
| 2 | `BoardStyle.swift` | Added an explicit `"system"` case that returns the brown scheme with a comment documenting why (iOS always falls back to brown since `CorePalette`/Material You is Android-only) |
| 3 | `DailyPuzzleEntry.swift` | Changed the placeholder FEN to the position after `1.e4 e5 2.Nf3 Nc6` (`w` to move) with `lastMove: "b8c6"` — so `isWhiteToMove == true` and the board renders from white's perspective |
| 4 | `app.dart` | Added `prev != null` guard (equivalent to kidMode's `state.hasValue`) so the cold-start fire with `prev = nil` is ignored and the widget isn't reloaded on every app launch |
| 5 | `DailyPuzzleFetcher.swift` | `nextUpdateDate` now constructs a UTC `Calendar` (`TimeZone(identifier: "UTC")`) before computing the next 00:05 trigger |
| 6 | `DailyPuzzleProvider.swift` | `snapshot` simply returns `.placeholder` — no network call; the `isPreview` check was redundant since the real fix is to not hit the network at all in snapshot |
| 7 | `DailyPuzzleWidgetView.swift` | `errorView` now renders `Text(message)` instead of the hardcoded string, so the parameter is actually used |
| 8 | `BoardStyle.swift` | Removed `let teal = …` from the top of `from()` and made it a `private static let tealLastMove` — allocated once lazily, referenced only by the three cases that use it |
@veloce

veloce commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

What an impressive work! I will take the time to test and review it. Just responding to your questions for now:

Is small puzzle widget of any value? It only shows the board, it is very small and if we ever add another chessboard-based widget it will bring confusion since it has no title. Maybe we should simply drop it and only have a big one, or a medium one with title (which I implemented and removed but could bring it back).

Yes indeed the small puzzle widget has low value. Moreover if we add later other board widgets (like correspondence games for instance) we'd not be able to distinguish them. So I think you should drop it.
Whether we do the medium size is up to you. To me the added value is that it takes less vertical space than the full size one so it is interesting for people wanting to save space. That being said it could be added in another PR as the full size one is already good for a first version.

Image assets are currently copied from flutter-chessground using a script. This is convinient and rather low maintenance. However, I've been thinking of having a separate repo (e.g. native-chessground) that would provide a simple Swift and Android libraries containing chessboard and piece sets in native formats. This would mean that we do not have to have these files in the mobile repo. @veloce, if you find this idea legit, please decide - I could either prep this now and we wait with merging the PR or we do merge it and extract the resources later.

I think this is a good idea yes. If you feel like it is not too much work we could do it already in this PR to avoid adding too much assets in this repo.

@r3econ

r3econ commented Apr 13, 2026

Copy link
Copy Markdown
Contributor Author

I think we're slowly getting there 😎

SCR-20260413-udsd-tile

@HaonRekcef

Copy link
Copy Markdown
Collaborator

Looks amazing 💯

Minor nitpick:
Can we have a nice puzzle in the preview instead of a standard opening position?

@r3econ

r3econ commented Apr 13, 2026

Copy link
Copy Markdown
Contributor Author

Looks amazing 💯

Minor nitpick: Can we have a nice puzzle in the preview instead of a standard opening position?

@HaonRekcef of course, I'd just need the FEN, do you have something specific in mind? 🙂

@HaonRekcef

HaonRekcef commented Apr 13, 2026

Copy link
Copy Markdown
Collaborator

What about a smothered mate like this:
image

FEN:
1n3rk1/4ppbp/rq1p2p1/3P4/2p1P3/2N2P1n/PPN3PP/R1BQ1R1K b - - 11 18

from this puzzle: https://lichess.org/training/cGsUy

@r3econ

r3econ commented Apr 13, 2026

Copy link
Copy Markdown
Contributor Author

Indeed, it looks classy 🥇

image

@ijm8710

ijm8710 commented Apr 13, 2026

Copy link
Copy Markdown

Noah's puzzle pointed out another minor graphical bug

Puzzles over 999 should have no comma 😉

@r3econ

r3econ commented Apr 13, 2026

Copy link
Copy Markdown
Contributor Author

I'll check tomorrow but I suspect it's not a bug but a feature. Number formatting depends on the device's region setting. So it could well be it is correct

@veloce veloce left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Great work as usual.

@veloce veloce merged commit b615b8e into lichess-org:main Apr 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants