Skip to content

Commit fa8b19e

Browse files
ADFA-4853: post-install ZIM provisioning drain (live)
ZimProvisioner mirrors BooksProvisioner: once installed and the server is up, it resolves each banked 'project|lang|flavour' selector against the offline catalog (KiwixCatalog / kiwix_catalog.csv) into a real ZIM file + label + size and hands them to the existing ZimDownloadService (live REST, foreground, per-item retry), then clears the wishlist. The home drains Books and ZIM one-shot when it sees the server alive.
1 parent 21aef81 commit fa8b19e

2 files changed

Lines changed: 82 additions & 4 deletions

File tree

‎controller/app/src/main/java/org/iiab/controller/redesign/LibraryHomeFragment.java‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,12 @@ private void refreshStatuses() {
241241
return;
242242
}
243243

244-
// ADFA-4853: system is installed and the server is up — drain any wizard Books order into
245-
// the live download engine (one-shot; the wishlist is cleared once handed off).
246-
if (alive && BooksProvisioner.hasPending(requireContext())) {
247-
BooksProvisioner.drain(requireContext());
244+
// ADFA-4853: system is installed and the server is up — drain any wizard content orders
245+
// (Books, ZIM) into the live download engines (one-shot; each wishlist is cleared once
246+
// handed off, and each service downloads one item at a time with per-item retry).
247+
if (alive) {
248+
if (BooksProvisioner.hasPending(requireContext())) BooksProvisioner.drain(requireContext());
249+
if (ZimProvisioner.hasPending(requireContext())) ZimProvisioner.drain(requireContext());
248250
}
249251

250252
for (final Card c : cards) {
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* ============================================================================
3+
* Name : ZimProvisioner.java
4+
* Author : AppDevForAll
5+
* Copyright : Copyright (c) 2026 AppDevForAll
6+
* Description : ADFA-4853. Post-install drain of the ZIM/Wikipedia wishlist. Mirrors
7+
* BooksProvisioner: once the system is installed and the server is up, it resolves
8+
* each banked selector "project|lang|flavour" against the offline catalog
9+
* (kiwix_catalog.csv, via KiwixCatalog) into a real ZIM file + label + size, then
10+
* hands them to the existing ZimDownloadService (the live REST route, foreground,
11+
* per-item retry). ZIM is a LIVE operation (server up), so this must only run when
12+
* the server is alive. Idempotent: the wishlist is cleared once handed off.
13+
* ============================================================================
14+
*/
15+
package org.iiab.controller.redesign;
16+
17+
import android.content.Context;
18+
19+
import org.json.JSONArray;
20+
import org.json.JSONObject;
21+
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
25+
public final class ZimProvisioner {
26+
private ZimProvisioner() {}
27+
28+
/** True when there is a banked ZIM order waiting to be provisioned. */
29+
public static boolean hasPending(Context ctx) {
30+
return ZimWishlist.size(ctx) > 0;
31+
}
32+
33+
/** Resolve the wishlist against the offline catalog and hand it to ZimDownloadService.
34+
* No-op if empty or a session is already running. Requires the server to be up. */
35+
public static void drain(Context ctx) {
36+
if (ZimDownloadService.isRunning() || ZimDownloadService.hasSession()) return;
37+
if (ZimWishlist.size(ctx) == 0) return;
38+
final Context app = ctx.getApplicationContext();
39+
KiwixCatalog.getOrFetch(app, new KiwixCatalog.Listener() {
40+
@Override public void onReady(JSONObject catalog) { resolveAndStart(app, catalog); }
41+
@Override public void onError(String message) { /* leave the wishlist for a later retry */ }
42+
});
43+
}
44+
45+
private static void resolveAndStart(Context app, JSONObject catalog) {
46+
JSONArray order = ZimWishlist.all(app);
47+
List<String> files = new ArrayList<>(), labels = new ArrayList<>();
48+
List<Long> bytes = new ArrayList<>();
49+
for (int i = 0; i < order.length(); i++) {
50+
JSONObject o = order.optJSONObject(i);
51+
if (o == null) continue;
52+
String[] p = o.optString("key", "").split("\\|", 3); // project | lang | entryKey
53+
if (p.length < 3) continue;
54+
JSONObject ld = KiwixCatalog.langData(catalog, p[0], p[1]);
55+
JSONObject v = ld != null ? ld.optJSONObject(p[2]) : null;
56+
if (v == null) continue;
57+
files.add(v.optString("file"));
58+
labels.add(label(p[0], v.optString("creator"), v.optString("flavour")));
59+
bytes.add(v.optLong("size", o.optLong("bytes", 0)));
60+
}
61+
if (files.isEmpty()) { ZimWishlist.clear(app); return; }
62+
long[] b = new long[bytes.size()];
63+
for (int i = 0; i < b.length; i++) b[i] = bytes.get(i);
64+
ZimDownloadService.start(app, files.toArray(new String[0]), labels.toArray(new String[0]), b);
65+
ZimWishlist.clear(app); // handed off; the service owns retry from here
66+
}
67+
68+
private static String label(String project, String creator, String flavour) {
69+
KiwixCategories.Category c = KiwixCategories.byKey(project);
70+
String cat = c != null ? c.title : project;
71+
if (flavour == null || flavour.isEmpty() || "all".equalsIgnoreCase(flavour)) {
72+
return (creator == null || creator.isEmpty()) ? cat : cat + " · " + creator;
73+
}
74+
return cat + " · " + flavour.replace('_', ' ').replace('-', ' ');
75+
}
76+
}

0 commit comments

Comments
 (0)