diff --git a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleActionSheet.java b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleActionSheet.java
index e8ff5cdc..978bff33 100644
--- a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleActionSheet.java
+++ b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleActionSheet.java
@@ -79,7 +79,14 @@ public static void show(Activity act, String endpoint, String title, int iconRes
hcol.addView(tv);
TextView subtitle = new TextView(ctx);
String project = (card != null) ? act.getString(card.subRes) : "";
- subtitle.setText(project.isEmpty() ? stateLabel(act, state) : project + " · " + stateLabel(act, state));
+ int sizeRes = ModuleCards.sizeLabelRes(key); // ADFA-4958 §5.3: subtitle is project · state · size
+ long bytes = ModuleSizes.bytesFor(ctx, key);
+ StringBuilder sub = new StringBuilder();
+ if (!project.isEmpty()) sub.append(project).append(" · ");
+ sub.append(stateLabel(act, state));
+ if (sizeRes != 0) sub.append(" · ").append(act.getString(sizeRes));
+ else if (bytes >= 0) sub.append(" · ≈ ").append(org.iiab.controller.util.ByteFormatter.toHuman(bytes));
+ subtitle.setText(sub.toString());
subtitle.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodySmall);
subtitle.setTextColor(ContextCompat.getColor(ctx, R.color.k2go_muted));
hcol.addView(subtitle);
diff --git a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleCards.java b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleCards.java
index 2c88403d..f86c90ef 100644
--- a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleCards.java
+++ b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleCards.java
@@ -114,6 +114,21 @@ public static String license(String key) {
}
}
+ /** ADFA-4958: curated size label for modules whose real footprint is selection-dependent
+ * (maps grows with the layers/levels the user picks), shown instead of a single measured
+ * value. 0 -> fall back to the measured ModuleSizes value. */
+ public static int sizeLabelRes(String key) {
+ if ("maps".equals(key)) return R.string.k2go_mod_maps_size;
+ if ("matomo".equals(key)) return R.string.k2go_mod_matomo_size; // ADFA-4958: curated (~114 MB, incl. MariaDB + tarball)
+ return 0;
+ }
+
+ /** ADFA-4958: matomo ships as a demo/example module — it runs, but it is not a real production
+ * feature; flagged so the detail can show a "Demo" chip. */
+ public static boolean isDemo(String key) {
+ return "matomo".equals(key);
+ }
+
/** ADFA-4958: "What it includes" line — makes module-vs-content explicit. 0 -> hide. */
public static int includesRes(String key) {
if (key == null) return 0;
diff --git a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleDetailFragment.java b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleDetailFragment.java
index 79ceaaf0..20c50a02 100644
--- a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleDetailFragment.java
+++ b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleDetailFragment.java
@@ -66,14 +66,16 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
// ADFA-4958: meta chips (size / version / Runs offline), "What it includes", and license.
LinearLayout chips = root.findViewById(R.id.k2go_moddet_chips);
+ int sizeRes = ModuleCards.sizeLabelRes(c.key()); // ADFA-4958: maps uses a curated "200 MB+" floor
long bytes = ModuleSizes.bytesFor(requireContext(), c.key());
- String sizeText = (bytes >= 0)
- ? "\u2248 " + org.iiab.controller.util.ByteFormatter.toHuman(bytes)
+ String sizeText = (sizeRes != 0) ? getString(sizeRes)
+ : (bytes >= 0) ? "\u2248 " + org.iiab.controller.util.ByteFormatter.toHuman(bytes)
: "\u2248 NA";
chips.addView(chip(sizeText, R.color.k2go_teal));
String ver = ModuleCards.version(c.key());
if (ver != null) chips.addView(chip("v" + ver, R.color.k2go_teal));
chips.addView(chip(getString(R.string.k2go_mod_runs_offline), R.color.k2go_leaf));
+ if (ModuleCards.isDemo(c.key())) chips.addView(chip(getString(R.string.k2go_mod_demo), R.color.k2go_amber_text)); // ADFA-4958
int inc = ModuleCards.includesRes(c.key());
if (inc != 0) {
@@ -120,8 +122,14 @@ private TextView chip(String text, int colorRes) {
TextView t = new TextView(requireContext());
t.setText(text);
t.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_LabelMedium);
- t.setTextColor(ContextCompat.getColor(requireContext(), colorRes));
- t.setBackgroundResource(R.drawable.k2go_chip_bg);
+ int color = ContextCompat.getColor(requireContext(), colorRes); // ADFA-4958 §5.4: outlined pill (teal-on-teal fill was invisible)
+ t.setTextColor(color);
+ android.graphics.drawable.GradientDrawable bg = new android.graphics.drawable.GradientDrawable();
+ bg.setShape(android.graphics.drawable.GradientDrawable.RECTANGLE);
+ bg.setColor(android.graphics.Color.TRANSPARENT);
+ bg.setCornerRadius(11 * d);
+ bg.setStroke(Math.max(1, Math.round(1.4f * d)), color);
+ t.setBackground(bg);
int hp = Math.round(10 * d), vp = Math.round(5 * d);
t.setPadding(hp, vp, hp, vp);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
diff --git a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleHubFragment.java b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleHubFragment.java
index 18d6379d..c3d9e7d3 100644
--- a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleHubFragment.java
+++ b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleHubFragment.java
@@ -220,10 +220,7 @@ private void addHiddenSection() {
col.addView(sub);
row.addView(col, new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f));
- TextView restore = new TextView(requireContext());
- restore.setText(R.string.k2go_mod_restore);
- restore.setTextColor(ContextCompat.getColor(requireContext(), R.color.k2go_teal));
- restore.setBackgroundResource(R.drawable.k2go_chip_bg);
+ TextView restore = statePill(getString(R.string.k2go_mod_restore), R.color.k2go_teal); // ADFA-4958 §5.7: outlined teal pill
restore.setPadding(px(14), px(6), px(14), px(6));
restore.setOnClickListener(v -> { HiddenModules.remove(requireContext(), key); buildCards(); });
row.addView(restore);
diff --git a/controller/app/src/main/res/values/strings_k2go.xml b/controller/app/src/main/res/values/strings_k2go.xml
index 4f3b0e09..d904bc1f 100644
--- a/controller/app/src/main/res/values/strings_k2go.xml
+++ b/controller/app/src/main/res/values/strings_k2go.xml
@@ -664,6 +664,9 @@
Offline world maps to browse and search on the device. Pick the layers and region, then it builds into your system.
Runs offline
+ 200 MB+
+ ≈ 114 MB
+ Demo
What it includes
License · %1$s
Sample courses included — add more in Get more.