Commit graph halkyon/halkyon_learn_flutter
Author SHA1 Message Date
40e4fb49fc
chore(release): v0.17.0
All checks were successful
CI / check (push) Successful in 18m19s
CI / deploy (push) Successful in 29s
Build 20.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:49:57 +02:00
3a328d2bb8
feat(profile): a handle in a studyset opens its person's profile
The summary's first block now reads as a studyset's card: its secondary
title, its title, then by @handle; the blocks' second heading is
Material. A licence holder written as a handle of the instance
(@raisondetredev) reads © raisondetredev, the © standing for the @,
and is a link, apart from a name from elsewhere such as Tae Kim's; it
and the author open their public profile in a sheet: avatar, name,
address, bio and links, as the instance's profiles.byHandle gives them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:54 +02:00
500ce1a25b
fix(explore): the summary in blocks: what it is, what it holds, its release
The summary sheet ran its parts together, each aligned its own way. Now
it groups them in cards, as the Profile tab does its parts: what the
studyset is (its colour along the top, its secondary title, author and
description), what it holds (languages, contents, learners), and its
latest release with its notes and Reports and suggestions; its credits
centred beneath them, as at the foot of a studyset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:54 +02:00
11b0935728
test: two test names quoted as the lints ask
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:54 +02:00
9c39155b94
fix(studyset): an exam's pace keeps its rate, and plans hold what they show
The pace kept a week for reviews only while more than two weeks were
left: followed from further off, it halved its rate at two weeks and
brought new cards until the exam. It now keeps a week, or half the days
left when the exam is closer, and the sheet says so.

An exam whose plan is gone said "Today", as the days left came from the
pace, which needs the plan; they are now counted from the date alone.
Once the exam's day was over, the study plan still asked for everything
new at once and Study for the exam queued every new card; now neither
shows, and a session for it studies as usual.

Cards tagged HSK 3 alone offered HSK 1 and 2, plans covering nothing;
a level offers a plan only when it covers some tag present. The plan
editor kept topics deleted or moved out since and tags spelled in
another case, chosen but not shown, and ticking such a tag added it
twice; once it has read what a plan may cover, only that stays chosen,
each tag as the flashcards spell it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:54 +02:00
57240f01f3
fix(explore): copies take the author's later changes to exam plans
Taking a newer release kept every exam plan of a copy as it was. Copying
names a plan's topics by the copy's own studysets, so the copy's plans
never equalled the release it last took, which names the author's, and
were kept as the learner's change. Releases also hold their keys sorted
at every level while the app writes its own order, so the comparison of
a field failed on the order alone: a plan with topics and tags, and the
description of every copy, whose rich text nests maps, never took a
change either.

Now the plans of both releases name the copy's studysets before they
are compared (topics new in the release are named once their studysets
are made, as before), and fields compare whatever the order of their
keys. A plan the learner changed stays theirs. The updater's tests now
build releases with sorted keys, as the server writes them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:53 +02:00
87b200e3eb
perf(studyset): read exam plans only after changes that matter, once they settle
Every studyset screen holds an exam cubit, those stacked beneath the one
in view and beneath a study session too, and each read the plans again
on every change of cards, reviews, paths, their progress, PDFs or tags:
with every rating, each of them decoded every card of its studyset, some
8,000 in a language's, and its progress with an exam chosen too.

Now the plans are read again only when studysets, cards or tags change,
and the progress alone on reviews, paths, their progress and PDFs, only
while an exam is chosen. Reading waits until changes have settled for
2 s (cancelled when the cubit closes), and a burst still reads once.
Studysets and tags handed out again unchanged are no change, and a
change of the studyset itself (the choice, its author's plans) shows at
once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:53 +02:00
fe80c565d1
fix(explore): the summary's foot lines up with the rest of it
The summary sheet started its lines at the edge, set Reports and
suggestions in by its button's padding, and centred the licence as the
foot of a studyset's screen does: three alignments in one sheet. Now
every line starts at the edge; the studyset's screen keeps its footer
centred.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:53 +02:00
e1032caf7e
fix(dictionary): a Greek letter found opens no empty sheet of strokes
Tapping a letter of the Greek alphabet among the dictionary's results
opened the character sheet, which could only say that there's no stroke
order for it. A letter of an alphabet has no strokes drawn, so the
dictionary now offers the tap only for characters of a script whose
strokes are drawn (Han characters, kana, Hangul), as a studied
character's answer does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:53 +02:00
fd783df649
fix(study): a Japanese word's romaji reading is not typed as pinyin
Any reading in Latin letters counted as pinyin, whatever the studyset's
language, so a Japanese word read in romaji (東京 as Tōkyō or toukyou,
common in imported decks), which was never typed for having no kana, was
typed with pinyin's tone numbers and hint, and tokyo was marked wrong.

A reading is now pinyin only when the studied studyset's fronts are in
Chinese (zh, in any script or region), its own language or inherited: the
session reads it as each round starts, the card the same languages its
screen is set in. A Japanese studyset studies as it did before pinyin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:52 +02:00
6ea7375376
fix(study): pinyin of names and sayings is typed and checked right
CC-CEDICT capitalises names, so their readings start with a capital vowel
with its tone mark (欧洲 Ōu zhōu, 澳门 Ào mén, 俄语 É yǔ), which the test
for pinyin didn't know: those words were never typed. It now reads the
reading in lower case.

CC-CEDICT also keeps a saying's comma, written between spaces (bù pà màn ,
jiù pà zhàn), and the comma split the reading into two readings, so typing
the whole saying was wrong and half of it right. A comma with a space
before it now stays part of the reading, and commas count for nothing when
readings are compared; a comma written straight after a reading (xíng,
háng) still separates readings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:52 +02:00
d3063e82e1
fix(dictionary): a German separated verb is a verb, never a joined noun or particle
A clause ending in a separable particle joined each word before it to the
particle and offered whatever the dictionary found, so "Er holt mich ab."
offered aber, "Er schläft ein." einer and "Er hört dem Lehrer zu." zudem.
Now only an entry that is a verb is offered, and a capitalised word after
the clause's first is taken for a noun and never joined.

The particles of fernsehen, hochheben, durchlesen, unterbringen,
übersetzen and bereitstellen were missing, as were the spoken rein, raus
and runter, so "Ich sehe heute Abend fern." now finds fernsehen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:52 +02:00
21b71a4413
feat(explore): cards as the library's, in its colour, with a description of their own
Explore lists its studysets in a grid as the library does: each card in
the studyset's colour along the top, its title under its secondary
title, the start of its description and what it holds, then, quieter,
its author's handle, the release and the licence, and a compact Add.
A tap opens the summary, which shows the colour too.

The Publish sheet has a Description on Explore, starting from the
latest release's, else the studyset's own, and sent with the release:
a studyset may introduce itself to strangers while its own description
stays empty in the library.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:52 +02:00
31eed85aff
fix(card): a search for blue no longer finds blunt
The card browser looked for a query also with every ae, oe and ue made
a, o and u, so that maedchen found Mädchen: in any language, so blue
found blunt, Spanish que found aquí, and ue nearly everything. A card's
umlauts are written out on its side instead, beside its folded text,
and a query is matched as typed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:51 +02:00
4eb2640be6
fix(study): a map question names none of Japan's parts before it is answered
The chips above Japan's map (Hokkaidō, Tōhoku, Kantō …) showed while a
prefecture's question was answered: Hokkaidō's and Okinawa's chip was
the answer itself, and the others named the region the prefecture lies
in. A study card now offers them only once checked; tapping the map
still opens the part tapped. The world's continents keep their chips:
shortcuts no question asks for. Writing a question offers them all, as
before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 18:23:51 +02:00
26dbc84865
chore(release): v0.16.0
All checks were successful
CI / deploy (push) Successful in 28s
CI / check (push) Successful in 17m3s
Build 19.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 15:07:53 +02:00
0a52a3947a
test(publish): publishing end to end against a running server
All checks were successful
CI / check (push) Successful in 16m58s
CI / deploy (push) Successful in 1m28s
A sync test of the public tier as a whole: the author's device syncs a
studyset (a topic, tagged cards, a note, an exam plan, an exam of their
own), the instance builds the first release from what it holds, another
person finds it in Explore and adds it to their library (the topic, the
tags, the note and the plan's topic come along, the exam stays the
author's), a second release is offered and taken while the learner's own
edit stays, and a third is offered no more once the author withdraws.
Until now each half had tests of its own only: the server's publish from
rows written into its database, the app's copy and update from releases
through fakes.

A test can't sign in to GitHub, so it gives the author the identified
scope by SQL, on the person and their sessions, as linking GitHub does.
The devices' clients are exposed for what lives on the instance rather
than in the synced data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 14:35:36 +02:00
dd6c567ad0
feat(studyset): prepare for an exam, with plans, a date and the pace to it
A studyset plans for exams: each plan names what an exam covers, the
topics it takes whole (with their flashcards, learning paths and PDFs)
and the tags whose flashcards it takes from anywhere in the studyset.
The author's plans are published with the studyset (payload schema 7,
`examPlans`); copying a release and taking a newer one point their
topics at the copy's own studysets. Plans are also offered from level
tags: JLPT N5 to N1, HSK 1 to 7-9 and KRDict's levels, each taking the
levels below it, as the exams do.

The person chooses a plan and the exam's day (`exam`), which stays
theirs: the server leaves it out of a release, as a PDF's deadline.
The study plan then shows the days left, how many of the plan's
flashcards were started, its paths' steps done and its PDFs' pages
read, and the pace that gets everything new learnt a week before the
exam (by the exam when two weeks or fewer are left): new flashcards a
day, steps a week, pages a day. Study for the exam studies only what
the plan covers, its new cards at that pace (counted as the day began)
and every review due.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 14:35:36 +02:00
31e4d7d64b
feat(studyset): an empty tab says its material is in the topics, and leads there
People testing the app looked for the material of a studyset that groups
topics in its own empty tabs, which said "No flashcards yet" and how to
add some. A tab with none of its own while the topics hold some now says
so: "The flashcards are in its topics", each topic holding some with how
much (everything inside it counted), opening it; for flashcards Browse
all of them in one list; and, quieter, how to add some here after all.
Opened for the first time, such a studyset shows the first tab its topics
fill. The tabs' counts stay the studyset's own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 14:35:36 +02:00
8dde0fa42a
feat(assistant): a question opens in the AI assistant chosen, Proton's Lumo by default
Questions asked from the app went to Claude alone. Settings › Assistant
now chooses where they open (decided 2026-10-14): Lumo, the default, by
its guest chat with the question in the address's fragment (Lumo's
`prefill`, which needs no account and reaches no server; the address for
one's own account loses the question when nobody is signed in), ChatGPT,
Claude, Mistral, Perplexity, Duck.ai, Grok, Kagi Assistant, HuggingChat,
or an address of one's own with %s. Each link fills the question in for
the person to send (Perplexity answers at once, Grok asks first); Gemini,
which has no such link, and Copilot, whose stopped working, are left out.
The field names the assistant ("Ask Lumo…"). A device that sent questions
to Claude goes on asking an assistant, now Lumo. Connecting Claude to read
studysets stays as it was.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 14:35:35 +02:00
e7f3abdb8d
fix(dictionary): a Hanja reads 물 수, and each radical's form shows once
Korean names a Hanja by its meaning, then its sound; simplified Chinese
shares some radicals' forms with Japanese (麦), which showed twice, and
writes 黑 as itself. A test can read a language's strokes beforehand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 14:35:35 +02:00
93c33ce079
feat(dictionary): a German verb is found with its particle at the clause's end
"Ich rufe dich morgen an": where a clause ends in a separable particle,
each word before it is also asked for with the particle joined on, as a
subordinate clause writes the verb (anrufe), which Wiktionary lists among
anrufen's forms. The verb is offered beside its stem and its particle,
as the longer words running over a Japanese word are.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 14:35:35 +02:00
87bebd1953
feat(card): the card browser finds and sorts words of any language as typed
Search folded case and katakana only, for Japanese. It now also leaves out
accents, tone marks and umlauts (strasse finds Straße, maedchen and
madchen Mädchen, σπιτι σπίτι, xue xi xué xí), and A–Z sorts by the same
bare letters, so Ärger stands among the a's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 14:35:34 +02:00
e93f37ce68
fix(studyset): a studyset's title shows in its language's shapes outside it too
The library's cards and Explore's drew Chinese and Korean titles with
Japanese shapes first (骨, 直): each card now sets its studyset's
languages, as every screen inside a studyset does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 14:35:34 +02:00
5479b973fc
feat(dictionary): characters of Chinese, Korean and Greek, written by hand; pinyin typed
Parity with Japanese's kanji and kana:

- The characters' tab is named by its language (Hanzi, Hangul & Hanja,
  Alphabet), its groups too: HSK levels and the characters in common use
  (Hong Kong's grades for traditional ones); Hangul and the Hanja taught
  in schools; Greek's letters. Radicals for Chinese and Korean in their
  own forms (讠 for 言 in simplified Chinese), none for Greek.
- A character's readings are named as its language names them: On and
  Kun, Pinyin, Eum and Hun (음, 훈); a letter means its sound and name.
- How characters are written comes by language: Chinese from Make Me a
  Hanzi (its medians in KanjiVG's square, Arphic Public License, a data
  file beside the app, never in cards), the Hangul letters drawn by the
  curator; a Korean word is written letter by letter (닭: ㄷ ㅏ ㄺ). Words
  of alphabets (German, Greek) aren't written by hand.
- A Chinese word's pinyin is typed in a session, tone numbers turning
  into marks (ni3 → nǐ); KRDict's levels (초급, 중급, 고급) tag Korean
  words; a Korean word's pronunciation shows in brackets ([가치]).
- Smaller: Look up in the composer keeps a noun's article; the Watch
  filter names its level list; hints and placeholders by language.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 14:35:34 +02:00
4e6581b9a5
chore(release): v0.15.0
All checks were successful
CI / deploy (push) Successful in 28s
CI / check (push) Successful in 16m38s
Build 18.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 10:58:00 +02:00
2c4d760eac
feat(dictionary): a Chinese word's row says its HSK level
As a Japanese word's says its JLPT level: HSK 1 … HSK 6, HSK 7–9. The
levels' scheme (`WordLevels`, `levelOf`) moves from the Watch screen's
filter into the dictionary's model, which both name levels with.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 09:39:31 +02:00
a2441ecdf2
feat(dictionary): German, Greek, English, Chinese and Korean words
A studyset in German, Greek, English, Chinese or Korean finds its
dictionary as one in Japanese does (ADR 0008), and its subtitles are cut
into words by its language (`WordCutting`): Chinese by its longest
words as they stand, the longer words over each cut offered as for
Japanese; Korean at its spaces, a word the dictionary lacks as it stands
taken without the particle it ends with (집에서 is 집, 아이 stays a
child); every other language at its spaces, a word written exactly so
first (the noun Essen before the verb essen). A studyset finds the
dictionary of its language tag, else of its language alone (zh for
zh-Hans).

A Wiktionary word shows its genders, principal forms, IPA, romanisation
and Hanja; a German or Greek noun of one gender goes onto its card with
its article (das Haus, το σπίτι); its tag is its word class, named in
full (Noun, Adjective, Preposition), as Wiktionary's adj and adv would
read as JMdict's codes. Articles, pronouns, prepositions and
conjunctions are left out of a video's words. Chinese words show their
pinyin over each character on the Watch screen, carry their HSK level
as a tag (HSK-1 … HSK-7-9), and the dictionary adds a level whole; the
Watch screen filters by HSK levels for Chinese, JLPT's for Japanese, and
by none for a language without. A reading is typed in a session only
when it is kana, so pinyin isn't. Words are looked up on the web on
Jisho in Japanese, on Wiktionary at the language's section otherwise,
and a search's hint speaks of kana and romaji only in Japanese.

`DICTIONARY_LANGUAGES` in deploy/.env names the languages an instance
keeps (unset: de,el,en,ko,zh; empty: none).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 09:39:30 +02:00
5683a1f33e
test(tag): the tag filter has room beside four material tabs
The test font draws every letter as a full square, so at 1,200 wide the
four tabs left the flashcards' filter folded into the menu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 09:39:29 +02:00
f8336ada90
test(studyset): every empty material tab is opened, as each has one
Since paths moved out of the Study plan, every empty section the test
looks at is a tab of Material, so the check for one without a tab is
always true, which the analyser refuses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 09:39:29 +02:00
ed34503cda
feat(studyset): an empty material tab shows no count
With four tabs, Paths 5, Flashcards 12, Notes 0 and Files 0 don't fit a
phone, and Files scrolls out of sight. An empty tab says so itself once
opened, so its count goes (decided 2026-10-14, after the trial's
screenshots); the four tabs then fit as long as a few are empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 09:39:28 +02:00
c3f7de9607
feat(studyset): learning paths are material, the study plan refers to them
A learning path is material too, as its flashcards, notes and files are,
and the study plan only refers to it (decided 2026-10-13), as it will to
an exam's date. Material's tabs are now Paths, Flashcards, Notes and
Files, the paths first as the way through the rest, with Reorder beside
them; opened here for the first time, Material shows the first tab with
something in it. Study plan keeps how many paths are finished and Next
up, which names the next step of each path under way ("Step 3 of 6: が"),
or offers to start the first path not finished when none is, and lists
how far every path has come, its steps done in a bar, each opening the
path. The path list's state now knows each path's steps done and next
step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 09:39:23 +02:00
744a068c97
chore(release): v0.14.0
All checks were successful
CI / deploy (push) Successful in 14s
CI / check (push) Successful in 15m45s
Build 17.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 06:02:07 +02:00
107160cac4
fix(jellyfin): a tap on someone a server shows names them, the password asked
Jellyfin v10.11 and later no longer say which accounts have a password
(HasPassword is always true, jellyfin/jellyfin#14950), so the demo's
account was listed as "With a password" and only named in the form.
Every listed account is now named in the form with the password field
focused, which says to leave it empty for an account without one, as
Jellyfin's own apps do; the line under each account goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 01:55:12 +02:00
48ac84d92c
feat(jellyfin): any stretch of a line's characters chosen by hand
The cut takes the longest word and knows no grammar, so 今日は reads as
こんにちは where it is 今日 and は. Any stretch of a line's characters can
now be chosen by hand: dragged across with a mouse, Shift+clicked from
the word or stretch chosen, or on a touch screen held on a character and
dragged on. It is looked up as one word, as it stands or as a form of
one, in one small request (the instance has the line's text already);
while it is chosen the line reads it as that word (きょう over 今日), and
what the dictionary lacks as one word is offered as a search on Jisho.

The line's words move into line_words.dart, out of the Watch screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 00:33:51 +02:00
85506ac7eb
feat(jellyfin): the instance suggests a Jellyfin server, signed in to with a tap
An instance now names a Jellyfin server for its people to learn from
(instance.info().jellyfinUrl): its operator's JELLYFIN_URL (`none`: none),
else https://jellyfin. on the domain registered for its public host, as
learn.halkyon.eu suggests jellyfin.halkyon.eu, once that answers as a
Jellyfin server. The registered domain comes from Mozilla's Public Suffix
List, kept in the server's data folder, so an instance at example.co.uk
never names someone else's jellyfin.co.uk. The instance looks as it
starts and again hourly when asked; the app never reaches for a guessed
address.

In the app, Add material offers From Jellyfin as soon as the instance
suggests a server, before anyone signed in to one. The sign-in fills the
server in and finds it by itself, and lists the people the server shows
on its login screen: one without a password, as a demo's, signs in with
a tap; one with a password is named in the form, which asks for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 00:33:50 +02:00
63c2f86b12
chore(release): v0.13.0
All checks were successful
CI / deploy (push) Successful in 14s
CI / check (push) Successful in 15m59s
Build 16.

Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:48:52 +02:00
d552f8bea0
feat(jellyfin): From Jellyfin once signed in, the panel in the glow's colour, adding the words listed
All checks were successful
CI / check (push) Successful in 16m0s
CI / deploy (push) Successful in 1m13s
Add material's entry is now From Jellyfin (Aus Jellyfin), with a play
icon rather than a TV, as it plays music too, and shows only once the
device is signed in to a server in Settings, as the assistant shows only
once switched on; Settings says where it then is. The screen it opens is
called Jellyfin, and its search finds music too.

The words' panel takes the glow's colour as the scene changes: each copy
the glow takes (every 3 s) gives its average, no lighter than 35 % so the
text stays readable, as strong as the glow and fading into the next as
it does. In the light theme, which has no glow, the panel is tinted from
it while the pointer is over it. What lights up in the panel takes a
scheme made from the same colour; the episode's thumbnail is no longer
used.

While the studyset holds none of the video's words, the study button
adds the words listed (Add 11 words, as the filter shows them), tagged
as a word added alone is; afterwards it studies them, and its menu adds
the new ones listed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:21:50 +02:00
c6e7a53dd6
feat(tag): one switch hides the tags from Jellyfin while studying
Every tag the app makes for where words were met on Jellyfin (the show
and the episode, the artist and the song) now says so (`origin` in tag
schema 2, written only for such a tag), in place of a tag hidden one by
one. Manage tags, where there are such tags, has one switch, Hide tags
from Jellyfin while studying (`hideJellyfinTags`, settings schema 9,
following the person): with it on, cards being studied leave them out of
their row at once, and Tags and Manage tags list them faint. They still
filter and narrow a session. The per-tag eye button is gone.

A word added while watching no longer takes the line it was met in as
its first hint: its hints are the dictionary's examples alone. Tatoeba's
sentences are checked, a subtitle line may be wrong or mistyped, a word
met again in a better line wouldn't get it, and every episode's line
would pile up on a common word.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:21:50 +02:00
cc777d6b06
fix(study): cramming again after turning front and back
A session begun anew (turned to the other side, its settings changed, or
tried again) kept the cards it had crammed before, so a cram of a few
cards turned round said at once there was nothing to study. It now
crams every card again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:21:50 +02:00
22f5a4fcd1
feat(jellyfin): songs and their lyrics, read as subtitles are
A music library's artists and albums open as shows and seasons do, and
can be tied to a studyset. A song plays as sound alone (`/Audio/{id}/
stream`, as stored) with its lyrics as Jellyfin keeps them (`/Audio/{id}/
Lyrics`: an LRC file beside it, or its tags), cut into the dictionary's
words as a video's subtitles are, with no translation. Timed lyrics
follow the song: the line sung large and bright among the others faded,
scrolled to as it comes, a line tapped played from its start; untimed
ones show whole. A song without lyrics shows greyed and doesn't open
(`HasLyrics`), as there is nothing in it to read. Its cover stands where
the picture would, glowing as a video does, and its words are tagged
with the artist, shown, and "artist · title", hidden.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:21:50 +02:00
436dc884b6
feat(jellyfin): an episode's own tag, and studying an episode's words
A word added from an episode gets the show's tag and the episode's own ("あかね噺 S1 E1"), hidden on cards. The words panel's Study button studies the studyset's cards of the video's words, on their schedules or crammed (each once): it pauses the video and first gives the episode's tag to the cards of its words the studyset held before, then opens the session on that tag. A study focus can now ask for cramming.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:21:49 +02:00
68945b2224
feat(tag): a tag can be hidden on cards being studied
A tag's eye in Manage tags hides it on cards being studied, or shows it again: for the many tags naming where a word was met (an episode, a song), which would crowd a common word's card. A hidden tag still filters, narrows a study session and shows where tags are edited. Tag schema 2 adds 'hidden', written only for a hidden tag, so older apps go on reading every other.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:21:49 +02:00
747d73b867
fix(jellyfin): Add and Jisho on the word's own line, entries unfold after 0.6 s
The Watch screen's entries carry Jisho's link and Add at the end of the headword's line, aligned right, rather than beside the senses; and an entry unfolds over the list once the pointer has rested on it for 0.6 s, as 0.3 s opened entries the pointer only passed over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:21:49 +02:00
8fb5e105c9
fix(dictionary): a long kana word stands, and a word offers the longer ones
Cutting a line into words, kana that is no common word gave way to a
shorter common one whatever its length, so もうろく (耄碌, senility) was
taken as もう and ろく. The rule now holds only for kana of up to three
characters (が and まだ still win over がま, a cattail, and だ); a longer
kana word stands even when uncommon, as ichi.moe's segmenter weighs long
kana words by their length. And as no cut is always right, each word now
knows the longer words running over it into its neighbours, worked out
from the same lookup, which the Watch screen's panel offers beneath its
entries ("Longer words here"), each to add with the line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:21:49 +02:00
fbe53c3441
feat(jellyfin): the words' panel unfolds senses, shows progress, filters
The panel beside the video lists each entry's senses one to a line, as
Jisho does (and as every dictionary list in the app now does), folded
to two lines; an entry unfolds over the list, not in it, after a moment
under the pointer or on a tap, in the video's colour, so nothing moves
under the pointer and words of many senses (上げる has 25) crowd out
nothing. Each entry links to the word on Jisho.org, opened only when
tapped. A word the studyset holds shows how far its card is learnt:
New, Learning, Due, or Learned with when it comes again. The video's
words go through a filter in place of New only: new to the studyset,
held or all, JLPT levels, and word classes. The dictionary's sources
stay in the panel's lower right corner, and the player's controls hide
after 2 seconds rather than 3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:21:49 +02:00
48a9564231
feat(jellyfin): the player as players are, with the settings under a cog
The Watch screen's player takes the shape people know from players,
YouTube's first: the picture set in from every side with rounded
corners, so the glow of its colours shows all around it, and over it
play or pause in the middle with 10 seconds back and on beside it, and
along its foot where the video is (0:05 ──── 23:47) and a cog. The
controls fade out while it plays and the pointer rests, and come back as
it moves, on a tap with a finger, on a jump and while paused. The cog
opens a panel inside the picture, so nothing runs off the window: Pause
after each line, the subtitles, the translation and the sound, each
track named by its language in the app's words, and the keyboard
shortcuts. The buttons for the line before, again and the next sit
beside the subtitles they act on, no longer looking like a player's
skip to the next video. Keys are YouTube's (Space or K, J and L, the
arrows, 0 to 9, Home, End) with Shift and the arrows for lines, R, P and
Esc; ? lists them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:21:48 +02:00
96cbd912de
fix(ui): a window resized across 600 dp keeps every screen as it was
Crossing from compact to medium windows or back built screens anew,
losing what they held: a study session started over, a card being
written lost its text, a video began again. The frame around a screen
over the tabs (FramedScreen) was added above it only from medium windows
on, and the snack bars' width (FittedSnackBars) put a Theme above the
app's navigator only there, so the screens below sat at another depth
after the change. The snack bars now always keep their Theme, changing
only the width in it, and the framed screen keeps its screen under a
global key, which moves it whole between the two places.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:21:48 +02:00
da51ef73cb
feat(jellyfin): watch from one's own Jellyfin server and learn the words of its subtitles
Animelon's way of learning from video, from the person's own Jellyfin
server: connected per device (Settings, or a studyset's Add material ›
Watch from Jellyfin) with a name and password or a Quick Connect code,
over HTTPS only (plain HTTP only to a server on the same machine); the
token stays in the system's keyring. Shows, films and videos tied to a
studyset follow the person in their settings as the server's and the
item's ids alone (settings schema 9), named by the server when shown.

The Watch screen plays the video (video_player on Android, media_kit's
libmpv on Linux and Windows) with the line in the studyset's front
language cut into the dictionary's words with furigana, and the back
language's line beneath; a word tapped pauses the video and becomes a
card with the line and its translation as its first hint, tagged with
the show. The video's words are listed, most frequent first. The sound is
the track in the studyset's language, whichever the file marks default,
and the menu switches it; the subtitles read are a whole track, never a
forced one (which only covers what the sound doesn't say), and captions
for the hard of hearing only without plain ones. The line and its
translation take the video's width in a box of a fixed height, so the
video keeps its size; in the dark theme the video's colours glow around
it, as YouTube's ambient mode, and the words' panel takes the colour of
the episode's picture under the pointer.

A line is cut into words with one request: DictionaryEndpoint.withKeys
looks up every stretch of it that may be a word, as it stands and as
every word it may be a conjugation of, in the new dictionary_key table
(one row per key, indexed; migration dictionary-keys adds the table and
its index, nothing else), which the loader fills beside the entries.
The instance gets the text of each line looked up and keeps none of it,
as the Watch screen says.

Linux builds need libmpv-dev, and the app links libmpv: the snap stages
Ubuntu's libmpv2, makes the update-alternatives links for BLAS and LAPACK
that ffmpeg's speech recognition needs (staging never runs install
scripts), and removes what the GNOME runtime and core24 already hold, as
older copies of cairo, pango and librsvg hid the runtime's from its GTK.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:21:48 +02:00
61bf7b2fa0
feat(citation): sources are books and articles, websites or YouTube videos
A source was a book's or an article's parts, however a website or a
video had to be squeezed into them. Adding one to a bibliography or a
step now asks what it is, and its form asks for what cites it: a book
or an article its parts as before; a website the page's link, title,
the site's name, authors and year; a YouTube video its link (checked to
be one), title, channel and year. Websites and videos need their link,
marked as required. A video is cited as APA cites one ("[Video]", a
part of YouTube) and plays in the app where it can, else on YouTube.

The kind is kept in the source's JSON, left out for a book or an
article; a kind this app doesn't know reads as a work. The studyset's
payload goes to schema 6 and a step's to schema 4 for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-13 21:21:48 +02:00