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