diff --git a/README.md b/README.md index 235cb1e..f58b1bb 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,19 @@ Android 7 o superior, 64 bits · se instala junto al Oasis oficial sin pisarlo - **Al día con Oasis 1.3.3**: karma en el perfil, salas con directo, fotos selladas en chats privados y tribus, visibilidad de menciones y las traducciones nuevas. +- **Tema Acampada por defecto**: blanco, negro y cian, títulos en Anton y botones que + se hunden al pulsar, con los colores de acampada26s.net. Los otros temas siguen en + *Ajustes → Tema*. - **Arranca en modo activistas**: chats, Karvan, pads, foro, imágenes, vídeos, wiki y blogs. Todo cabe en una pantalla; el resto se activa en *Ajustes → Workflows*. - **Filtros en fichas**: en chats, feed, foros o pads los filtros ya no son botones gigantes que tapan el contenido, sino fichas pequeñas en fila. - **Tarjetas más limpias**: borrar, fijar, enlazar y abrir van en una fila de iconos. - **Karvan**: tus mensajes salen a la derecha también al volver a entrar en la sala. +- **Fotos más seguras**: si una foto no se puede limpiar de metadatos (ubicación, + cámara…), no se sube y se avisa. Antes se subía tal cual. +- **DNS**: primero el resolutor del sistema, que respeta la VPN y el DNS privado de + Android; los públicos quedan de respaldo. --- @@ -41,7 +48,7 @@ Android 7 o superior, 64 bits · se instala junto al Oasis oficial sin pisarlo |---|---|---| | **Salas efímeras** | — | Karvan: mensajes que solo viven en memoria y se autodestruyen | | **Videollamadas** | — | Audio y vídeo por WebRTC, sin servidores de terceros | -| **Interfaz de móvil** | El menú de escritorio en una pantalla pequeña | Lanzador de módulos, filtros en fichas y barra de cuatro atajos | +| **Interfaz de móvil** | El menú de escritorio en una pantalla pequeña | Tema Acampada, lanzador de módulos, filtros en fichas y barra de cuatro atajos | | **Primer arranque** | Casi sesenta módulos encendidos | Modo activistas: lo justo para organizarse | | **Varias identidades** | Una por instalación | Varias en el mismo móvil, con aviso si dos comparten clave | | **Respuesta citada** | — | Responder a un mensaje concreto dentro de un chat | diff --git a/docs/capturas/00-portada.png b/docs/capturas/00-portada.png index 760d223..23118e0 100644 Binary files a/docs/capturas/00-portada.png and b/docs/capturas/00-portada.png differ diff --git a/docs/capturas/01-portada.png b/docs/capturas/01-portada.png index 9414b81..4e31078 100644 Binary files a/docs/capturas/01-portada.png and b/docs/capturas/01-portada.png differ diff --git a/docs/capturas/02-chats.png b/docs/capturas/02-chats.png index a02fe5d..4c68f10 100644 Binary files a/docs/capturas/02-chats.png and b/docs/capturas/02-chats.png differ diff --git a/docs/capturas/03-karvan.png b/docs/capturas/03-karvan.png index 21ab81a..91e9bfd 100644 Binary files a/docs/capturas/03-karvan.png and b/docs/capturas/03-karvan.png differ diff --git a/docs/capturas/04-foros.png b/docs/capturas/04-foros.png index 5ff5a44..c20a66f 100644 Binary files a/docs/capturas/04-foros.png and b/docs/capturas/04-foros.png differ diff --git a/docs/capturas/05-feed.png b/docs/capturas/05-feed.png index f1f0d9f..845bee9 100644 Binary files a/docs/capturas/05-feed.png and b/docs/capturas/05-feed.png differ diff --git a/docs/capturas/06-barra.png b/docs/capturas/06-barra.png index f6ceed1..245ce11 100644 Binary files a/docs/capturas/06-barra.png and b/docs/capturas/06-barra.png differ diff --git a/docs/capturas/07-karvan-salas.png b/docs/capturas/07-karvan-salas.png index f6f873b..09501c5 100644 Binary files a/docs/capturas/07-karvan-salas.png and b/docs/capturas/07-karvan-salas.png differ diff --git a/docs/capturas/esquema-interfaz.png b/docs/capturas/esquema-interfaz.png index 2337e79..0f6d51e 100644 Binary files a/docs/capturas/esquema-interfaz.png and b/docs/capturas/esquema-interfaz.png differ diff --git a/docs/capturas/generar_portada.py b/docs/capturas/generar_portada.py new file mode 100644 index 0000000..cf72516 --- /dev/null +++ b/docs/capturas/generar_portada.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +"""Portada y esquema de la interfaz del README, con la paleta del tema Acampada. + +Las capturas de movil (01..07) se hacen aparte, con la app arrancada; este script +solo compone 00-portada.png a partir de ellas y dibuja esquema-interfaz.png. +El texto vive aqui: se cambia y se relanza, nunca se retocan los PNG a mano. + + python3 docs/capturas/generar_portada.py +""" +import math +from pathlib import Path +from PIL import Image, ImageDraw, ImageFont + +HERE = Path(__file__).resolve().parent +ANTON = HERE.parents[1] / "src/client/assets/fonts/Anton-Regular.ttf" +SANS = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf" + +BG, FG, NEON, MUTED = "#ffffff", "#000000", "#00e5ff", "#555555" + + +def font(path, size): + return ImageFont.truetype(str(path), size) + + +def phone(shot, width): + """Una captura dentro de un marco negro grueso con la sombra cian de los botones.""" + im = Image.open(HERE / shot).convert("RGB") + h = round(im.height * width / im.width) + im = im.resize((width, h), Image.LANCZOS) + pad, radius, shadow = 10, 34, 10 + frame = Image.new("RGBA", (width + 2 * pad, h + 2 * pad + shadow), (0, 0, 0, 0)) + d = ImageDraw.Draw(frame) + d.rounded_rectangle((0, shadow, width + 2 * pad - 1, h + 2 * pad + shadow - 1), radius, fill=NEON) + d.rounded_rectangle((0, 0, width + 2 * pad - 1, h + 2 * pad - 1), radius, fill=FG) + mask = Image.new("L", im.size, 0) + ImageDraw.Draw(mask).rounded_rectangle((0, 0, width - 1, h - 1), radius - pad, fill=255) + frame.paste(im, (pad, pad), mask) + return frame + + +def portada(): + W, H = 1600, 1100 + out = Image.new("RGB", (W, H), BG) + d = ImageDraw.Draw(out) + d.text((80, 40), "OASIS MOBILE", font=font(ANTON, 92), fill=FG) + bottom = d.textbbox((80, 40), "OASIS MOBILE", font=font(ANTON, 92))[3] + d.rectangle((80, bottom + 12, 420, bottom + 20), fill=FG) + d.text((80, 196), "Rama PRUEBAS del hacklab · base Oasis 1.3.3 · tema Acampada, pensado para el pulgar", + font=font(SANS, 27), fill=MUTED) + shots = [("01-portada.png", "Lanzador de módulos"), ("03-karvan.png", "Karvan: salas efímeras"), + ("04-foros.png", "Filtros en fichas"), ("06-barra.png", "Tu barra de 4 atajos")] + pw, gap, top = 320, 50, 270 + x = (W - (4 * (pw + 20) + 3 * gap)) // 2 + cap = font(ANTON, 34) + for shot, label in shots: + fr = phone(shot, pw) + out.paste(fr, (x, top), fr) + tw = d.textlength(label.upper(), font=cap) + d.text((x + (fr.width - tw) / 2, top + fr.height + 18), label.upper(), font=cap, fill=FG) + x += fr.width + gap + out.save(HERE / "00-portada.png", optimize=True) + + +def caja(d, box, titulo, lineas, relleno=BG): + x0, y0, x1, y1 = box + d.rounded_rectangle((x0, y0 + 6, x1, y1 + 6), 18, fill=FG) + d.rounded_rectangle(box, 18, fill=relleno, outline=FG, width=4) + t = font(ANTON, 30) + d.text(((x0 + x1 - d.textlength(titulo, font=t)) / 2, y0 + 18), titulo, font=t, fill=FG) + s = font(SANS, 18) + for i, l in enumerate(lineas): + d.text(((x0 + x1 - d.textlength(l, font=s)) / 2, y0 + 70 + i * 26), l, font=s, fill=FG) + + +def esquema(): + W, H = 1400, 840 + out = Image.new("RGB", (W, H), BG) + d = ImageDraw.Draw(out) + d.text((46, 26), "LA INTERFAZ DE MÓVIL, POR DENTRO", font=font(ANTON, 46), fill=FG) + bottom = d.textbbox((46, 26), "LA INTERFAZ DE MÓVIL, POR DENTRO", font=font(ANTON, 46))[3] + d.rectangle((46, bottom + 10, 260, bottom + 16), fill=FG) + d.text((46, bottom + 30), "Casi sesenta módulos no caben en una pantalla de teléfono. Se reparten en tres piezas.", + font=font(SANS, 18), fill=MUTED) + + # el movil esquematico + px0, py0, px1, py1 = 110, 170, 470, 790 + d.rounded_rectangle((px0, py0, px1, py1), 30, outline=FG, width=5) + d.rounded_rectangle((px0 + 16, py0 + 20, px1 - 16, py0 + 84), 14, fill=BG, outline=FG, width=3) + s = font(SANS, 15) + d.text((px0 + 46, py0 + 42), "logo · (Personal | Social) · avatar", font=s, fill=FG) + secciones = [("COMUNIDAD", 8), ("BIBLIOTECA", 2), ("HERRAMIENTAS", 5)] + y = py0 + 110 + for nombre, n in secciones: + d.text((px0 + 40, y), nombre, font=font(ANTON, 17), fill=FG) + d.line((px0 + 40, y + 26, px1 - 40, y + 26), fill=FG, width=3) + y += 38 + for i in range(n): + cx = px0 + 48 + (i % 4) * 76 + if i and i % 4 == 0: + y += 62 + d.rounded_rectangle((cx, y + 4, cx + 48, y + 52), 12, fill=FG) + d.rounded_rectangle((cx, y, cx + 48, y + 48), 12, fill=BG, outline=FG, width=3) + y += 72 + d.rounded_rectangle((px0 + 16, py1 - 84, px1 - 16, py1 - 20), 14, fill=NEON, outline=FG, width=3) + d.text((px0 + 92, py1 - 62), "barra: 4 atajos que eliges tú", font=s, fill=FG) + + bx0, bx1 = 560, 1320 + cajas = [ + ((bx0, 190, bx1, 340), "ARRIBA — LA BARRA SUPERIOR", + ["El logo vuelve al inicio y el avatar abre tu perfil.", + "Con muchos módulos activos salen los filtros Personal y Social;", + "en modo activistas todo cabe en una pantalla y no hacen falta."], BG), + ((bx0, 375, bx1, 565), "EN MEDIO — EL LANZADOR", + ["Los módulos activos en una rejilla de iconos, por secciones,", + "como el cajón de apps del móvil. Los nombres son los del Oasis", + "oficial: Comunidad, Biblioteca, Herramientas…", + "Solo en la pantalla de inicio; dentro de cada módulo, filtros en fichas."], BG), + ((bx0, 600, bx1, 750), "ABAJO — LOS ATAJOS", + ["Cuatro módulos a tu elección: ni uno más, que es para el pulgar.", + "Se cambian en Herramientas → Tu barra. La elección se guarda", + "en tu nodo, así que sigue ahí después de cerrar la aplicación."], NEON), + ] + flechas = [((px1 + 10, py0 + 52), (bx0 - 12, 262)), ((px1 + 10, 440), (bx0 - 12, 470)), + ((px1 + 10, py1 - 52), (bx0 - 12, 675))] + for (a, b) in flechas: + ang = math.atan2(b[1] - a[1], b[0] - a[0]) + tip = lambda da, r: (b[0] - r * math.cos(ang + da), b[1] - r * math.sin(ang + da)) + d.line((a, tip(0, 12)), fill=FG, width=4) + d.polygon([b, tip(0.45, 20), tip(-0.45, 20)], fill=FG) + for box, t, l, r in cajas: + caja(d, box, t, l, r) + out.save(HERE / "esquema-interfaz.png", optimize=True) + + +if __name__ == "__main__": + portada() + esquema()