Poets grid, category browsing and a poem reader backed by github.com/anas-rashid/ganjoor-data over jsDelivr — no backend, addressed by Ganjoor URLs rather than numeric ids, with a 64 MB OkHttp disk cache so anything already read stays readable offline. Reading: couplets stack with the first hemistich at the start of the line and the second at the end; prose sections fill the column. Bundled Noto Naskh Arabic and Noto Nastaliq Urdu, switchable while reading, with the extra leading nastaliq needs. Five themes (system, light, dark, sepia, sepia night) and a text size slider, all persisted. Whole app lays out right-to-left. Verified on an API 36 emulator through poets -> category -> poem in both sepia schemes and both fonts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
3.9 KiB
Ganjoor for Android
An Android reader for Ganjoor, the open archive of Persian poetry — 240 poets and ~135,000 poems, laid out for comfortable long-form reading in Persian, Urdu and Arabic script.
Jetpack Compose, Material 3, minSdk 24.
What's here
Reading. Poems render as couplets: the two hemistichs of each line stack on a phone, the first aligned to the start of the line and the second to the end, the way Ganjoor itself reads. Prose sections (Golestan, for example) fill the column instead. The whole app lays out right-to-left.
Fonts. Two bundled Noto families, switchable while reading:
| Font | File | Note |
|---|---|---|
| Naskh | res/font/noto_naskh_arabic.ttf |
Covers Persian, Urdu, Arabic and Latin — also carries the UI |
| Nastaliq | res/font/noto_nastaliq_urdu.ttf |
Traditional hanging script, needs ~2.4× leading (see readingStyle) |
Both are variable fonts shipped at their default weight; Android synthesises bold, since
variable axes would need API 26+. Licences are in licenses/ (SIL OFL 1.1).
Themes. Five modes, persisted across launches: System, Light, Dark, Sepia and Sepia night. The two sepia schemes are warm paper tones for long sessions — the dark one has no blue cast.
Text size. A slider from 14 to 40 sp with a live preview in the settings sheet.
Summaries. Ganjoor publishes AI-generated summaries for some poems and couplets. They are off by default and labelled as AI-generated wherever they appear.
Where the poems come from
There is no backend. Every "endpoint" is a JSON file in
anas-rashid/ganjoor-data, served over
jsDelivr's CDN, and addressed by the poem's own Ganjoor URL:
/hafez/ghazal/sh1 -> poets/hafez/ghazal/sh1.json
/hafez/ghazal -> poets/hafez/ghazal/_cat.json
Because paths are URLs, the app never touches the numeric id indexes. Responses land in a 64 MB OkHttp disk cache, so anything already read stays readable offline.
See data/Ganjoor.kt — the client is
about thirty lines.
Build
./gradlew :app:assembleDebug # APK
./gradlew :app:testDebugUnitTest # couplet grouping tests
Layout
data/Ganjoor.kt models, couplet grouping, the static-file client
ui/GanjoorApp.kt nav graph; routes carry Ganjoor URLs
ui/PoetsScreen.kt poet grid with name filter
ui/CategoryScreen.kt collections and poem lists
ui/PoemScreen.kt the reader
ui/ReadingSettings.kt theme / font / size sheet
ui/Settings.kt preferences
ui/Load.kt fetch + loading + retry
ui/theme/ colour schemes and typography
Single module, no DI framework, no ViewModels yet — screens fetch through Load and lean on the
HTTP cache. ponytail: comments mark the deliberate shortcuts and what would replace them.
Not built yet
- Search. The data set has no search index; this needs either a client-side index or
api.ganjoor.net's/api/ganjoor/poems/search. - Bookmarks and reading position. Nothing is stored locally beyond preferences.
- Recitations. Ganjoor has audio for many poems; it isn't in this data set.
- Offline download. The HTTP cache covers what you've read, not a whole divan on demand.
Licensing
The app code is MIT (see LICENSE). Two things worth knowing about what it builds on:
- The poetry is classical Persian verse, long out of copyright.
- The data set (
ganjoor/ganjoor-data) carries no licence file. Worth asking upstream to add an explicit one. - GanjoorService, Ganjoor's own backend and site, is GPL-3.0. This app uses none of its code — only data over HTTPS — so it is not a derivative work of it.
Fonts are SIL OFL 1.1, which permits bundling in an application.
Not affiliated with or endorsed by Ganjoor.