Skip to content

Commit abc0fab

Browse files
committed
merge: theme toggle alignment and logo cleanup
2 parents 8dcf041 + e262e3a commit abc0fab

5 files changed

Lines changed: 37 additions & 31 deletions

File tree

docs/logo/recolor_variant.py

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,20 @@
2020

2121
# Darkest and lightest tone of each block. The shades in between are taken from
2222
# the source's own brightness, which is what keeps the speckle pattern.
23+
WHITE = (0xFF, 0xFF, 0xFF)
24+
DARK = (0x1A, 0x14, 0x0A)
25+
26+
# dark tone, light tone, glyph. Pass None for the glyph to have it chosen by
27+
# contrast, which is the safe default for a new ramp.
2328
RAMPS = {
2429
# Gold is a flatter block in game, so its ramp is deliberately short: the
25-
# same speckle at full strength reads as sand.
26-
"gold": ((0xC2, 0x9E, 0x1A), (0xFA, 0xF0, 0x62)),
27-
# Stone is speckled exactly like this, so it takes the full contrast.
28-
"stone": ((0x5E, 0x5E, 0x5E), (0xA8, 0xA8, 0xA8)),
30+
# same speckle at full strength reads as sand. The glyph is dark because
31+
# the white one it inherited from dirt vanished against yellow.
32+
"gold": ((0xC2, 0x9E, 0x1A), (0xFA, 0xF0, 0x62), DARK),
33+
# Stone is speckled exactly like this, so it takes the full contrast. Its
34+
# glyph is white by choice rather than by the contrast rule, which would
35+
# pick dark here.
36+
"stone": ((0x5E, 0x5E, 0x5E), (0xA8, 0xA8, 0xA8), WHITE),
2937
}
3038

3139

@@ -58,14 +66,15 @@ def glyph_color(dark, light):
5866
def is_texture(pixel):
5967
"""True for block pixels, false for the glyph drawn on top of them.
6068
61-
The glyph is white or near-grey; every texture tone is saturated, so the
62-
spread between the channels separates the two cleanly.
69+
The glyph is pure white and nothing else in the source is. Judging by
70+
saturation instead looks reasonable and is wrong: dirt has seven near-grey
71+
speckles scattered across the block, which are texture, and treating them
72+
as glyph left dark flecks all over the recoloured gold.
6373
"""
64-
r, g, b = pixel[:3]
65-
return max(r, g, b) - min(r, g, b) > 25
74+
return tuple(pixel[:3]) != WHITE
6675

6776

68-
def recolor(image, dark, light):
77+
def recolor(image, dark, light, glyph=None):
6978
# Read through tobytes rather than getdata, which Pillow has deprecated in
7079
# favour of a method too new to rely on here.
7180
raw = image.tobytes()
@@ -75,26 +84,13 @@ def recolor(image, dark, light):
7584
high = max(luminance(p) for p in texture)
7685
span = high - low or 1
7786

78-
glyph = glyph_color(dark, light)
79-
glyph_low = min(luminance(p) for p in pixels if not is_texture(p))
80-
glyph_high = max(luminance(p) for p in pixels if not is_texture(p))
81-
glyph_span = glyph_high - glyph_low or 1
87+
glyph = glyph or glyph_color(dark, light)
8288

8389
out = []
8490
for pixel in pixels:
91+
# The glyph is one flat tone, so it is replaced rather than mapped.
8592
if not is_texture(pixel):
86-
# The glyph has a lighter body and a darker edge. Both are moved
87-
# together so the edge keeps softening the corners as before.
88-
t = (luminance(pixel) - glyph_low) / glyph_span
89-
edge = tuple(round(c * 0.55 + 128 * 0.45) for c in glyph)
90-
out.append(
91-
(
92-
round(edge[0] + (glyph[0] - edge[0]) * t),
93-
round(edge[1] + (glyph[1] - edge[1]) * t),
94-
round(edge[2] + (glyph[2] - edge[2]) * t),
95-
pixel[3],
96-
)
97-
)
93+
out.append((*glyph, pixel[3]))
9894
continue
9995
t = (luminance(pixel) - low) / span
10096
out.append(
@@ -113,9 +109,9 @@ def recolor(image, dark, light):
113109

114110
def main():
115111
source = Image.open(SOURCE).convert("RGBA")
116-
for name, (dark, light) in RAMPS.items():
112+
for name, (dark, light, glyph) in RAMPS.items():
117113
path = os.path.join("variants", f"{name}.png")
118-
recolor(source, dark, light).save(path)
114+
recolor(source, dark, light, glyph).save(path)
119115
print(f"wrote {path}")
120116
source.close()
121117

docs/logo/variants/gold.png

-24 Bytes
Loading

docs/logo/variants/stone.png

-14 Bytes
Loading

lib/views/preferences_view.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,19 @@ class _PreferencesViewState extends State<PreferencesView> {
9393
children: [
9494
Row(
9595
children: [
96-
// Flexible, not fixed: the button beside it is wide
97-
// enough to overflow this row on a narrow window.
98-
Flexible(
96+
// Expanded rather than Flexible plus a Spacer: both
97+
// default to flex 1, so they split the free space
98+
// between them and leave the button mid-card instead
99+
// of against the right edge. Taking all of it here
100+
// also lets the label ellipsize rather than overflow.
101+
Expanded(
99102
child: Text(
100103
'Color theme',
101104
maxLines: 1,
102105
overflow: TextOverflow.ellipsis,
103106
style: Theme.of(context).textTheme.labelLarge,
104107
),
105108
),
106-
const Spacer(),
107109
TextButton.icon(
108110
// Not prefixed 'app-theme-', which identifies the
109111
// tiles themselves and is counted as such.

test/views/tabs_view_test.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,14 @@ void main() {
198198
final collapsed = tester.widgetList(tiles).length;
199199
expect(collapsed, lessThan(AppTheme.values.length));
200200

201+
// Hard against the right edge of the tiles below it. Flexible plus a
202+
// Spacer put it halfway across the card, because both default to flex 1
203+
// and split the free space.
204+
final toggleRight =
205+
tester.getRect(find.byKey(const ValueKey('theme-expand-toggle'))).right;
206+
final tilesRight = tester.getRect(tiles.last).right;
207+
expect((toggleRight - tilesRight).abs(), lessThan(1));
208+
201209
await tester.tap(find.byKey(const ValueKey('theme-expand-toggle')));
202210
await tester.pumpAndSettle();
203211
expect(tester.widgetList(tiles).length, AppTheme.values.length);

0 commit comments

Comments
 (0)