diff --git a/controller/app/src/main/java/org/iiab/controller/install/presentation/InstallService.java b/controller/app/src/main/java/org/iiab/controller/install/presentation/InstallService.java
index 37805312..06c7be3d 100644
--- a/controller/app/src/main/java/org/iiab/controller/install/presentation/InstallService.java
+++ b/controller/app/src/main/java/org/iiab/controller/install/presentation/InstallService.java
@@ -135,6 +135,15 @@ public final class InstallService extends Service {
private volatile boolean finished = false;
private volatile boolean started = false;
+ // ADFA-4898 P4: movement-based stall detection for the running module (surface only, never kills).
+ /** Generous, minute-scale: well above a quiet git-clone/apt phase, so a slow-but-alive install is
+ * never flagged. Above Freshness.STALE_MS (30s), which is tuned for ~1s-cadence REST polls. */
+ private static final long MODULE_STALL_MS = 120_000L;
+ private static final long MODULE_STALL_POLL_MS = 15_000L;
+ private volatile long lastModuleMovementMs = 0L; // stamped on a runrole output line OR write-dir growth
+ private volatile long lastModuleDirSize = -1L;
+ private Runnable moduleStallCheck; // main-thread poller; null when not watching
+
/**
* ADFA-5119: which kind of work is running, for the one question Cancel has to answer — does
* abandoning it leave the device with no system (see {@code AbandonedInstall}).
@@ -955,9 +964,11 @@ private void installNextModule() {
// ADFA-4435: Ansible can print its failure to stdout yet still exit 0, so the verdict
// considers the output as well as the exit code (pure, unit-tested domain object).
final AnsibleRunOutcome outcome = new AnsibleRunOutcome();
+ startModuleStallWatch(nextModule); // ADFA-4898 P4: watch this runrole for a stall (surface only)
prootEngine.executeInContainer(this, debianRootfs.getAbsolutePath(), installCmd, new PRootEngine.OutputListener() {
@Override
public void onOutputLine(String line) {
+ lastModuleMovementMs = android.os.SystemClock.elapsedRealtime(); // ADFA-4898 P4: heartbeat
outcome.observe(line);
log("[Ansible] " + line);
// ADFA-5228: advance the determinate bar as known tasks are reached. Post only on a
@@ -1043,12 +1054,20 @@ private static long estimateEtaSeconds(org.iiab.controller.install.domain.Runrol
}
/**
- * ADFA-4435: roll back the speculative local_vars edit made before runrole, so a failed
- * install is not left looking installed/enabled. Always runs {@code then} afterwards.
+ * ADFA-4435: roll back the speculative local_vars edit made before runrole, so a failed or
+ * cancelled install is not left looking installed/enabled. Always runs {@code then} afterwards.
+ *
+ *
ADFA-4898 P5: write {@code _install: False} / {@code _enabled: False} explicitly
+ * rather than only deleting the speculative lines. Both read as "not installed" (the reader keys on
+ * the flag being true), but an explicit False also tells a later ansible run the module is off, so a
+ * partially-installed module is never offered as installed. The leading sed-delete keeps it
+ * idempotent, and the write-before-runrole path deletes these lines before echoing True on a retry.
*/
private void revertModuleInLocalVars(String module, Runnable then) {
if (prootEngine == null) prootEngine = new PRootEngine();
- String revertCmd = "sed -i -E '/^[[:space:]]*" + module + "_(install|enabled)[[:space:]]*:/d' /etc/iiab/local_vars.yml";
+ String revertCmd = "sed -i -E '/^[[:space:]]*" + module + "_(install|enabled)[[:space:]]*:/d' /etc/iiab/local_vars.yml && " +
+ "echo '" + module + "_install: False' >> /etc/iiab/local_vars.yml && " +
+ "echo '" + module + "_enabled: False' >> /etc/iiab/local_vars.yml";
prootEngine.executeInContainer(this, debianRootfs.getAbsolutePath(), revertCmd, new PRootEngine.OutputListener() {
@Override public void onOutputLine(String line) { }
@Override public void onProcessExit(int exitCode) { then.run(); }
@@ -1056,6 +1075,93 @@ private void revertModuleInLocalVars(String module, Runnable then) {
});
}
+ // ---- ADFA-4898 P4: movement-based stall watch (surface only, never kills) -------------------
+
+ /**
+ * Watch the running module for movement — a runrole output line (stamped in onOutputLine) OR growth
+ * of its on-disk write directory. When neither moves for {@link #MODULE_STALL_MS}, publish a
+ * "stalled" hint the live card shows; the install is never touched. Re-armed per module; the
+ * dir-growth backstop covers quiet network phases (e.g. calibre-web's git clone) that emit no log.
+ */
+ private void startModuleStallWatch(final String moduleKey) {
+ stopModuleStallWatch();
+ lastModuleMovementMs = android.os.SystemClock.elapsedRealtime();
+ lastModuleDirSize = -1L;
+ ModuleQueueRepository.get().postStalled(false);
+ // ADFA-4898 P4: make write-dir drift visible instead of silent. If a module has no mapped dir
+ // (a new module added without updating moduleWriteDirRel), the watch still works off the log
+ // heartbeat — but this line says so in the log, so the missing backstop is noticed, not hidden.
+ if (moduleWriteDirRel(moduleKey) == null) {
+ log("[Stall] no write-dir backstop mapped for '" + moduleKey
+ + "'; stall watch relies on the log heartbeat only");
+ }
+ moduleStallCheck = new Runnable() {
+ @Override public void run() {
+ if (finished || cancelled) return;
+ org.iiab.controller.util.AppExecutors.get().io().execute(() -> {
+ long size = moduleWriteDirSize(moduleKey);
+ if (size >= 0 && size != lastModuleDirSize) {
+ lastModuleDirSize = size;
+ lastModuleMovementMs = android.os.SystemClock.elapsedRealtime();
+ }
+ boolean fresh = org.iiab.controller.env.Freshness.fresh(
+ lastModuleMovementMs, android.os.SystemClock.elapsedRealtime(), MODULE_STALL_MS);
+ ModuleQueueRepository.get().postStalled(!fresh);
+ });
+ heldHandler.postDelayed(this, MODULE_STALL_POLL_MS);
+ }
+ };
+ heldHandler.postDelayed(moduleStallCheck, MODULE_STALL_POLL_MS);
+ }
+
+ private void stopModuleStallWatch() {
+ if (moduleStallCheck != null) { heldHandler.removeCallbacks(moduleStallCheck); moduleStallCheck = null; }
+ ModuleQueueRepository.get().postStalled(false);
+ }
+
+ /** Total bytes under the module's write directory on the host rootfs, or -1 if unknown/absent. */
+ private long moduleWriteDirSize(String key) {
+ String rel = moduleWriteDirRel(key);
+ if (rel == null || debianRootfs == null) return -1L;
+ File d = new File(debianRootfs, rel);
+ if (!d.isDirectory()) return -1L;
+ return boundedDirSize(d, 20000);
+ }
+
+ /**
+ * Where each module does its heavy on-disk writes (relative to the rootfs), for the stall watch's
+ * growth backstop. Heuristic and best-effort — keep it in sync with the ansible roles. If a key is
+ * unmapped or the path drifts, the watch silently falls back to the log heartbeat (never a false
+ * verdict); {@link #startModuleStallWatch} logs the unmapped case so that drift is visible, not silent.
+ */
+ private static String moduleWriteDirRel(String key) {
+ if (key == null) return null;
+ switch (key) {
+ case "calibreweb": return "usr/local/calibre-web-py3"; // git clone + venv
+ case "maps": return "library/downloads/maps";
+ case "matomo": return "library/www/matomo";
+ case "kolibri": return "var/cache/apt/archives"; // chatty on stdout too; disk is the fallback
+ default: return null;
+ }
+ }
+
+ /** Iterative, file-capped directory size so a large tree can't make the poll expensive. */
+ private static long boundedDirSize(File root, int fileCap) {
+ long total = 0L; int count = 0;
+ java.util.ArrayDeque stack = new java.util.ArrayDeque<>();
+ stack.push(root);
+ while (!stack.isEmpty() && count < fileCap) {
+ File[] kids = stack.pop().listFiles();
+ if (kids == null) continue;
+ for (File k : kids) {
+ if (count >= fileCap) break;
+ if (k.isDirectory()) stack.push(k);
+ else { total += k.length(); count++; }
+ }
+ }
+ return total;
+ }
+
/**
* ADFA-4900: build the maps runrole command from the wizard's per-layer selection. Translates
* the selection into the maps role's local_vars (roles/maps/tasks/install_frontend.yml):
@@ -1096,6 +1202,7 @@ public static void retryModules(Context ctx, java.util.List modules) {
private void finishModuleQueue() {
if (finished) return;
finished = true;
+ stopModuleStallWatch(); // ADFA-4898 P4
persistClearQueue();
// ADFA-4842: clear the durable install guard BEFORE publishing DONE so the LibraryActivity
// observer that restarts the server (canStartServer() requires !InstallGuard.inProgress) is not
@@ -1485,10 +1592,27 @@ private void doCancel() {
} catch (Exception ignored) {
}
if (moduleMode) {
- persistClearQueue();
- ModuleQueueRepository.get().postDone(
- failedModules != null ? new java.util.ArrayList<>(failedModules) : new java.util.ArrayList<>());
- teardown();
+ // ADFA-4898 P5: user-confirmed cancel of a running module install. Kill the in-flight runrole
+ // (proot runs with --kill-on-exit, so its container children go with it), roll back that
+ // module's speculative _install so a cancel is not left looking installed, and surface it
+ // as failed so the existing per-module Retry is offered immediately. Ordering mirrors
+ // finishModuleQueue: clear InstallGuard BEFORE postDone so the server-restart observer (the
+ // server was pdsm-stopped for the runroles) is not raced by teardown's later clear.
+ final String cur = ModuleQueueRepository.get().current().currentModule;
+ stopModuleStallWatch(); // ADFA-4898 P4
+ if (prootEngine != null) prootEngine.killProcess();
+ if (failedModules == null) failedModules = new java.util.ArrayList<>();
+ if (cur != null && !failedModules.contains(cur)) failedModules.add(cur);
+ final java.util.List failedSnapshot = new java.util.ArrayList<>(failedModules);
+ final Runnable finishCancel = () -> {
+ persistClearQueue();
+ org.iiab.controller.InstallGuard.end(this);
+ ModuleQueueRepository.get().postDone(failedSnapshot);
+ if (!failedSnapshot.isEmpty()) postModuleFailureNotification(failedSnapshot);
+ teardown();
+ };
+ if (cur != null) revertModuleInLocalVars(cur, finishCancel); // best-effort rollback, then finish
+ else finishCancel.run();
return;
}
if (!org.iiab.controller.install.domain.AbandonedInstall.leavesNoSystem(work)) {
diff --git a/controller/app/src/main/java/org/iiab/controller/install/presentation/ModuleQueueRepository.java b/controller/app/src/main/java/org/iiab/controller/install/presentation/ModuleQueueRepository.java
index f5d43156..ab983097 100644
--- a/controller/app/src/main/java/org/iiab/controller/install/presentation/ModuleQueueRepository.java
+++ b/controller/app/src/main/java/org/iiab/controller/install/presentation/ModuleQueueRepository.java
@@ -29,6 +29,9 @@ public static ModuleQueueRepository get() {
}
private final MutableLiveData state = new MutableLiveData<>(ModuleQueueState.idle());
+ /** ADFA-4898 P4: movement-based stall hint for the current module (surface only, never auto-kill).
+ * Kept separate from the immutable ModuleQueueState so a transient hint never rewrites the queue. */
+ private final MutableLiveData stalled = new MutableLiveData<>(false);
private long seq = 0L;
private ModuleQueueRepository() {
@@ -38,6 +41,16 @@ public LiveData state() {
return state;
}
+ /** ADFA-4898 P4: true while the current module's runrole has shown no movement (log line or write-dir
+ * growth) for the stall window. A surface-only hint — the install keeps running. */
+ public LiveData stalled() {
+ return stalled;
+ }
+
+ public void postStalled(boolean isStalled) {
+ stalled.postValue(isStalled);
+ }
+
public ModuleQueueState current() {
ModuleQueueState s = state.getValue();
return s != null ? s : ModuleQueueState.idle();
@@ -64,8 +77,8 @@ public boolean isInstalling(String moduleKey) {
public void postRunning(String currentModule, int remaining, int percent) { post(ModuleQueueState.running(currentModule, remaining, percent)); }
/** ADFA-5228: running with a determinate percent and an estimated seconds-remaining. */
public void postRunning(String currentModule, int remaining, int percent, long etaSeconds) { post(ModuleQueueState.running(currentModule, remaining, percent, etaSeconds)); }
- public void postDone(List failedModules) { post(ModuleQueueState.done(failedModules)); }
- public void postIdle() { post(ModuleQueueState.idle()); }
+ public void postDone(List failedModules) { stalled.postValue(false); post(ModuleQueueState.done(failedModules)); }
+ public void postIdle() { stalled.postValue(false); post(ModuleQueueState.idle()); }
private synchronized void post(ModuleQueueState s) {
state.postValue(s.withSeq(++seq));
diff --git a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleInstallFragment.java b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleInstallFragment.java
index 8a5514f9..5918e889 100644
--- a/controller/app/src/main/java/org/iiab/controller/redesign/ModuleInstallFragment.java
+++ b/controller/app/src/main/java/org/iiab/controller/redesign/ModuleInstallFragment.java
@@ -84,6 +84,16 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
updateStatus();
ModuleQueueRepository.get().state().observe(getViewLifecycleOwner(), st -> updateStatus());
+ // ADFA-4898 P4: surface a "seems stalled" hint over the frozen status line while this module is
+ // the one running and no movement (log line / write-dir growth) has arrived for the stall window.
+ // Surface only — the install keeps going; a new log line or updateStatus restores the live line.
+ ModuleQueueRepository.get().stalled().observe(getViewLifecycleOwner(), isStalled -> {
+ if (Boolean.TRUE.equals(isStalled) && installing() && !terminalDone) {
+ status.setText(getString(R.string.k2go_mod_phase_stalled));
+ } else {
+ updateStatus();
+ }
+ });
logListener = new LogRepository.Listener() {
@Override public void onAppend(String line) {
diff --git a/controller/app/src/main/java/org/iiab/controller/redesign/SetupProgressActivity.java b/controller/app/src/main/java/org/iiab/controller/redesign/SetupProgressActivity.java
index ca64c587..42b5a0c0 100644
--- a/controller/app/src/main/java/org/iiab/controller/redesign/SetupProgressActivity.java
+++ b/controller/app/src/main/java/org/iiab/controller/redesign/SetupProgressActivity.java
@@ -1321,15 +1321,26 @@ private boolean isLiveDetail(String key) {
*/
private void configureDetailBar() {
if (!showingDetail || detailKey == null || detailBackBtn == null) return;
- boolean moduleFailed = detailKey.startsWith("mod:")
- && ModuleQueueRepository.get().current().didFail(detailKey.substring(4));
+ final boolean isModule = detailKey.startsWith("mod:");
+ final String moduleKey = isModule ? detailKey.substring(4) : null;
+ ModuleQueueState mq = ModuleQueueRepository.get().current();
+ boolean moduleFailed = isModule && mq.didFail(moduleKey);
+ boolean moduleRunning = isModule && mq.isInstalling(moduleKey);
if (moduleFailed) {
- final String moduleKey = detailKey.substring(4);
detailBackBtn.setText(R.string.k2go_home_retry);
detailBackBtn.setOnClickListener(v -> ModuleRetry.fire(v, moduleKey));
detailRunBgBtn.setText(R.string.k2go_setup_back);
detailRunBgBtn.setOnClickListener(v -> backToIndex());
detailRunBgBtn.setVisibility(View.VISIBLE);
+ } else if (moduleRunning) {
+ // ADFA-4898 P5: while this module's runrole runs, offer a confirmed Cancel in the same
+ // secondary slot (Back stays primary). Cancel kills the runrole and surfaces the module as
+ // failed, so the Retry above appears on the next tick — the "immediate retry" of the ticket.
+ detailBackBtn.setText(R.string.k2go_setup_back);
+ detailBackBtn.setOnClickListener(v -> backToIndex());
+ detailRunBgBtn.setText(R.string.k2go_setup_cancel);
+ detailRunBgBtn.setOnClickListener(v -> confirmCancelModule());
+ detailRunBgBtn.setVisibility(View.VISIBLE);
} else {
detailBackBtn.setText(R.string.k2go_setup_back);
detailBackBtn.setOnClickListener(v -> backToIndex());
@@ -1339,6 +1350,22 @@ private void configureDetailBar() {
}
}
+ /**
+ * ADFA-4898 P5: strong confirmation before cancelling a running module install, then send
+ * ACTION_CANCEL. The service kills the runrole (proot --kill-on-exit), rolls back the speculative
+ * flag and marks the module failed; the base system is untouched and the server restarts.
+ */
+ private void confirmCancelModule() {
+ new com.google.android.material.dialog.MaterialAlertDialogBuilder(this)
+ .setTitle(R.string.k2go_mod_cancel_title)
+ .setMessage(R.string.k2go_mod_cancel_body)
+ .setNegativeButton(R.string.k2go_mod_cancel_dismiss, null)
+ .setPositiveButton(R.string.k2go_mod_cancel_confirm, (d, w) ->
+ startService(new android.content.Intent(this, org.iiab.controller.install.presentation.InstallService.class)
+ .setAction(org.iiab.controller.install.presentation.InstallService.ACTION_CANCEL)))
+ .show();
+ }
+
private void backToIndex() {
showingDetail = false;
detailKey = null;
diff --git a/controller/app/src/main/res/values-ar/strings.xml b/controller/app/src/main/res/values-ar/strings.xml
index e9ab4aca..8bd38485 100644
--- a/controller/app/src/main/res/values-ar/strings.xml
+++ b/controller/app/src/main/res/values-ar/strings.xml
@@ -1294,4 +1294,9 @@
تحميل المزيد
عرض %1$d كتاب
هذا كل شيء · %1$d كتاب
+ لا يزال يعمل — يستغرق وقتًا أطول من المعتاد. يمكنك الانتظار أو الإلغاء وإعادة المحاولة.
+ إيقاف التثبيت؟
+ يُتراجع عمّا تم حتى الآن ولن يُثبَّت المكوّن. يمكنك بدؤه من جديد لاحقًا.
+ إيقاف التثبيت
+ متابعة التثبيت
diff --git a/controller/app/src/main/res/values-az/strings.xml b/controller/app/src/main/res/values-az/strings.xml
index 62380746..fb2773a4 100644
--- a/controller/app/src/main/res/values-az/strings.xml
+++ b/controller/app/src/main/res/values-az/strings.xml
@@ -1314,4 +1314,9 @@
Daha çox yüklə
%1$d kitab göstərilir
Hamısı budur · %1$d kitab
+ Hələ də işləyir — bu, adətən olduğundan daha uzun çəkir. Gözləyə, yaxud ləğv edib yenidən cəhd edə bilərsiniz.
+ Quraşdırma dayandırılsın?
+ İndiyədək edilənlər geri qaytarılır və modul quraşdırılmayacaq. Onu sonra yenidən başlada bilərsiniz.
+ Quraşdırmanı dayandır
+ Quraşdırmaya davam et
diff --git a/controller/app/src/main/res/values-bg/strings.xml b/controller/app/src/main/res/values-bg/strings.xml
index 3cd970df..d38407fb 100644
--- a/controller/app/src/main/res/values-bg/strings.xml
+++ b/controller/app/src/main/res/values-bg/strings.xml
@@ -1301,4 +1301,9 @@
Зареди още
Показани %1$d книги
Това е всичко · %1$d книги
+ Все още работи — отнема повече време от обичайното. Можете да изчакате или да откажете и опитате отново.
+ Спиране на инсталацията?
+ Направеното дотук се връща назад и модулът няма да бъде инсталиран. Можете да го стартирате отново по-късно.
+ Спри
+ Продължи инсталацията
diff --git a/controller/app/src/main/res/values-bn/strings.xml b/controller/app/src/main/res/values-bn/strings.xml
index 70aa6314..a5f6bd26 100644
--- a/controller/app/src/main/res/values-bn/strings.xml
+++ b/controller/app/src/main/res/values-bn/strings.xml
@@ -1307,4 +1307,9 @@
আরও লোড করুন
%1$d টি বই দেখানো হচ্ছে
এটুকুই · %1$d টি বই
+ এখনও চলছে — এটি স্বাভাবিকের চেয়ে বেশি সময় নিচ্ছে। আপনি অপেক্ষা করতে পারেন, অথবা বাতিল করে আবার চেষ্টা করতে পারেন।
+ ইনস্টল করা বন্ধ করবেন?
+ এ পর্যন্ত যা হয়েছে তা পূর্বাবস্থায় ফিরিয়ে আনা হয় এবং মডিউলটি ইনস্টল হবে না। আপনি পরে আবার এটি শুরু করতে পারেন।
+ ইনস্টল বন্ধ করুন
+ ইনস্টল চালিয়ে যান
diff --git a/controller/app/src/main/res/values-cs/strings.xml b/controller/app/src/main/res/values-cs/strings.xml
index 46619322..6710a80d 100644
--- a/controller/app/src/main/res/values-cs/strings.xml
+++ b/controller/app/src/main/res/values-cs/strings.xml
@@ -1301,4 +1301,9 @@
Načíst další
Zobrazeno %1$d knih
To je vše · %1$d knih
+ Stále probíhá — trvá to déle než obvykle. Můžete počkat, nebo zrušit a zkusit to znovu.
+ Zastavit instalaci?
+ Dosud provedené se vrátí zpět a modul se nenainstaluje. Můžete jej spustit znovu později.
+ Zastavit
+ Pokračovat v instalaci
diff --git a/controller/app/src/main/res/values-de/strings.xml b/controller/app/src/main/res/values-de/strings.xml
index b6d74167..7542c3ec 100644
--- a/controller/app/src/main/res/values-de/strings.xml
+++ b/controller/app/src/main/res/values-de/strings.xml
@@ -1294,4 +1294,9 @@
Mehr laden
%1$d Bücher angezeigt
Das ist alles · %1$d Bücher
+ Läuft noch — das dauert länger als üblich. Du kannst warten oder abbrechen und erneut versuchen.
+ Installation abbrechen?
+ Das bisher Erledigte wird zurückgesetzt und das Modul wird nicht installiert. Du kannst es später erneut starten.
+ Abbrechen
+ Weiter installieren
diff --git a/controller/app/src/main/res/values-el/strings.xml b/controller/app/src/main/res/values-el/strings.xml
index cc2c19c0..204ccc0b 100644
--- a/controller/app/src/main/res/values-el/strings.xml
+++ b/controller/app/src/main/res/values-el/strings.xml
@@ -1301,4 +1301,9 @@
Φόρτωση περισσότερων
Εμφανίζονται %1$d βιβλία
Αυτά ήταν όλα · %1$d βιβλία
+ Ακόμη σε εξέλιξη — καθυστερεί περισσότερο από το συνηθισμένο. Μπορείτε να περιμένετε ή να ακυρώσετε και να δοκιμάσετε ξανά.
+ Διακοπή εγκατάστασης;
+ Ό,τι έγινε μέχρι τώρα αναιρείται και η μονάδα δεν θα εγκατασταθεί. Μπορείτε να την ξεκινήσετε ξανά αργότερα.
+ Διακοπή
+ Συνέχιση εγκατάστασης
diff --git a/controller/app/src/main/res/values-es/strings.xml b/controller/app/src/main/res/values-es/strings.xml
index 8f30400c..0611fa68 100644
--- a/controller/app/src/main/res/values-es/strings.xml
+++ b/controller/app/src/main/res/values-es/strings.xml
@@ -1370,4 +1370,9 @@
Cargar más
Mostrando %1$d libros
Eso es todo · %1$d libros
+ Sigue trabajando — está tardando más de lo normal. Puedes seguir esperando, o cancelar y reintentar.
+ ¿Detener la instalación?
+ Lo hecho hasta ahora se revierte y el módulo no se instalará. Puedes iniciarlo de nuevo después.
+ Detener instalación
+ Seguir instalando
diff --git a/controller/app/src/main/res/values-fa/strings.xml b/controller/app/src/main/res/values-fa/strings.xml
index a61a398f..ff8cad4f 100644
--- a/controller/app/src/main/res/values-fa/strings.xml
+++ b/controller/app/src/main/res/values-fa/strings.xml
@@ -1294,4 +1294,9 @@
بارگذاری بیشتر
نمایش %1$d کتاب
همین · %1$d کتاب
+ هنوز در حال کار است — بیش از حد معمول طول میکشد. میتوانید صبر کنید یا لغو کرده و دوباره تلاش کنید.
+ نصب متوقف شود؟
+ کارهای انجامشده تا کنون بازگردانده میشود و ماژول نصب نخواهد شد. میتوانید بعداً دوباره آن را شروع کنید.
+ توقف نصب
+ ادامه نصب
diff --git a/controller/app/src/main/res/values-fr/strings.xml b/controller/app/src/main/res/values-fr/strings.xml
index 5bc1d863..aa121355 100644
--- a/controller/app/src/main/res/values-fr/strings.xml
+++ b/controller/app/src/main/res/values-fr/strings.xml
@@ -1381,4 +1381,9 @@
Charger plus
%1$d livres affichés
C\'est tout · %1$d livres
+ Toujours en cours — cela prend plus de temps que d\'habitude. Vous pouvez patienter, ou annuler et réessayer.
+ Arrêter l\'installation ?
+ Ce qui a été fait jusqu\'ici est annulé et le module ne sera pas installé. Vous pourrez le relancer plus tard.
+ Arrêter
+ Continuer
diff --git a/controller/app/src/main/res/values-gu/strings.xml b/controller/app/src/main/res/values-gu/strings.xml
index eb72bc0b..a0f8e7b3 100644
--- a/controller/app/src/main/res/values-gu/strings.xml
+++ b/controller/app/src/main/res/values-gu/strings.xml
@@ -1307,4 +1307,9 @@
વધુ લોડ કરો
%1$d પુસ્તકો બતાવ્યાં
એટલું જ · %1$d પુસ્તકો
+ હજી ચાલી રહ્યું છે — સામાન્ય કરતાં વધુ સમય લાગી રહ્યો છે. તમે રાહ જોઈ શકો છો, અથવા રદ કરીને ફરી પ્રયાસ કરી શકો છો.
+ ઇન્સ્ટોલ કરવાનું બંધ કરવું છે?
+ અત્યાર સુધી થયેલું પાછું વળે છે અને મોડ્યુલ ઇન્સ્ટોલ થશે નહીં. તમે તેને પછીથી ફરી શરૂ કરી શકો છો.
+ ઇન્સ્ટોલ બંધ કરો
+ ઇન્સ્ટોલ ચાલુ રાખો
diff --git a/controller/app/src/main/res/values-hi/strings.xml b/controller/app/src/main/res/values-hi/strings.xml
index 17c63e66..c7c09444 100644
--- a/controller/app/src/main/res/values-hi/strings.xml
+++ b/controller/app/src/main/res/values-hi/strings.xml
@@ -1371,4 +1371,9 @@
और लोड करें
%1$d किताबें दिखाई जा रही हैं
बस इतना ही · %1$d किताबें
+ अभी भी चल रहा है — इसमें सामान्य से ज़्यादा समय लग रहा है. आप प्रतीक्षा कर सकते हैं, या रद्द करके फिर से कोशिश कर सकते हैं.
+ इंस्टॉल करना रोकें?
+ अब तक जो हुआ है वह पूर्ववत हो जाता है और मॉड्यूल इंस्टॉल नहीं होगा. आप इसे बाद में फिर से शुरू कर सकते हैं.
+ इंस्टॉल रोकें
+ इंस्टॉल जारी रखें
diff --git a/controller/app/src/main/res/values-hu/strings.xml b/controller/app/src/main/res/values-hu/strings.xml
index c3be8b4b..9a949172 100644
--- a/controller/app/src/main/res/values-hu/strings.xml
+++ b/controller/app/src/main/res/values-hu/strings.xml
@@ -1294,4 +1294,9 @@
Továbbiak betöltése
%1$d könyv megjelenítve
Ennyi · %1$d könyv
+ Még dolgozik — a szokásosnál tovább tart. Várhatsz, vagy megszakíthatod és újrapróbálhatod.
+ Leállítod a telepítést?
+ Az eddigiek visszavonásra kerülnek, és a modul nem lesz telepítve. Később újraindíthatod.
+ Leállítás
+ Telepítés folytatása
diff --git a/controller/app/src/main/res/values-in/strings.xml b/controller/app/src/main/res/values-in/strings.xml
index 92330824..fdea3091 100644
--- a/controller/app/src/main/res/values-in/strings.xml
+++ b/controller/app/src/main/res/values-in/strings.xml
@@ -1301,4 +1301,9 @@
Muat lebih banyak
Menampilkan %1$d buku
Itu saja · %1$d buku
+ Masih berjalan — ini memakan waktu lebih lama dari biasanya. Anda dapat menunggu, atau membatalkan dan mencoba lagi.
+ Hentikan pemasangan?
+ Yang sudah dilakukan sejauh ini dibatalkan dan modul tidak akan dipasang. Anda dapat memulainya lagi nanti.
+ Hentikan pemasangan
+ Lanjutkan pemasangan
diff --git a/controller/app/src/main/res/values-it/strings.xml b/controller/app/src/main/res/values-it/strings.xml
index 3704f639..8a54b1b5 100644
--- a/controller/app/src/main/res/values-it/strings.xml
+++ b/controller/app/src/main/res/values-it/strings.xml
@@ -1294,4 +1294,9 @@
Carica altro
%1$d libri mostrati
È tutto · %1$d libri
+ Ancora in corso — sta impiegando più del solito. Puoi aspettare, oppure annullare e riprovare.
+ Interrompere l\'installazione?
+ Quanto fatto finora viene annullato e il modulo non verrà installato. Puoi riavviarlo in seguito.
+ Interrompi
+ Continua a installare
diff --git a/controller/app/src/main/res/values-ja/strings.xml b/controller/app/src/main/res/values-ja/strings.xml
index 9deb712b..557ec183 100644
--- a/controller/app/src/main/res/values-ja/strings.xml
+++ b/controller/app/src/main/res/values-ja/strings.xml
@@ -1295,4 +1295,9 @@
もっと読み込む
%1$d 冊を表示中
以上です · %1$d 冊
+ まだ実行中です — 通常より時間がかかっています。このまま待つか、キャンセルして再試行できます。
+ インストールを停止しますか?
+ これまでの作業は元に戻され、モジュールはインストールされません。後でもう一度開始できます。
+ インストールを停止
+ インストールを続行
diff --git a/controller/app/src/main/res/values-ko/strings.xml b/controller/app/src/main/res/values-ko/strings.xml
index 5c53ea75..14fdebf9 100644
--- a/controller/app/src/main/res/values-ko/strings.xml
+++ b/controller/app/src/main/res/values-ko/strings.xml
@@ -1295,4 +1295,9 @@
더 보기
%1$d권 표시 중
여기까지입니다 · %1$d권
+ 아직 진행 중입니다 — 평소보다 오래 걸리고 있습니다. 기다리거나, 취소하고 다시 시도할 수 있습니다.
+ 설치를 중지할까요?
+ 지금까지 진행된 내용은 되돌려지고 모듈이 설치되지 않습니다. 나중에 다시 시작할 수 있습니다.
+ 설치 중지
+ 설치 계속
diff --git a/controller/app/src/main/res/values-lt/strings.xml b/controller/app/src/main/res/values-lt/strings.xml
index 6a3275b5..cbd570e3 100644
--- a/controller/app/src/main/res/values-lt/strings.xml
+++ b/controller/app/src/main/res/values-lt/strings.xml
@@ -1311,4 +1311,9 @@
Įkelti daugiau
Rodoma knygų: %1$d
Tai viskas · %1$d knygų
+ Vis dar vyksta — tai užtrunka ilgiau nei įprastai. Galite palaukti arba atšaukti ir bandyti dar kartą.
+ Stabdyti diegimą?
+ Iki šiol atlikti veiksmai atšaukiami ir modulis nebus įdiegtas. Vėliau galėsite pradėti iš naujo.
+ Stabdyti diegimą
+ Tęsti diegimą
diff --git a/controller/app/src/main/res/values-nl/strings.xml b/controller/app/src/main/res/values-nl/strings.xml
index ec92aebc..292df82d 100644
--- a/controller/app/src/main/res/values-nl/strings.xml
+++ b/controller/app/src/main/res/values-nl/strings.xml
@@ -1294,4 +1294,9 @@
Meer laden
%1$d boeken weergegeven
Dat is alles · %1$d boeken
+ Nog bezig — dit duurt langer dan normaal. Je kunt wachten, of annuleren en opnieuw proberen.
+ Installatie stoppen?
+ Wat tot nu toe is gedaan wordt teruggedraaid en de module wordt niet geïnstalleerd. Je kunt het later opnieuw starten.
+ Stoppen
+ Doorgaan met installeren
diff --git a/controller/app/src/main/res/values-no/strings.xml b/controller/app/src/main/res/values-no/strings.xml
index 6503bc98..192ec1c0 100644
--- a/controller/app/src/main/res/values-no/strings.xml
+++ b/controller/app/src/main/res/values-no/strings.xml
@@ -1304,4 +1304,9 @@
Last inn mer
Viser %1$d bøker
Det var alt · %1$d bøker
+ Fortsatt i gang — dette tar lengre tid enn vanlig. Du kan vente, eller avbryte og prøve igjen.
+ Stoppe installasjonen?
+ Det som er gjort så langt tilbakestilles, og modulen blir ikke installert. Du kan starte den på nytt senere.
+ Stopp installasjon
+ Fortsett installasjonen
diff --git a/controller/app/src/main/res/values-pl/strings.xml b/controller/app/src/main/res/values-pl/strings.xml
index 19c051b0..40ce0a24 100644
--- a/controller/app/src/main/res/values-pl/strings.xml
+++ b/controller/app/src/main/res/values-pl/strings.xml
@@ -1304,4 +1304,9 @@
Załaduj więcej
Wyświetlono %1$d książek
To wszystko · %1$d książek
+ Wciąż trwa — trwa to dłużej niż zwykle. Możesz poczekać albo anulować i spróbować ponownie.
+ Zatrzymać instalację?
+ Dotychczasowe działania zostaną cofnięte, a moduł nie zostanie zainstalowany. Możesz uruchomić go ponownie później.
+ Zatrzymaj
+ Kontynuuj instalację
diff --git a/controller/app/src/main/res/values-pt/strings.xml b/controller/app/src/main/res/values-pt/strings.xml
index 51f7fa8a..7dc86b89 100644
--- a/controller/app/src/main/res/values-pt/strings.xml
+++ b/controller/app/src/main/res/values-pt/strings.xml
@@ -1373,4 +1373,9 @@
Carregar mais
A mostrar %1$d livros
É tudo · %1$d livros
+ Ainda trabalhando — está demorando mais que o normal. Você pode aguardar, ou cancelar e tentar de novo.
+ Parar a instalação?
+ O que foi feito até agora é revertido e o módulo não será instalado. Você pode iniciá-lo novamente depois.
+ Parar instalação
+ Continuar instalando
diff --git a/controller/app/src/main/res/values-ro/strings.xml b/controller/app/src/main/res/values-ro/strings.xml
index f79c7d72..367f2c6c 100644
--- a/controller/app/src/main/res/values-ro/strings.xml
+++ b/controller/app/src/main/res/values-ro/strings.xml
@@ -1294,4 +1294,9 @@
Încarcă mai multe
%1$d cărți afișate
Asta e tot · %1$d cărți
+ Încă lucrează — durează mai mult decât de obicei. Poți aștepta sau anula și reîncerca.
+ Oprești instalarea?
+ Ce s-a făcut până acum se anulează și modulul nu va fi instalat. Îl poți porni din nou mai târziu.
+ Oprește
+ Continuă instalarea
diff --git a/controller/app/src/main/res/values-ru-rRU/strings.xml b/controller/app/src/main/res/values-ru-rRU/strings.xml
index 89ae5209..cb19f667 100644
--- a/controller/app/src/main/res/values-ru-rRU/strings.xml
+++ b/controller/app/src/main/res/values-ru-rRU/strings.xml
@@ -1370,4 +1370,9 @@
Загрузить ещё
Показано книг: %1$d
Это всё · %1$d книг
+ Ещё выполняется — это занимает больше времени, чем обычно. Можно подождать или отменить и повторить.
+ Остановить установку?
+ Сделанное до сих пор отменяется, и модуль не будет установлен. Вы сможете запустить его снова позже.
+ Остановить
+ Продолжить установку
diff --git a/controller/app/src/main/res/values-sk/strings.xml b/controller/app/src/main/res/values-sk/strings.xml
index b15ae842..d5171d5d 100644
--- a/controller/app/src/main/res/values-sk/strings.xml
+++ b/controller/app/src/main/res/values-sk/strings.xml
@@ -1301,4 +1301,9 @@
Načítať ďalšie
Zobrazených %1$d kníh
To je všetko · %1$d kníh
+ Stále prebieha — trvá to dlhšie než zvyčajne. Môžete počkať, alebo zrušiť a skúsiť znova.
+ Zastaviť inštaláciu?
+ Doteraz vykonané sa vráti späť a modul sa nenainštaluje. Môžete ho spustiť znova neskôr.
+ Zastaviť
+ Pokračovať v inštalácii
diff --git a/controller/app/src/main/res/values-sr/strings.xml b/controller/app/src/main/res/values-sr/strings.xml
index 46adb6d4..077d037d 100644
--- a/controller/app/src/main/res/values-sr/strings.xml
+++ b/controller/app/src/main/res/values-sr/strings.xml
@@ -1307,4 +1307,9 @@
Учитај још
Приказано %1$d књига
То је све · %1$d књига
+ Још увек ради — траје дуже него обично. Можете сачекати или отказати и покушати поново.
+ Зауставити инсталацију?
+ Оно што је до сада урађено се поништава и модул неће бити инсталиран. Можете га поново покренути касније.
+ Заустави
+ Настави инсталацију
diff --git a/controller/app/src/main/res/values-sw/strings.xml b/controller/app/src/main/res/values-sw/strings.xml
index 5e27f12c..1453d267 100644
--- a/controller/app/src/main/res/values-sw/strings.xml
+++ b/controller/app/src/main/res/values-sw/strings.xml
@@ -1314,4 +1314,9 @@
Pakia zaidi
Inaonyesha vitabu %1$d
Ndio hivyo · vitabu %1$d
+ Bado inaendelea — inachukua muda mrefu kuliko kawaida. Unaweza kusubiri, au kughairi na kujaribu tena.
+ Kusimamisha usakinishaji?
+ Yaliyofanyika hadi sasa yanabatilishwa na moduli haitasakinishwa. Unaweza kuanza tena baadaye.
+ Simamisha usakinishaji
+ Endelea kusakinisha
diff --git a/controller/app/src/main/res/values-ta/strings.xml b/controller/app/src/main/res/values-ta/strings.xml
index 6991df67..7d5da6c8 100644
--- a/controller/app/src/main/res/values-ta/strings.xml
+++ b/controller/app/src/main/res/values-ta/strings.xml
@@ -1314,4 +1314,9 @@
மேலும் ஏற்று
%1$d புத்தகங்கள் காட்டப்படுகின்றன
இவ்வளவுதான் · %1$d புத்தகங்கள்
+ இன்னும் இயங்குகிறது — வழக்கத்தை விட அதிக நேரம் எடுக்கிறது. நீங்கள் காத்திருக்கலாம் அல்லது ரத்து செய்து மீண்டும் முயற்சிக்கலாம்.
+ நிறுவலை நிறுத்தவா?
+ இதுவரை செய்தது மீட்டமைக்கப்படும், தொகுதி நிறுவப்படாது. பிறகு மீண்டும் தொடங்கலாம்.
+ நிறுவலை நிறுத்து
+ நிறுவலைத் தொடர்
diff --git a/controller/app/src/main/res/values-tr/strings.xml b/controller/app/src/main/res/values-tr/strings.xml
index dbe64dc0..3143e2eb 100644
--- a/controller/app/src/main/res/values-tr/strings.xml
+++ b/controller/app/src/main/res/values-tr/strings.xml
@@ -1294,4 +1294,9 @@
Daha fazla yükle
%1$d kitap gösteriliyor
Hepsi bu · %1$d kitap
+ Hâlâ çalışıyor — bu her zamankinden uzun sürüyor. Bekleyebilir ya da iptal edip yeniden deneyebilirsiniz.
+ Kurulum durdurulsun mu?
+ Şimdiye kadar yapılanlar geri alınır ve modül kurulmaz. Daha sonra yeniden başlatabilirsiniz.
+ Kurulumu durdur
+ Kuruluma devam et
diff --git a/controller/app/src/main/res/values-uk/strings.xml b/controller/app/src/main/res/values-uk/strings.xml
index 19c86de6..a3b06ed8 100644
--- a/controller/app/src/main/res/values-uk/strings.xml
+++ b/controller/app/src/main/res/values-uk/strings.xml
@@ -1294,4 +1294,9 @@
Завантажити ще
Показано книг: %1$d
Це все · %1$d книг
+ Ще триває — це займає більше часу, ніж зазвичай. Можна зачекати або скасувати та повторити.
+ Зупинити встановлення?
+ Зроблене досі скасовується, і модуль не буде встановлено. Ви зможете запустити його знову пізніше.
+ Зупинити
+ Продовжити встановлення
diff --git a/controller/app/src/main/res/values-vi/strings.xml b/controller/app/src/main/res/values-vi/strings.xml
index f6d3097c..61c47a0b 100644
--- a/controller/app/src/main/res/values-vi/strings.xml
+++ b/controller/app/src/main/res/values-vi/strings.xml
@@ -1294,4 +1294,9 @@
Tải thêm
Đang hiển thị %1$d cuốn sách
Hết rồi · %1$d cuốn sách
+ Vẫn đang chạy — việc này lâu hơn bình thường. Bạn có thể chờ, hoặc hủy và thử lại.
+ Dừng cài đặt?
+ Những gì đã làm đến giờ sẽ được hoàn tác và mô-đun sẽ không được cài đặt. Bạn có thể bắt đầu lại sau.
+ Dừng cài đặt
+ Tiếp tục cài đặt
diff --git a/controller/app/src/main/res/values-yo/strings.xml b/controller/app/src/main/res/values-yo/strings.xml
index 29c618a0..51d5fb4b 100644
--- a/controller/app/src/main/res/values-yo/strings.xml
+++ b/controller/app/src/main/res/values-yo/strings.xml
@@ -1314,4 +1314,9 @@
Gbé afikun wọlé
Ń fi ìwé %1$d hàn
Ìyẹn ni gbogbo rẹ̀ · ìwé %1$d
+ Ó ṣì ń ṣiṣẹ́ — ó ń gba àkókò ju bí ó ṣe máa ń rí lọ. O lè dúró, tàbí fagilé kí o sì gbìyànjú lẹ́ẹ̀kansí.
+ Ṣé kí a dá fífi sórí ẹ̀rọ dúró?
+ Ohun tí a ti ṣe títí di báyìí ni a ó yí padà, a kì yóò sì fi módùlù náà sórí ẹ̀rọ. O lè bẹ̀rẹ̀ rẹ̀ lẹ́ẹ̀kansí lẹ́yìn náà.
+ Dá dúró
+ Máa bá a lọ
diff --git a/controller/app/src/main/res/values-zh-rCN/strings.xml b/controller/app/src/main/res/values-zh-rCN/strings.xml
index d04bef6e..f4281372 100644
--- a/controller/app/src/main/res/values-zh-rCN/strings.xml
+++ b/controller/app/src/main/res/values-zh-rCN/strings.xml
@@ -1295,4 +1295,9 @@
加载更多
正在显示 %1$d 本书
就这些 · %1$d 本书
+ 仍在进行 — 用时比平常长。您可以继续等待,或取消并重试。
+ 停止安装?
+ 目前所做的更改将被撤销,模块不会被安装。您稍后可以重新开始。
+ 停止安装
+ 继续安装
diff --git a/controller/app/src/main/res/values/strings.xml b/controller/app/src/main/res/values/strings.xml
index c357b85d..b2e08c97 100644
--- a/controller/app/src/main/res/values/strings.xml
+++ b/controller/app/src/main/res/values/strings.xml
@@ -1474,4 +1474,9 @@
Done — go to my library
%1$d course(s) didn\'t finish.
Retry the ones that failed before you leave — leaving clears this list.
+ Still working — this is taking longer than usual. You can keep waiting, or cancel and retry.
+ Stop installing?
+ What\'s been done so far is rolled back and the module won\'t be installed. You can start it again afterward.
+ Stop install
+ Keep installing