Skip to content

Commit 553e5d1

Browse files
Merge pull request #14 from appdevforall/feat/theming-tokens-dashboard
feat(controller): semantic colour tokens + migrate Dashboard (theming…
2 parents 8307ec3 + ec68f2d commit 553e5d1

6 files changed

Lines changed: 103 additions & 17 deletions

File tree

‎CLAUDE.md‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,34 @@ live-size data behind the reference slice.
184184

185185
---
186186

187+
## Theming (colors) — mandatory for all UI
188+
189+
The app supports light and dark via `DayNight` (toggle in `MainActivity`), but most
190+
screens historically hardcoded dark-tuned hex, so the light theme is broken wherever
191+
that happens. We are migrating to one semantic colour-token system, screen by screen
192+
(refactor-by-feature).
193+
194+
Rules for any new or migrated UI:
195+
196+
1. **No hardcoded colours.** No `#RRGGBB` in layouts and no `Color.parseColor("#…")`
197+
/ `Color.WHITE` etc. in code. Reference a semantic token instead:
198+
`@color/<token>` in XML, `ContextCompat.getColor(ctx, R.color.<token>)` in code.
199+
2. **Every token has a light value in `values/colors.xml` and a dark twin in
200+
`values-night/colors.xml`.** If you add a token, add both.
201+
3. **Use the semantic families**: surfaces (`surface_background`, `surface_card`,
202+
`surface_section`), text (`text_primary`, `text_secondary`, `text_disabled`,
203+
`text_on_accent`), `accent`/`accent_muted`, status
204+
(`status_success/warning/danger/info`), `divider_line`, and data-viz
205+
(`chart_storage/ram/swap/os/maps/wiki/track`). Pick by role, not by look.
206+
4. **Legitimately fixed colours stay fixed:** a QR must be black/white to scan, so
207+
`qr_foreground`/`qr_background` are mode-independent (no `-night` override).
208+
5. **Verify both modes** on a device before merge.
209+
210+
Legacy tokens (`dash_*`, `white`, `black`, `section_*`, `btn_*`) are retired as screens
211+
migrate. Reference migration: the Dashboard (`fragment_dashboard` + `DashboardFragment`).
212+
213+
---
214+
187215
## Tech-debt watch list (controller) — opportunistic targets
188216

189217
Evident debt noticed while building the pilot. Chip away at these **only when

‎controller/app/src/main/java/org/iiab/controller/DashboardFragment.java‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,8 @@ private void updateSystemStats() {
283283
int baseColorSwap = ContextCompat.getColor(requireContext(), R.color.dash_bar_swap);
284284
int baseColorStorage = ContextCompat.getColor(requireContext(), R.color.dash_bar_storage);
285285

286-
int warnColor = Color.parseColor("#FF9800"); // Orange
287-
int dangerColor = Color.parseColor("#F44336"); // Red
286+
int warnColor = ContextCompat.getColor(requireContext(), R.color.status_warning); // Orange
287+
int dangerColor = ContextCompat.getColor(requireContext(), R.color.status_danger); // Red
288288

289289
// RAM Gauge (Warning at 90%, Danger at 95%)
290290
int finalColorRam = memProgress >= 95 ? dangerColor : (memProgress >= 90 ? warnColor : baseColorRam);
@@ -344,9 +344,9 @@ private void updateSystemStats() {
344344
if (batLevel <= 33) {
345345
colorBattery = warnColor; // Orange (1-33%)
346346
} else if (batLevel <= 66) {
347-
colorBattery = Color.parseColor("#4CAF50"); // Green (34-66%)
347+
colorBattery = ContextCompat.getColor(requireContext(), R.color.status_success); // Green (34-66%)
348348
} else {
349-
colorBattery = Color.parseColor("#2196F3"); // Blue (67-100%)
349+
colorBattery = ContextCompat.getColor(requireContext(), R.color.status_info); // Blue (67-100%)
350350
}
351351

352352
// Update the gauge with the newly assigned 4-parameter method

‎controller/app/src/main/java/org/iiab/controller/ResourceGaugeView.java‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import android.animation.ValueAnimator;
1212
import android.content.Context;
1313
import android.graphics.Canvas;
14-
import android.graphics.Color;
1514
import android.graphics.Paint;
1615
import android.graphics.RectF;
1716
import android.graphics.Typeface;
@@ -30,7 +29,7 @@ public class ResourceGaugeView extends View {
3029
private String centerText = "0%";
3130
private String bottomText = "-- / --";
3231

33-
private int currentColor = Color.parseColor("#4CAF50");
32+
private int currentColor;
3433

3534
public ResourceGaugeView(Context context, AttributeSet attrs) {
3635
super(context, attrs);
@@ -40,10 +39,11 @@ public ResourceGaugeView(Context context, AttributeSet attrs) {
4039
private void init(Context context) {
4140
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
4241
rectF = new RectF();
42+
currentColor = androidx.core.content.ContextCompat.getColor(context, R.color.status_success);
4343

4444
bgArcPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
4545
bgArcPaint.setStyle(Paint.Style.STROKE);
46-
bgArcPaint.setColor(Color.parseColor("#333333"));
46+
bgArcPaint.setColor(androidx.core.content.ContextCompat.getColor(context, R.color.chart_track));
4747
bgArcPaint.setStrokeCap(Paint.Cap.ROUND);
4848
bgArcPaint.setPathEffect(null);
4949

@@ -57,16 +57,16 @@ private void init(Context context) {
5757

5858
percentPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
5959
percentPaint.setTextAlign(Paint.Align.CENTER);
60-
percentPaint.setColor(androidx.core.content.ContextCompat.getColor(context, R.color.dash_text_inverted));
60+
percentPaint.setColor(androidx.core.content.ContextCompat.getColor(context, R.color.text_primary));
6161
percentPaint.setFakeBoldText(true);
6262

6363
valuePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
6464
valuePaint.setTextAlign(Paint.Align.CENTER);
65-
valuePaint.setColor(Color.parseColor("#AAAAAA"));
65+
valuePaint.setColor(androidx.core.content.ContextCompat.getColor(context, R.color.text_secondary));
6666

6767
titlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
6868
titlePaint.setTextAlign(Paint.Align.CENTER);
69-
titlePaint.setColor(Color.parseColor("#CCCCCC"));
69+
titlePaint.setColor(androidx.core.content.ContextCompat.getColor(context, R.color.text_secondary));
7070
titlePaint.setFakeBoldText(true);
7171

7272
// LOAD AND APPLY ORBITRON

‎controller/app/src/main/res/layout/fragment_dashboard.xml‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,14 @@
117117
android:layout_width="16dp"
118118
android:layout_height="16dp"
119119
android:src="@drawable/outline_android_wifi_3_bar_24"
120-
app:tint="#888888"
120+
app:tint="@color/text_secondary"
121121
android:layout_centerVertical="true" />
122122

123123
<TextView
124124
android:layout_width="wrap_content"
125125
android:layout_height="wrap_content"
126126
android:text="Wi-Fi"
127-
android:textColor="#888888"
127+
android:textColor="@color/text_secondary"
128128
android:textSize="13sp"
129129
android:layout_toEndOf="@id/ic_wifi"
130130
android:layout_marginStart="6dp"
@@ -154,14 +154,14 @@
154154
android:layout_width="16dp"
155155
android:layout_height="16dp"
156156
android:src="@drawable/outline_connect_without_contact_24"
157-
app:tint="#888888"
157+
app:tint="@color/text_secondary"
158158
android:layout_centerVertical="true" />
159159

160160
<TextView
161161
android:layout_width="wrap_content"
162162
android:layout_height="wrap_content"
163163
android:text="Hotspot"
164-
android:textColor="#888888"
164+
android:textColor="@color/text_secondary"
165165
android:textSize="13sp"
166166
android:layout_toEndOf="@id/ic_hotspot"
167167
android:layout_marginStart="6dp"
@@ -193,13 +193,13 @@
193193
android:layout_width="16dp"
194194
android:layout_height="16dp"
195195
android:src="@drawable/outline_clock_arrow_up_24"
196-
app:tint="#888888" />
196+
app:tint="@color/text_secondary" />
197197

198198
<TextView
199199
android:layout_width="wrap_content"
200200
android:layout_height="wrap_content"
201201
android:text="Uptime:"
202-
android:textColor="#888888"
202+
android:textColor="@color/text_secondary"
203203
android:textSize="13sp"
204204
android:layout_marginStart="6dp"
205205
android:layout_marginEnd="8dp" />
@@ -339,7 +339,7 @@
339339
android:layout_height="wrap_content"
340340
android:text="@string/dash_offline"
341341
android:background="@drawable/rounded_button"
342-
android:backgroundTint="#555555"
342+
android:backgroundTint="@color/surface_section"
343343
android:textColor="@color/dash_text_primary"
344344
android:fontFamily="@font/orbitron"
345345
android:textSize="11sp"

‎controller/app/src/main/res/values-night/colors.xml‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,27 @@
1818

1919
<color name="divider_color">#444444</color>
2020
<color name="dash_bar_bg">#333333</color>
21+
22+
<!-- Semantic theming tokens (dark) — twins of values/colors.xml -->
23+
<color name="surface_background">#121212</color>
24+
<color name="surface_card">#1E1E1E</color>
25+
<color name="surface_section">#2A2A2A</color>
26+
<color name="text_primary">#FAFAFA</color>
27+
<color name="text_secondary">#BDBDBD</color>
28+
<color name="text_disabled">#7A7A7A</color>
29+
<color name="text_on_accent">#FFFFFF</color>
30+
<color name="accent">#4CAF50</color>
31+
<color name="accent_muted">#2E5A30</color>
32+
<color name="status_success">#66BB6A</color>
33+
<color name="status_warning">#FFB300</color>
34+
<color name="status_danger">#EF5350</color>
35+
<color name="status_info">#42A5F5</color>
36+
<color name="divider_line">#333333</color>
37+
<color name="chart_storage">#4DB6AC</color>
38+
<color name="chart_ram">#FFB300</color>
39+
<color name="chart_swap">#7986CB</color>
40+
<color name="chart_os">#26C6DA</color>
41+
<color name="chart_maps">#FF9800</color>
42+
<color name="chart_wiki">#66BB6A</color>
43+
<color name="chart_track">#333333</color>
2144
</resources>

‎controller/app/src/main/res/values/colors.xml‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,41 @@
4444

4545
<color name="footer_text_color">#5F6368</color>
4646

47+
<!-- ============================================================= -->
48+
<!-- Semantic theming tokens (light). Each has a values-night twin. -->
49+
<!-- Rule: reference these, never a hardcoded hex. See CLAUDE.md. -->
50+
<!-- ============================================================= -->
51+
<!-- Surfaces -->
52+
<color name="surface_background">#F4F5F7</color>
53+
<color name="surface_card">#FFFFFF</color>
54+
<color name="surface_section">#E8EAED</color>
55+
<!-- Text -->
56+
<color name="text_primary">#202124</color>
57+
<color name="text_secondary">#5F6368</color>
58+
<color name="text_disabled">#9AA0A6</color>
59+
<color name="text_on_accent">#FFFFFF</color>
60+
<!-- Brand / accent -->
61+
<color name="accent">#2E7D32</color>
62+
<color name="accent_muted">#A5D6A7</color>
63+
<!-- Status -->
64+
<color name="status_success">#2E7D32</color>
65+
<color name="status_warning">#E65100</color>
66+
<color name="status_danger">#C62828</color>
67+
<color name="status_info">#1565C0</color>
68+
<!-- Borders / dividers -->
69+
<color name="divider_line">#E0E0E0</color>
70+
<!-- Data-viz (categorical) -->
71+
<color name="chart_storage">#00897B</color>
72+
<color name="chart_ram">#FF8F00</color>
73+
<color name="chart_swap">#5C6BC0</color>
74+
<color name="chart_os">#00838F</color>
75+
<color name="chart_maps">#EF6C00</color>
76+
<color name="chart_wiki">#2E7D32</color>
77+
<color name="chart_track">#C4C7CC</color>
78+
<!-- Fixed (NOT theme-dependent: a QR must stay black/white to scan,
79+
so these intentionally have no values-night override). -->
80+
<color name="qr_foreground">#000000</color>
81+
<color name="qr_background">#FFFFFF</color>
4782
</resources>
4883

4984

0 commit comments

Comments
 (0)