The check for whether the system has been asked to stop animating
things looked at two of Android's scale settings and treated either
one being off as an answer. Turning off only the transition scale, a
thing developer options can do on its own, then stopped a page turned
by a tap or a key while still letting a page dragged across with a
finger spring back into place, which is the sort of disagreement this
change set out to remove in the first place.
It now reads the animator scale alone. That is the one Compose itself
consults, so everything in the reader moves or stays still together.
The accessibility switch turns every scale off at once, so it is still
heard.
Turning a page while the reading menu was open used a different
animation from turning it with the menu closed: the page slid across
instead of lifting, took longer, and the page number at the bottom
only caught up once the slide had finished. The lift needs a
photograph of the page to animate it, and it cannot take one while
the menu is covering the page, so it handed the turn to a slide
instead. It now goes straight to the next page, which is where the
lift ends up anyway.
The app also took no notice of the system's "Remove animations"
accessibility setting. It now reads it, so a reader who has turned
animations off for the whole device gets plain, instant page turns
without having to find the matching setting inside the app as well.
Changing it takes effect in an already open book. Dragging a page
across with a finger still works, since that follows the hand rather
than playing something at the reader.
Closes#201
A book that lists the same file twice has two copies of every page in
it, and a scrolled reading position records no page number, so there is
nothing to tell the copies apart by. The bookmark ribbon now treats that
as two different pages rather than guessing, which at worst offers a
bookmark the page already has, instead of taking one off the other copy.
Tidying an old bookmark's page number also writes that number alone now,
so a mark the sync had just changed or removed is left as it is.
Two books were told apart wrongly when deciding whether the page on
screen already carries a bookmark.
A book whose lines run down the page always scrolls, and a fixed-layout
book never does, whatever the reading setting says. The bookmark ribbon
was reading the setting rather than what the book was actually doing, so
it used the wrong test on both.
A book that lists the same file twice in its reading order has two
copies of every page in it. Nothing in a saved bookmark can tell those
copies apart, so a mark made in one showed up in the other, and removing
it there deleted the original. The page numbers already know which copy
is which, and are now asked first.
Tapping the bookmark button often left the ribbon empty and, tapped
again, piled up copies of the same bookmark. Other times the ribbon
stayed out for pages after the bookmarked one had gone by.
Both came from the same place. Writing a bookmark filed it under one
measurement of the page and testing for one used another, so a bookmark
just made could fail to match the page it was made on, and the next tap
added a second instead of removing the first. The measurement they were
compared by is also far coarser than a screen: several screens in a row
share a page number, so a bookmark kept matching pages the reader had
long since turned past, and two bookmarks on those screens could not be
told apart at all.
A bookmark now marks the screen it was made on and is recognised by the
place it already recorded rather than by its page number. The number
beside a bookmark is now only what the list prints, and it is taken from
the same measurement the footer shows, so it says what the reader saw.
Bookmarks written by older versions have that number corrected when the
book next opens. A scrolled book has no pages to be exact about, so
there the ribbon still follows the screenful the footer counts.
Switching the app theme in Settings left the status and navigation bar
icons the colour they were when the app started. Going from light to
dark put black icons on a black bar, where they were invisible until
something happened to recreate the screen.
The icon colour is chosen once, at startup, from the configuration the
app happened to open in, and nothing asks again afterwards. The reader
already had an effect that answers that question whenever the answer
moves; it is now shared, and the library uses it too.
The effect is unchanged, only relocated, so the reader keeps behaving
exactly as it did.
A reading theme set to follow the app is worked out from whether the
app is dark, so it needs an answer from the app's settings as well as
the reader's. Only the reader's was waited for, and the app's was
assumed to be the default until it loaded.
On a phone where the two disagree, a book opened for a moment in the
wrong colours: the app's saved choice arriving a beat late meant the
page was picked from whatever the system was doing instead.
Both are now waited for, so the first frame of a book is the colour it
should be.
With a sepia reading theme, tapping Define on a long-pressed word
opened a bottom sheet painted white. The reading theme and the app
theme are deliberately separate, so everything the reader raised over
the page came up in the app's colours rather than the paper's.
The definition sheet was one of a dozen: the typography sheet, the
Advanced sheet, the selection bar, the note editor, Go to page and the
loading and error screens all had the same problem. Most of the wrong
colour was not written down anywhere, either — it came from the
defaults inside Material's own dialogs, sliders, switches, menus and
text fields.
So the reading theme now becomes a colour scheme, derived once and
installed over the whole reader. Surfaces are the page and text is its
ink, while the accent colours are inherited from the app's palette at
the page's own lightness, which is what keeps buttons looking like
buttons and makes the error red right on a night page. Nothing had to
be repainted by hand, and a sheet added later is on the paper without
being told.
Wallpaper colours now stop at the reader's door. A colour taken from
somebody's wallpaper has never been checked against a page Liseur
picked, and a pale one on white paper is unreadable. The library and
settings screens keep following the wallpaper as before.
The status and navigation bar icons follow the page too, so a black
page under a light app no longer hides them, and the bars are handed
back as they were found on the way out.
Closes#212
Three small holes in restoring an orphaned book are closed. A restore
interrupted between its two writes could leave a replaced book carrying
the old reading; the cleanup now lands first, so an interrupted pass is
finished by the next one. A copy made for a restore that was then
refused stayed behind in the app's storage; it is now removed. And the
storage summary's new provider lookup runs off the main thread.
A restored orphan's file is a document in the reader's own folder or a
copy under a content-derived name in the app's storage, and both were
invisible to the paths that assume a copy named after the server id.
The storage summary now asks the document's provider for its size
instead of reporting zero, and removing the download or deleting the
book from the server now also deletes a copy the app owns, so it does
not linger unreachable. A document in the reader's own folder is never
deleted.
The restored entry was marked readable before the picked file had been
opened, so a corrupt or unreachable file left a book on the shelf that
would not open. The file is now read first, and a pick that cannot be
read leaves the entry as it was. When the reading shows a different
book took over the path, the entry also drops its link to the server's
copy of the old book, so syncing cannot mix the two up.
Restoring an orphaned book stored the picked location even when the
provider only granted temporary access, which left a book that stopped
opening once that access expired. The file is now copied into the
app's own storage in that case, the same way a book shared in from
another app already was.
Restoring an orphaned book by picking its file again now re-reads the
file first. If a different EPUB took over the path while the row was
orphaned, the old reading position and marks describe nothing that is
still there, so the book starts fresh, the same way a folder scan
treats a file rewritten in place.
Removing a watched folder kept an uploaded book on the shelf but left
it with no readable file. Picking that same file again only reported
it as already shelved, and the dialog's Open button did nothing. Now
picking the file, or sharing it in from another app, gives the entry
its readable copy back, and the book opens straight away with the
reader's place and marks intact.
Fixes#207
The pace tile now says "Pace (synced reading)" to admit the figure
leaves out reading this phone has not sent yet. The tile it sits in
allowed its label one line and cut the rest, so on a narrow screen, or
at a large font scale, the label became "Pace" again and the figure read
as though it covered everything.
The label may now take a second line.
The tile said "Pace (other devices)", but the pace comes from every
sitting the server holds, which includes the ones this phone uploaded.
What it leaves out is reading captured here that has not been sent. It
now reads "Pace (synced reading)".
The test that checked a headline reports no pace when the snapshot has
none had been renamed into the new server-only case rather than kept
beside it, so nothing covered the absent pace any more. It is back, and
also asserts the headline makes no server-only claim.
A test added alongside the pace work passed reading sessions straight to
a function that takes spans, so the unit tests did not compile.
Added support for displaying the reading pace from server snapshots when
viewing combined device statistics. Updated the user interface to label
this metric clearly and added tests to verify the behavior.
Added a watched folders list in settings with an option to remove
individual folders. Users needed a way to stop tracking folders and
clean up their library without deleting the underlying files from their
device. Books unique to the removed folder were cleared from the
database while retaining any files still covered by another folder.
Fixes#204
Blank chapter names now leave the chapter page count empty, matching books that have no named chapter. The ADR now matches the position-based fallback used when an EPUB repeats a reading-order link.
The reader footer gained a mode that shows how many Readium positions remain in the current chapter. The count is hidden when the app cannot name a real chapter, and duplicate book links use the chapter that matches the saved reading position before showing a number.
Closes#172
The sheet that asks which kind of server your library lives on opened
at about half the height of the screen. Four kinds fitted in that
space and the fifth, Custom/OPDS, sat below the edge with nothing to
say it was there, so readers reasonably concluded that OPDS was not
supported. It opens at its full height now, and all five are in view
on an ordinary phone. The list still scrolls on a short screen or at a
large text size, where the choices genuinely do not fit at once.
Once the local network has been refused for good, the notice under the
connect form sends the reader to the phone's settings, but coming back
from there having allowed it left the same notice up, still offering
the page they had just come back from. The only way on was to work out
for oneself that Connect would now work. The notice is now spent along
with the refusal.
A sync partner whose saved password this phone cannot read back, which
is what a backup restored onto a new phone leaves behind, also stopped
raising the notice. Nothing will ever dial it, so no permission could
help it.
A server called something like 127.books.home is a name, not an
address, and it was being read as the phone talking to itself — which
is the one case the permission check deliberately lets through. A
reader with such a server would have got the timeout rather than the
prompt. All four parts of an address now have to be numbers before it
is treated as one.
Once the local network has been refused for good, the only way back is
the phone's own settings app, and Liseur was not treating a return
from there as the yes it is: the account went on showing that it was
blocked until the reader turned a page or pressed Sync now. Coming
back with the permission newly allowed now asks for a sync, exactly as
answering the prompt does. Coming back having changed nothing still
does nothing.
Pulling the library to refresh it against a server on a home network
the phone is blocking went straight to the connection, which is
swallowed rather than refused, so the reader watched the spinner for
fifteen seconds and was then told the server was too slow. The refresh
now stops before it dials and says what is actually wrong, which the
library screen already knew how to explain.
When two devices disagree about where a book was left off, Liseur
offers the reader both positions. Accepting the other device's is
purely local work: the position was fetched and written down by an
earlier sync, so choosing it changes nothing but this phone, which is
why it works on a plane. The new local network check was refusing it
anyway. Sending this device's position, which does reach the server,
is still refused.
Turning a page in a book that was copied onto the phone still opens a
connection to whichever server is connected, before finding there is
nothing there matching it. The new local network check was skipping
those books, on the reasoning that the server had nothing to say about
them, which left exactly the timeouts it was meant to avoid. Whether
the connection would be made is now the only question asked.
The notification connection Liseur holds open to a liseur-sync server
is opened once and kept for as long as the app is on screen, so a
reader who allowed the local network from the connected account card
would have got nothing from it until they next left the app for a
while. Allowing it now says so, and the connection is made straight
away. A refusal changes nothing, so a working connection is never
dropped and reopened for no reason.
Liseur keeps a notification connection open to a liseur-sync server
while it is on screen, so it hears about a page turned on another
device. That connection was not covered by the new local network
check, so a server on the home network that the phone is blocking
would have had it opened, timed out and opened again for as long as
the app was in front of the reader. It is now simply not opened, and
the next attempt picks up a granted permission.
Two addresses that mean the machine itself were also being read as
ordinary home addresses and raising a prompt for a connection that
was never going to be blocked: a lookup that answers in hexadecimal,
and a name written out to its root. Both are now recognised, by the
same address parser the rest of the app uses rather than a second
one.
The check that decides whether a background sync is being blocked by
the phone's local network rules used to guess at an account's address
by looking at which kind of server was connected. That guess was wrong
in both directions: a pairing left behind by an account switch has an
address stored but never dials it, and a composite account has two
partners with two different addresses.
Every position sync now answers for itself which address it is about
to dial, or says it would not dial at all, so the guard asks the one
component that knows. A partner that cannot read its stored password
names nothing, rather than a machine it will never reach.
Settling a reading conflict by hand is refused the same way, instead
of being left to time out.
Loopback written the long way round, which is what a dual-stack
lookup hands back, is now recognised as loopback and raises no
prompt.
Android 17 stops an app from reaching anything on the same network as
the phone unless the reader has allowed it. Liseur never asked, so a
server in the next room went quiet: connecting sat there until it gave
up, while the same server reached over the internet worked fine.
Liseur now asks, but only when the address typed in is one on the home
network, since a server out on the internet never needs the permission
and nobody should be asked for something they will not use. The
question comes up before the attempt rather than after a long wait, a
reader who says no can be asked again, and an account already set up
gets a line on its card saying what is wrong and where to change it.
Background syncing stops and says so instead of timing out over and
over, and it stops for the one server that is out of reach rather than
for all of them.
This lets Liseur talk to self-hosted servers that use a local CA, like a
Caddy root issued for a home network. It keeps HTTPS checks on while
allowing the same trusted roots Android already trusts on the device.
Plain HTTP stays limited to the local-server cases Liseur already
allows.
Fixes#196
Long-pressing the first word of a paragraph selected it but painted
the start handle on the paragraph's last hyphen, or off the page when
that hyphen was in another column. Dragging then grabbed the whole
paragraph and the reader could not shrink it. This is an Android
WebView bug (Chromium 522869957): a hyphen's offsets are relative to
itself, so a selection starting at the very beginning of a paragraph
makes every hyphen claim the start bound.
Each block that opens with text now begins with two invisible
non-breaking spaces at zero size, so the real first letter is never at
the offset that trips the bug. Nothing moves on the page, drop caps
keep their letter, and highlights and positions never see the spaces.
Blocks that only contain other blocks, and blocks whose author already
generates content there, are left alone.
Closes#189
Refs #125
Note timestamps previously relied on the general annotation update time,
which caused changes like highlight recoloring or peer syncing to
falsely display notes as edited. Dedicated note timestamps were
introduced so edit indicators only reflected actual text revisions.
Signed-off-by: Chmouel Boudjnah <chmouel@chmouel.com>
Tapping a highlight that carries a note now opens a sheet in the reading
theme showing the passage, the note and when it was written, with the
colour chips, Share, Delete and Edit underneath. Plain highlights, and
any passage selected by hand, keep the compact bar. Recolouring from
the sheet leaves it open so the change is seen where the reader is
looking.