Commit Graph

11 Commits

Author SHA1 Message Date
6590a6b21a Move the download under the opening paragraph
Below the tech line is already too far down. Someone who has just read what the
app is wants the app next, not the toolkit it is written in.

One line now, as a heading so it reads as a button rather than prose, with the
facts that decide whether to tap it beside it — Android version, size, older
releases, checksum — and the install warning under it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-07 23:19:32 +02:00
66d8b82648 Put the download where someone looking for it will look
The APK has been in releases/ all along, but nothing on the front page said so,
and the first thing most people want from an app's repository is the app.

A Download section above the fold: the current build as a relative link that
works on any forge, the raw URL spelled out for anywhere the relative one does
not resolve, the checksum to verify it, and a pointer to releases/ for every
earlier version.

It also says plainly that Android will call the developer unknown and ask to
install anyway. That warning is what Android says about every app installed
outside a store, and read cold it looks like the app is unsafe rather than
merely unlisted — better to say so first than to let someone find out and
assume the worst.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-07 23:17:49 +02:00
Claude
8451cc45fb
Open reading settings in the left-hand panel on large screens
On a tablet or an unfolded foldable the gear now opens reading settings
as a panel on the left, where the dictionary opens, instead of a bottom
sheet. The page stays in view beside it, so a change of theme, font,
weight or size shows on the poem as it is made. The sheet and the panel
share one ReadingSettingsContent; phones keep the sheet.

Adds wireframe 8 and notes in the design docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhmDdrN5hgWrgRcFLAMsV6
2026-10-07 14:51:12 +00:00
Claude
cf65072af4
Add a column layout for tablets and unfolded foldables
At 600dp and wider, opening a poet turns the home grid into a narrow
column of poets on the right, with a column for each level of the open
book (books, chapters, poems) beside it and the page in the rest of the
screen. Columns narrow as more open and while a poem is being read, and
can be hidden for a reader view, with a floating button to bring them
back. Below 840dp only the newest list column is shown. The routes are
the same as on a phone, so folding or unfolding keeps your place.

On large screens the dictionary opens in a panel to the left of the poem
rather than as a bottom sheet, and the looked-up word stays highlighted.

Loading no longer covers the whole screen with a spinner, on phones too:
only the part that is waiting shows a skeleton shaped like its content,
under the real top bar, and fades into the content when it arrives.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhmDdrN5hgWrgRcFLAMsV6
2026-10-07 14:05:07 +00:00
50bbe0b729 Correct the unofficial statement: separate, not unendorsed
The first wording claimed this app is "not affiliated with, endorsed by" the
owners of ganjoor.net and that they "bear no responsibility for it". That
overstates the distance: permission to build it was given. What is true, and
all that needed saying, is that this is a separate project and they do not run
or manage it. The denial of endorsement is gone from all three languages and
from both places in the README.

The author is named in full — Muhammad Anas Rashid — everywhere it appears.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-07 15:12:11 +02:00
16bcd6949f Say plainly that this is an unofficial client, and name what it is built on
Someone arriving from ganjoor.net had to infer from the credits that this is a
separate project. The About page now opens with it, before the licence list,
in all three interface languages: independent, unofficial, maintained by Anas
Rashid, not affiliated with or endorsed by the owners of ganjoor.net, who carry
no responsibility for it. The README leads with the same paragraph and points
issues here rather than at the Ganjoor project.

The README also gains a full inventory of the open source this app is built on
— Ganjoor and GanjoorService, ganjoor-data, Daneshjoo, Wiktionary and Urdu
Wiktionary, wiktextract, the three fonts, and every library — each with its
repository and terms. licenses/README.md already carried most of it, but a
reader looking for "which repos does this use" should not have to open a second
file to find out.

GanjoorService is listed with the point that matters: GPL-3.0, no code used,
only data over HTTPS.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-07 14:58:28 +02:00
Anas Rashid
0d083b6638 Make OLED a switch on the dark themes, and stream recitations
OLED was a sixth theme, which meant choosing it threw away sepia night. It is
a switch now, applied to whichever dark theme is in use: the surfaces move
towards black rather than being replaced by it, so sepia night keeps its warmth
and only the background goes truly black. Text and accents are untouched.
Anyone who had picked the old Black theme comes out as Dark with the switch on.

Recitations: Ganjoor hosts readings of the poems — twenty of Hafez's first
ghazal alone — and the poem screen now plays them. Streamed, never stored,
because a dozen readings of one ghazal would dwarf the poems themselves, which
also makes this the one part of the app that genuinely needs a connection; it
doesn't appear without one. The platform's MediaPlayer rather than ExoPlayer:
one URL, play and pause, nothing to justify a media library.

Pronunciations were laid out as a flowing row, which put Latin IPA and Urdu
spelling in the same right-to-left run — the chips reordered and each label
ended up under someone else's value. They are one per line now, in a single
direction.

Verified on an API 36 emulator: sepia night with the switch on is black with
warm cards; the player shows play on arrival with no network call, and streams
on press.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-04 18:05:21 +02:00
Anas Rashid
c548e6ec07 Add a tap-a-word dictionary, layering Wiktionary and Daneshjoo
Tapping a word in a poem now opens its meaning. Neither source covers enough
alone — Daneshjoo reaches 71% of real poem vocabulary — so both ship, each row
carrying its source so the credit stays attached and either can be dropped
later. Together with the lookup chain that reaches 88%, and 13 of the 55
remaining misses are Arabic lines quoted inside Persian poems.

Lookup widens until something matches: the word as written, the lemma it
inflects from, the word with an affix stripped, then the parts of a ZWNJ
compound. The lemma step is what makes classical verse readable, and it comes
from Wiktionary's 149,589 form->lemma pairs: افتاد is only findable as افتادن.
The Arabic definite article is stripped too, since poems quote Arabic.

Two things the build taught me. Wiktionary's 93 MB export is 0.94 MB of
definitions wrapped in inflection tables, etymology templates and IPA, so
tools/build_dictionary.py keeps the definitions and the form index and drops
the rest. And the packager silently gunzips .gz assets and strips the
extension, which shipped the database under a name the code wasn't opening —
every lookup failed silently until the APK listing gave it away.

Hit testing needed care as well: nastaliq is set with 2.4x leading, so most of
a line box is empty space, and a tap there clamps to the line's first
character — which made every tap return the opening word. Taps are now checked
against the baseline band, with the multipliers left as a knob for swapped
fonts. Definitions are English, so they read left-to-right inside the
otherwise right-to-left sheet.

Verified on the release build, where R8 could have broken the SQLite path:
tapping عشق returns both sources, and دانند resolves to دانستن.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-04 02:02:00 +02:00
Anas Rashid
a5fc608bca Add poem search, an OLED theme, and credit every licence
Search: full-text across the poems, scoped to all poets, a few, or one. The
static data set has no index, so this is ganjoor.net's own search endpoint,
which scopes to one poet at a time — several picked poets run as several
queries and merge. Entry is the poets filter box, which now sits in the bottom
bar within thumb reach and offers its own words to the poem search one tap
further. Snippets show the line the term is actually on.

Themes: a sixth, true black, for OLED panels where an unlit pixel costs no
power. Surfaces step up in near-blacks so cards stay distinguishable.

Licences: every component is now credited in-app under Reading settings >
About & licences, with the full text bundled in assets/licenses — the OFL
requires the licence to travel with the software, so linking to it wasn't
enough. licenses/README.md indexes the same thing for the repo. The credits
list and the licence texts lay out left-to-right in English, since the rest of
the app is right-to-left for the poetry's sake and English prose is unreadable
right-aligned.

Fixes a crash: the settings sheet was composed outside the provider supplying
LocalOpenAbout, so opening it threw.

Search decoding is covered by a unit test against a real API response; the
rest verified on an API 36 emulator.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-04 01:05:52 +02:00
Anas Rashid
abcffbc43b Add offline reading, bookmarks, three UI languages and downloads
Reading
- Naskh is now the default face, and both Arabic-script fonts are registered
  at four weights so the text can be thickened for a lit screen.
- Category listings show each poem's opening line, fetched best-effort from
  api.ganjoor.net since the data set doesn't carry excerpts.
- Tap a couplet to save that passage or copy it; a saved passage keeps a
  tappable link back to its poem. Poem text is selectable for plain copying.

Languages
- Persian, Urdu and English, Persian by default whatever the phone's locale,
  applied in attachBaseContext and switchable from the top bar or the sheet.
- English chrome uses Libron (OFL); poems stay naskh or nastaliq throughout.
- Each language gets its own values-* folder: with Farsi only in values/,
  Android was resolving it to the Urdu strings, since a same-script locale
  outranks the default.

Offline
- Downloaded poets mirror the data set's layout under filesDir, so offline
  mode is one lookup rather than a parallel path. Downloads run one poet at
  a time, skip what's on disk, and resume by restarting.
- Downloads screen lists every poet with their portrait and tick boxes for
  picking several, plus storage used, delete, and download-everything behind
  a size warning.
- Offline mode refuses the network and says what's missing rather than
  blaming the connection.

Also: poet sort (Ganjoor's order or alphabetical, via a Persian collator),
RTL nav transitions, an original shamsa launcher icon with a monochrome layer
for themed icons, and preferences written with commit so they survive the
process being killed.

F-Droid: dependenciesInfo off, optional signing so the build works with no
keystore, fastlane metadata in three languages, cleartext traffic disabled.

Verified on an API 36 emulator: downloaded a poet, pulled the emulator's
network, read them offline, and confirmed an undownloaded poet reports being
missing rather than erroring.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-03 23:20:42 +02:00
Anas Rashid
d9915eac6c Build the Ganjoor reader on the static ganjoor-data set
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>
2026-10-03 22:46:09 +02:00