wiki: dos paginas nuevas y las capturas que faltaban

Estructura del codigo: donde vive cada fichero y por que ahi, con la tabla de
los diez propios y a que fichero de upstream se parece cada uno. Incluye las
tres decisiones que no son obvias (rutas aparte, interfaz de movil suelta,
traducciones como overlay), con los datos que las justifican, y lo que se
quito por sobrar.

Si algo va mal: los fallos que han pasado de verdad y su arreglo. Arranque
lento, error de conexion, espacio insuficiente, el umbral de almacenamiento
que rechaza instalar con hueco de sobra, la APK con el backend viejo, el
downgrade de versionCode, los permisos de camara, los iconos sin fuente, el
EXIF y el cambio de identidad.

Capturas nuevas: la pantalla de espera del arranque y la app en horizontal.
SITO 2026-08-19 20:48:19 +02:00
parent 781270f0fb
commit b6cb172963
7 changed files with 291 additions and 14 deletions

131
Estructura.md Normal file

@ -0,0 +1,131 @@
# Cómo está organizado el código
> ⚠ Rama experimental, no oficial. El Oasis oficial es
> https://github.com/epsylon/oasis · [Volver a la portada](Home)
Esta rama tiene que hacer dos cosas a la vez: añadir funciones y **seguir el ritmo de
epsylon**, que publica una versión cada pocos días. Lo segundo solo sale bien si el
código propio se distingue del suyo y no le estorba.
Esta página explica dónde vive cada cosa y por qué ahí.
---
## La regla
**Upstream no usa ni un solo subdirectorio** en `src/views`, `src/backend`,
`src/models`, `src/client/assets/styles` ni `src/client/assets/translations`: 66 vistas
y 67 modelos, todos planos. La rama sigue esa misma forma. Nada de carpetas propias.
Y los nombres, los suyos: `*_model.js` para modelos, `*_view.js` para vistas,
`*_views.js` cuando son varias.
## Los diez ficheros propios
| Fichero | Qué es | A qué se parece en upstream |
|---|---|---|
| `src/models/karvan_model.js` | Las salas efímeras y su ciclo de vida | `polls_model.js` |
| `src/views/karvan_view.js` | La lista de salas y la sala | `chats_view.js` |
| `src/backend/karvan_routes.js` | Las rutas del módulo | — (ver abajo) |
| `src/client/public/js/karvan.js` | El cliente WebRTC del navegador | `pdf-viewer.js` |
| `src/client/assets/styles/karvan.css` | Los estilos del módulo | `highlight.css` |
| `src/views/hive_views.js` | El panal, la topbar y la barra inferior | `main_views.js` |
| `src/views/identities_view.js` | El selector de identidades | cualquier `*_view.js` |
| `src/backend/accounts.js` | Encontrar y elegir identidades | `nameCache.js` |
| `src/backend/turnCredentials.js` | Credenciales efímeras para TURN | `wallet_addresses.js` |
| `src/client/assets/translations/i18n_fork.js` | Los textos de la rama | junto a `i18n.js` |
## Y lo que se toca de lo suyo
**+247 líneas repartidas en 21 ficheros** — una media de once líneas por fichero. Casi
todo son enganches de una línea:
```js
// main_views.js: la interfaz de móvil se llama, no se escribe aquí
const forkNav = require('./hive_views')({ i18n });
```
La excepción es `OasisMobile.css`, con unas mil líneas: es el tema de la rama, y un
tema es un fichero entero por definición.
## Las tres decisiones que no son obvias
### Por qué las rutas van aparte
Upstream mete **625 rutas** en `backend.js`, en una sola cadena. Ese fichero se
reescribe en cada versión: `+833/-286` líneas en la 0.9.2, `+266/-31` en la 0.9.1.
Una ruta añadida en medio de esa cadena entra en conflicto **cada vez**. Por eso las
del módulo viven en `karvan_routes.js`, montadas en un router propio que se inserta
antes del de upstream: lo que no casa cae a `next()` y sigue su curso.
Es la única pieza que no imita una existente, y por un motivo medible.
### Por qué la interfaz de móvil está en un fichero suelto
`hive_views.js` no se limita a agrupar: **existe para que `main_views.js` no crezca**.
Ese fichero cambia mucho entre versiones, y tener el panal dentro obligaría a rehacerlo
en cada integración.
Sus tres funciones empiezan igual:
```js
if (process.env.OASIS_MOBILE !== '1') return "";
```
Así el mismo `main_views.js` sirve para las dos ramas: en escritorio no dibujan nada.
Por eso [OASIS_LINUX](https://gitea.laenre.net/hacklab/OASIS_LINUX) puede llevarlo
idéntico sin heredar la interfaz de móvil.
### Por qué las traducciones son un overlay
Upstream tiene once ficheros `oasis_XX.js` y **los reescribe enteros** en cada versión.
Añadir claves dentro significaría perderlas cada vez.
`i18n_fork.js` las lleva aparte y `i18n.js` las mezcla con un enganche de tres líneas:
```js
try {
const overlay = require('./i18n_fork.js');
languages.forEach(l => Object.assign(i18n[l] = i18n[l] || {}, overlay[l] || overlay.en || {}));
} catch (e) {}
```
Dentro va **solo lo de la rama**. Los nombres de las categorías, por ejemplo, no están:
son los de epsylon y se leen de los suyos.
---
## Lo que se ha quitado por sobrar
Revisando esto salieron cosas que no deberían haber estado:
| Qué | Por qué sobraba |
|---|---|
| `views/fork/` y `translations/fork/` | Subdirectorios propios; upstream no tiene ninguno |
| Una segunda ruta `/legacy/export` | Copia exacta de la del dev, en otro fichero |
| `media-favorites.js` y su JSON | De una versión anterior; nadie lo requería |
| El campo `subtopic` en el foro | Resto de unos subtemas propios que se descartaron |
Los subtemas de verdad son los de upstream, con sus rutas y sus vistas.
---
## Cómo comprobarlo
Contra un clon de upstream de la misma versión:
```sh
# ficheros propios de la rama
for d in src/backend src/models src/views; do
diff <(ls ../oasis/$d) <(ls $d) | grep '^>'
done
# subdirectorios que upstream no tiene (no debería salir ninguno)
find src/views src/backend src/models -maxdepth 1 -type d | tail -n +2
# líneas añadidas sobre cada fichero suyo
for f in $(git ls-files 'src/**/*.js'); do
[ -f ../oasis/$f ] && n=$(diff ../oasis/$f $f | grep -c '^>') && [ $n -gt 0 ] && echo "$n $f"
done | sort -rn
```

@ -34,6 +34,8 @@ Pixel 9 (Android 16). No hay ningún montaje: es lo que se ve al usarla.
| **[Módulos](Modulos)** | Encender y apagar partes de la aplicación |
| **[Identidades](Identidades)** | Varias cuentas en el mismo móvil, y el aviso que evita perder una |
| **[Compilar la APK](Compilar)** | Cómo se construye, de dónde sale cada pieza |
| **[Estructura del código](Estructura)** | Dónde vive cada fichero y por qué ahí |
| **[Si algo va mal](Problemas)** | Los fallos que han pasado de verdad, y su arreglo |
| **[Estado y hoja de ruta](Roadmap)** | Qué funciona, qué no, y qué está bloqueado |
| **[Qué NO tiene](Limitaciones)** | Lo que falta respecto al oficial, sin adornos |

@ -165,7 +165,20 @@ tres piezas no se dibujan.
---
## 8. Los nombres son los de epsylon
## 8. En horizontal
![La misma pantalla girada](img/27-horizontal.png)
El panal se reparte a lo ancho y la barra de abajo se estira. Girar el móvil **no
recarga la página** ni pierde lo que estuvieras escribiendo: la aplicación se queda
donde estaba.
Eso hubo que arreglarlo —antes girar dejaba un error de conexión en pantalla—, y está
contado en [Si algo va mal](Problemas).
---
## 9. Los nombres son los de epsylon
<img src="img/25-castellano.png" width="300" align="right">
@ -188,24 +201,17 @@ cae al inglés.
## Cómo está hecho
Todo lo de esta página vive en **un solo fichero nuevo**, `src/views/fork/hive_nav.js`,
que exporta las tres funciones de dibujo y la lista de módulos que se pueden anclar.
Todo lo de esta página vive en **un solo fichero**, `src/views/hive_views.js`, que
exporta las tres funciones de dibujo y la lista de módulos que se pueden anclar.
`main_views.js` lo llama en tres sitios.
Se hizo así a propósito: cuando epsylon publica una versión nueva, `main_views.js`
cambia mucho, y tener la interfaz de la rama en un fichero aparte evita rehacerla en
cada actualización.
Las tres funciones empiezan igual:
Las tres empiezan igual:
```js
if (process.env.OASIS_MOBILE !== '1') return "";
```
Así el mismo código sirve para las dos ramas: en escritorio no dibujan nada. Por eso
[OASIS_LINUX](https://gitea.laenre.net/hacklab/OASIS_LINUX) puede llevar el mismo
`main_views.js` sin heredar la interfaz de móvil.
Así el mismo código sirve para las dos ramas: en escritorio no dibujan nada.
Los textos propios de la rama están en `src/client/assets/translations/fork/i18n_fork.js`,
que se mezcla con el `i18n.js` de upstream mediante un enganche de tres líneas. Igual
que antes: si epsylon reescribe sus traducciones, las de la rama no se pierden.
Está desarrollado, con el resto de decisiones, en
**[Estructura del código](Estructura)**.

133
Problemas.md Normal file

@ -0,0 +1,133 @@
# Si algo va mal
> ⚠ Rama experimental, no oficial. El Oasis oficial es
> https://github.com/epsylon/oasis · [Volver a la portada](Home)
Todo lo de esta página ha pasado de verdad durante el desarrollo. No es una lista de
casos imaginarios.
---
## Al abrir, se queda en una pantalla con un contador
<img src="img/26-espera.png" width="280" align="right">
**No está colgada, está arrancando.** El primer arranque descomprime el servidor —unos
230 MB— y levanta SSB. En el emulador tarda 15 segundos; en un móvil lento, más.
La pantalla enseña los segundos que lleva para que se note que sigue viva. Cuando el
servidor responde, carga la interfaz sola.
Si pasa de un par de minutos, mira el registro:
```sh
adb logcat -s OASIS-NODE:V
```
Tiene que llegar a `[Oasis] Backend started on port 3000`.
<br clear="all">
## Se ve un error de conexión y no se recupera
No debería pasar ya. Si la página no carga, la aplicación **vuelve a esperar al
servidor y recarga sola** la última pantalla que sí cargó.
Antes sí ocurría, y por dos motivos que están arreglados:
- **Al girar el móvil.** Faltaba una entrada en la lista de cambios de configuración
del manifiesto (`smallestScreenSize`), así que Android recreaba la pantalla y el
navegador interno recargaba antes de tiempo.
- **Cuando Android mataba el servidor** por falta de memoria: se quedaba muerta. Ahora
vuelve sola en unos veinte segundos.
## No se puede instalar: falta espacio
```
INSTALL_FAILED_INSUFFICIENT_STORAGE
```
La APK son unos 80 MB y el servidor se descomprime dentro de los datos de la
aplicación: cuenta con **unos 350 MB libres**.
Ojo con una trampa: Android rechaza instalar cuando el disco baja de cierto umbral,
**aunque el hueco dé de sobra para la APK**. En un emulador se ve así, con 500 MB
libres y una APK de 80. Si te pasa en un emulador de pruebas:
```sh
adb shell settings put global sys_storage_threshold_percentage 2
```
En un móvil de verdad, libera espacio y ya está.
## Instalé una APK nueva pero se comporta como la vieja
Pasa si el paquete del servidor no se rehizo. La APK lleva el backend dentro como un
zip, y si se compila sin volver a empaquetarlo, la aplicación arranca **con el código
anterior**.
Usa siempre el script, que lo rehace y lo comprueba:
```sh
cd android
./scripts/release.sh
```
Verifica que la APK lleva el servidor, el motor de Node y los dos permisos de cámara y
micrófono. Ver [Compilar la APK](Compilar).
## No deja instalar: dice que es una versión anterior
```
INSTALL_FAILED_VERSION_DOWNGRADE
```
El número de versión sale del número de commits. Si compilas a mano con `./gradlew`
sin las variables de entorno, sale **1**, que es menor que la instalada. Compila con
`./scripts/release.sh`, que lo calcula.
## Al pulsar Llamar no pasa nada
Comprueba, por este orden:
1. **Que concediste los permisos.** Ajustes → Aplicaciones → Oasis → Permisos. Si
dijiste *Don't allow*, no se vuelve a preguntar.
2. **Que la APK los declara.** La oficial no lo hace, y entonces ni siquiera aparecen
como opción:
```sh
aapt dump permissions oasis.apk | grep -E "CAMERA|RECORD_AUDIO"
```
3. **Que hay otro participante.** Una llamada con uno solo enciende tu cámara y poco
más. Ver [Llamadas](Llamadas).
## Los iconos se ven como cuadros vacíos (□)
En el móvil no debería pasar. En **escritorio** sí, y no es un fallo de Oasis: usa
caracteres Unicode poco comunes y al sistema le falta una fuente que los cubra.
```sh
sudo apt install fonts-noto-core # Debian, Ubuntu y derivadas
```
## Subí una foto y llevaba mi ubicación
Es un problema conocido y **sin resolver**: las imágenes suben con sus metadatos EXIF,
incluida la posición GPS.
Mientras tanto: quita la ubicación de las fotos antes de subirlas, o desactiva el
guardado de ubicación en la cámara. Ver [Qué NO tiene](Limitaciones).
## Se cierra al salir de la aplicación
No debería: el servidor corre como servicio en primer plano justamente para seguir
replicando en segundo plano. Comprobado a los veinte minutos.
Si se corta, mira si la notificación de Oasis sigue en la barra. Si la denegaste, el
sistema puede matar el servicio antes con la memoria justa. Se vuelve a conceder en
Ajustes → Aplicaciones → Oasis → Notificaciones.
## Cambié de identidad y sigo viendo la anterior
El cambio **se aplica al reiniciar**, no al momento. En el móvil hay un botón
**Reiniciar ahora** en la misma pantalla; sin él, cerrar la aplicación no basta porque
el servidor sigue vivo en segundo plano. Ver [Identidades](Identidades).

@ -13,6 +13,11 @@
- [Módulos](Modulos)
- [Identidades](Identidades)
- [Compilar la APK](Compilar)
- [Estructura del código](Estructura)
---
- [Si algo va mal](Problemas)
---

BIN
img/26-espera.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
img/27-horizontal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB