La ficha del libro, las estanterías y la búsqueda #22

Closed
HBB wants to merge 0 commits from HBB:feat/book-detail-and-shelves into main
First-time contributor

29 commits sobre main (v1.2.0), 41 archivos, +4874/−382. Todo gira alrededor de la ficha
del libro: lo que enseña, lo que deja hacer sin salir de ella, y lo que cuesta abrirla.

Búsqueda y estanterías

  • La búsqueda encuentra también los libros de tus propias estanterías, sin pedir nada a la red.
  • El salto a la estantería recoloca el libro mientras siguen llegando páginas, en vez de subir y bajar buscándolo.
  • La estantería deja de encogerse y crecer al refrescarse.
  • Tocar «Mis libros» estando ya allí vuelve a la lista de estanterías.
  • «Leídos» se puede ver agrupado por series, con los libros ordenados por su número dentro de cada una.

La ficha del libro

  • Se abre al instante y sin conexión: la ficha se guarda al cerrarla y abrir un libro deja de pedir lo mismo dos veces.
  • La pestaña «Diverse» enseña todo lo que ya se sabe del libro (autor, idioma, formato, editorial, fechas, temas, ISBN…), incluida la serie y el número del libro en ella.
  • El subtítulo se muestra sobre la portada.
  • La acción principal (poner en estantería / empezar a leer / anotar progreso) está abajo del todo y visible en las tres pestañas.
  • La ficha sabe en qué estantería está el libro aunque se abra desde la búsqueda, la actividad o un perfil: lo dice su propia página.
  • Avisa cuando otra edición del mismo libro ya está en una de tus estanterías, que es como se acaba con el mismo libro dos veces.
  • Elegir edición: la lista de ediciones de la obra, con filtro por idioma, y cambiarse a la que de verdad se lee. La estantería, las fechas y la valoración se van con ella.
  • Poner un libro en una estantería y quitarlo de ella, desde la propia ficha.
  • Fechas de lectura: se ponen y se corrigen sin salir de la ficha, y las relecturas se enseñan una a una.
  • Progreso: se puede anotar en páginas del ebook y se traduce a la página de la edición impresa.

Perfil y detalles

  • Bloque de los libros mejor valorados.
  • La valoración media se redondea a media estrella y los días por libro salen en enteros.
  • Los fallos de la instancia se cuentan en palabras, no en «timeout».

Cómo se obtienen los datos

Casi todo sale de la página HTML del libro, que ya se descarga: autor, valoración, fechas,
idioma, serie, estantería y los identificadores para quitarlo de ella. Se lee una vez por
libro y se cachea en disco (enrichment_cache.json), así que la segunda vez no cuesta nada.
Solo la lista de ediciones pide una página aparte, y solo al abrirla.

Ojo con las ediciones: la instancia las ordena por un ranking con muchos empates y las sirve
de quince en quince, y en dos peticiones seguidas los empates no salen en el mismo orden, así
que al pasar de página se pierde alguna. Por eso el filtro por idioma, que deja el resultado
en una sola página; los idiomas los da la propia instancia mirando todas las ediciones a la vez.

Notas

  • El último commit devuelve los finales de línea a los del proyecto: la rama venía de antes del
    cambio a CRLF de la 1.2.0, y sin eso el diff se leería como una reescritura de cada archivo.
    Los archivos que en el proyecto son LF (NetworkClient, SearchScreen, HomeViewModel, HomeUiState)
    siguen en LF.
  • Incluye el arreglo de la 0.80 de moveToShelf (el respaldo de reading-status a shelveBook)
    ya integrado con los cambios de esta rama.
  • Textos nuevos en values, values-da y values-es; el resto de idiomas cae al inglés.
  • ./gradlew testDebugUnitTest assembleDebug pasa. Probado en un Galaxy S23 contra bookwyrm.social.
29 commits sobre `main` (v1.2.0), 41 archivos, +4874/−382. Todo gira alrededor de la ficha del libro: lo que enseña, lo que deja hacer sin salir de ella, y lo que cuesta abrirla. ## Búsqueda y estanterías - La búsqueda encuentra también los libros de tus propias estanterías, sin pedir nada a la red. - El salto a la estantería recoloca el libro mientras siguen llegando páginas, en vez de subir y bajar buscándolo. - La estantería deja de encogerse y crecer al refrescarse. - Tocar «Mis libros» estando ya allí vuelve a la lista de estanterías. - «Leídos» se puede ver agrupado por series, con los libros ordenados por su número dentro de cada una. ## La ficha del libro - Se abre al instante y sin conexión: la ficha se guarda al cerrarla y abrir un libro deja de pedir lo mismo dos veces. - La pestaña «Diverse» enseña todo lo que ya se sabe del libro (autor, idioma, formato, editorial, fechas, temas, ISBN…), incluida la **serie y el número** del libro en ella. - El subtítulo se muestra sobre la portada. - La acción principal (poner en estantería / empezar a leer / anotar progreso) está abajo del todo y visible en las tres pestañas. - La ficha sabe **en qué estantería está el libro** aunque se abra desde la búsqueda, la actividad o un perfil: lo dice su propia página. - Avisa cuando **otra edición del mismo libro** ya está en una de tus estanterías, que es como se acaba con el mismo libro dos veces. - **Elegir edición**: la lista de ediciones de la obra, con filtro por idioma, y cambiarse a la que de verdad se lee. La estantería, las fechas y la valoración se van con ella. - Poner un libro en una estantería y quitarlo de ella, desde la propia ficha. - Fechas de lectura: se ponen y se corrigen sin salir de la ficha, y las relecturas se enseñan una a una. - Progreso: se puede anotar en páginas del ebook y se traduce a la página de la edición impresa. ## Perfil y detalles - Bloque de los libros mejor valorados. - La valoración media se redondea a media estrella y los días por libro salen en enteros. - Los fallos de la instancia se cuentan en palabras, no en «timeout». ## Cómo se obtienen los datos Casi todo sale de la página HTML del libro, que ya se descarga: autor, valoración, fechas, idioma, serie, estantería y los identificadores para quitarlo de ella. Se lee una vez por libro y se cachea en disco (`enrichment_cache.json`), así que la segunda vez no cuesta nada. Solo la lista de ediciones pide una página aparte, y solo al abrirla. Ojo con las ediciones: la instancia las ordena por un ranking con muchos empates y las sirve de quince en quince, y en dos peticiones seguidas los empates no salen en el mismo orden, así que al pasar de página se pierde alguna. Por eso el filtro por idioma, que deja el resultado en una sola página; los idiomas los da la propia instancia mirando todas las ediciones a la vez. ## Notas - El último commit devuelve los finales de línea a los del proyecto: la rama venía de antes del cambio a CRLF de la 1.2.0, y sin eso el diff se leería como una reescritura de cada archivo. Los archivos que en el proyecto son LF (NetworkClient, SearchScreen, HomeViewModel, HomeUiState) siguen en LF. - Incluye el arreglo de la 0.80 de `moveToShelf` (el respaldo de `reading-status` a `shelveBook`) ya integrado con los cambios de esta rama. - Textos nuevos en `values`, `values-da` y `values-es`; el resto de idiomas cae al inglés. - `./gradlew testDebugUnitTest assembleDebug` pasa. Probado en un Galaxy S23 contra bookwyrm.social.
HBB added 29 commits 2026-08-01 13:26:39 +00:00
Los libros que ya están en las estanterías del usuario se buscan en la caché
local, sin ninguna petición de red, así que se filtran mientras se escribe en
vez de esperar al botón. Aparecen antes que los de la instancia, con un
distintivo de la estantería en la que están, y al pulsarlos se salta a «Mis
libros», se abre esa estantería y se resalta el libro un momento.

La coincidencia ignora mayúsculas y acentos ("bronte" encuentra "Brontë") y
pliega las letras que el Unicode no descompone ("sondergaard" encuentra
"Søndergaard"). La consulta se parte en palabras y se exigen todas, aunque
vengan de campos distintos, de modo que "orwell 1984" encuentra el libro.

El objetivo del salto vive en HomeViewModel porque el paginador descarta el
estado de las pestañas que quedan fuera de la vista.

Una estantería solo aporta resultados una vez que se ha abierto al menos una
vez, igual que ocurre con las estadísticas del perfil.
Se daba el salto por hecho tras el primer desplazamiento, pero la estantería
sigue paginando detrás y cada tanda reordena la lista, así que el libro se
alejaba de su sitio. Ahora se recoloca en cada tanda y solo se resalta cuando ya
no llegan más páginas.
Solo se anima el primer viaje, para que se vea adónde lleva el salto. La
estantería sigue trayendo páginas detrás y cada una recompone la lista, así que
el libro cambia de posición varias veces; esos reajustes ahora son instantáneos y
el libro se queda quieto mientras la lista crece bajo él. Animarlos también hacía
que la pantalla subiese y bajase hasta que terminaba la paginación.

El resaltado se enciende ya en el primer viaje, en vez de esperar al final, y su
cuenta atrás empieza al asentarse la lista para que no se apague mientras todavía
se recoloca.
Al refrescar se sustituía lo que había en pantalla por la primera página, así que
una estantería de setenta libros encogía a diez y volvía a crecer página a
página. Estando arriba apenas se nota, pero al saltar a un libro concreto desde
la búsqueda el libro desaparecía de la lista hasta que llegaba su página, y la
vista daba tumbos buscándolo.

Ahora la lista que llega de la red se compone aparte y se cambia de una sola vez
al terminar; mientras tanto se sigue viendo la cacheada, entera. Un refresco que
falla a medias no toca ni la pantalla ni el disco: es mejor la lista de antes,
completa, que la nueva a trozos. Si la estantería ha quedado vacía la pantalla sí
se actualiza, pero la caché no se pisa con una lista vacía.
El menú de tres puntos solo permitía mover el libro entre estanterías. Ahora
ofrece además «Quitar de la estantería», con un diálogo de confirmación antes
de hacer nada.

La vista `unshelve` de BookWyrm identifica la estantería por su ID numérico,
no por el identificador de texto que usa `shelve`, y ese ID solo aparece en el
formulario oculto de la página del libro. Como esa página ya se descarga para
el enriquecimiento, se recogen ahí mismo los dos identificadores en lugar de
pedirla otra vez: si vienen de la caché, la opción aparece al instante.

El formulario solo se renderiza cuando el libro está en alguna estantería, así
que su ausencia sirve para ocultar la opción cuando no se puede quitar.

Las entradas de caché guardadas antes de este cambio no traen esos campos, de
modo que `BookEnrichment` gana una versión de formato y la estantería vuelve a
leer una sola vez las que se quedaron atrás. Así se distingue «nunca se buscó»
de «se buscó y el libro no está en ninguna estantería», y esta última no se
vuelve a pedir en cada apertura.
El subtítulo ya venía en el Edition del .json, tanto en la ficha del libro como
en el de la estantería, pero los modelos no lo recogían y se descartaba. No hace
falta ninguna petición extra.

Se muestra centrado sobre la portada en la ficha y bajo el título en las tarjetas
de la estantería, algo más pequeño. Los libros sin subtítulo no emiten nada, así
que el diseño queda igual que antes.
Quitarlo funcionaba en el servidor, pero seguía en pantalla hasta reabrir la app.

En la estantería, `onShelved` no rehacía la lista: el efecto que la carga también
depende de la página actual, y tras paginarla entera se queda en la última, así
que volver a lanzarlo pedía esa página otra vez en lugar de reconstruir desde la
primera. En vez de tocar esa lógica de refresco, la ficha avisa con el id del
libro y la estantería lo saca de la lista visible y de la que se está recomponiendo
por detrás, sin ninguna petición.

La búsqueda entre las estanterías propias lee la caché en disco, que nadie
actualizaba: ahora la ficha borra el libro de las tres estanterías de estado de
lectura (solo puede estar en una, así que es seguro), pase por donde pase.

Y el índice en memoria de la búsqueda se construía una sola vez, de modo que la
caché limpia no cambiaba nada hasta reiniciar. Se rehace al empezar cada búsqueda,
y si el libro se quita desde el propio resultado, se retira del índice al instante.
Enseñaba cinco líneas sueltas mientras el resto de la respuesta se tiraba: el
.json del libro ya traía serie, materias, editorial, formato, primera edición,
ISBN, OCLC y la clave de Open Library, pero el modelo no tenía esos campos. Y de
la página HTML ya se leía la fecha de inicio de lectura, que no se mostraba en
ninguna parte. Nada de esto cuesta una petición más: es lo que ya se descargaba.

Ahora son tres bloques: lo tuyo (valoración, fechas y los días que duró la
lectura), el libro (autor, serie, páginas, idioma, formato, editorial, fechas y
las materias como chips) y sus números. Cada dato es opcional y un bloque sin
nada que enseñar no se dibuja, así que un libro escueto no deja huecos.

Las fechas se formatean en el idioma del dispositivo; la de publicación se
quedaba en ISO crudo mientras la de lectura sí se formateaba.

El cálculo de días de lectura estaba solo en la estantería; se mueve a
`ReadingStatsCalculator` para que la ficha y la tarjeta no puedan discrepar.
El menú de tres puntos listaba los estantes como entradas sangradas bajo una
etiqueta desactivada, y al tocar una pedía además confirmación. Ahora hay una
sola entrada, «Cambiar de estantería», que abre un diálogo con un botón por
estantería, cada uno con el mismo icono que tiene en «Mis libros». El estante en
el que ya está el libro no aparece.

Se quita la confirmación: elegir en una lista propia ya es un acto deliberado, y
encadenar tres pasos para mover un libro sobraba. El toque por error, que es lo
que justificaba preguntar, era un riesgo del menú desplegable, donde las opciones
quedaban pegadas al resto de acciones.
Cinco libros de «Leídos», del mejor valorado al peor. Cuando hay más empatados
arriba que sitios —diez con cinco estrellas para cinco huecos— entran los leídos
más recientemente, de modo que el bloque acompaña a lo que se va leyendo en vez
de quedarse fijo en los primeros que se puntuaron. Sin valoración no se entra, y
a igual nota el que no tiene fecha de fin queda detrás.

Tocar un libro abre su ficha, como en las filas de portadas del perfil.

Sale de la caché («Leídos» más el enriquecimiento), así que no añade ninguna
petición: hace falta haber abierto esa estantería alguna vez, igual que el resto
de estadísticas. Es un bloque más del perfil, así que se puede mover y ocultar;
a quien ya tenga una disposición guardada le aparecerá al final, que es como
`ProfileLayout.decode` acomoda los bloques nuevos.
"12,4 días por libro" aparenta una precisión que no existe: la media se calcula
sobre los pocos libros que tienen fecha de inicio y de fin.

Se redondea con roundToInt y no dejando el trabajo a NumberFormat, que redondea
al par más cercano: 12,5 habría bajado a 12 mientras 13,5 subía a 14. Solo
cambia lo que se enseña; el cálculo sigue igual.
Un 4,28 de media no se corresponde con ninguna puntuación que se pueda dar:
media estrella es el paso mínimo en BookWyrm. Se redondea a ese paso al
mostrarla; el reparto de valoraciones ya venía en medias estrellas y no cambia.
La hoja de progreso queda para el progreso y nada más: el valor, la unidad
y el botón de guardar. La publicación en el feed (comentario, spoiler y
privacidad) se traslada a su propia hoja, a la que se llega con «Publicar»;
se envía todo junto en la misma petición, así que no se actualiza dos veces.

Junto a páginas y porcentaje hay ahora una tercera unidad: páginas del
ebook. Como su paginación depende del tamaño de letra, se pregunta cuántas
páginas tiene el ebook de quien lee, se guarda solo en el dispositivo y
sirve para convertir la página en el porcentaje que entiende BookWyrm. De
paso se enseña a qué página de la edición impresa equivale, y la ficha
traduce el porcentaje de vuelta a la página del ebook.

La unidad y el total del ebook se deciden una vez por libro: después se
enseñan bloqueados, con un enlace «Editar» para cambiarlos, de modo que
actualizar el progreso sea escribir un número. Cada libro recuerda la suya,
y la última usada se propone al estrenar otro. Todo se olvida cuando el
libro pasa a «Leídos».
Hasta ahora la única fecha que la app sabía escribir era la de fin, y siempre
la de hoy, al terminar un libro. Los libros que llevaban tiempo en «Leídos» se
quedaban sin fechas, y corregir una equivocada obligaba a ir a la web.

La ficha del libro tiene ahora «Editar fechas de lectura», tanto en el menú de
tres puntos como al pie de «Tu lectura». El diálogo trae las lecturas que ya
tiene el libro (con sus fechas puestas), deja elegir cuál se toca si hay más de
una y añadir otra distinta, y cada fecha se elige en un calendario que no
permite el futuro, porque BookWyrm lo rechaza.

Por debajo son los dos formularios de la web: create-readthrough para una
lectura nueva y edit-readthrough para cambiar una que ya existe. Al crear, un
200 es el formulario devuelto con errores, así que solo la redirección cuenta
como guardado. Una fecha ya guardada se puede corregir pero no vaciar: BookWyrm
ignora los campos vacíos al editar, y para eso hay que borrar la lectura entera
desde la web.

Los identificadores (lecturas, libro y usuario) se leen de la propia página del
libro, buscando los formularios por su acción y no por el id del modal, que lo
comparten trozos suyos sin fechas. Esa lectura del HTML queda en una función
aparte, con pruebas sobre un recorte de la página.

Como la caché de enriquecimiento no se vuelve a leer una vez guardada, la ficha
avisa ahora de lo que lee de la web y la estantería lo guarda: las fechas
recién cambiadas se ven sin esperar a un resincronizado. De paso, la fecha de
fin de «Tu lectura» se etiqueta «Terminado» en lugar de «Leídos».
Cuando la instancia se cae, va lenta o pide un control de seguridad, la app
enseñaba el detalle técnico tal cual: «Fejl ved indlæsning af detaljer: timeout»
o «Serverfejl: 502». Quien lee eso no sabe si ha roto algo, si le falla el
teléfono o si es que bookwyrm.social está teniendo un mal día.

Ahora hay un traductor de fallos ([NetworkErrors]) que reparte los errores de red
y los códigos HTTP en los pocos casos que de verdad importan —sin conexión, la
instancia no contesta, la instancia tiene problemas (5xx), pide esperar (429),
la sesión ha caducado (401/403), ya no existe (404) y la respuesta no es la
esperada (el HTML de un control tipo Anubis donde debía venir JSON)— y de cada
uno sale una frase que dice qué ha pasado y qué hacer. Lo que no reconoce sigue
saliendo como antes, con su detalle técnico. La clasificación no toca Android,
así que se prueba en la JVM: 12 pruebas nuevas.

Los 26 sitios que enseñaban un error de red o un código de servidor pasan por
ahí, así que el mensaje es el mismo se caiga por donde se caiga.

De paso, en la estantería un tropiezo puntual ya no se lleva por delante los
libros que había en pantalla: el aviso se pone encima de la lista y solo ocupa
la pantalla entera cuando no hay nada que enseñar. Y al volver a abrir un libro
se borra el aviso anterior, que antes se quedaba pegado aunque ya funcionara.
Al tocar un libro ya no hay que esperar a la instancia: se enseña la
ficha que se guardó la última vez que se abrió y, por detrás, se pide la
de verdad, que la sustituye y queda guardada para la próxima. Sin nada
guardado todo sigue igual que antes.

Si la instancia no contesta pero la ficha ya está en pantalla, no se
avisa de nada: hay algo que leer y el refresco llegará otro día. El
aviso de red se reserva para cuando de verdad no hay nada que enseñar.

Las cuatro pantallas desde las que se toca un libro (estantería,
actividad, perfil y búsqueda) compartían el mismo código repetido; ahora
pasan por BookPageLoader. En la estantería, además, cada apertura lleva
su número, así que una respuesta que llega tarde ya no pinta encima de
otro libro ni reabre una ficha recién cerrada.
Un progreso anotado en porcentaje —así viaja siempre el del ebook— no
dice por dónde se va. La ficha lo traducía a la página del ebook de
quien lee, que solo significa algo en su lector y con su tamaño de
letra: para hablar del libro con cualquiera sirve la página de la
edición del libro, que es la misma para todos.

Así que bajo el porcentaje se enseña esa página en lugar de la del
ebook. Anotado en páginas no cambia nada: eso ya lo dice la línea de
arriba.
Al libro al que se llega buscándolo, lo primero que se quiere hacer con
él es ponerlo en una estantería, y hasta ahora eso estaba escondido en
el menú de ⋮. Ahora hay un botón fijo abajo del todo, «Añadir a
estantería», que abre la misma lista de siempre: pendiente, leyendo o
leído.

Solo aparece mientras no conste que el libro está ya en una: la ficha
abierta desde una estantería no lo enseña, y desaparece en cuanto la
página del libro dice a cuál pertenece. La lista es la que ya existía;
cambia el título, porque a un libro que no está en ninguna no se le
cambia de estantería, se le añade a una.

La cadena «Añadir a estantería» ya estaba traducida a los 17 idiomas de
una versión anterior; se le quitan los dos puntos del final, que sobran
en un botón.
Con una estantería abierta, el botón de «Mis libros» de la barra de
abajo no hacía nada: la pestaña ya estaba puesta. Ahora ese segundo
toque devuelve a la lista de estanterías, que es lo que hace cualquier
aplicación con su barra de abajo, y ahorra buscar el «Volver» de arriba.

El aviso baja como un número que sube en cada toque. Solo cuenta que
suba: al componerse la pantalla llega con el valor que lleve la sesión,
y hacerle caso entonces cerraría la estantería que abre la búsqueda al
tocar un libro de las propias.
La estantería «Leídos» dice ahora de qué serie es cada libro y qué
número hace en ella, y un icono en la barra la reordena por series: la
lista de las series de las que se ha leído algo, cada una con su nombre
y las portadas en abanico, y al tocar una, sus libros en el orden en que
se leen. «Volver» deshace un paso cada vez, de la serie a la lista de
series y de ahí a la estantería.

La serie no viaja en el .json del ejemplar. BookWyrm la convirtió en un
objeto propio, con su página y su numeración, y los viejos campos series
y series_number se quedaron vacíos: atar un libro a una serie hoy borra
el número que hubiera suelto. Pero la página del libro sí la enseña, y
marcada con microdatos schema.org:

  <span itemprop="isPartOf" itemtype=".../BookSeries">
    Book <span itemprop="position">5</span> in <em><a href="/series/…">Nombre</a></em>
  </span>

Así que se lee de ahí, de las propiedades y no del texto, que está
traducido. Esa página ya se raspa una vez por libro para el autor, la
valoración y las fechas, de modo que las series no cuestan ni una
petición más. Los libros se agrupan por la URL de la serie y no por su
nombre: dos series pueden llamarse igual, y el nombre cambia si alguien
lo corrige.

La versión del enriquecimiento sube a 3 para que las cachés ya guardadas
se relean una vez y aparezcan las series de lo ya leído.
Abrir una ficha costaba cinco peticiones, y tres sobraban: dos POST a
resolve-book/ y dos descargas de la misma página HTML. Se quedan en una
descarga y ningún POST.

resolve-book/ no es una consulta: es el POST con el que la instancia
*importa* un libro remoto a su base de datos. Se llamaba con todos, y
los de las propias estanterías son de casa por definición. Ahora un
libro cuyo host es el de la sesión se devuelve tal cual, sin preguntar;
lo federado se resuelve como siempre, y ante la duda —sin sesión aún, o
una URL ilegible— también. Además, quien de verdad lo necesita no lo
necesitaba tanto: fetchHtmlWithRedirects ya sigue las redirecciones.

La otra mitad era la página del libro. Las reseñas y el enriquecimiento
la quieren en el mismo instante al abrir la ficha, y cada uno la pedía
por su cuenta. Ahora pasan las dos por fetchBookPage, que guarda la
última quince segundos; el candado hace además que quien llegue segundo
espere al primero en vez de pedirla otra vez. La clave ignora el sufijo
del título y el .json, porque cada lado llega con la URL que tiene a
mano y todas son el mismo libro.

Donde más se nota es al rellenar una estantería entera: el repaso de 66
libros pasa de unas 132 peticiones a 66, la mitad de ellas POST que ya
no se hacen.
La fila «Serie» salía casi siempre vacía: se leía del .json del ejemplar,
donde series/seriesNumber no vienen rellenos aunque la instancia sí tenga
el libro atado a una serie. Ahora se toma del enriquecimiento, que ya
raspa esos datos de la página del libro para agrupar «Leídos» por series,
así que no cuesta ninguna petición extra.

El .json se sigue usando de reserva por si algún ejemplar los trae, pero
nombre y número salen siempre de la misma fuente para no mezclar el
número de una serie con el nombre de otra.
«Empezar a leer» y «Actualizar progreso» estaban al final de la pestaña
«Diverse», detrás de toda la ficha: desde el resumen o las reseñas no se
veían, y había que cambiar de pestaña y desplazarse hasta abajo para dar
con ellas.

Ahora son la barra inferior del diálogo, junto a «Poner en estantería»,
que ya vivía ahí. Los tres casos se excluyen entre sí, así que la barra
enseña una sola acción: la que toca según dónde esté el libro.
La búsqueda abre la ficha con el identificador suelto («1977202») y las
estanterías con la URL entera. Sin completar, aquello no llega ni a ser
una URL: al leer la página del libro reventaba, el fallo se tragaba con
el resto y la ficha se quedaba sin autor, sin idioma y sin serie. Justo
en los libros que se acaban de encontrar, que son los que se añaden.

Ahora se normaliza a la entrada (canonicalBookUrl) y esa misma forma es
la clave con la que se guarda, así que lo leído desde la búsqueda lo
encuentra después la estantería. Y la ficha cachea por su cuenta en vez
de esperar a que quien la abrió se lo pida: por la búsqueda y por la
actividad pasan los libros que aún no están en ninguna estantería.

Poner un libro en una estantería ya no obliga por tanto a releer su
página en el siguiente resincronizado: llega hecho.

De paso, el resincronizado guarda libro a libro en vez de volcar el mapa
entero. Volcar una copia hecha antes borraba lo que la ficha acabara de
apuntar mientras tanto, y ahora lo ya leído queda guardado aunque se
salga a mitad.
La búsqueda, la actividad y el perfil abrían la ficha en blanco y el
autor, las estrellas y la serie no aparecían hasta que terminaba de
leerse la página del libro. La estantería no: ella lleva su caché en
memoria y ya se los pasaba.

Ahora las cuatro buscan en la misma caché en disco antes de abrir, con la
clave normalizada, y se lo pasan a la ficha. Un libro que se ha abierto
antes sale completo de entrada y lo que llegue de la web solo lo
actualiza.
Tres cosas más de la misma página del libro, que ya se descarga entera:

1. En qué estantería está. El botón grande no dice dónde está el libro
   sino cuál es el paso siguiente, y de todas las opciones deja visible
   solo esa: se lee y se deshace la cuenta. Abierto desde la búsqueda, la
   actividad o un perfil, un libro que se está leyendo no ofrecía ni el
   progreso ni «Empezar a leer», porque nadie sabía dónde estaba. La
   actividad y el perfil, además, daban todos los libros por «leyendo»,
   así que uno ya terminado invitaba a anotar progreso; eso se quita y lo
   decide la página.

2. Otra edición del mismo libro ya guardada. Las estanterías guardan
   ediciones concretas, así que sin el aviso se acaba con el mismo libro
   dos veces, cada una en un idioma. Sale junto al botón de abajo, que es
   donde se decide.

3. Cada lectura por separado, no solo el primer inicio y el último fin.
   Con una relectura salen las dos, y los días de lectura se cuentan
   sobre una sola: antes medían también los años que el libro estuvo en
   la estantería entre una y otra.

El esquema del enriquecimiento sube a 4, así que la próxima vez que se
abra una estantería se releen sus libros una vez.
En BookWyrm la estantería, las fechas de lectura y la valoración cuelgan
de una edición concreta, no del título. Un libro se encuentra casi
siempre en inglés (o en italiano), y quien lo lee en otro idioma se queda
con la edición equivocada guardada para siempre.

«Elegir edición», en el menú de la ficha, trae la lista de ediciones de la
obra y cambia a la que se toque. La lista cuesta su propia petición, así
que se pide solo al abrirla y no va con el enriquecimiento.

Con el filtro por idioma delante, que es lo que se busca («la tengo en
italiano, pero la leí en danés»). No es un adorno: la instancia ordena las
ediciones por un ranking con muchos empates y las sirve de quince en
quince, y como en dos peticiones seguidas los empates no salen igual, al
pasar de página se pierde alguna —de 35 ediciones llegaban 33, y entre
las que faltaban estaba justo la danesa—. Filtrando por idioma el
resultado cabe en una página y no hay nada que perder. Los idiomas los da
la propia instancia mirando todas las ediciones de golpe, así que están
todos aunque la lista no lo esté.

El número de ediciones va en el título por lo mismo: que se vea de un
vistazo con cuántas se está tratando.
La instancia escribe el nombre de la estantería en el suyo, así que el
aviso salía como «...está en tu estantería Read» con la app en danés. El
enlace del aviso lleva además el identificador, que no se traduce: con él
se dice «Læst», «Læser» o «Vil læse» como en el resto de la app, y solo
las estanterías propias del usuario se siguen enseñando tal cual las
llama la instancia.

Esquema del enriquecimiento a 5.
El proyecto pasó a CRLF en la 1.2.0 y esta rama venía de antes, así que
sin esto el cambio se leería como si cada archivo estuviera reescrito de
arriba abajo. Cada archivo queda como lo tiene el proyecto: los que ya
eran LF (NetworkClient, SearchScreen, HomeViewModel, HomeUiState) siguen
en LF, y los nuevos entran en CRLF como el resto.
Owner

Fusionado

Fusionado
ferlagod closed this pull request 2026-08-01 19:01:50 +00:00

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
ferlagod/rocinante_android!22
No description provided.