Skip to content
28 changes: 28 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,34 @@ live-size data behind the reference slice.

---

## Theming (colors) — mandatory for all UI

The app supports light and dark via `DayNight` (toggle in `MainActivity`), but most
screens historically hardcoded dark-tuned hex, so the light theme is broken wherever
that happens. We are migrating to one semantic colour-token system, screen by screen
(refactor-by-feature).

Rules for any new or migrated UI:

1. **No hardcoded colours.** No `#RRGGBB` in layouts and no `Color.parseColor("#…")`
/ `Color.WHITE` etc. in code. Reference a semantic token instead:
`@color/<token>` in XML, `ContextCompat.getColor(ctx, R.color.<token>)` in code.
2. **Every token has a light value in `values/colors.xml` and a dark twin in
`values-night/colors.xml`.** If you add a token, add both.
3. **Use the semantic families**: surfaces (`surface_background`, `surface_card`,
`surface_section`), text (`text_primary`, `text_secondary`, `text_disabled`,
`text_on_accent`), `accent`/`accent_muted`, status
(`status_success/warning/danger/info`), `divider_line`, and data-viz
(`chart_storage/ram/swap/os/maps/wiki/track`). Pick by role, not by look.
4. **Legitimately fixed colours stay fixed:** a QR must be black/white to scan, so
`qr_foreground`/`qr_background` are mode-independent (no `-night` override).
5. **Verify both modes** on a device before merge.

Legacy tokens (`dash_*`, `white`, `black`, `section_*`, `btn_*`) are retired as screens
migrate. Reference migration: the Dashboard (`fragment_dashboard` + `DashboardFragment`).

---

## Tech-debt watch list (controller) — opportunistic targets

Evident debt noticed while building the pilot. Chip away at these **only when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,8 @@ private void updateSystemStats() {
int baseColorSwap = ContextCompat.getColor(requireContext(), R.color.dash_bar_swap);
int baseColorStorage = ContextCompat.getColor(requireContext(), R.color.dash_bar_storage);

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

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

// Update the gauge with the newly assigned 4-parameter method
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
Expand All @@ -30,7 +29,7 @@ public class ResourceGaugeView extends View {
private String centerText = "0%";
private String bottomText = "-- / --";

private int currentColor = Color.parseColor("#4CAF50");
private int currentColor;

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

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

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

percentPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
percentPaint.setTextAlign(Paint.Align.CENTER);
percentPaint.setColor(androidx.core.content.ContextCompat.getColor(context, R.color.dash_text_inverted));
percentPaint.setColor(androidx.core.content.ContextCompat.getColor(context, R.color.text_primary));
percentPaint.setFakeBoldText(true);

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

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

// LOAD AND APPLY ORBITRON
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,13 +267,13 @@ public void updateUIColorsAndVisibility() {
button_browse_content.setEnabled(true);
button_browse_content.setBackgroundTintList(ContextCompat.getColorStateList(requireContext(), R.color.btn_explore_disabled));
button_browse_content.setAlpha(1.0f);
button_browse_content.setTextColor(Color.WHITE);
button_browse_content.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_on_accent));
} else if (mainActivity.isNegotiating) {
button_browse_content.setEnabled(true);
button_browse_content.setTextColor(Color.WHITE);
button_browse_content.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_on_accent));
} else {
button_browse_content.setEnabled(true);
button_browse_content.setTextColor(Color.WHITE);
button_browse_content.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_on_accent));
button_browse_content.setBackgroundTintList(ContextCompat.getColorStateList(requireContext(), R.color.btn_explore_ready));
button_browse_content.setAlpha(1.0f);
}
Expand Down Expand Up @@ -467,7 +467,7 @@ public void highlightServerButton() {
// We use ofArgb for a perfect color transition
android.animation.ValueAnimator colorAnim = android.animation.ValueAnimator.ofArgb(
Color.TRANSPARENT,
Color.parseColor("#00E5FF") // Color Cyan
ContextCompat.getColor(requireContext(), R.color.status_info) // Color Cyan
);
colorAnim.setDuration(350);
colorAnim.setRepeatCount(5);
Expand Down
14 changes: 7 additions & 7 deletions controller/app/src/main/res/layout/fragment_dashboard.xml
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,14 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/outline_android_wifi_3_bar_24"
app:tint="#888888"
app:tint="@color/text_secondary"
android:layout_centerVertical="true" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Wi-Fi"
android:textColor="#888888"
android:textColor="@color/text_secondary"
android:textSize="13sp"
android:layout_toEndOf="@id/ic_wifi"
android:layout_marginStart="6dp"
Expand Down Expand Up @@ -154,14 +154,14 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/outline_connect_without_contact_24"
app:tint="#888888"
app:tint="@color/text_secondary"
android:layout_centerVertical="true" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hotspot"
android:textColor="#888888"
android:textColor="@color/text_secondary"
android:textSize="13sp"
android:layout_toEndOf="@id/ic_hotspot"
android:layout_marginStart="6dp"
Expand Down Expand Up @@ -193,13 +193,13 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/outline_clock_arrow_up_24"
app:tint="#888888" />
app:tint="@color/text_secondary" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Uptime:"
android:textColor="#888888"
android:textColor="@color/text_secondary"
android:textSize="13sp"
android:layout_marginStart="6dp"
android:layout_marginEnd="8dp" />
Expand Down Expand Up @@ -339,7 +339,7 @@
android:layout_height="wrap_content"
android:text="@string/dash_offline"
android:background="@drawable/rounded_button"
android:backgroundTint="#555555"
android:backgroundTint="@color/surface_section"
android:textColor="@color/dash_text_primary"
android:fontFamily="@font/orbitron"
android:textSize="11sp"
Expand Down
28 changes: 14 additions & 14 deletions controller/app/src/main/res/layout/fragment_usage.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
android:text="@string/control_enable"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#FFFFFF"
android:textColor="@color/text_on_accent"
android:background="@drawable/rounded_button"
android:backgroundTint="@color/btn_vpn_off"
android:textAllCaps="false"
Expand Down Expand Up @@ -138,7 +138,7 @@
android:text="@string/browse_content"
android:textSize="21sp"
android:textStyle="bold"
android:textColor="#FFFFFF"
android:textColor="@color/text_on_accent"
android:background="@drawable/rounded_button"
android:backgroundTint="@color/btn_explore_disabled"
android:textAllCaps="false"
Expand Down Expand Up @@ -179,8 +179,8 @@
android:text="@string/apps"
android:layout_marginBottom="12dp"
android:background="@drawable/rounded_button"
android:backgroundTint="#673AB7"
android:textColor="#FFFFFF"
android:backgroundTint="@color/accent_secondary"
android:textColor="@color/text_on_accent"
android:textAllCaps="false" />

<TextView
Expand Down Expand Up @@ -227,7 +227,7 @@
android:text="@string/maintenance_warning_msg"
android:textSize="11sp"
android:textStyle="italic"
android:textColor="#FF9800"
android:textColor="@color/status_warning"
android:layout_marginBottom="8dp"
android:visibility="gone" />

Expand All @@ -238,8 +238,8 @@
android:text="@string/save"
android:layout_marginTop="8dp"
android:background="@drawable/rounded_button"
android:backgroundTint="#555555"
android:textColor="#FFFFFF"
android:backgroundTint="@color/btn_neutral"
android:textColor="@color/text_on_accent"
android:textAllCaps="false" />

<TextView
Expand Down Expand Up @@ -396,7 +396,7 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="12dp"
android:layout_marginBottom="8dp"
android:background="#00000000"
android:background="@android:color/transparent"
android:padding="3dp"
android:orientation="horizontal">

Expand All @@ -407,13 +407,13 @@
android:text="Launch Server"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#FFFFFF"
android:textColor="@color/text_on_accent"
android:background="@drawable/rounded_button"
android:backgroundTint="@color/btn_success"
android:textAllCaps="false"
app:progressButtonHeight="6dp"
app:progressButtonDuration="@integer/server_cool_off_duration_ms"
app:progressButtonColor="#FF9800" />
app:progressButtonColor="@color/status_warning" />
</LinearLayout>

<View
Expand Down Expand Up @@ -463,8 +463,8 @@
android:id="@+id/connection_log"
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="#000000"
android:textColor="#00FF00"
android:background="@color/terminal_background"
android:textColor="@color/terminal_text"
android:padding="8dp"
android:visibility="gone"
android:scrollbars="vertical"
Expand Down Expand Up @@ -502,7 +502,7 @@
android:textSize="12sp"
android:background="@drawable/rounded_button"
android:backgroundTint="@color/btn_danger"
android:textColor="#FFFFFF"
android:textColor="@color/text_on_accent"
android:textAllCaps="false"
android:layout_marginEnd="4dp" />

Expand All @@ -515,7 +515,7 @@
android:textSize="12sp"
android:background="@drawable/rounded_button"
android:backgroundTint="@color/btn_success"
android:textColor="#FFFFFF"
android:textColor="@color/text_on_accent"
android:textAllCaps="false"
android:layout_marginStart="4dp" />
</LinearLayout>
Expand Down
36 changes: 36 additions & 0 deletions controller/app/src/main/res/values-night/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,40 @@

<color name="divider_color">#444444</color>
<color name="dash_bar_bg">#333333</color>

<!-- Semantic theming tokens (dark) — twins of values/colors.xml -->
<color name="surface_background">#121212</color>
<color name="surface_card">#1E1E1E</color>
<color name="surface_section">#2A2A2A</color>
<color name="text_primary">#FAFAFA</color>
<color name="text_secondary">#BDBDBD</color>
<color name="text_disabled">#7A7A7A</color>
<color name="text_on_accent">#FFFFFF</color>
<color name="accent">#4CAF50</color>
<color name="accent_muted">#2E5A30</color>
<color name="status_success">#66BB6A</color>
<color name="status_warning">#FFB300</color>
<color name="status_danger">#EF5350</color>
<color name="status_info">#42A5F5</color>
<color name="divider_line">#333333</color>
<color name="chart_storage">#4DB6AC</color>
<color name="chart_ram">#FFB300</color>
<color name="chart_swap">#7986CB</color>
<color name="chart_os">#26C6DA</color>
<color name="chart_maps">#FF9800</color>
<color name="chart_wiki">#66BB6A</color>
<color name="chart_track">#333333</color>
<!-- Round 2 (Usage/Install/Share migration) — twins of values/colors.xml -->
<color name="surface_active_success">#173317</color>
<color name="surface_active_info">#17263A</color>
<color name="surface_active_danger">#5C1A1A</color>
<color name="surface_active_warning">#3A2A0E</color>
<color name="status_pending">#FFCA28</color>
<color name="accent_secondary">#B39DDB</color>
<color name="btn_neutral">#424242</color>
<color name="text_on_warning">#212121</color>
<color name="terminal_background">#0D0D0D</color>
<color name="terminal_text">#33FF33</color>
<color name="overlay_scrim">#CC000000</color>
<color name="toggle_selected">#3A3A3A</color>
</resources>
Loading
Loading