quitar el proyecto Gradle propio y lo que dependia de el
La APK se monta sobre la oficial con sobre_oficial.sh; el proyecto Gradle, sus scripts, el workflow de gitea, la guia en PDF y el pad de usabilidad ya no se usan.
This commit is contained in:
parent
e4bbbc23f2
commit
2d79e6779c
30 changed files with 17 additions and 2330 deletions
|
|
@ -1,213 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Portada y esquemas del README.
|
||||
|
||||
Las capturas de movil (01..06) se hacen aparte, con la app arrancada en un nodo de
|
||||
pruebas a 412x915 y escala 2, en español y con lo que trae de serie (perfil Minimo y
|
||||
colores del dev; 03 a 06 con el perfil Activista). Este script compone 00-portada.png
|
||||
a partir de ellas, con los colores de serie, y dibuja esquema-interfaz.png,
|
||||
esquema-rama.png y esquema-llamadas.png (estos aun con la paleta de Acampada).
|
||||
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"
|
||||
# colores de serie del movil (los de la APK oficial del dev)
|
||||
DEV_BG, DEV_CARD, DEV_FG, DEV_ACCENT, DEV_MUTED = "#121212", "#1e1e1e", "#ffd700", "#ffa300", "#bbbbbb"
|
||||
SANS_BOLD = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
|
||||
|
||||
|
||||
def font(path, size):
|
||||
return ImageFont.truetype(str(path), size)
|
||||
|
||||
|
||||
def phone(shot, width, fg=FG, neon=NEON):
|
||||
"""Una captura dentro de un marco grueso con una sombra de color debajo."""
|
||||
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), DEV_BG)
|
||||
d = ImageDraw.Draw(out)
|
||||
d.text((80, 40), "OASIS MOBILE", font=font(SANS_BOLD, 84), fill=DEV_FG)
|
||||
bottom = d.textbbox((80, 40), "OASIS MOBILE", font=font(SANS_BOLD, 84))[3]
|
||||
d.rectangle((80, bottom + 12, 420, bottom + 18), fill=DEV_ACCENT)
|
||||
d.text((80, 186), "Rama PRUEBAS del hacklab · base Oasis 1.3.5 · lo que sale al instalarla",
|
||||
font=font(SANS, 27), fill=DEV_MUTED)
|
||||
shots = [("01-actividad.png", "Actividad al abrir"), ("02-menu.png", "Menú, perfil Mínimo"),
|
||||
("03-menu-activista.png", "Menú, perfil Activista"), ("04-tribu.png", "Una tribu")]
|
||||
pw, gap, top = 320, 50, 260
|
||||
x = (W - (4 * (pw + 20) + 3 * gap)) // 2
|
||||
cap = font(SANS_BOLD, 26)
|
||||
for shot, label in shots:
|
||||
fr = phone(shot, pw, fg="#000000", neon=DEV_ACCENT)
|
||||
out.paste(fr, (x, top), fr)
|
||||
tw = d.textlength(label, font=cap)
|
||||
d.text((x + (fr.width - tw) / 2, top + fr.height + 18), label, font=cap, fill=DEV_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. Lo primero es lo que pasa; el resto, en el menú.",
|
||||
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 · no molestar · avatar", font=s, fill=FG)
|
||||
# en medio, la actividad: lo que ha pasado en la red
|
||||
y = py0 + 110
|
||||
d.text((px0 + 40, y), "ACTIVIDAD", font=font(ANTON, 22), fill=FG)
|
||||
d.line((px0 + 40, y + 32, px1 - 40, y + 32), fill=FG, width=3)
|
||||
y += 52
|
||||
for i in range(4):
|
||||
d.rounded_rectangle((px0 + 40, y, px1 - 40, y + 86), 12, fill=BG, outline=FG, width=3)
|
||||
d.rectangle((px0 + 56, y + 18, px0 + 150, y + 30), fill=FG)
|
||||
d.rectangle((px0 + 56, y + 44, px1 - 70, y + 52), fill=MUTED)
|
||||
d.rectangle((px0 + 56, y + 62, px1 - 120, y + 70), fill=MUTED)
|
||||
y += 104
|
||||
d.rounded_rectangle((px0 + 16, py1 - 84, px1 - 16, py1 - 20), 14, fill=NEON, outline=FG, width=3)
|
||||
d.text((px0 + 62, py1 - 62), "4 atajos que eliges tú · MENÚ", 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.",
|
||||
"En medio, el botón de No molestar del Teléfono.",
|
||||
"Con muchos módulos activos salen también los filtros Personal y Social."], BG),
|
||||
((bx0, 375, bx1, 565), "EN MEDIO — LA ACTIVIDAD",
|
||||
["Al abrir la app se ve lo que ha pasado en la red, no un menú.",
|
||||
"Dentro de cada módulo, los filtros van en fichas pequeñas",
|
||||
"y el botón principal (crear tribu, crear sala…) siempre igual."], BG),
|
||||
((bx0, 600, bx1, 750), "ABAJO — LOS ATAJOS Y EL MENÚ",
|
||||
["Cuatro atajos a tu elección y una quinta pestaña fija, Menú,",
|
||||
"que abre desde abajo una hoja con todos los módulos por secciones",
|
||||
"(Comunidad, Biblioteca, Gobernanza…). Está en todas las pantallas."], 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)
|
||||
|
||||
|
||||
def flecha(d, a, b, ancho=4):
|
||||
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=ancho)
|
||||
d.polygon([b, tip(0.45, 20), tip(-0.45, 20)], fill=FG)
|
||||
|
||||
|
||||
def titulo(d, texto, sub):
|
||||
d.text((46, 26), texto, font=font(ANTON, 46), fill=FG)
|
||||
bottom = d.textbbox((46, 26), texto, font=font(ANTON, 46))[3]
|
||||
d.rectangle((46, bottom + 10, 260, bottom + 16), fill=FG)
|
||||
d.text((46, bottom + 30), sub, font=font(SANS, 18), fill=MUTED)
|
||||
|
||||
|
||||
def esquema_rama():
|
||||
"""Como va la rama encima de Oasis: lo del dev abajo, lo nuestro encima."""
|
||||
W, H = 1400, 760
|
||||
out = Image.new("RGB", (W, H), BG)
|
||||
d = ImageDraw.Draw(out)
|
||||
titulo(d, "CÓMO VA LA RAMA ENCIMA DE OASIS",
|
||||
"Oasis lo cambia el dev, casi una versión al día. La rama solo cambia cómo se ve y se usa en el móvil.")
|
||||
capa = [
|
||||
((60, 210, 380, 400), "ASPECTO",
|
||||
["mobile_base.css: la maqueta", "mobile_ux.css: márgenes, letra,", "botones y piezas nuevas",
|
||||
"Acampada.css: el skin"], NEON),
|
||||
((400, 210, 720, 400), "PANTALLAS",
|
||||
["mobile_ui.js y las vistas", "mobile_*.js. En una vista", "del dev, como mucho una", "línea que las llama"], NEON),
|
||||
((740, 210, 1060, 400), "RUTAS",
|
||||
["fork_routes.js, delante", "del router del dev: lo", "que no atiende pasa al", "suyo"], NEON),
|
||||
((1080, 210, 1340, 400), "ANDROID",
|
||||
["la app del dev tal cual,", "con nuestro backend", "dentro y paquete", "propio"], NEON),
|
||||
]
|
||||
for box, t, l, r in capa:
|
||||
caja(d, box, t, l, r)
|
||||
d.text((60, 166), "LO DE LA RAMA", font=font(ANTON, 26), fill=FG)
|
||||
for x in (220, 560, 900, 1210):
|
||||
flecha(d, (x, 418), (x, 478))
|
||||
caja(d, (60, 500, 1340, 690), "OASIS DEL DEV: NO SE TOCA",
|
||||
["backend.js y su middleware · los modelos (lo que se publica y cómo se cuenta) · SSB y su arranque",
|
||||
"las traducciones · style.css y mobile.css · los temas, también OasisMobile.css",
|
||||
"Comparado con su APK oficial, la rama cambia 17 ficheros suyos y 561 líneas. Ver GUIA_DE_DESARROLLO.md"], BG)
|
||||
out.save(HERE / "esquema-rama.png", optimize=True)
|
||||
|
||||
|
||||
def esquema_llamadas():
|
||||
"""Las llamadas son las del dev; en Android pasan por un puente nativo de la app."""
|
||||
W, H = 1400, 700
|
||||
out = Image.new("RGB", (W, H), BG)
|
||||
d = ImageDraw.Draw(out)
|
||||
titulo(d, "LLAMADAS: LAS DEL DEV",
|
||||
"Teléfono y Salas son de Oasis. En Android el sonido y la cámara pasan por un puente nativo de la app.")
|
||||
cajas = [
|
||||
((50, 200, 360, 430), "TELÉFONO Y SALAS",
|
||||
["De Oasis, tal cual.", "Llamadas de uno a uno", "con buzón de voz; salas", "de hasta 50, con vídeo,", "grabación y emisión."], BG),
|
||||
((400, 200, 700, 430), "LOS ENCHUFES",
|
||||
["phone_*_android.js", "(del dev): se conectan", "a un puerto local que", "deja la app en", ".audio_bridge"], BG),
|
||||
((740, 200, 1040, 430), "EL PUENTE NATIVO",
|
||||
["Dentro de la app:", "R graba el micro", "P reproduce", "V saca la cámara", "S emite un fichero"], NEON),
|
||||
((1080, 200, 1350, 430), "EL MÓVIL",
|
||||
["Micrófono, cámara", "y altavoz, con los", "permisos que se piden", "la primera vez."], BG),
|
||||
]
|
||||
for box, t, l, r in cajas:
|
||||
caja(d, box, t, l, r)
|
||||
for a, b in (((362, 315), (398, 315)), ((702, 315), (738, 315)), ((1042, 315), (1078, 315))):
|
||||
flecha(d, a, b)
|
||||
caja(d, (50, 480, 1350, 630), "DÓNDE ESTÁ CADA COSA",
|
||||
["El puente está en la app Android del dev, que no tiene el código publicado. Por eso la APK de la",
|
||||
"rama se monta sobre la oficial: su app tal cual, nuestro backend dentro y paquete propio."], BG)
|
||||
out.save(HERE / "esquema-llamadas.png", optimize=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
# sin argumentos, todo; con nombres, solo esos (p. ej. "portada")
|
||||
for name in sys.argv[1:] or ["portada", "esquema", "esquema_rama", "esquema_llamadas"]:
|
||||
globals()[name]()
|
||||
Loading…
Add table
Add a link
Reference in a new issue