33 * Name : DashNodeGate.java
44 * Author : AppDevForAll
55 * Copyright : Copyright (c) 2026 AppDevForAll
6- * Description : K2GO-430. Gate a module install batch on the box dash-node version. Two mechanisms:
6+ * Description : K2GO-430. Gate a module install on the box dash-node version. Two mechanisms:
77 * HARD block : a module that declares a minimum (DashNodeRequirement, e.g. Forgejo -> 1.3.7)
88 * cannot install on a box below it; show a dialog and route to the dashboard update.
9- * SOFT suggest : for any install , when a dashboard update is available, recommend updating
10- * first (Update / Install anyway). Reuses the existing version read (DashboardVersion, from
11- * the rootfs, no network/proot) and the cached update-check (UpdateStatusCache), so the gate
12- * is synchronous.
9+ * SOFT suggest : for a batch , when a dashboard update is available, recommend updating first
10+ * (Update / Install anyway). Reuses the existing version read (DashboardVersion, from the
11+ * rootfs, no network/proot) and the cached update-check (UpdateStatusCache), so the gate is
12+ * synchronous.
1313 * ============================================================================
1414 */
1515package org .appdevforall .k2go .dependency .presentation ;
1616
1717import android .app .Activity ;
1818import android .content .Context ;
19+ import android .content .Intent ;
1920
2021import androidx .annotation .NonNull ;
2122import androidx .annotation .Nullable ;
3031public final class DashNodeGate {
3132 private DashNodeGate () {}
3233
33- /** True when the box dash-node is below {@code moduleKey}'s hard minimum (null key / no minimum = false). */
34+ /** True when the box dash-node is below {@code moduleKey}'s hard minimum (null key / no minimum = false).
35+ * A null (unreadable) installed version blocks a module that HAS a minimum: do not install it against
36+ * a dashboard we cannot verify. */
3437 public static boolean installBlocked (@ NonNull Context ctx , @ Nullable String moduleKey ) {
3538 int [] min = DashNodeRequirement .minFor (moduleKey );
3639 return min != null && !DashboardVersion .atLeast (DashboardVersion .installed (ctx ), min [0 ], min [1 ], min [2 ]);
@@ -56,27 +59,43 @@ public static void guardModuleBatch(@NonNull Activity act, @Nullable String[] ba
5659 onProceed .run ();
5760 }
5861
59- private static void showBlocked (@ NonNull Activity act , @ NonNull String moduleKey ) {
60- new BrandDialog (act )
62+ /**
63+ * Gate a single-module (re)install, e.g. a retry: returns false (and shows the block dialog) when the
64+ * module is below its dash-node minimum, true when it may proceed. Hard block only (a retry does not
65+ * carry the soft update suggestion). Covers the install paths that start the index directly, not via
66+ * the batch gate.
67+ */
68+ public static boolean allowInstall (@ NonNull Context ctx , @ Nullable String moduleKey ) {
69+ if (installBlocked (ctx , moduleKey )) { showBlocked (ctx , moduleKey ); return false ; }
70+ return true ;
71+ }
72+
73+ private static void showBlocked (@ NonNull Context ctx , @ NonNull String moduleKey ) {
74+ new BrandDialog (ctx )
6175 .setTitle (R .string .k2go_dep_required_title )
62- .setMessage (act .getString (R .string .k2go_dep_required_msg_fmt , DashNodeRequirement .minLabel (moduleKey )))
63- .setPositive (R .string .k2go_dep_update_dashboard , BrandDialog .Role .PRIMARY , () -> openDashboard (act ))
76+ .setMessage (ctx .getString (R .string .k2go_dep_required_msg_fmt , DashNodeRequirement .minLabel (moduleKey )))
77+ .setPositive (R .string .k2go_dep_update_dashboard , BrandDialog .Role .PRIMARY , () -> openDashboard (ctx ))
6478 .setNegative (android .R .string .cancel , null )
6579 .show ();
6680 }
6781
68- private static void showSuggest (@ NonNull Activity act , @ NonNull Runnable onProceed ) {
69- new BrandDialog (act )
82+ private static void showSuggest (@ NonNull Context ctx , @ NonNull Runnable onProceed ) {
83+ new BrandDialog (ctx )
7084 .setTitle (R .string .k2go_dep_suggest_title )
7185 .setMessage (R .string .k2go_dep_suggest_msg )
72- .setPositive (R .string .k2go_dep_update_dashboard , BrandDialog .Role .PRIMARY , () -> openDashboard (act ))
86+ .setPositive (R .string .k2go_dep_update_dashboard , BrandDialog .Role .PRIMARY , () -> openDashboard (ctx ))
7387 .setNegative (R .string .k2go_dep_install_anyway , onProceed ::run )
88+ // The suggestion is optional: dismissing it (back / tap-outside) proceeds with the install
89+ // the user already asked for, rather than silently swallowing it.
90+ .setOnCancel (onProceed ::run )
7491 .show ();
7592 }
7693
77- /** Open the dashboard detail (the Rebuild/Update card) so the user can update the dash-node. Reuses
78- * the canonical navigation intent instead of rebuilding it here. */
79- private static void openDashboard (@ NonNull Activity act ) {
80- act .startActivity (OpReturnNavigator .dashboardRebuild (act ));
94+ /** Open the dashboard detail (the Rebuild/Update card) so the user can update the dash-node. Reuses the
95+ * canonical navigation intent instead of rebuilding it here. */
96+ private static void openDashboard (@ NonNull Context ctx ) {
97+ Intent i = OpReturnNavigator .dashboardRebuild (ctx );
98+ if (!(ctx instanceof Activity )) i .addFlags (Intent .FLAG_ACTIVITY_NEW_TASK );
99+ ctx .startActivity (i );
81100 }
82101}
0 commit comments