diff --git a/controller/app/src/main/java/org/appdevforall/k2go/kolibri/presentation/KolibriBrowseFragment.java b/controller/app/src/main/java/org/appdevforall/k2go/kolibri/presentation/KolibriBrowseFragment.java
index d3e1b0640..12c6532e1 100644
--- a/controller/app/src/main/java/org/appdevforall/k2go/kolibri/presentation/KolibriBrowseFragment.java
+++ b/controller/app/src/main/java/org/appdevforall/k2go/kolibri/presentation/KolibriBrowseFragment.java
@@ -37,6 +37,7 @@
import org.appdevforall.k2go.R;
import org.appdevforall.k2go.applang.data.ContentLanguage;
import org.appdevforall.k2go.kolibri.domain.Channel;
+import org.appdevforall.k2go.redesign.K2GoFilterChip;
import org.appdevforall.k2go.redesign.SetupLibraryActivity;
import org.appdevforall.k2go.redesign.ZimLanguageDialog;
import org.appdevforall.k2go.util.ByteFormatter;
@@ -80,8 +81,8 @@ public final class KolibriBrowseFragment extends Fragment {
private TextView storageLabel;
private ProgressBar storageBar;
private LinearLayout chips;
- private TextView sortSize;
- private TextView sortName;
+ private com.google.android.material.chip.Chip sortSize;
+ private com.google.android.material.chip.Chip sortName;
private LinearLayout list;
private Button review;
@@ -281,11 +282,10 @@ private void updateSortControls() {
pill(sortName, s.isName());
}
- /** The one pill style in the app: teal filled when on, hairline outline when off. */
- private void pill(TextView t, boolean on) {
- t.setBackgroundResource(on ? R.drawable.k2go_chip_bg : R.drawable.k2go_pill_bg);
- t.setTextColor(ContextCompat.getColor(requireContext(),
- on ? android.R.color.white : R.color.k2go_ink));
+ // K2GO-385 (PR3): the shared filter chip (8dp, 32dp, check when active) -- the sort toggles now match
+ // the ZIM sort chips and the category/Books filters; the label still carries the sort direction.
+ private void pill(com.google.android.material.chip.Chip t, boolean on) {
+ K2GoFilterChip.style(t, on);
}
/**
@@ -456,25 +456,19 @@ private void buildChips(KolibriCatalogUiState s) {
}
private View chip(String label, final String group) {
- TextView t = new TextView(requireContext());
- t.setText(label);
- t.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodySmall);
- t.setGravity(Gravity.CENTER);
- t.setMinHeight(px(48)); // tap target, even though the pill looks smaller
- t.setPadding(px(14), px(8), px(14), px(8));
- pill(t, group.equals(groupFilter));
-
+ // K2GO-385 (PR3): category chips use the shared filter chip too.
+ com.google.android.material.chip.Chip c = K2GoFilterChip.create(requireContext(), label,
+ group.equals(groupFilter), x -> {
+ if (!group.equals(groupFilter)) {
+ groupFilter = group;
+ render(vm.state().getValue());
+ }
+ });
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
lp.rightMargin = px(8);
- t.setLayoutParams(lp);
- t.setOnClickListener(x -> {
- if (!group.equals(groupFilter)) {
- groupFilter = group;
- render(vm.state().getValue());
- }
- });
- return t;
+ c.setLayoutParams(lp);
+ return c;
}
private void updateStorage() {
diff --git a/controller/app/src/main/java/org/appdevforall/k2go/redesign/BooksLandingFragment.java b/controller/app/src/main/java/org/appdevforall/k2go/redesign/BooksLandingFragment.java
index 8bc56283e..c884fef7d 100644
--- a/controller/app/src/main/java/org/appdevforall/k2go/redesign/BooksLandingFragment.java
+++ b/controller/app/src/main/java/org/appdevforall/k2go/redesign/BooksLandingFragment.java
@@ -37,6 +37,8 @@
import androidx.fragment.app.Fragment;
import org.appdevforall.k2go.PortalActivity;
+import com.google.android.material.chip.Chip;
+
import org.appdevforall.k2go.R;
import org.appdevforall.k2go.config.BoxEndpoints;
import org.json.JSONArray;
@@ -200,22 +202,10 @@ private void openLanguagePicker() {
() -> { lang = ""; updateLangPill(); loadBooks(); });
}
- private TextView chip(String text, boolean on, Runnable onClick) {
- TextView t = new TextView(requireContext());
- t.setText(text);
- t.setPadding(px(14), px(8), px(14), px(8));
- t.setBackgroundResource(on ? R.drawable.k2go_chip_bg : R.drawable.k2go_pill_bg);
- // ADFA-5248: apply the text appearance FIRST, then the color. TextAppearance_Material3_*
- // carries its own colorOnSurface, so setting the color before it silently overwrote the chip
- // color (the real bug the ticket reported: onSurface flips with the theme, giving dark-on-
- // dark-teal in light mode and light-on-aqua in dark mode — never legible on the teal fill).
- // With the order fixed, k2go_on_teal sticks: it flips against the fill (light text on the
- // dark-teal light-mode fill, dark text on the light-aqua dark-mode fill).
- t.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodySmall);
- t.setTextColor(ContextCompat.getColor(requireContext(), on ? R.color.k2go_on_teal : R.color.k2go_ink));
- t.setClickable(true);
- t.setOnClickListener(v -> onClick.run());
- return t;
+ // K2GO-385 (PR3): the shared filter chip (8dp corner, 32dp, check when selected). Replaces the
+ // per-screen k2go_chip_bg/k2go_pill_bg drawable pair that had drifted from the other filter surfaces.
+ private Chip chip(String text, boolean on, Runnable onClick) {
+ return K2GoFilterChip.create(requireContext(), text, on, v -> onClick.run());
}
private void loadLibrary() {
diff --git a/controller/app/src/main/java/org/appdevforall/k2go/redesign/CloneFragment.java b/controller/app/src/main/java/org/appdevforall/k2go/redesign/CloneFragment.java
index 6b4f94e0e..dbdc14ae6 100644
--- a/controller/app/src/main/java/org/appdevforall/k2go/redesign/CloneFragment.java
+++ b/controller/app/src/main/java/org/appdevforall/k2go/redesign/CloneFragment.java
@@ -581,8 +581,8 @@ private void render() {
updateBackGuard(); // ADFA-5151: keep the Back confinement in step with side + transfer state
if (showcode != null) { showcode.setVisibility(View.GONE); codeblock.setVisibility(View.GONE); }
if (stepTitle != null) { stepTitle.setVisibility(View.GONE); shareWifi.setVisibility(View.GONE); }
- paintTab(tabSend, side == Side.SEND);
- paintTab(tabReceive, side == Side.RECEIVE);
+ SegmentedTabs.paint(tabSend, side == Side.SEND);
+ SegmentedTabs.paint(tabReceive, side == Side.RECEIVE);
if (atFork) {
cloneHdr.setVisibility(View.VISIBLE);
@@ -638,8 +638,8 @@ private void render() {
// ADFA-5154: Send is two pages. Common chrome, then the page.
actionFooter.setVisibility(View.GONE); // ADFA-5154: default hidden; only Copy's states re-show it
netRow.setVisibility(View.VISIBLE);
- paintTab(tabHotspot, mode == Mode.HOTSPOT);
- paintTab(tabWifi, mode == Mode.WIFI);
+ SegmentedTabs.paint(tabHotspot, mode == Mode.HOTSPOT);
+ SegmentedTabs.paint(tabWifi, mode == Mode.WIFI);
steps.setVisibility(View.VISIBLE);
buildSteps();
advance.setVisibility(View.VISIBLE);
@@ -1569,11 +1569,6 @@ private View arrow() {
return a;
}
- private void paintTab(TextView t, boolean on) {
- t.setBackgroundResource(on ? R.drawable.k2go_primary_bg : 0);
- t.setTextColor(ContextCompat.getColor(requireContext(), on ? R.color.k2go_on_teal : R.color.k2go_muted));
- }
-
private void styleAdvance(boolean filled) {
// ADFA-5346: shape/size come from the style; only toggle the fill + label emphasis by state.
K2GoButtons.setFilledEmphasis(advance, filled);
diff --git a/controller/app/src/main/java/org/appdevforall/k2go/redesign/ConnectFragment.java b/controller/app/src/main/java/org/appdevforall/k2go/redesign/ConnectFragment.java
index d2f6a3e33..c377d11d2 100644
--- a/controller/app/src/main/java/org/appdevforall/k2go/redesign/ConnectFragment.java
+++ b/controller/app/src/main/java/org/appdevforall/k2go/redesign/ConnectFragment.java
@@ -155,8 +155,8 @@ public void onDestroyView() {
private void render() {
if (!isAdded() || secSingle == null) return;
- paintTab(tabHotspot, mode == Mode.HOTSPOT);
- paintTab(tabWifi, mode == Mode.WIFI);
+ SegmentedTabs.paint(tabHotspot, mode == Mode.HOTSPOT);
+ SegmentedTabs.paint(tabWifi, mode == Mode.WIFI);
finish.setVisibility(View.GONE);
connFooter.setVisibility(View.VISIBLE); // default; the no-system state hides it
advance.setVisibility(View.GONE);
@@ -358,11 +358,6 @@ private View arrow() {
return a;
}
- private void paintTab(TextView t, boolean on) {
- t.setBackgroundResource(on ? R.drawable.k2go_primary_bg : 0);
- t.setTextColor(ContextCompat.getColor(requireContext(), on ? R.color.k2go_on_teal : R.color.k2go_muted));
- }
-
private void styleAdvance(boolean filled) {
// ADFA-5346: shape/size from the style; only toggle the fill + label emphasis by state.
K2GoButtons.setFilledEmphasis(advance, filled);
diff --git a/controller/app/src/main/java/org/appdevforall/k2go/redesign/FqrController.java b/controller/app/src/main/java/org/appdevforall/k2go/redesign/FqrController.java
index 42d8c622e..ab42de623 100644
--- a/controller/app/src/main/java/org/appdevforall/k2go/redesign/FqrController.java
+++ b/controller/app/src/main/java/org/appdevforall/k2go/redesign/FqrController.java
@@ -443,13 +443,15 @@ private void showOverlay(String name, long sizeBytes) {
// ADFA-4896: Stop/Retry beside Cancel. The label follows the reported state; the tap fires the
// matching verb and the poll (onPaused/onProgress) is the source of truth.
overlayStopped = false;
- overlayStop = new MaterialButton(themed, null,
- com.google.android.material.R.attr.materialButtonOutlinedStyle);
+ // K2GO-385 (PR3): the download controls use the app button system (K2Go outlined stadium) via the
+ // shared overlay, not a bare Material3 outlined button. FQR's overlay is a themed (day/night)
+ // surface, so the K2Go outlined style's theme teal is right here -- not the fixed boot tokens.
+ ContextThemeWrapper btnCtx = new ContextThemeWrapper(themed, R.style.ThemeOverlay_K2Go_Button_Outlined);
+ overlayStop = new MaterialButton(btnCtx, null);
overlayStop.setText(R.string.k2go_clone_stop_confirm);
overlayStop.setOnClickListener(v -> toggleStop());
row.addView(overlayStop);
- MaterialButton cancel = new MaterialButton(themed, null,
- com.google.android.material.R.attr.materialButtonOutlinedStyle);
+ MaterialButton cancel = new MaterialButton(btnCtx, null);
cancel.setText(R.string.k2go_cancel);
cancel.setOnClickListener(v -> { client.cancel(); hideOverlay(); });
row.addView(cancel);
diff --git a/controller/app/src/main/java/org/appdevforall/k2go/redesign/K2GoFilterChip.java b/controller/app/src/main/java/org/appdevforall/k2go/redesign/K2GoFilterChip.java
new file mode 100644
index 000000000..50b560fb1
--- /dev/null
+++ b/controller/app/src/main/java/org/appdevforall/k2go/redesign/K2GoFilterChip.java
@@ -0,0 +1,101 @@
+/*
+ * ============================================================================
+ * Name : K2GoFilterChip.java
+ * Author : AppDevForAll
+ * Copyright : Copyright (c) 2026 AppDevForAll
+ * Description : K2GO-385 (PR3). The shared FILTER CHIP (pill-roles design decision, board
+ * k2go-chip-vs-button-v1): a selectable/toggle chip -- Popular / Educational, a ZIM
+ * category, a sort order. Per the decision it is an 8dp-corner, ~32dp Material 3 chip
+ * with a leading check when selected -- "8dp corner + check = toggle", distinct on
+ * purpose from the stadium action button, the dot+text status and the 8dp metadata
+ * tag. Built ONCE here instead of the three drifted per-screen chip builders it
+ * replaces (ZimLanding / ZimCategory / BooksLanding). Colour is the app teal (filled +
+ * on-teal text when selected; transparent + teal outline + teal text when not). Pure
+ * UI; no domain/data dependencies.
+ * ============================================================================
+ */
+package org.appdevforall.k2go.redesign;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.HorizontalScrollView;
+
+import androidx.core.content.ContextCompat;
+
+import com.google.android.material.chip.Chip;
+
+import org.appdevforall.k2go.R;
+
+public final class K2GoFilterChip {
+
+ private K2GoFilterChip() {}
+
+ /**
+ * Build a selectable filter chip. {@code selected} sets the checked look (teal fill + check);
+ * {@code onClick} fires on tap -- the caller owns the selection model (usually rebuilding the
+ * row), so the chip is a view of that state, not the source of truth.
+ */
+ public static Chip create(Context ctx, CharSequence label, boolean selected, View.OnClickListener onClick) {
+ Chip chip = new Chip(ctx);
+ chip.setText(label);
+ style(chip, selected);
+ chip.setOnClickListener(onClick);
+ return chip;
+ }
+
+ /**
+ * Apply the filter-chip look + selected state to an EXISTING chip (e.g. one inflated from XML,
+ * like the ZimCategory sort chips). Idempotent -- safe to call on every render. The caller owns
+ * the text (so a sort chip can carry its "By size ▲" direction) and the click.
+ */
+ public static void style(Chip chip, boolean selected) {
+ Context ctx = chip.getContext();
+ float d = ctx.getResources().getDisplayMetrics().density;
+ chip.setCheckable(true);
+ chip.setChecked(selected);
+ chip.setCheckedIconVisible(true); // the "check" cue the design calls for
+ // A bare new Chip(ctx) picks up the theme's default (Assist) chipStyle, which has NO checkedIcon,
+ // so set a plain check explicitly -- otherwise setCheckedIconVisible shows nothing.
+ chip.setCheckedIcon(ContextCompat.getDrawable(ctx, R.drawable.ic_check_16));
+ chip.setChipCornerRadius(8 * d); // 8dp corner = chip/toggle (not a stadium pill)
+ chip.setChipMinHeight(32 * d); // the 32dp step on the 4dp role ladder
+ chip.setEnsureMinTouchTargetSize(true); // keep a >=48dp touch target on the 32dp chip
+ chip.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_LabelLarge);
+
+ int teal = ContextCompat.getColor(ctx, R.color.k2go_teal);
+ int onTeal = ContextCompat.getColor(ctx, R.color.k2go_on_teal);
+ int[][] states = { new int[]{ android.R.attr.state_checked }, new int[0] };
+ chip.setChipBackgroundColor(new ColorStateList(states, new int[]{ teal, Color.TRANSPARENT }));
+ chip.setChipStrokeColor(new ColorStateList(states, new int[]{ Color.TRANSPARENT, teal }));
+ chip.setChipStrokeWidth(Math.max(1, Math.round(1.4f * d)));
+ chip.setTextColor(new ColorStateList(states, new int[]{ onTeal, teal }));
+ chip.setCheckedIconTint(ColorStateList.valueOf(onTeal));
+ }
+
+ /**
+ * Wire a horizontally-scrollable filter-chip row so it never reads as "the last chip": a soft fade
+ * at the scrolled edges (right while there is more to the right, left once scrolled), and on
+ * (re)build a scroll that reveals the selected chip with its neighbours peeking instead of pinned
+ * flush to an edge. Call after (re)populating the row. K2GO-385 (design k2go-chip-scroll-affordance-v1).
+ */
+ public static void revealSelected(HorizontalScrollView scroll, ViewGroup row) {
+ float d = scroll.getResources().getDisplayMetrics().density;
+ scroll.setHorizontalFadingEdgeEnabled(true);
+ // 34dp (a touch longer than the default) so the edge fade stays legible for low vision, not so
+ // faint it can be missed when a chip happens to end right at the row edge.
+ scroll.setFadingEdgeLength(Math.round(34 * d));
+ scroll.post(() -> {
+ for (int i = 0; i < row.getChildCount(); i++) {
+ View c = row.getChildAt(i);
+ if (c instanceof Chip && ((Chip) c).isChecked()) {
+ int peek = c.getWidth(); // keep one chip of context so the active chip is not pinned
+ scroll.smoothScrollTo(Math.max(0, c.getLeft() - peek), 0);
+ return;
+ }
+ }
+ });
+ }
+}
diff --git a/controller/app/src/main/java/org/appdevforall/k2go/redesign/SegmentedTabs.java b/controller/app/src/main/java/org/appdevforall/k2go/redesign/SegmentedTabs.java
new file mode 100644
index 000000000..234993baf
--- /dev/null
+++ b/controller/app/src/main/java/org/appdevforall/k2go/redesign/SegmentedTabs.java
@@ -0,0 +1,46 @@
+/*
+ * ============================================================================
+ * Name : SegmentedTabs.java
+ * Author : AppDevForAll
+ * Copyright : Copyright (c) 2026 AppDevForAll
+ * Description : K2GO-385 (pill roles Q6, light variant). The Connect / Clone mode strips stay a
+ * two-segment teal strip (active = teal pill + on-teal text), but read as a
+ * single-select radio group to accessibility services: each tab is announced as a
+ * checkable RadioButton, checked when active, and marked selected. One definition
+ * instead of the identical paintTab that lived in both ConnectFragment and
+ * CloneFragment. Touch ripple comes from android:foreground on the tab in the layout.
+ * ============================================================================
+ */
+package org.appdevforall.k2go.redesign;
+
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.core.content.ContextCompat;
+import androidx.core.view.AccessibilityDelegateCompat;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
+
+import org.appdevforall.k2go.R;
+
+public final class SegmentedTabs {
+
+ private SegmentedTabs() {}
+
+ /** Paint one segment of a two-way mode strip and expose it as a checked/unchecked radio. */
+ public static void paint(TextView tab, boolean checked) {
+ tab.setBackgroundResource(checked ? R.drawable.k2go_primary_bg : 0);
+ tab.setTextColor(ContextCompat.getColor(tab.getContext(),
+ checked ? R.color.k2go_on_teal : R.color.k2go_muted));
+ tab.setSelected(checked);
+ ViewCompat.setAccessibilityDelegate(tab, new AccessibilityDelegateCompat() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ info.setClassName("android.widget.RadioButton");
+ info.setCheckable(true);
+ info.setChecked(host.isSelected());
+ }
+ });
+ }
+}
diff --git a/controller/app/src/main/java/org/appdevforall/k2go/redesign/SettingsSubFragment.java b/controller/app/src/main/java/org/appdevforall/k2go/redesign/SettingsSubFragment.java
index fd209d64f..f81b412d9 100644
--- a/controller/app/src/main/java/org/appdevforall/k2go/redesign/SettingsSubFragment.java
+++ b/controller/app/src/main/java/org/appdevforall/k2go/redesign/SettingsSubFragment.java
@@ -402,7 +402,7 @@ private void buildAuthentication(Context ctx, LinearLayout list) {
SettingsUi.caption(ctx, list, getString(R.string.k2go_auth_list_note));
}
- /** A navigable row per service with a state chip (Default / Custom / Not installed). A service
+ /** A navigable row per service with a state badge (Default / Custom / Not installed). A service
* that isn't reachable is dimmed but stays tappable so the sign-in can be pre-set. */
private void authServiceRow(Context ctx, LinearLayout list, String service, String name, String platform) {
LinearLayout row = new LinearLayout(ctx);
@@ -426,13 +426,12 @@ private void authServiceRow(Context ctx, LinearLayout list, String service, Stri
com.google.android.material.R.style.TextAppearance_Material3_BodySmall, R.color.k2go_muted));
row.addView(col);
- final TextView chip = new TextView(ctx);
- chip.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_LabelSmall);
- chip.setPadding(SettingsUi.dp(ctx, 10), SettingsUi.dp(ctx, 4), SettingsUi.dp(ctx, 10), SettingsUi.dp(ctx, 4));
- chip.setVisibility(View.GONE);
- LinearLayout.LayoutParams chlp = new LinearLayout.LayoutParams(-2, -2);
- chlp.rightMargin = SettingsUi.dp(ctx, 8);
- row.addView(chip, chlp);
+ // K2GO-385 (pill roles Q4): the service state (Default / Custom / Not installed) is a STATUS,
+ // so it reads as a dot+text badge, not a filled pill. Colours unchanged -- Default/Not installed
+ // neutral, Custom teal. Built once, GONE until the async probe resolves.
+ final LinearLayout badge = K2GoStatusBadge.create(ctx, "", R.color.k2go_muted);
+ badge.setVisibility(View.GONE);
+ row.addView(badge);
TextView chev = new TextView(ctx);
chev.setText("›");
@@ -445,26 +444,24 @@ private void authServiceRow(Context ctx, LinearLayout list, String service, Stri
if (!isAdded()) return;
row.setAlpha(reachable ? 1f : 0.5f);
if (!reachable) {
- setChip(chip, getString(R.string.k2go_auth_chip_notinstalled), R.drawable.k2go_pill_bg, R.color.k2go_muted);
+ setBadge(badge, getString(R.string.k2go_auth_chip_notinstalled), R.color.k2go_muted);
return;
}
CredentialsClient.describe(service, new CredentialsClient.DescribeCb() {
@Override public void onOk(String user, String pass, boolean isDefault) {
if (!isAdded()) return;
- if (isDefault) setChip(chip, getString(R.string.k2go_auth_chip_default), R.drawable.k2go_pill_bg, R.color.k2go_muted);
- else setChip(chip, getString(R.string.k2go_auth_chip_custom), R.drawable.k2go_pill_teal, R.color.k2go_teal);
+ if (isDefault) setBadge(badge, getString(R.string.k2go_auth_chip_default), R.color.k2go_muted);
+ else setBadge(badge, getString(R.string.k2go_auth_chip_custom), R.color.k2go_teal);
}
- @Override public void onErr() { /* leave the chip hidden on a load error */ }
+ @Override public void onErr() { /* leave the badge hidden on a load error */ }
});
});
}
- /** Style + reveal a state chip (Default / Custom / Not installed). */
- private void setChip(TextView chip, String text, int bgRes, int colorRes) {
- chip.setText(text);
- chip.setBackgroundResource(bgRes);
- chip.setTextColor(ContextCompat.getColor(requireContext(), colorRes));
- chip.setVisibility(View.VISIBLE);
+ /** Style + reveal the service state badge (Default / Custom / Not installed). */
+ private void setBadge(LinearLayout badge, String text, int colorRes) {
+ K2GoStatusBadge.style(badge, text, colorRes);
+ badge.setVisibility(View.VISIBLE);
}
private void buildServiceAuth(Context ctx, LinearLayout list, String service) {
diff --git a/controller/app/src/main/java/org/appdevforall/k2go/redesign/Step1SystemFragment.java b/controller/app/src/main/java/org/appdevforall/k2go/redesign/Step1SystemFragment.java
index 5dc991ccd..232f6556a 100644
--- a/controller/app/src/main/java/org/appdevforall/k2go/redesign/Step1SystemFragment.java
+++ b/controller/app/src/main/java/org/appdevforall/k2go/redesign/Step1SystemFragment.java
@@ -25,10 +25,10 @@ public class Step1SystemFragment extends Fragment {
private static final class Edition {
final InstallationPlanner.Tier tier; final String name;
- final String desc; final boolean recommended;
+ final String desc;
ImageView radio; TextView sizeView;
- Edition(InstallationPlanner.Tier t, String n, String d, boolean r) {
- tier = t; name = n; desc = d; recommended = r;
+ Edition(InstallationPlanner.Tier t, String n, String d) {
+ tier = t; name = n; desc = d;
}
}
@@ -56,14 +56,14 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
tint(barFree, R.color.k2go_hairline);
editions.clear();
+ // ADFA-5295: no "Recommended" edition -- Standard's size edge no longer buys a real UX
+ // advantage, so we don't steer users. K2GO-385: the dead badge scaffolding was removed.
editions.add(new Edition(InstallationPlanner.Tier.BASIC, getString(R.string.k2go_edition_basic),
- getString(R.string.k2go_edition_basic_desc), false));
- // ADFA-5295: no "Recommended" badge on Standard anymore — its size edge no longer buys a
- // real design/UX advantage, so we don't steer users to it.
+ getString(R.string.k2go_edition_basic_desc)));
editions.add(new Edition(InstallationPlanner.Tier.STANDARD, getString(R.string.k2go_edition_standard),
- getString(R.string.k2go_edition_standard_desc), false));
+ getString(R.string.k2go_edition_standard_desc)));
editions.add(new Edition(InstallationPlanner.Tier.FULL, getString(R.string.k2go_edition_full),
- getString(R.string.k2go_edition_full_desc), false));
+ getString(R.string.k2go_edition_full_desc)));
LinearLayout host = root.findViewById(R.id.k2go_editions);
for (Edition e : editions) {
@@ -72,8 +72,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
((TextView) row.findViewById(R.id.k2go_edition_desc)).setText(e.desc);
e.sizeView = row.findViewById(R.id.k2go_edition_size);
e.sizeView.setText(sizeText(InstallationPlanner.fallbackOsSizeGb(e.tier))); // instant last-known
- row.findViewById(R.id.k2go_edition_reco)
- .setVisibility(e.recommended ? View.VISIBLE : View.GONE);
e.radio = row.findViewById(R.id.k2go_edition_radio);
row.setOnClickListener(v -> select(e.tier));
host.addView(row);
diff --git a/controller/app/src/main/java/org/appdevforall/k2go/redesign/ZimCategoryFragment.java b/controller/app/src/main/java/org/appdevforall/k2go/redesign/ZimCategoryFragment.java
index a8ea53d2d..2477eedab 100644
--- a/controller/app/src/main/java/org/appdevforall/k2go/redesign/ZimCategoryFragment.java
+++ b/controller/app/src/main/java/org/appdevforall/k2go/redesign/ZimCategoryFragment.java
@@ -71,7 +71,8 @@ private static final class Entry {
private long freeMb = 0, totalMb = 0;
private LinearLayout list;
- private TextView freeLabel, sortSize, sortName, sortGroup, count, langCurrent, langSub;
+ private TextView freeLabel, count, langCurrent, langSub;
+ private com.google.android.material.chip.Chip sortSize, sortName, sortGroup;
private ProgressBar bar;
private Button add;
@@ -275,10 +276,11 @@ private void addHeader(String title, String desc) {
list.addView(h);
}
- private void chip(TextView t, boolean on) {
- t.setBackgroundResource(on ? R.drawable.k2go_chip_bg : R.drawable.k2go_pill_bg);
- // ADFA-4910: white on the selected (teal) chip (same fix as Books / MapsChoose).
- t.setTextColor(ContextCompat.getColor(requireContext(), on ? android.R.color.white : R.color.k2go_ink));
+ // K2GO-385 (PR3): the sort chips use the one shared filter chip (8dp, 32dp, check when active) so
+ // they stop looking different from the category/Books filter chips; the label still carries the
+ // sort direction (e.g. "By size ▲").
+ private void chip(com.google.android.material.chip.Chip t, boolean on) {
+ K2GoFilterChip.style(t, on);
}
// ADFA-5033: flat list row (spec §10) — a simple line with a hairline between rows, NOT a card.
diff --git a/controller/app/src/main/java/org/appdevforall/k2go/redesign/ZimLandingFragment.java b/controller/app/src/main/java/org/appdevforall/k2go/redesign/ZimLandingFragment.java
index 4872bc334..4005aba4f 100644
--- a/controller/app/src/main/java/org/appdevforall/k2go/redesign/ZimLandingFragment.java
+++ b/controller/app/src/main/java/org/appdevforall/k2go/redesign/ZimLandingFragment.java
@@ -18,6 +18,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
@@ -28,6 +29,8 @@
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
+import com.google.android.material.chip.Chip;
+
import org.appdevforall.k2go.R;
import org.appdevforall.k2go.applang.data.ContentLanguage;
import org.json.JSONObject;
@@ -46,6 +49,7 @@ public class ZimLandingFragment extends Fragment {
private long freeMb = 0, totalMb = 0;
private LinearLayout cats;
private LinearLayout chipRow;
+ private HorizontalScrollView chipScroll;
private TextView status, langLabel, langSub, storageLabel;
private ProgressBar storageBar;
private Button review;
@@ -74,6 +78,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
cats = root.findViewById(R.id.k2go_zim_cats);
chipRow = root.findViewById(R.id.k2go_zim_chips);
+ chipScroll = root.findViewById(R.id.k2go_zim_chips_scroll);
status = root.findViewById(R.id.k2go_zim_status);
langLabel = root.findViewById(R.id.k2go_zim_lang);
langSub = root.findViewById(R.id.k2go_zim_lang_sub);
@@ -249,40 +254,24 @@ private void buildChips() {
chipRow.removeAllViews();
chipRow.addView(chip(getString(R.string.k2go_zim_grp_all), null));
for (KiwixGroups.Group g : KiwixGroups.ALL) chipRow.addView(chip(getString(g.chipLabel), g.key));
+ K2GoFilterChip.revealSelected(chipScroll, chipRow);
}
private View chip(String label, String groupKey) {
boolean selected = (groupKey == null) ? (selectedGroup == null) : groupKey.equals(selectedGroup);
- int teal = ContextCompat.getColor(requireContext(), R.color.k2go_teal);
- TextView t = new TextView(requireContext());
- t.setText(label);
- t.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_LabelLarge);
- t.setGravity(Gravity.CENTER);
- t.setMinHeight(px(48)); // ADFA-5033: ≥48dp tap target (spec §9)
- t.setPadding(px(14), px(6), px(14), px(6));
- android.graphics.drawable.GradientDrawable bg = new android.graphics.drawable.GradientDrawable();
- bg.setShape(android.graphics.drawable.GradientDrawable.RECTANGLE);
- bg.setCornerRadius(px(24)); // full pill at 48dp
- if (selected) {
- bg.setColor(teal);
- t.setTextColor(android.graphics.Color.WHITE);
- } else {
- bg.setColor(android.graphics.Color.TRANSPARENT);
- bg.setStroke(Math.max(1, Math.round(1.4f * getResources().getDisplayMetrics().density)), teal);
- t.setTextColor(teal);
- }
- t.setBackground(bg);
- LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
- lp.rightMargin = px(8);
- t.setLayoutParams(lp);
- t.setOnClickListener(v -> {
+ // K2GO-385 (PR3): one shared filter chip (8dp corner, 32dp, check when selected) -- replaces the
+ // per-screen 48dp teal pill that had drifted from the other filter surfaces.
+ Chip c = K2GoFilterChip.create(requireContext(), label, selected, v -> {
selectedGroup = groupKey;
expanded = false;
buildChips();
buildRows();
});
- return t;
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+ lp.rightMargin = px(8);
+ c.setLayoutParams(lp);
+ return c;
}
/** Teal caps section header (MOST CONTENT / group headers). */
diff --git a/controller/app/src/main/res/drawable/bg_beta_pill.xml b/controller/app/src/main/res/drawable/bg_beta_pill.xml
deleted file mode 100644
index 37005ecf0..000000000
--- a/controller/app/src/main/res/drawable/bg_beta_pill.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
diff --git a/controller/app/src/main/res/drawable/ic_check_16.xml b/controller/app/src/main/res/drawable/ic_check_16.xml
new file mode 100644
index 000000000..c9610dda7
--- /dev/null
+++ b/controller/app/src/main/res/drawable/ic_check_16.xml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/controller/app/src/main/res/drawable/ic_share.xml b/controller/app/src/main/res/drawable/ic_share.xml
new file mode 100644
index 000000000..6eb493c0c
--- /dev/null
+++ b/controller/app/src/main/res/drawable/ic_share.xml
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/controller/app/src/main/res/layout/activity_k2go_setup_progress.xml b/controller/app/src/main/res/layout/activity_k2go_setup_progress.xml
index 6b3414937..daea558be 100644
--- a/controller/app/src/main/res/layout/activity_k2go_setup_progress.xml
+++ b/controller/app/src/main/res/layout/activity_k2go_setup_progress.xml
@@ -93,9 +93,6 @@
android:layout_height="52dp"
android:layout_marginTop="16dp"
android:text="@string/k2go_zim_finish"
- android:textColor="@android:color/white"
- android:textAllCaps="false"
- android:backgroundTint="@color/k2go_teal"
android:visibility="gone" />
+ android:text="@string/k2go_setup_back" />