Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
33 changes: 17 additions & 16 deletions controller/app/src/main/java/org/iiab/controller/SyncFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import java.util.List;

import android.widget.RadioButton;
import androidx.core.content.ContextCompat;

public class SyncFragment extends Fragment {

Expand Down Expand Up @@ -318,14 +319,14 @@ private void startShareDaemon(File rootfsDir) {
qrDisplaySection.setVisibility(View.VISIBLE);
qrCardContainer.setVisibility(View.VISIBLE);
imgQrCode.setAlpha(1f);
cardShareSystem.setBackgroundTintList(android.content.res.ColorStateList.valueOf(android.graphics.Color.parseColor("#173317")));
cardShareSystem.setBackgroundTintList(android.content.res.ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.surface_active_success)));

rgNetworkSelector.setVisibility((wifiIp != null && hotspotIp != null) ? View.VISIBLE : View.GONE);
showingWifi = (wifiIp != null);
updateQrDisplayRsync();

btnStartServer.setText(getString(R.string.sync_btn_stop_server));
btnStartServer.setBackgroundTintList(android.content.res.ColorStateList.valueOf(android.graphics.Color.parseColor("#F44336"))); // Red
btnStartServer.setBackgroundTintList(android.content.res.ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.status_danger))); // Red
btnShareApp.setVisibility(View.GONE);
} else {
Toast.makeText(getContext(), getString(R.string.sync_error_daemon_failed), Toast.LENGTH_SHORT).show();
Expand All @@ -341,7 +342,7 @@ private void updateQrDisplayRsync() {

String baseText = showingWifi ? getString(R.string.sync_share_status_wifi) : getString(R.string.sync_share_status_hotspot);
txtShareStatus.setText(baseText);
txtShareStatus.setTextColor(android.graphics.Color.parseColor("#AAAAAA"));
txtShareStatus.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_secondary));
}

private void stopShareDaemon() {
Expand All @@ -352,13 +353,13 @@ private void stopShareDaemon() {

qrDisplaySection.setVisibility(View.GONE);
btnStartServer.setText(getString(R.string.sync_btn_start_server));
cardShareSystem.setBackgroundTintList(android.content.res.ColorStateList.valueOf(android.graphics.Color.parseColor("#222222")));
cardShareSystem.setBackgroundTintList(android.content.res.ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.surface_card)));

btnStartServer.setText(getString(R.string.sync_btn_start_server));
btnStartServer.setBackgroundTintList(android.content.res.ColorStateList.valueOf(android.graphics.Color.parseColor("#008000"))); // Green
btnStartServer.setBackgroundTintList(android.content.res.ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.status_success))); // Green
btnShareApp.setVisibility(View.VISIBLE);
txtShareStatus.setText(getString(R.string.sync_share_status_off));
txtShareStatus.setTextColor(android.graphics.Color.parseColor("#FF9800")); // Orange
txtShareStatus.setTextColor(ContextCompat.getColor(requireContext(), R.color.status_warning)); // Orange
}

// --- APK SERVER METHODS ---
Expand All @@ -375,14 +376,14 @@ private void startApkServer() {
qrCardContainer.setVisibility(View.VISIBLE);
updateCardOrder(true);
imgQrCode.setAlpha(1f);
cardShareApk.setBackgroundTintList(android.content.res.ColorStateList.valueOf(android.graphics.Color.parseColor("#17263A")));
cardShareApk.setBackgroundTintList(android.content.res.ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.surface_active_info)));

rgNetworkSelector.setVisibility((wifiIp != null && hotspotIp != null) ? View.VISIBLE : View.GONE);
showingWifi = (wifiIp != null);
updateQrDisplayApk();

btnShareApp.setText(getString(R.string.sync_btn_stop_app));
btnShareApp.setBackgroundTintList(android.content.res.ColorStateList.valueOf(android.graphics.Color.parseColor("#F44336"))); // Red
btnShareApp.setBackgroundTintList(android.content.res.ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.status_danger))); // Red
btnStartServer.setVisibility(View.GONE);

} catch (Exception e) {
Expand All @@ -400,7 +401,7 @@ private void updateQrDisplayApk() {

String baseText = showingWifi ? getString(R.string.sync_app_status_wifi) : getString(R.string.sync_app_status_hotspot);
txtShareStatus.setText(baseText);
txtShareStatus.setTextColor(android.graphics.Color.parseColor("#AAAAAA"));
txtShareStatus.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_secondary));
}

private void stopApkServer() {
Expand All @@ -413,13 +414,13 @@ private void stopApkServer() {

qrDisplaySection.setVisibility(View.GONE);
btnShareApp.setText(getString(R.string.sync_btn_share_app));
cardShareApk.setBackgroundTintList(android.content.res.ColorStateList.valueOf(android.graphics.Color.parseColor("#222222")));
cardShareApk.setBackgroundTintList(android.content.res.ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.surface_card)));

btnShareApp.setText(getString(R.string.sync_btn_share_app));
btnShareApp.setBackgroundTintList(android.content.res.ColorStateList.valueOf(android.graphics.Color.parseColor("#0055A4"))); // Blue
btnShareApp.setBackgroundTintList(android.content.res.ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.status_info))); // Blue
btnStartServer.setVisibility(View.VISIBLE);
txtShareStatus.setText(getString(R.string.sync_share_status_off));
txtShareStatus.setTextColor(android.graphics.Color.parseColor("#FF9800")); // Orange
txtShareStatus.setTextColor(ContextCompat.getColor(requireContext(), R.color.status_warning)); // Orange
}

// --- CLIENT (RECEIVER) METHODS ---
Expand Down Expand Up @@ -776,16 +777,16 @@ private void showArchCompatibilitySuccess(Runnable onComplete) {
}

if (txtGuestArchLabel != null) {
txtGuestArchLabel.setBackgroundTintList(android.content.res.ColorStateList.valueOf(android.graphics.Color.parseColor("#00E676")));
txtGuestArchLabel.setTextColor(android.graphics.Color.BLACK);
txtGuestArchLabel.setBackgroundTintList(android.content.res.ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.status_success)));
txtGuestArchLabel.setTextColor(ContextCompat.getColor(requireContext(), R.color.text_on_warning));
}

Snackbar.make(requireView(), getString(R.string.sync_msg_arch_compatible), Snackbar.LENGTH_SHORT).show();

new Handler(Looper.getMainLooper()).postDelayed(() -> {
if (txtGuestArchLabel != null) {
txtGuestArchLabel.setBackgroundTintList(android.content.res.ColorStateList.valueOf(android.graphics.Color.parseColor("#1A1A1A")));
txtGuestArchLabel.setTextColor(android.graphics.Color.parseColor("#4CAF50"));
txtGuestArchLabel.setBackgroundTintList(android.content.res.ColorStateList.valueOf(ContextCompat.getColor(requireContext(), R.color.surface_section)));
txtGuestArchLabel.setTextColor(ContextCompat.getColor(requireContext(), R.color.status_success));
}
onComplete.run();
}, 1500);
Expand Down
2 changes: 1 addition & 1 deletion controller/app/src/main/res/drawable/radio_selector_bg.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<item android:state_checked="true">
<shape android:shape="rectangle">
<corners android:radius="8dp" />
<solid android:color="#444444" /> </shape>
<solid android:color="@color/toggle_selected" /> </shape>
</item>
<item>
<shape android:shape="rectangle">
Expand Down
14 changes: 7 additions & 7 deletions controller/app/src/main/res/layout/activity_qr.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#DD000000"
android:background="@color/overlay_scrim"
android:padding="24dp">

<LinearLayout
Expand All @@ -18,7 +18,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/rounded_button"
android:backgroundTint="#1A1A1A"
android:backgroundTint="@color/surface_card"
android:elevation="8dp"
android:padding="16dp">

Expand All @@ -35,7 +35,7 @@
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/btn_flip_qr"
android:text="@string/qr_title_wifi"
android:textColor="#FFFFFF"
android:textColor="@color/text_primary"
android:textSize="22sp"
android:textStyle="bold" />

Expand All @@ -48,7 +48,7 @@
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@android:drawable/ic_popup_sync"
android:contentDescription="@string/qr_flip_network"
android:tint="#FFFFFF"
android:tint="@color/text_primary"
android:scaleType="fitCenter"
android:padding="8dp"
android:visibility="gone" />
Expand All @@ -59,7 +59,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="http://---"
android:textColor="#AAAAAA"
android:textColor="@color/text_secondary"
android:textSize="16sp"
android:layout_marginBottom="16dp" />

Expand All @@ -69,7 +69,7 @@
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:background="#FFFFFF"
android:background="@color/qr_background"
android:padding="16dp" />

</LinearLayout>
Expand All @@ -82,6 +82,6 @@
android:layout_marginTop="24dp"
android:text="@string/qr_btn_close"
android:backgroundTint="@color/btn_danger"
android:textColor="#FFFFFF" />
android:textColor="@color/text_on_accent" />

</LinearLayout>
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
Loading
Loading