Let the launcher icon catch up with the mark v2 already drew everywhere else

TitleBar and PhoneShell have drawn >_ knocked out of a solid accent tile since
v2, and both say in a comment that the launcher icon draws the same thing so the
three cannot drift. The launcher was still v1: an outlined square in the accent.
The comments are true now.

On Android the tile is the background layer rather than a rounded rectangle in
the foreground, because the rounding a launcher applies is its mask. Drawing the
tile would put a second rounded shape inside the mask, clipped at the corners on
any device whose mask is not the one it was drawn for; leaving it to the mask
gets a squircle on one device and a circle on another for free. Windows has no
mask, so dodossh.ico still draws its own corners.

The monochrome layer keeps only the glyph. A themed icon drops the background,
which is where the tile now lives, and a layer filled to the edges to stand in
for it would tint to a featureless square.

The glyph is half the width of the safe zone, taken from the two headers rather
than invented -- both set >_ a little under half the tile across. It is also
markedly more legible small than the outline was: dark on accent at 16px is a
mark, where a sub-pixel hairline was a smudge.
This commit is contained in:
2026-08-03 14:45:18 +02:00
parent c7c844f7bd
commit d6cd8825fc
6 changed files with 71 additions and 68 deletions
@@ -1,25 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
The launcher mark, and it is the same mark ServerScreen and LockedScreen draw: a square
outline in the accent with >_ inside it. Redrawn as a vector rather than exported as a
bitmap so there is one geometry to change and no set of five PNG densities to forget one
of.
The launcher mark, and it is the same mark PhoneShell's header and the desktop titlebar draw:
>_ in the canvas colour on a solid accent tile. Filled rather than outlined since v2.
#5B8CFF is AccentColor from DodoSSH.Client.Shell's Theme/Palette.axaml, written out
because an Android resource cannot reference a XAML dictionary. The same duplication
colors.xml already carries for the window background, and the same rule applies: if the
palette moves, this moves with it.
The tile is not in this file. It is the background layer — @color/dodo_accent, see ic_launcher.xml
— and that is the whole trick of the filled design on Android: the rounding a launcher applies is
its mask, so letting the mask make the tile gets a squircle on one device and a circle on another
without either being drawn here. A rounded rectangle painted into this layer would be a second
rounded shape inside the first, visibly clipped at the corners on any device whose mask is not the
one it was drawn for.
108x108 with the artwork inside the middle 72 is the adaptive-icon contract — the outer
18 on each edge is what the launcher eats for masking and parallax. That 72 is a width,
though, and the mark is a square: its corners are what a circular mask reaches first. At
48 across the corners land 33.9 out against a radius of 36 and read as clipped even
though they technically clear it. 42 puts them at 29.7, which is margin one can see.
#0E1220 is AccentInk from DodoSSH.Client.Shell's Theme/Palette.axaml, written out because an
Android resource cannot reference a XAML dictionary. It equals Canvas today and is named
separately in the palette for a reason worth keeping in mind here: this is ink on the accent, not
the window behind it, and it follows AccentInk if the two ever part.
The stroke widths are the one place this deliberately departs from the screen. In the app
the box is a 1px border on 44px; scaled honestly that would be 1.0 here, and a launcher
drawing this at 48dp would render it at half a pixel and show nothing. 2.2 and 2.8 are
what keep it reading as the same hairline mark at the size it is actually looked at.
108x108 with the artwork inside the middle 72 is the adaptive-icon contract — the outer 18 on each
edge is what the launcher eats for masking and parallax. The glyph spans 36.06..71.94, which is
half the width of that 72 and centred in it. That half is taken from the headers rather than
invented: the phone draws >_ at font size 10 on a 26px tile and the titlebar at 9 on 20px, both a
little under half the tile across, and a launcher icon is looked at from further away than either.
The stroke width is the one place this deliberately departs from the screen. In the app the glyph
is a bold mono face whose stems come out near a fifth of its height; 5.4 here is nearer a quarter,
which is what keeps it reading as the same mark at the size it is actually looked at.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
@@ -27,28 +31,21 @@
android:viewportWidth="108"
android:viewportHeight="108">
<!-- The box: 42 across, centred, square-cornered as the Border in the app is. -->
<path
android:pathData="M33,33 L75,33 L75,75 L33,75 Z"
android:fillColor="#00000000"
android:strokeColor="#5B8CFF"
android:strokeWidth="2.2" />
<!-- The chevron of >_ -->
<path
android:pathData="M44.8,48.75 L51.9,54 L44.8,59.25"
android:pathData="M36.06,43.33 L49.91,53.57 L36.06,63.8"
android:fillColor="#00000000"
android:strokeColor="#5B8CFF"
android:strokeWidth="2.8"
android:strokeColor="#0E1220"
android:strokeWidth="5.4"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
<!-- The underscore, on the baseline the chevron bottoms out at. -->
<path
android:pathData="M54,59.7 L63.2,59.7"
android:pathData="M54,64.68 L71.94,64.68"
android:fillColor="#00000000"
android:strokeColor="#5B8CFF"
android:strokeWidth="2.8"
android:strokeColor="#0E1220"
android:strokeWidth="5.4"
android:strokeLineCap="round" />
</vector>