diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt index 319293d69c..ea62ebdb9d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/elements/DisplayOts.kt @@ -61,8 +61,8 @@ fun DisplayOts( } HeaderPill( - symbol = MaterialSymbols.CheckCircle, - text = stringRes(R.string.existed_since, timeStr), + symbol = MaterialSymbols.OpenTimestamps, + text = timeStr, contentDescription = stringRes(R.string.ots_info_title), onClick = { accountViewModel.toastManager.toast( @@ -75,8 +75,8 @@ fun DisplayOts( }, whenPending = { HeaderPill( - symbol = MaterialSymbols.Schedule, - text = stringRes(id = R.string.timestamp_pending_short), + symbol = MaterialSymbols.OpenTimestamps, + text = stringRes(id = R.string.pending), contentDescription = stringRes(R.string.ots_info_title), ) }, diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml index a3ef6e6b7d..71c5cba0c2 100644 --- a/amethyst/src/main/res/values/strings.xml +++ b/amethyst/src/main/res/values/strings.xml @@ -45,6 +45,7 @@ Timestamp it Timestamp: Pending Confirmations OTS: Pending + Pending Request Deletion Block / Report diff --git a/commons/src/commonMain/composeResources/font/material_symbols_outlined.ttf b/commons/src/commonMain/composeResources/font/material_symbols_outlined.ttf index 01bd58472e..fde397e9ef 100644 Binary files a/commons/src/commonMain/composeResources/font/material_symbols_outlined.ttf and b/commons/src/commonMain/composeResources/font/material_symbols_outlined.ttf differ diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/symbols/MaterialSymbols.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/symbols/MaterialSymbols.kt index a038c5603d..7ef5919971 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/symbols/MaterialSymbols.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/icons/symbols/MaterialSymbols.kt @@ -167,6 +167,12 @@ object MaterialSymbols { val Numbers = MaterialSymbol("\uEAC7") val OpenInBrowser = MaterialSymbol("\uE89D") val OpenInFull = MaterialSymbol("\uF1CE") + + // Custom glyph (not part of Google's Material Symbols): the OpenTimestamps + // stamp logo, baked into the subset font by + // tools/material-symbols-subset/add_custom_glyphs.py from custom/opentimestamps.svg. + val OpenTimestamps = MaterialSymbol("\uF8F0") + val Paid = MaterialSymbol("\uF041") val PanTool = MaterialSymbol("\uE925") val Pause = MaterialSymbol("\uE034") diff --git a/tools/material-symbols-subset/README.md b/tools/material-symbols-subset/README.md index c6f689020b..9db8fea879 100644 --- a/tools/material-symbols-subset/README.md +++ b/tools/material-symbols-subset/README.md @@ -54,3 +54,15 @@ Commit the regenerated `.ttf` alongside the `MaterialSymbols.kt` change. glyph and OpenType feature not reachable from those codepoints, and rewrites `name`, `cmap`, and `GSUB` tables accordingly. The Compose resource pipeline treats the result as a normal TTF — no code changes needed. + +## Custom glyphs + +`custom/` holds traced SVG outlines for icons the upstream font will never +carry (third-party logos — currently the OpenTimestamps stamp). +`add_custom_glyphs.py` bakes them into the subset TTF at end-of-PUA +codepoints (U+F8F0 and up); `subset.sh` runs it automatically after +`pyftsubset`, so regenerating the subset keeps them. To add one: trace the +logo to a single-color SVG (potrace output works as-is), drop it in +`custom/`, register it in the `CUSTOM` map in `add_custom_glyphs.py`, add the +matching `MaterialSymbol("\uF8Fx")` to `MaterialSymbols.kt`, and rerun +`subset.sh` (or `add_custom_glyphs.py ` to patch the existing font). diff --git a/tools/material-symbols-subset/add_custom_glyphs.py b/tools/material-symbols-subset/add_custom_glyphs.py new file mode 100644 index 0000000000..158c98e438 --- /dev/null +++ b/tools/material-symbols-subset/add_custom_glyphs.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 +"""Append custom (non-Material) glyphs to the subset Material Symbols font. + +Some icons Amethyst needs are third-party logos that Google's Material +Symbols font will never carry (e.g. the OpenTimestamps stamp). Their traced +SVG outlines live in `custom/` and this script bakes them into the subset +TTF at private-use codepoints, so `MaterialSymbols.kt` can reference them +exactly like any Material glyph. + +subset.sh runs this automatically after pyftsubset; it can also be run +directly against an existing font: + + python3 add_custom_glyphs.py + +The SVGs are potrace output: the raw path coordinates are y-up already (the +file's group transform re-flips them for SVG display), so they map into font +space with a plain uniform scale + translate. +""" + +import os +import re +import sys + +from fontTools.pens.boundsPen import BoundsPen +from fontTools.pens.cu2quPen import Cu2QuPen +from fontTools.pens.transformPen import TransformPen +from fontTools.pens.ttGlyphPen import TTGlyphPen +from fontTools.svgLib.path import parse_path +from fontTools.ttLib import TTFont + +HERE = os.path.dirname(os.path.abspath(__file__)) + +# codepoint -> (glyph name, traced SVG). Keep codepoints at the very end of +# the BMP private-use area (U+F8xx tail) to stay clear of the range Material +# Symbols actually allocates. +CUSTOM = { + 0xF8F0: ("opentimestamps", os.path.join(HERE, "custom", "opentimestamps.svg")), +} + +# Fit content into the same square Material Symbols draw in (its check_circle +# glyph spans 80..880 in a 960 upm font). Scaled to the font's real upm. +BOX_MIN_FRAC = 80 / 960 +BOX_MAX_FRAC = 880 / 960 + + +def svg_path_data(svg_file): + with open(svg_file, "r", encoding="utf-8") as f: + svg = f.read() + return re.findall(r']*\bd="([^"]+)"', svg) + + +def draw_svg(paths, pen): + for d in paths: + parse_path(d, pen) + + +def build_glyph(paths, upm): + # First pass: raw outline bounds. + bounds = BoundsPen(None) + draw_svg(paths, bounds) + x_min, y_min, x_max, y_max = bounds.bounds + + # Uniform scale into the Material content box, centered on both axes. + box_min = BOX_MIN_FRAC * upm + box_max = BOX_MAX_FRAC * upm + box = box_max - box_min + scale = box / max(x_max - x_min, y_max - y_min) + tx = box_min + (box - (x_max - x_min) * scale) / 2 - x_min * scale + ty = box_min + (box - (y_max - y_min) * scale) / 2 - y_min * scale + + tt_pen = TTGlyphPen(None) + quad_pen = Cu2QuPen(tt_pen, max_err=1.0) + draw_svg(paths, TransformPen(quad_pen, (scale, 0, 0, scale, tx, ty))) + return tt_pen.glyph() + + +def main(font_path): + font = TTFont(font_path) + upm = font["head"].unitsPerEm + order = font.getGlyphOrder() + + for codepoint, (name, svg_file) in sorted(CUSTOM.items()): + glyph = build_glyph(svg_path_data(svg_file), upm) + + if name not in order: + order.append(name) + font.setGlyphOrder(order) + font["glyf"][name] = glyph + glyph.recalcBounds(font["glyf"]) + font["hmtx"][name] = (upm, glyph.xMin) + for table in font["cmap"].tables: + if table.isUnicode(): + table.cmap[codepoint] = name + print(f"Added {name} at U+{codepoint:04X}") + + font["maxp"].numGlyphs = len(order) + font.save(font_path) + print(f"Wrote {font_path}") + + +if __name__ == "__main__": + if len(sys.argv) != 2: + sys.exit(__doc__) + main(sys.argv[1]) diff --git a/tools/material-symbols-subset/custom/opentimestamps.svg b/tools/material-symbols-subset/custom/opentimestamps.svg new file mode 100644 index 0000000000..054387593f --- /dev/null +++ b/tools/material-symbols-subset/custom/opentimestamps.svg @@ -0,0 +1,130 @@ + + + + +Created by potrace 1.16, written by Peter Selinger 2001-2019 + + + + + diff --git a/tools/material-symbols-subset/subset.sh b/tools/material-symbols-subset/subset.sh index 0689a78aec..640964d342 100755 --- a/tools/material-symbols-subset/subset.sh +++ b/tools/material-symbols-subset/subset.sh @@ -59,4 +59,8 @@ pyftsubset "$SOURCE_TTF" \ --glyph-names \ --symbol-cmap +# Bake in the custom (non-Material) glyphs from custom/ — third-party logos +# like OpenTimestamps that the upstream font will never carry. +python3 "$REPO_ROOT/tools/material-symbols-subset/add_custom_glyphs.py" "$TARGET" + echo "Wrote $TARGET ($(du -h "$TARGET" | cut -f1))"