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
Original file line number Diff line number Diff line change
Expand Up @@ -202,35 +202,28 @@ public static void show(Activity act, String endpoint, String title, int iconRes
content.addView(row(ctx, R.drawable.ic_arrow_right, act.getString(R.string.k2go_sheet_open),
Emphasis.ACCENT, null, false, v -> { dlg.dismiss(); openContent(act, endpoint); }));
content.addView(about);
// K2GO-422: an installed forgejo with the example repos present -> offer "Update repos"
// here (the module action menu). Gated by the SAME status the detail uses (hasRepos), read
// off the main thread; the row is inserted after About when the box answers, if the sheet
// is still up. Tapping runs the shared refresh IN the sheet (it does NOT dismiss).
if ("forgejo".equals(key)) {
// K2GO-449: an installed content module's update action comes from the ModuleActions
// registry. A plain entry (code_addons, code_assets) shows its row now; a gated entry
// (forgejo "Update repos") checks its gate off the main thread and, if it passes and the
// sheet is still up, inserts the row after About. The module detail screen keeps Forgejo's
// richer install-repos / blocked flow.
final ModuleActions.InstalledAction ia = ModuleActions.installed(key);
final ModuleActions.Gate gate = ia == null ? null : ia.gate;
if (ia != null && gate == null) {
content.addView(row(ctx, ia.iconRes, act.getString(ia.labelRes),
Emphasis.ACCENT, null, false, v -> ia.handler.run(act, v)));
} else if (ia != null) {
final LinearLayout host = content;
org.appdevforall.k2go.util.AppExecutors.get().io().execute(() -> {
final org.appdevforall.k2go.forgejo.data.ForgejoStatusClient.Status st =
new org.appdevforall.k2go.forgejo.data.ForgejoStatusClient().fetch();
// Gate on canUpdateRepos (manageable AND repos present): a null read (cannot tell),
// no repos, or an admin we cannot authenticate (blocked) shows no Update row.
if (st == null || !st.canUpdateRepos()) return;
if (!gate.canShow()) return;
act.runOnUiThread(() -> {
if (!dlg.isShowing()) return;
View urow = row(ctx, R.drawable.ic_refresh,
act.getString(R.string.k2go_forgejo_update_repos), Emphasis.ACCENT, null, false,
v -> org.appdevforall.k2go.forgejo.presentation.ForgejoRepoRefresh.start(act, v));
host.addView(urow, host.indexOfChild(about) + 1);
View arow = row(ctx, ia.iconRes, act.getString(ia.labelRes),
Emphasis.ACCENT, null, false, v -> ia.handler.run(act, v));
host.addView(arow, host.indexOfChild(about) + 1);
});
});
}
// K2GO-449: an installed content module's update action comes from the ModuleActions
// registry (code_addons, code_assets, ...), so this sheet no longer carries one if per
// module. Forgejo's repos action stays special above (status-gated).
ModuleActions.InstalledAction ia = ModuleActions.installed(key);
if (ia != null) {
content.addView(row(ctx, ia.iconRes, act.getString(ia.labelRes),
Emphasis.ACCENT, null, false, v -> ia.handler.run(act, v)));
}
break;
case SCHEDULED: {
content.addView(about);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
* action shown once the module is installed), so ModuleActionSheet and
* ModuleDetailFragment iterate it instead of each carrying a per-module if block. A new
* content module registers an entry here; the shared UI files stop changing per module.
* Static config only, no runtime state. Forgejo's repos action stays special for now (it
* is status-gated / async), so it is not in this registry yet.
* Static config only, no runtime state. An entry may carry a Gate: a check run off the
* main thread (it may hit the box) that decides whether to offer the action right now.
* Forgejo's "Update repos" is such a gated entry. Forgejo's RICHER detail-screen flow
* (install-repos / blocked / update, the repos opt-in checkbox, and the seed prefs) is
* intrinsically Forgejo-specific and stays in ModuleDetailFragment, not here.
* ============================================================================
*/
package org.appdevforall.k2go.redesign;
Expand All @@ -30,13 +33,21 @@ private ModuleActions() {}
/** Runs a module's installed action, anchored to a view (for the snackbar / inline progress). */
public interface Handler { void run(Activity act, View anchor); }

/** The update action a module offers once installed: a labeled, iconed row that runs {@link #handler}. */
/** Decides whether an installed action should be offered now. Run OFF the main thread (it may hit
* the box), so a module can gate its action on live server status. */
public interface Gate { boolean canShow(); }

/** The update action a module offers once installed: a labeled, iconed row that runs {@link #handler}.
* When {@link #gate} is null the row always shows; otherwise the UI runs the gate off the main thread
* and shows the row only if it returns true. */
public static final class InstalledAction {
public final int labelRes;
public final int iconRes;
public final Handler handler;
InstalledAction(int labelRes, int iconRes, Handler handler) {
this.labelRes = labelRes; this.iconRes = iconRes; this.handler = handler;
@Nullable public final Gate gate;
InstalledAction(int labelRes, int iconRes, Handler handler) { this(labelRes, iconRes, handler, null); }
InstalledAction(int labelRes, int iconRes, Handler handler, @Nullable Gate gate) {
this.labelRes = labelRes; this.iconRes = iconRes; this.handler = handler; this.gate = gate;
}
}

Expand All @@ -49,9 +60,21 @@ public static final class InstalledAction {
INSTALLED.put("code_assets", new InstalledAction(
R.string.k2go_code_assets_update, R.drawable.ic_refresh,
(act, v) -> org.appdevforall.k2go.codeassets.presentation.CodeAssetsRefresh.start(act, v)));
// K2GO-422 / K2GO-449: Forgejo "Update repos", gated on live box status (manageable AND repos
// present). The gate reads ForgejoStatusClient off the main thread. The module detail screen keeps
// its own richer Forgejo flow (install-repos / blocked / update plus the repos opt-in); this entry
// covers the simple gated action the module action sheet offers.
INSTALLED.put("forgejo", new InstalledAction(
R.string.k2go_forgejo_update_repos, R.drawable.ic_refresh,
(act, v) -> org.appdevforall.k2go.forgejo.presentation.ForgejoRepoRefresh.start(act, v),
() -> {
org.appdevforall.k2go.forgejo.data.ForgejoStatusClient.Status st =
new org.appdevforall.k2go.forgejo.data.ForgejoStatusClient().fetch();
return st != null && st.canUpdateRepos();
}));
}

/** The installed action for {@code key}, or null when the module has none (or is handled specially). */
/** The installed action for {@code key}, or null when the module has none. */
@Nullable
public static InstalledAction installed(@Nullable String key) {
return key == null ? null : INSTALLED.get(key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,10 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
});
}
// K2GO-449: an installed content module's update action comes from the ModuleActions
// registry (code_addons, code_assets, ...), so this fragment no longer carries one if
// per module. Forgejo's repos action stays special above (status-gated).
// registry (code_addons, code_assets, ...). A gated entry (forgejo) is handled by the
// module's own status flow above, so apply only the plain (ungated) entries here.
ModuleActions.InstalledAction ia = ModuleActions.installed(c.key());
if (ia != null) {
if (ia != null && ia.gate == null) {
installNowBtn.setText(ia.labelRes);
installNowBtn.setOnClickListener(v -> ia.handler.run(requireActivity(), installNowBtn));
installNowBtn.setVisibility(View.VISIBLE);
Expand Down
Loading