1
0
forked from GRIN/grim

goblin: UI pack 153 (portrait lock, home logo, GoblinPay badge, plain QR)

1. Lock Android to portrait (screenOrientation="portrait" on MainActivity).
   Phone-first GRIM-style wallet; no cheap phone/tablet split so the whole
   Android app is locked, matching the single phone surface.
2. Enlarge the mobile Home header wordmark: mark 24 to 36 (+50%), "goblin"
   text 18 to 26, gap 8 to 9, so the top-left lockup carries the same
   visual weight as the 40 to 44px right cluster (owner asked for a
   noticeably bigger bump than the first +25% pass).
3. Swap the Pay-screen inline mark for the official GoblinPay lockup: the
   black Apple-Pay-style badge on light surfaces, the white wordmark on
   dark (theme dark_base split). New img assets from the GoblinPay repo.
4. Plain GoblinPay/receive QR: drop the yellow center-mark overlay from
   w::qr_code (mirrors the prior "plain QR default" decision). Test
   goblin_receive_qr_decodes updated to the plain render.
This commit is contained in:
2ro
2026-07-06 18:50:07 -04:00
parent 55d8f038dc
commit f7689077d4
6 changed files with 127 additions and 32 deletions
+1
View File
@@ -41,6 +41,7 @@
<activity
android:launchMode="singleTask"
android:name=".MainActivity"
android:screenOrientation="portrait"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|uiMode|density|locale|layoutDirection|fontScale|colorMode"
android:exported="true">
+48
View File
@@ -0,0 +1,48 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 98 40" role="img" aria-label="GoblinPay" preserveAspectRatio="xMidYMid meet">
<rect width="98" height="40" rx="8" fill="#000000"/>
<!-- Goblin girl head mark (reused geometry, white for the black badge) -->
<g transform="translate(13,8) scale(0.039933)">
<g transform="translate(0,601) scale(0.05,-0.05)" fill="#ffffff" stroke="none">
<path d="M195 11784 c-515 -1551 98 -2966 1520 -3514 171 -66 171 -72 2 -72
-415 0 -893 215 -1273 572 -178 167 -181 163 -77 -83 478 -1130 1770 -1734
2963 -1384 283 83 309 101 420 292 376 648 1038 1116 1763 1245 l143 26 100
202 c887 1780 -911 3344 -3076 2675 l-170 -52 220 -14 c480 -32 818 -114 1118
-273 258 -137 548 -414 624 -597 l32 -76 -87 76 c-435 375 -938 524 -1557 461
-273 -28 -340 -39 -740 -120 -893 -182 -1449 24 -1756 650 l-98 200 -71 -214z"/>
<path d="M9720 10053 c0 -146 -256 -556 -441 -705 -381 -308 -766 -380 -1559
-290 -1209 137 -2026 -255 -2519 -1208 -78 -151 -82 -156 -72 -77 18 140 128
450 210 592 43 74 73 135 67 135 -25 0 -397 -184 -512 -253 -966 -580 -1594
-1674 -1594 -2777 0 -104 -4 -190 -10 -190 -5 0 -65 43 -132 95 -650 503
-1118 775 -1606 935 -290 95 -302 94 -242 -15 52 -95 166 -372 191 -465 9 -33
34 -121 56 -195 48 -161 120 -508 194 -935 118 -684 437 -1371 795 -1715 185
-178 324 -239 594 -262 144 -13 150 -15 147 -63 -1 -27 -14 -174 -28 -326 -83
-902 258 -1568 1037 -2024 139 -81 161 -80 127 4 -37 96 -85 369 -96 546 l-10
170 46 -60 c328 -431 869 -753 1497 -891 351 -77 1285 -67 1426 15 9 5 -104
50 -250 98 -649 217 -1341 668 -1680 1096 -81 102 -88 147 -11 78 157 -142
653 -406 925 -493 783 -249 1542 -242 2332 20 l274 91 106 -83 c298 -236 798
-328 1259 -231 197 42 196 38 32 169 -156 124 -344 356 -443 546 l-60 116 70
52 c544 408 783 906 627 1300 l-41 102 170 138 c442 355 584 624 813 1537 186
742 257 952 452 1328 l118 227 -145 -14 c-693 -68 -1425 -411 -1729 -810 -99
-130 -112 -127 -165 44 -54 175 -217 511 -308 636 -64 88 -70 91 -224 117
-314 52 -637 184 -956 390 -260 168 -509 436 -280 302 127 -74 302 -160 430
-211 97 -38 146 -55 348 -118 335 -105 983 -129 1280 -47 961 264 1554 1048
1729 2286 28 199 45 685 23 677 -9 -4 -73 -77 -141 -163 -650 -810 -1594
-1147 -2451 -873 -251 80 -246 76 -171 121 395 240 638 767 578 1253 -25 209
-77 395 -77 278z m-682 -4962 c306 -158 601 -1396 416 -1747 -118 -224 -283
-345 -526 -387 -455 -78 -577 227 -456 1143 96 725 320 1118 566 991z m-3115
-156 c371 -172 699 -815 799 -1565 34 -251 19 -307 -108 -422 -575 -519 -1624
-162 -1931 657 -265 709 593 1630 1240 1330z m5261 -120 c20 -377 -135 -912
-290 -995 -70 -38 -72 -35 -157 230 l-64 200 -24 -90 c-50 -192 -144 -340
-215 -340 -111 0 -316 804 -228 893 53 53 200 -130 226 -283 l14 -80 36 105
c100 293 222 333 332 109 l54 -110 35 105 c89 260 271 427 281 256z m-8491
-284 l75 -230 52 160 c89 272 210 336 295 154 126 -268 210 -757 142 -825 -44
-44 -163 120 -247 340 -12 33 -19 24 -39 -50 -89 -330 -286 -346 -374 -30
l-22 80 -35 -125 c-54 -196 -223 -428 -275 -377 -37 37 -29 448 11 608 70 276
219 524 314 524 17 0 56 -87 103 -229z m4164 -2698 c137 -311 883 -373 1408
-116 162 78 171 64 42 -61 -317 -305 -854 -408 -1271 -244 -223 87 -516 338
-516 442 0 53 140 267 212 324 l58 46 14 -152 c8 -84 31 -191 53 -239z"/>
</g>
</g>
<!-- "Pay" wordmark: font-stack-safe, matches the existing GoblinPay wordmark treatment -->
<text x="46" y="28" font-family="system-ui,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif" font-size="22" font-weight="700" letter-spacing="-0.5" fill="#ffffff">Pay</text>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

+51
View File
@@ -0,0 +1,51 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="600.000000pt" height="232.000000pt" viewBox="0 0 600.000000 232.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,232.000000) scale(0.050000,-0.050000)"
fill="#ffffff" stroke="none">
<path d="M52 4522 c-131 -444 37 -874 416 -1064 l122 -61 -95 11 c-111 13
-226 67 -324 154 -83 72 -86 66 -28 -48 140 -278 398 -434 715 -434 197 0 331
45 362 120 62 150 316 340 520 391 271 67 273 570 2 813 -194 175 -626 253
-842 152 l-70 -33 91 -1 c191 -4 428 -112 506 -231 36 -53 15 -72 -26 -23 -89
108 -361 154 -623 104 -384 -72 -552 -22 -664 197 l-30 60 -32 -107z"/>
<path d="M4560 2533 l0 -1610 285 3 285 4 5 573 6 573 484 9 c534 10 636 29
838 158 583 370 592 1348 15 1718 -240 155 -320 167 -1163 175 l-755 7 0
-1610z m1450 1080 c389 -170 416 -801 42 -998 -75 -40 -118 -44 -497 -51
l-415 -8 0 554 0 554 395 -8 c319 -7 410 -15 475 -43z"/>
<path d="M3139 3938 c-92 -222 -202 -268 -639 -268 -462 0 -625 -70 -783 -338
-58 -100 -60 -71 -4 66 37 92 27 95 -96 29 -298 -160 -537 -548 -537 -871 0
-117 -1 -117 -150 -4 -124 94 -359 217 -456 240 l-55 13 43 -108 c23 -59 67
-230 98 -381 87 -422 215 -636 412 -686 l94 -23 -4 -152 c-8 -255 71 -431 252
-564 108 -79 133 -87 119 -36 -6 19 -16 75 -24 125 l-14 90 86 -87 c155 -155
391 -243 648 -243 238 1 257 17 94 80 -148 58 -352 193 -453 300 l-60 63 150
-81 c278 -149 618 -181 915 -86 79 25 130 33 138 20 43 -71 324 -122 433 -79
31 12 26 23 -37 83 -138 133 -143 166 -41 260 116 107 160 201 145 310 -11 78
-6 89 69 162 122 118 151 178 228 468 39 147 96 319 127 383 65 137 62 139
-143 85 -158 -41 -258 -93 -362 -188 l-84 -77 -33 95 c-42 118 -118 202 -181
202 -63 0 -316 127 -366 183 -21 23 -29 39 -18 34 11 -5 54 -25 96 -44 600
-273 1151 104 1154 791 l0 94 -101 -107 c-197 -209 -486 -299 -738 -231 l-88
23 64 51 c95 74 147 190 147 330 0 142 -10 158 -45 74z m-172 -1574 c115 -128
161 -505 71 -595 -162 -162 -289 -89 -286 164 3 327 112 544 215 431z m-1030
-33 c101 -52 201 -243 241 -459 71 -385 -574 -317 -668 70 -55 226 234 489
427 389z m1703 -77 c0 -181 -102 -341 -141 -222 l-24 74 -27 -63 c-47 -112
-128 -19 -128 146 0 76 37 97 54 31 12 -47 46 -54 46 -9 0 48 62 61 92 19 26
-35 27 -35 41 2 37 103 87 116 87 22z m-2770 -34 c16 -73 41 -77 58 -10 33
129 140 -19 128 -177 l-6 -83 -43 66 -42 66 -13 -51 c-14 -56 -66 -69 -85 -21
-17 45 -36 36 -61 -30 -50 -132 -103 -48 -68 108 39 175 108 243 132 132z
m1350 -837 c0 -123 205 -183 399 -116 109 38 122 31 46 -24 -212 -151 -633
-30 -516 148 43 65 71 62 71 -8z"/>
<path d="M7910 3299 c-533 -109 -818 -523 -817 -1189 0 -436 84 -696 300 -929
341 -369 1014 -413 1335 -88 l90 92 -13 -78 c-7 -42 -13 -99 -14 -127 l-1 -50
250 -6 c138 -3 270 -1 295 6 l45 11 0 1159 0 1160 -281 0 -281 0 14 -125 14
-125 -82 84 c-183 188 -531 271 -854 205z m590 -485 c333 -171 432 -878 177
-1262 -222 -336 -773 -264 -938 121 -297 691 196 1430 761 1141z"/>
<path d="M9680 3249 c0 -6 211 -496 469 -1090 l469 -1078 -84 -201 c-162 -386
-315 -476 -665 -388 l-49 12 0 -231 c0 -269 -11 -255 217 -268 402 -22 736
151 909 470 43 81 553 1429 994 2630 l57 155 -296 0 -295 0 -256 -730 c-141
-402 -260 -726 -265 -722 -5 5 -146 331 -314 725 l-305 717 -293 6 c-161 3
-293 0 -293 -7z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

+4 -9
View File
@@ -473,11 +473,11 @@ mod tests {
use super::*;
/// Render a QR the way the goblin receive card paints it (dark modules
/// on a white plate with ~5% padding, goblin mark covering the center)
/// and prove the camera scanner pipeline (rqrr) decodes it. Guards both
/// the scan path and the card's scannability by third-party apps.
/// on a white plate with ~5% padding, plain — no center mark) and prove
/// the camera scanner pipeline (rqrr) decodes it. Guards both the scan
/// path and the card's scannability by third-party apps.
#[test]
fn goblin_receive_qr_decodes_with_center_mark() {
fn goblin_receive_qr_decodes() {
let uri = "nostr:npub15l60z00nm4ptmnsj9lcp4husnaltytw85eu05dt7ksdmsje0p98su2f0ch";
let qr = qrcodegen::QrCode::encode_text(uri, qrcodegen::QrCodeEcc::High).unwrap();
let n = qr.size();
@@ -502,11 +502,6 @@ mod tests {
}
}
}
// The goblin mark backing square over the center modules.
let backing = size * 0.19;
let c = dim as f32 / 2.0;
fill(c - backing / 2.0, c - backing / 2.0, backing, backing, 255);
let mut prepared = rqrr::PreparedImage::prepare(img);
let grids = prepared.detect_grids();
assert_eq!(grids.len(), 1, "scanner should find exactly one QR");
+22 -9
View File
@@ -1431,11 +1431,13 @@ impl GoblinWalletView {
.unwrap_or_else(|| ("N".to_string(), String::new()));
let header_tex = self.handle_tex(ui.ctx(), wallet, &header_handle);
ui.horizontal(|ui| {
widgets_logo(ui);
ui.add_space(8.0);
// Owner-sized: +50% over the original 24px mark so the lockup
// carries the same visual weight as the 40-44px right cluster.
widgets_logo_sized(ui, 36.0);
ui.add_space(9.0);
ui.label(
RichText::new("goblin")
.font(FontId::new(18.0, fonts::bold()))
.font(FontId::new(26.0, fonts::bold()))
.color(theme::tokens().text),
);
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
@@ -1663,12 +1665,23 @@ impl GoblinWalletView {
.unwrap_or_else(|| ("N".to_string(), String::new()));
let header_tex = self.handle_tex(ui.ctx(), wallet, &header_handle);
ui.horizontal(|ui| {
// Goblin mark (left), sized to match the right-side controls.
ui.add(
egui::Image::new(egui::include_image!("../../../../img/goblin-logo2.svg"))
.tint(t.text)
.fit_to_exact_size(Vec2::splat(40.0)),
);
// Official GoblinPay lockup (left): the black Apple-Pay-style badge on
// light surfaces, the white wordmark on dark. Owner-specified brand mark.
if t.dark_base {
ui.add(
egui::Image::new(egui::include_image!(
"../../../../img/goblinpay-wordmark.svg"
))
.fit_to_exact_size(Vec2::new(84.0, 33.0)),
);
} else {
ui.add(
egui::Image::new(egui::include_image!(
"../../../../img/goblinpay-badge-black.svg"
))
.fit_to_exact_size(Vec2::new(98.0, 40.0)),
);
}
// Right cluster: scan QR (black, no background) then the profile
// picture at the far right; all three controls about the same size.
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
+1 -14
View File
@@ -402,7 +402,7 @@ pub fn chip(ui: &mut Ui, label: &str, active: bool) -> Response {
pub fn qr_code(ui: &mut Ui, text: &str, size: f32) {
let plate = Color32::WHITE;
let ink = Color32::from_rgb(0x0E, 0x0E, 0x0C);
// High error correction tolerates the center mark covering modules.
// Plain QR (no center mark): High ECC retained for robust scanning.
let Ok(qr) = qrcodegen::QrCode::encode_text(text, qrcodegen::QrCodeEcc::High) else {
return;
};
@@ -429,19 +429,6 @@ pub fn qr_code(ui: &mut Ui, text: &str, size: f32) {
}
}
}
// Goblin mark on a yellow backing square in the center, 19% footprint (larger
// obscures too many modules for a reliable decode). Yellow reads as "light" to
// a scanner like white, so the covered center is recovered by the High ECC.
let t = theme::tokens();
let backing = size * 0.19;
let b_rect = egui::Rect::from_center_size(rect.center(), Vec2::splat(backing));
ui.painter()
.rect_filled(b_rect, CornerRadius::same((backing * 0.18) as u8), t.accent);
let m_rect = egui::Rect::from_center_size(rect.center(), Vec2::splat(backing * 0.72));
egui::Image::new(egui::include_image!("../../../../img/goblin-logo2.svg"))
.tint(t.accent_ink)
.fit_to_exact_size(m_rect.size())
.paint_at(ui, m_rect);
}
/// A filled input well for a text field sitting on a card, so the field