From d6cd8825fc4f3badbe4f264765513e18d040d7ae Mon Sep 17 00:00:00 2001 From: Jaap-Jan de Wit | DodoTech Date: Mon, 3 Aug 2026 14:45:18 +0200 Subject: [PATCH] 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. --- .../drawable/ic_launcher_foreground.xml | 57 +++++++++--------- .../drawable/ic_launcher_monochrome.xml | 21 +++---- .../mipmap-anydpi-v26/ic_launcher.xml | 13 ++-- .../Resources/values/colors.xml | 7 +++ .../Assets/dodossh-icon.ps1 | 41 ++++++------- src/DodoSSH.Client.App/Assets/dodossh.ico | Bin 9397 -> 9872 bytes 6 files changed, 71 insertions(+), 68 deletions(-) diff --git a/src/DodoSSH.Client.Android/Resources/drawable/ic_launcher_foreground.xml b/src/DodoSSH.Client.Android/Resources/drawable/ic_launcher_foreground.xml index 3978443..51aa79e 100644 --- a/src/DodoSSH.Client.Android/Resources/drawable/ic_launcher_foreground.xml +++ b/src/DodoSSH.Client.Android/Resources/drawable/ic_launcher_foreground.xml @@ -1,25 +1,29 @@ - - - diff --git a/src/DodoSSH.Client.Android/Resources/drawable/ic_launcher_monochrome.xml b/src/DodoSSH.Client.Android/Resources/drawable/ic_launcher_monochrome.xml index 7dcd99a..f6b6885 100644 --- a/src/DodoSSH.Client.Android/Resources/drawable/ic_launcher_monochrome.xml +++ b/src/DodoSSH.Client.Android/Resources/drawable/ic_launcher_monochrome.xml @@ -4,9 +4,14 @@ 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". + Note what that means for the filled design: the accent tile is the background layer, and a + themed icon drops the background entirely. So the shape that survives here is the glyph, not + the tile — which is the right way round anyway. Filling this layer to the edges to stand in + for the tile would tint to a featureless square with nothing of the mark left in it. + 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. + drawn in blue is this one. --> - - diff --git a/src/DodoSSH.Client.Android/Resources/mipmap-anydpi-v26/ic_launcher.xml b/src/DodoSSH.Client.Android/Resources/mipmap-anydpi-v26/ic_launcher.xml index 3015cea..50cf812 100644 --- a/src/DodoSSH.Client.Android/Resources/mipmap-anydpi-v26/ic_launcher.xml +++ b/src/DodoSSH.Client.Android/Resources/mipmap-anydpi-v26/ic_launcher.xml @@ -5,12 +5,17 @@ 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. + The background is the accent, and that is the tile itself rather than a backdrop for one: + the v2 mark is >_ knocked out of a solid accent square, so the square is this layer and the + launcher's mask is what rounds it. See ic_launcher_foreground.xml for why the rounding is + left to the mask instead of drawn. + + It was @color/dodo_window until the mark went from outlined to filled, which is worth + knowing if a home screen still shows the dark version: a launcher caches icons, and the + cache outlives the install that changed them. --> - + diff --git a/src/DodoSSH.Client.Android/Resources/values/colors.xml b/src/DodoSSH.Client.Android/Resources/values/colors.xml index d6dc3c9..4e5c840 100644 --- a/src/DodoSSH.Client.Android/Resources/values/colors.xml +++ b/src/DodoSSH.Client.Android/Resources/values/colors.xml @@ -10,4 +10,11 @@ hidden. --> #0E1220 + + + #5B8CFF diff --git a/src/DodoSSH.Client.App/Assets/dodossh-icon.ps1 b/src/DodoSSH.Client.App/Assets/dodossh-icon.ps1 index 0093416..0f1b5a5 100644 --- a/src/DodoSSH.Client.App/Assets/dodossh-icon.ps1 +++ b/src/DodoSSH.Client.App/Assets/dodossh-icon.ps1 @@ -11,15 +11,19 @@ # Coordinates are the launcher's 108-unit viewport, mapped so the middle 72 fills the canvas. # That 72 is not an arbitrary crop: it is the part of an adaptive icon a launcher actually shows, # the outer 18 on each edge being what it eats for masking and parallax. Rendering the whole 108 -# here would draw the mark at 39% of the width — correct arithmetic, and a stamp lost in a field -# of background. Matching what the phone displays means matching the 72. +# here would draw the glyph at half the size it is meant to be — correct arithmetic, and a stamp +# lost in a field of accent. Matching what the phone displays means matching the 72. +# +# The one thing this draws that the phone's vector does not is the tile. On Android the tile is +# the background layer and the launcher's mask rounds it; Windows has no mask, so the rounding +# happens here. Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' Add-Type -AssemblyName System.Drawing -$window = [System.Drawing.ColorTranslator]::FromHtml('#0E1220') # dodo_window / CanvasColor -$accent = [System.Drawing.ColorTranslator]::FromHtml('#5B8CFF') # AccentColor +$accent = [System.Drawing.ColorTranslator]::FromHtml('#5B8CFF') # dodo_accent / AccentColor +$ink = [System.Drawing.ColorTranslator]::FromHtml('#0E1220') # AccentInk # Every size Windows asks for: 16 in a titlebar and a tree, 32 on the desktop, 48 in a large-icon # view, 256 for the preview pane. Shipping fewer means Windows downsamples one of these to fill @@ -33,7 +37,7 @@ function New-MarkPng([int]$size) $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias $g.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality - # The background, rounded as a launcher mask rounds it. A square-cornered tile would be the + # The accent tile, rounded as a launcher mask rounds it. A square-cornered tile would be the # one icon on the taskbar with corners, which reads as unfinished rather than as deliberate. $radius = [double]$size * 0.22 $d = $radius * 2.0 @@ -43,7 +47,7 @@ function New-MarkPng([int]$size) $path.AddArc($size - $d, $size - $d, $d, $d, 0, 90) $path.AddArc(0.0, $size - $d, $d, $d, 90, 90) $path.CloseFigure() - $brush = New-Object System.Drawing.SolidBrush($window) + $brush = New-Object System.Drawing.SolidBrush($accent) $g.FillPath($brush, $path) # 108-viewport units to pixels, with the outer 18 dropped on each edge. @@ -51,30 +55,21 @@ function New-MarkPng([int]$size) function P([double]$x, [double]$y) { New-Object System.Drawing.PointF((($x - 18.0) * $scale), (($y - 18.0) * $scale)) } # A stroke thinner than a pixel renders as a grey suggestion of itself, which at 16px is the - # difference between a mark and a smudge. The phone's file already bumps these widths for the + # difference between a mark and a smudge. The phone's file already bumps this width for the # same reason at 48dp; the floor is that argument carried down to the sizes Windows asks for. - function Pen([double]$units) - { - $pen = New-Object System.Drawing.Pen($accent, [float][Math]::Max($units * $scale, 1.0)) - $pen.StartCap = [System.Drawing.Drawing2D.LineCap]::Round - $pen.EndCap = [System.Drawing.Drawing2D.LineCap]::Round - $pen.LineJoin = [System.Drawing.Drawing2D.LineJoin]::Round - return $pen - } - - # The box: 42 across, centred, square-cornered as the Border in the app is. - $box = Pen 2.2 - $g.DrawPolygon($box, @((P 33 33), (P 75 33), (P 75 75), (P 33 75))) + $pen = New-Object System.Drawing.Pen($ink, [float][Math]::Max(5.4 * $scale, 1.0)) + $pen.StartCap = [System.Drawing.Drawing2D.LineCap]::Round + $pen.EndCap = [System.Drawing.Drawing2D.LineCap]::Round + $pen.LineJoin = [System.Drawing.Drawing2D.LineJoin]::Round # The chevron of >_ and the underscore on the baseline it bottoms out at. - $ink = Pen 2.8 - $g.DrawLines($ink, @((P 44.8 48.75), (P 51.9 54), (P 44.8 59.25))) - $g.DrawLine($ink, (P 54 59.7), (P 63.2 59.7)) + $g.DrawLines($pen, @((P 36.06 43.33), (P 49.91 53.57), (P 36.06 63.8))) + $g.DrawLine($pen, (P 54 64.68), (P 71.94 64.68)) $stream = New-Object System.IO.MemoryStream $bitmap.Save($stream, [System.Drawing.Imaging.ImageFormat]::Png) - $box.Dispose(); $ink.Dispose(); $brush.Dispose(); $path.Dispose(); $g.Dispose(); $bitmap.Dispose() + $pen.Dispose(); $brush.Dispose(); $path.Dispose(); $g.Dispose(); $bitmap.Dispose() return $stream.ToArray() } diff --git a/src/DodoSSH.Client.App/Assets/dodossh.ico b/src/DodoSSH.Client.App/Assets/dodossh.ico index c3326f9fd31fb97e9044bc6a0d12e1d1dcaf501a..e10fb8827bdb89f01cd99e9c1051ab6851875834 100644 GIT binary patch literal 9872 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 literal 9397 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 e{C0