M10: store assets - Plain Files naming, generated icon/feature graphic, listing copy

This commit is contained in:
2026-10-14 17:47:02 +02:00
parent e3de9a2fc0
commit d845a7646e
11 changed files with 313 additions and 13 deletions
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
#
# Generates the Google Play store graphics from the app's own icon vectors.
#
# ./tools/make-store-assets.sh [output-dir] # default: ./store-assets
#
# Produces, matching Play's asset specs:
# icon-512.png 512 x 512 32-bit PNG *with* alpha (ours is full-bleed,
# so every pixel ends up opaque anyway)
# feature-graphic-1024x500.png 1024 x 500 24-bit PNG, no alpha
#
# Output lands in ./store-assets/ *inside* the repo, never in $HOME: the editable sources are
# the SVGs in tools/store-assets/ and these PNGs are the files that get uploaded to the Play
# Console, so they belong with the release they were made for. Pass a directory to override.
set -euo pipefail
here="$(cd "$(dirname "$0")" && pwd)"
repo="$(dirname "$here")"
out="${1:-$repo/store-assets}"
mkdir -p "$out"
render() { # <svg> <width> <height> <filename> <keep-alpha|flatten>
local svg="$1" width="$2" height="$3" name="$4" mode="$5"
inkscape "$svg" \
--export-type=png --export-width="$width" --export-height="$height" \
--export-filename="$out/$name" >/dev/null 2>&1
if [ "$mode" = keep-alpha ]; then
# Play asks for a 32-bit PNG here. The SVG's background rect covers the whole
# canvas, so the alpha channel is fully opaque — no accidental transparency.
magick "$out/$name" -alpha on PNG32:"$out/$name"
else
magick "$out/$name" -background '#1565C0' -alpha remove -alpha off PNG24:"$out/$name"
fi
printf ' %s ' "$out/$name"
magick identify -format '%wx%h %[channels] %b\n' "$out/$name"
}
echo "Writing store assets to $out"
render "$here/store-assets/icon.svg" 512 512 icon-512.png keep-alpha
render "$here/store-assets/feature-graphic.svg" 1024 500 feature-graphic-1024x500.png flatten
echo "Done. Screenshots: ./tools/make-store-screenshots.sh # reads store-assets/raw-screenshots/phone/"
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env bash
#
# Normalises `adb exec-out screencap` captures into the files that get uploaded to Play.
#
# ./tools/make-store-screenshots.sh # phone -> 1080x2160
# FORM_FACTOR=tablet-7in ./tools/make-store-screenshots.sh # 7-inch -> 1200x1920
# FORM_FACTOR=tablet-10in ./tools/make-store-screenshots.sh # 10-inch -> 1600x2560
#
# store-assets/raw-screenshots/<form>/ the raw captures (git-ignored)
# store-assets/screenshots/<form>/ what gets uploaded (committed)
#
# Play's rule that actually bites: JPEG or 24-bit PNG **without alpha**, shorter side >= 320,
# longer side <= 3840, and **longer side <= 2x the shorter side**. A phone at its native
# 1080x2400 is 2.22:1 and is therefore REJECTED, which is why the phone path crops system
# chrome (status + navigation bars) before clamping to 2:1. A tablet frame is already inside
# the 2:1 cap on every profile the SDK ships, so its crop defaults to 0 and is opt-in.
set -euo pipefail
here="$(cd "$(dirname "$0")" && pwd)"
repo="$(dirname "$here")"
form="${FORM_FACTOR:-phone}"
case "$form" in
phone) target_w=1080; target_h=2160; default_status=93; default_nav=130 ;;
tablet-7in) target_w=1200; target_h=1920; default_status=0; default_nav=0 ;;
tablet-10in) target_w=1600; target_h=2560; default_status=0; default_nav=0 ;;
*) echo "Unknown FORM_FACTOR '$form' (phone|tablet-7in|tablet-10in)" >&2; exit 1 ;;
esac
status_px="${STATUS_BAR_PX:-$default_status}"
nav_px="${NAV_BAR_PX:-$default_nav}"
raw="$repo/store-assets/raw-screenshots/$form"
out="$repo/store-assets/screenshots/$form"
mkdir -p "$out"
shopt -s nullglob
captures=("$raw"/*.png)
if [ ${#captures[@]} -eq 0 ]; then
echo "No captures in $raw — take some with:" >&2
echo " adb exec-out screencap -p > $raw/01-roots.png" >&2
exit 1
fi
echo "Normalising ${#captures[@]} capture(s) from $raw -> $out"
for capture in "${captures[@]}"; do
name="$(basename "$capture")"
magick "$capture" \
-gravity North -chop 0x"$status_px" \
-gravity South -chop 0x"$nav_px" \
+repage \
-resize "${target_w}x${target_h}^" \
-gravity Center -extent "${target_w}x${target_h}" \
-alpha remove -alpha off PNG24:"$out/$name"
printf ' %s ' "$out/$name"
magick identify -format '%wx%h %[channels] %b\n' "$out/$name"
done
echo "Done."
+43
View File
@@ -0,0 +1,43 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="500" viewBox="0 0 1024 500">
<!--
Play feature graphic (1024 x 500, no transparency).
Same palette as the app icon (#1565C0) with the icon motif on the left and the store copy
on the right. Text stays inside the middle band because Play crops this graphic to a
square for some placements, and the outer edges are what get cut.
-->
<defs>
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
<stop offset="0" stop-color="#0D3F7A" />
<stop offset="0.55" stop-color="#1565C0" />
<stop offset="1" stop-color="#2E7DD1" />
</linearGradient>
</defs>
<rect x="0" y="0" width="1024" height="500" fill="url(#bg)" />
<!--
The icon motif, on the left. The icon's own content spans roughly x 24..84 and y 38..77,
so it is centred on (54, 57.5).
-->
<g transform="translate(160,250) scale(3.4) translate(-54,-57.5)">
<path d="M34,38 h14 l5,5 h27 a4,4 0 0 1 4,4 v20 a4,4 0 0 1 -4,4 h-46 a4,4 0 0 1 -4,-4 v-25 a4,4 0 0 1 4,-4 z"
fill="#FFFFFF" fill-opacity="0.45" />
<path d="M28,44 h14 l5,5 h27 a4,4 0 0 1 4,4 v20 a4,4 0 0 1 -4,4 h-46 a4,4 0 0 1 -4,-4 v-25 a4,4 0 0 1 4,-4 z"
fill="#FFFFFF" />
<path d="M44,56 h20 a2,2 0 0 1 2,2 v12 a2,2 0 0 1 -2,2 h-20 a2,2 0 0 1 -2,-2 v-12 a2,2 0 0 1 2,-2 z"
fill="#1565C0" />
</g>
<!--
Store copy. Everything here stays inside x 262..762 — the centre square Play crops to for
some placements — so the name and the tagline survive the crop even though the motif does
not. Sizes were chosen by measuring the strings, not by eye.
-->
<text x="300" y="215" font-family="DejaVu Sans" font-weight="bold" font-size="50"
fill="#FFFFFF">Plain Files</text>
<text x="302" y="265" font-family="DejaVu Sans" font-size="20"
fill="#FFFFFF" fill-opacity="0.92">Browse and manage your files</text>
<text x="302" y="298" font-family="DejaVu Sans" font-size="20"
fill="#FFFFFF" fill-opacity="0.92">Ad-free, offline, no account. Pay once.</text>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+26
View File
@@ -0,0 +1,26 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 108 108">
<!--
Play app icon (512 x 512, 32-bit PNG with alpha).
This mirrors the app's own launcher icon exactly: `ic_launcher_background.xml` plus the
three paths from `ic_launcher_foreground.xml`. Background, paths and opacities are
identical, so the store icon *is* the launcher icon rather than a lookalike that drifts
after the next rebrand.
The blue rect covers the whole 108 dp canvas, which is what makes the PNG full bleed:
Play's mask can crop to any shape without revealing a gap.
-->
<rect x="0" y="0" width="108" height="108" fill="#1565C0" />
<!-- Back folder, offset up and to the right -->
<path d="M34,38 h14 l5,5 h27 a4,4 0 0 1 4,4 v20 a4,4 0 0 1 -4,4 h-46 a4,4 0 0 1 -4,-4 v-25 a4,4 0 0 1 4,-4 z"
fill="#FFFFFF" fill-opacity="0.45" />
<!-- Front folder -->
<path d="M28,44 h14 l5,5 h27 a4,4 0 0 1 4,4 v20 a4,4 0 0 1 -4,4 h-46 a4,4 0 0 1 -4,-4 v-25 a4,4 0 0 1 4,-4 z"
fill="#FFFFFF" />
<!-- Document tab -->
<path d="M44,56 h20 a2,2 0 0 1 2,2 v12 a2,2 0 0 1 -2,2 h-20 a2,2 0 0 1 -2,-2 v-12 a2,2 0 0 1 2,-2 z"
fill="#1565C0" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB