Public Access
Put the app's own mark on the launcher
The sign-in and locked screens both draw the same thing — a square outline in the accent with >_ inside it — and the launcher was still showing the stock Android silhouette, so the icon somebody taps and the icon the app opens onto had nothing to do with each other. Redrawn as a vector rather than exported from the screen as a bitmap. There is one geometry here and no set of density buckets to update four of and forget the fifth, and the accent stays a number that can be diffed against Palette.axaml rather than a colour baked into a PNG. The hex is written out because an Android resource cannot reference a XAML dictionary — the same duplication colors.xml already carries for the window background, with the same obligation attached. Adaptive only, no raster fallback. Adaptive icons landed in API 26 and this head requires 28, so there is no device it ships to that would need the bitmaps; density buckets exist to choose between PNGs and there is nothing to choose. The background layer is the same @color/dodo_window as the window and the status bar, so the mark sits on the app's own near-black rather than on a second one almost like it. Two departures from the screen, both because a launcher is looked at much smaller than a sign-in header. The box is 42 across rather than the 48 that first suggested itself: 72 of the 108 survives masking, but that is a width, and a square meets a circular mask at its corners — at 48 they land 33.9 out against a radius of 36 and read as clipped despite technically clearing it. And the strokes are 2.2 and 2.8 where proportional fidelity to a 1px border on 44px would be 1.0, which a launcher drawing this at 48dp would render as half a pixel of nothing. A monochrome layer too, for the Android 13+ themed-icon setting. Without one a launcher with themed icons on falls back to the full-colour icon, which would leave this the single green thing on an otherwise recoloured home screen. Verified in the packaged APK: the icon resolves at all five densities, the three layers resolve, and the compiled vector carries the geometry above. The launcher rendering itself was checked against local renders under circular and squircle masks at 144 and 64 px, not on the device — the phone was locked. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,7 +26,14 @@
|
|||||||
phone's outbox onto another, which is the same corruption ClientPaths already refuses by insisting on
|
phone's outbox onto another, which is the same corruption ClientPaths already refuses by insisting on
|
||||||
a local, non-roaming directory.
|
a local, non-roaming directory.
|
||||||
-->
|
-->
|
||||||
|
<!--
|
||||||
|
The launcher icon is the same >_ box the sign-in and locked screens draw, as a vector
|
||||||
|
adaptive icon. See Resources/mipmap-anydpi-v26/ic_launcher.xml. No android:roundIcon:
|
||||||
|
that attribute exists so a launcher wanting a circle can be handed a second bitmap, and
|
||||||
|
an adaptive icon is already masked to whatever shape the launcher asks for.
|
||||||
|
-->
|
||||||
<application android:label="DodoSSH"
|
<application android:label="DodoSSH"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:theme="@style/DodoTheme"
|
android:theme="@style/DodoTheme"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<?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.
|
||||||
|
|
||||||
|
#3CE88F 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
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="#3CE88F"
|
||||||
|
android:strokeWidth="2.2" />
|
||||||
|
|
||||||
|
<!-- The chevron of >_ -->
|
||||||
|
<path
|
||||||
|
android:pathData="M44.8,48.75 L51.9,54 L44.8,59.25"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#3CE88F"
|
||||||
|
android:strokeWidth="2.8"
|
||||||
|
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:fillColor="#00000000"
|
||||||
|
android:strokeColor="#3CE88F"
|
||||||
|
android:strokeWidth="2.8"
|
||||||
|
android:strokeLineCap="round" />
|
||||||
|
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
The themed-icon layer, for the Android 13+ setting that repaints every launcher icon in
|
||||||
|
the wallpaper's colours. The system tints this by its alpha and discards the colour, so
|
||||||
|
the geometry is the foreground's and white is only a way of saying "opaque here".
|
||||||
|
|
||||||
|
Worth shipping rather than leaving out: a launcher with themed icons on and no monochrome
|
||||||
|
layer to use falls back to the full-colour icon, so the one app on the home screen still
|
||||||
|
drawn in green is this one.
|
||||||
|
-->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:pathData="M33,33 L75,33 L75,75 L33,75 Z"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#FFFFFF"
|
||||||
|
android:strokeWidth="2.2" />
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:pathData="M44.8,48.75 L51.9,54 L44.8,59.25"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#FFFFFF"
|
||||||
|
android:strokeWidth="2.8"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="round" />
|
||||||
|
|
||||||
|
<path
|
||||||
|
android:pathData="M54,59.7 L63.2,59.7"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#FFFFFF"
|
||||||
|
android:strokeWidth="2.8"
|
||||||
|
android:strokeLineCap="round" />
|
||||||
|
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Adaptive only, with no raster fallback in mipmap-hdpi and the rest, and that is a
|
||||||
|
consequence of minSdk rather than a shortcut: this head requires API 28 (see the csproj),
|
||||||
|
adaptive icons landed in 26, so there is no device this ships to that would need the
|
||||||
|
bitmaps. Density buckets exist to pick a PNG; a vector has nothing to pick between.
|
||||||
|
|
||||||
|
The background is the same @color/dodo_window the window, status bar and navigation bar
|
||||||
|
use, so the mark sits on the app's own near-black rather than on a second dark that is
|
||||||
|
almost but not quite it.
|
||||||
|
-->
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/dodo_window" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||||
|
</adaptive-icon>
|
||||||
Reference in New Issue
Block a user