diff --git a/controller/app/src/main/java/org/iiab/controller/redesign/BackupJobFragment.java b/controller/app/src/main/java/org/iiab/controller/redesign/BackupJobFragment.java index 564c9c32..e2ed026c 100644 --- a/controller/app/src/main/java/org/iiab/controller/redesign/BackupJobFragment.java +++ b/controller/app/src/main/java/org/iiab/controller/redesign/BackupJobFragment.java @@ -3,19 +3,17 @@ * Name : BackupJobFragment.java * Author : AppDevForAll * Copyright : Copyright (c) 2026 AppDevForAll - * Description : ADFA-4952 / ADFA-4957. Dedicated per-operation screen for Backup OR Restore (mode arg), - * with the shared "working" Lottie + an animated status line. The heavy, kill-sensitive - * work is now OWNED by the foreground DeepOpService (not this Fragment): the screen just - * starts it and OBSERVES DeepOpProgressRepository — the app-scoped single source of truth - * — so the UI (status line, hard gate, Done) re-binds after a recreation or backgrounding - * and a notification tap can land back here. + * Description : ADFA-4952 / 4957 / 4961. Backup OR Restore operation screen (mode arg), styled as a + * compact copy of the module-install template (fragment_k2go_backup_job.xml): title + + * subtitle, the shared working Lottie with the app logo, a fixed 2-line status line, the + * "this takes time" card, and a Finish button. There is no Start button — the intro card + * is the trigger, so this screen auto-opens the file picker on a fresh entry. * - * Backup: SAF CreateDocument -> DeepOpService.startBackup (stop -> stream tar|gzip -> done). - * Restore: SAF OpenDocument -> copy to temp + validate + destructive confirm HERE (the - * pre-extract work is safe to lose on a kill) -> DeepOpService.startRestore (stop -> - * extract -> done). The service brackets EnvironmentLock (+ InstallGuard for restore); it - * does NOT boot the environment — LibraryActivity's auto-start boots it when the user - * returns Home (a failed restore keeps InstallGuard set, so recovery repairs it instead). + * Flow: pick (SAF) -> DeepOpService owns the kill-sensitive work off the UI -> this screen + * observes DeepOpProgressRepository (re-binds after recreation / notification return). At + * the terminal state it shows the result and STAYS (like the module card); Finish returns + * to the bifurcation (BackupRestoreFragment), which then runs the index-style "returning + * to Home" countdown. Back while running is consumed with a styled snackbar (hard gate). * ============================================================================ */ package org.iiab.controller.redesign; @@ -24,12 +22,9 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; -import android.widget.LinearLayout; import android.widget.TextView; import androidx.activity.result.ActivityResultLauncher; @@ -37,20 +32,18 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; -import androidx.core.widget.NestedScrollView; import androidx.fragment.app.Fragment; import com.airbnb.lottie.LottieAnimationView; -import com.airbnb.lottie.LottieDrawable; import org.iiab.controller.R; -import org.iiab.controller.backup.domain.BackupEngine; import org.iiab.controller.deepop.DeepOpProgressRepository; import org.iiab.controller.deepop.DeepOpService; import org.iiab.controller.deepop.DeepOpState; import org.iiab.controller.env.EnvironmentLock; import org.iiab.controller.ui.dialog.BrandDialog; import org.iiab.controller.util.AppExecutors; +import org.iiab.controller.util.Snackbars; import java.io.File; import java.io.InputStream; @@ -73,25 +66,21 @@ public static BackupJobFragment newInstance(String mode) { private final Handler main = new Handler(Looper.getMainLooper()); private String mode; private LottieAnimationView anim; - private TextView title, status; - private Button primary, done; + private TextView title, sub, status, finish; private org.iiab.controller.util.EllipsisAnimator statusDots; private boolean running = false; - private long lastSeq = -1L; // ADFA-4957: only react to NEW terminal transitions from the repo - // ADFA-4952: hard gate — while an op runs, back is consumed so a half-applied backup/restore can't - // be abandoned. Enabled only while running. + private long lastSeq = -1L; private androidx.activity.OnBackPressedCallback backGate; private final ActivityResultLauncher createDoc = registerForActivityResult(new ActivityResultContracts.CreateDocument("application/gzip"), uri -> { - if (uri != null) startBackup(uri); else showReady(); + if (uri != null) startBackup(uri); else popToIntro(false); }); private final ActivityResultLauncher openDoc = registerForActivityResult(new ActivityResultContracts.OpenDocument(), uri -> { - if (uri != null) prepareRestore(uri); else showReady(); + if (uri != null) prepareRestore(uri); else popToIntro(false); }); - private int px(int dp) { return Math.round(dp * getResources().getDisplayMetrics().density); } private boolean isRestore() { return MODE_RESTORE.equals(mode); } private EnvironmentLock.Owner myOwner() { return isRestore() ? EnvironmentLock.Owner.RESTORE : EnvironmentLock.Owner.BACKUP; } @@ -99,108 +88,62 @@ public static BackupJobFragment newInstance(String mode) { @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle s) { mode = getArguments() != null ? getArguments().getString(ARG_MODE, MODE_BACKUP) : MODE_BACKUP; - - NestedScrollView scroll = new NestedScrollView(requireContext()); - scroll.setFillViewport(true); - LinearLayout col = new LinearLayout(requireContext()); - col.setOrientation(LinearLayout.VERTICAL); - col.setGravity(Gravity.CENTER_HORIZONTAL); - col.setPadding(px(24), px(20), px(24), px(24)); - scroll.addView(col, new NestedScrollView.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - - TextView back = new TextView(requireContext()); - back.setText(getString(R.string.k2go_back_link)); - back.setTextColor(ContextCompat.getColor(requireContext(), R.color.k2go_teal)); - back.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyMedium); - LinearLayout.LayoutParams blp = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - back.setLayoutParams(blp); - back.setOnClickListener(v -> { if (!running) requireActivity().getOnBackPressedDispatcher().onBackPressed(); }); - col.addView(back); - - anim = new LottieAnimationView(requireContext()); - anim.setAnimation(R.raw.k2go_working_loop); - anim.setRepeatCount(LottieDrawable.INFINITE); - LinearLayout.LayoutParams alp = new LinearLayout.LayoutParams(px(180), px(180)); - alp.topMargin = px(24); - col.addView(anim, alp); - - title = new TextView(requireContext()); - title.setGravity(Gravity.CENTER); - title.setTypeface(title.getTypeface(), android.graphics.Typeface.BOLD); - title.setTextColor(ContextCompat.getColor(requireContext(), R.color.k2go_ink)); - title.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_HeadlineSmall); - LinearLayout.LayoutParams tlp = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - tlp.topMargin = px(16); - col.addView(title, tlp); - - status = new TextView(requireContext()); - status.setGravity(Gravity.CENTER); - status.setTextColor(ContextCompat.getColor(requireContext(), R.color.k2go_muted)); - status.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyMedium); - LinearLayout.LayoutParams slp = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - slp.topMargin = px(10); - col.addView(status, slp); + View v = inflater.inflate(R.layout.fragment_k2go_backup_job, container, false); + anim = v.findViewById(R.id.k2go_bj_anim); + // ADFA-4961: mode-specific working loop (box + streaming dots + glow); the app logo is composited + // on top by the layout scaffold, same as the module-install template. + anim.setAnimation(isRestore() ? R.raw.k2go_restore_loop : R.raw.k2go_backup_loop); + anim.setRepeatCount(com.airbnb.lottie.LottieDrawable.INFINITE); + anim.playAnimation(); + title = v.findViewById(R.id.k2go_bj_title); + sub = v.findViewById(R.id.k2go_bj_sub); + status = v.findViewById(R.id.k2go_bj_status); + finish = v.findViewById(R.id.k2go_bj_finish); statusDots = new org.iiab.controller.util.EllipsisAnimator(status); - primary = new Button(requireContext()); - LinearLayout.LayoutParams plp = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - plp.topMargin = px(28); - col.addView(primary, plp); - primary.setOnClickListener(v -> onPrimary()); - - done = new Button(requireContext()); - done.setText(getString(R.string.k2go_br_done)); - LinearLayout.LayoutParams donelp = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - donelp.topMargin = px(16); - col.addView(done, donelp); - done.setVisibility(View.GONE); - done.setOnClickListener(v -> goLibraryHome()); + title.setText(getString(isRestore() ? R.string.k2go_br_restore_title : R.string.k2go_br_backup_title)); + sub.setText(getString(isRestore() ? R.string.k2go_br_restore_sub : R.string.k2go_br_backup_sub)); + finish.setOnClickListener(x -> popToIntro(true)); - // ADFA-4952: intercept system/gesture back too (the back link already guards on `running`). + // Hard gate: while the op runs, back is consumed with a styled snackbar (module-index behavior). backGate = new androidx.activity.OnBackPressedCallback(false) { @Override public void handleOnBackPressed() { - android.widget.Toast.makeText(requireContext(), getString(R.string.k2go_br_busy_wait), - android.widget.Toast.LENGTH_SHORT).show(); + // ADFA-4961 (B): the op keeps running in DeepOpService, so leaving doesn't interrupt it. + // Show a soft, mode-specific hint (anchored to the activity so it survives the pop) and + // return to the bifurcation — no hard block. The notification brings the user back. + Snackbars.make(requireActivity().findViewById(android.R.id.content), + isRestore() ? R.string.k2go_br_leave_restore : R.string.k2go_br_leave_backup).show(); + popToIntro(false); } }; requireActivity().getOnBackPressedDispatcher().addCallback(getViewLifecycleOwner(), backGate); - showReady(); - // ADFA-4957: bind to the app-scoped op state. Seed lastSeq so a terminal from a PREVIOUS op - // (already the current value) doesn't fire a stale "done"; only new transitions count. - lastSeq = DeepOpProgressRepository.get().current().seq; + DeepOpState cur = DeepOpProgressRepository.get().current(); + lastSeq = cur.seq; DeepOpProgressRepository.get().state().observe(getViewLifecycleOwner(), this::onDeepOpState); - return scroll; - } - /** Idle "ready to start" state: title + warning + a Start button. */ - private void showReady() { - running = false; - if (backGate != null) backGate.setEnabled(false); // ADFA-4952: idle → back allowed - if (statusDots != null) statusDots.stop(); - title.setText(getString(isRestore() ? R.string.k2go_br_restore_title : R.string.k2go_br_backup_title)); - status.setText(getString(R.string.k2go_br_backup_warn)); // both stop the server - status.setVisibility(View.VISIBLE); - primary.setText(getString(isRestore() ? R.string.k2go_br_restore_pick : R.string.k2go_br_start)); - primary.setVisibility(View.VISIBLE); - done.setVisibility(View.GONE); - if (anim != null) { anim.setProgress(0f); anim.pauseAnimation(); } + if (cur.owner == myOwner() && cur.isRunning()) { + beginRunning(); // deep-link / recreation into a live op + setStatusAnimated(cur.step); + } else if (s != null && cur.owner == myOwner() && cur.isTerminal()) { + showTerminal(cur.phase == DeepOpState.Phase.SUCCESS, cur.message); // recreated at the result + } else if (s == null) { + v.post(this::launchPicker); // fresh entry: the intro card is the Start + } + return v; } - private void onPrimary() { - if (running) return; - if (EnvironmentLock.isHeld(requireContext())) { setStatusStatic(getString(R.string.k2go_install_busy)); return; } + private void launchPicker() { + if (EnvironmentLock.isHeld(requireContext())) { // another deep-env op owns the environment + Snackbars.make(requireView(), R.string.k2go_install_busy).show(); + popToIntro(false); + return; + } if (isRestore()) openDoc.launch(new String[]{"application/gzip", "application/x-gzip", "*/*"}); - else createDoc.launch(BackupEngine.suggestedFileName(requireContext())); + else createDoc.launch(org.iiab.controller.backup.domain.BackupEngine.suggestedFileName(requireContext())); } - // ---- BACKUP: hand off to the service; the observer drives the UI from here ---- + // ---- BACKUP ---- private void startBackup(Uri uri) { if (!isAdded()) return; beginRunning(); @@ -208,13 +151,12 @@ private void startBackup(Uri uri) { DeepOpService.startBackup(requireContext(), uri); } - // ---- RESTORE: copy + validate + confirm HERE (pre-extract, safe to lose), then the service ---- + // ---- RESTORE: copy + validate + destructive confirm HERE (pre-extract), then the service ---- private void prepareRestore(Uri uri) { if (!isAdded()) return; beginRunning(); setStatusAnimated(getString(R.string.k2go_br_status_checking)); AppExecutors.get().io().execute(() -> { - // Copy the SAF stream to a temp file — the validator (and the service's extractor) need a path. File temp = new File(requireContext().getCacheDir(), "restore.tar.gz"); boolean copied = false; try (InputStream in = requireContext().getContentResolver().openInputStream(uri); @@ -242,10 +184,9 @@ private void onValidated(File temp, org.iiab.controller.deploy.data.RootfsArchiv int msg = vr == org.iiab.controller.deploy.data.RootfsArchiveValidator.Result.WRONG_ARCH ? R.string.install_error_wrong_arch : vr == org.iiab.controller.deploy.data.RootfsArchiveValidator.Result.CORRUPT ? R.string.install_error_corrupt : R.string.install_error_not_rootfs; - finishResult(false, getString(msg)); + showTerminal(false, getString(msg)); return; } - // Valid → confirm the destructive replace, then hand the validated temp path to the service. new BrandDialog(requireContext()) .setTitle(getString(R.string.k2go_br_restore_title)) .setMessage(getString(R.string.k2go_br_restore_warn)) @@ -253,67 +194,59 @@ private void onValidated(File temp, org.iiab.controller.deploy.data.RootfsArchiv setStatusAnimated(getString(R.string.k2go_br_status_stopping)); DeepOpService.startRestore(requireContext(), temp.getAbsolutePath()); }) - .setNegative(R.string.cancel, () -> { if (temp.exists()) temp.delete(); showReady(); }) + .setNegative(R.string.cancel, () -> { if (temp.exists()) temp.delete(); popToIntro(false); }) .show(); } - // ---- observe the app-scoped op state (the service is the writer) ---- + // ---- observe the app-scoped op state (DeepOpService is the writer) ---- private void onDeepOpState(DeepOpState st) { - if (st == null || !isAdded()) return; - if (st.owner != myOwner()) return; // ignore an op for the other direction + if (st == null || !isAdded() || st.owner != myOwner()) return; if (st.isRunning()) { if (!running) beginRunning(); setStatusAnimated(st.step); } else if (st.isTerminal() && st.seq > lastSeq) { lastSeq = st.seq; - finishResult(st.phase == DeepOpState.Phase.SUCCESS, st.message); + showTerminal(st.phase == DeepOpState.Phase.SUCCESS, st.message); } } private void beginRunning() { running = true; - if (backGate != null) backGate.setEnabled(true); // ADFA-4952: hard gate on - primary.setVisibility(View.GONE); - done.setVisibility(View.GONE); - if (anim != null && !reduceMotion()) { anim.setRepeatCount(LottieDrawable.INFINITE); anim.playAnimation(); } + if (backGate != null) backGate.setEnabled(true); + finish.setVisibility(View.GONE); + if (anim != null) anim.playAnimation(); } - private void finishResult(boolean ok, String message) { + private void showTerminal(boolean ok, String message) { running = false; - if (backGate != null) backGate.setEnabled(false); // ADFA-4952: done → back allowed (Done button) - if (anim != null) anim.pauseAnimation(); + if (backGate != null) backGate.setEnabled(false); // done → back / Finish returns to the bifurcation if (statusDots != null) statusDots.stop(); + if (anim != null) anim.pauseAnimation(); title.setText(getString(ok ? R.string.k2go_br_done_title : R.string.k2go_br_failed_title)); status.setText(message); status.setTextColor(ContextCompat.getColor(requireContext(), ok ? R.color.k2go_leaf : R.color.k2go_amber_text)); - status.setVisibility(View.VISIBLE); - done.setVisibility(View.VISIBLE); - primary.setVisibility(View.GONE); + finish.setVisibility(View.VISIBLE); } private void setStatusAnimated(String text) { status.setTextColor(ContextCompat.getColor(requireContext(), R.color.k2go_muted)); - status.setVisibility(View.VISIBLE); if (statusDots != null) statusDots.start(text); } - private void setStatusStatic(String text) { - if (statusDots != null) statusDots.stop(); - status.setText(text); - status.setVisibility(View.VISIBLE); - } - - private void goLibraryHome() { - startActivity(new android.content.Intent(requireContext(), LibraryActivity.class) - .addFlags(android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP | android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP) - .putExtra(LibraryActivity.EXTRA_TAB, R.id.nav_library)); - requireActivity().finish(); - } - private boolean reduceMotion() { - try { - return android.provider.Settings.Global.getFloat(requireContext().getContentResolver(), - android.provider.Settings.Global.ANIMATOR_DURATION_SCALE, 1f) == 0f; - } catch (Exception e) { return false; } + /** Return to the bifurcation (BackupRestoreFragment). When {@code fromFinish}, arm the intro's + * index-style "returning to Home" countdown. */ + private void popToIntro(boolean fromFinish) { + if (!isAdded()) return; + if (fromFinish) BackupRestoreFragment.armReturnCountdown(); + androidx.fragment.app.FragmentManager fm = requireActivity().getSupportFragmentManager(); + if (fm.getBackStackEntryCount() > 0) { + fm.popBackStack(); + } else { + // Deep-linked straight to the job screen (no bifurcation underneath, e.g. the notification + // reopen) — show the bifurcation so Finish always lands there (which then runs the countdown + // to Home), never jumping straight Home. + fm.beginTransaction().replace(R.id.k2go_setup_host, new BackupRestoreFragment()).commit(); + } } @Override public void onDestroyView() { diff --git a/controller/app/src/main/java/org/iiab/controller/redesign/BackupRestoreFragment.java b/controller/app/src/main/java/org/iiab/controller/redesign/BackupRestoreFragment.java index a97cf6e3..7652d345 100644 --- a/controller/app/src/main/java/org/iiab/controller/redesign/BackupRestoreFragment.java +++ b/controller/app/src/main/java/org/iiab/controller/redesign/BackupRestoreFragment.java @@ -3,18 +3,25 @@ * Name : BackupRestoreFragment.java * Author : AppDevForAll * Copyright : Copyright (c) 2026 AppDevForAll - * Description : ADFA-4952. Backup & restore intro — a Clone-style screen: title + description + - * "what do you want to do?" with two cards (Back up / Restore). Each card opens its own - * dedicated job screen (BackupJobFragment) with the working Lottie + status. Hosted in - * SetupLibraryActivity (which owns the ServerController + coordinates via EnvironmentLock). + * Description : ADFA-4952 / 4961. Backup & restore bifurcation — title + description + "what do you + * want to do?" with two icon cards (Back up / Restore). Tapping a card IS the Start: it + * opens BackupJobFragment, which auto-opens the file picker. ADFA-4961: after an op + * finishes and its screen taps Finish, this bifurcation shows the module-index-style + * "returning to Home" countdown with a Cancel (armed via armReturnCountdown()). Hosted in + * SetupLibraryActivity. * ============================================================================ */ package org.iiab.controller.redesign; +import android.content.Intent; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; @@ -28,6 +35,19 @@ public class BackupRestoreFragment extends Fragment { + // ADFA-4961: one-shot flag set by BackupJobFragment's Finish, consumed here to run the "returning + // to Home" countdown. Process-scoped: the bifurcation is recreated when the job screen pops. + private static boolean sReturnPending = false; + public static void armReturnCountdown() { sReturnPending = true; } + + // ADFA-4961: like the module index, wait for the environment to actually be live before redirecting. + private static final long READY_POLL_MS = 2000L; + private static final long READY_TIMEOUT_MS = 45000L; + private final Handler main = new Handler(Looper.getMainLooper()); + private Runnable readyPoll; + private boolean returnCancelled = false; + private long returnStartMs = 0L; + private int px(int dp) { return Math.round(dp * getResources().getDisplayMetrics().density); } @Nullable @@ -63,11 +83,18 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); clp.topMargin = px(10); col.addView(cards, clp); - cards.addView(card(R.string.k2go_br_backup_title, R.string.k2go_br_backup_sub, + cards.addView(card(R.drawable.ic_archive, R.string.k2go_br_backup_title, R.string.k2go_br_backup_sub, v -> open(BackupJobFragment.MODE_BACKUP))); - cards.addView(card(R.string.k2go_br_restore_title, R.string.k2go_br_restore_sub, + cards.addView(card(R.drawable.ic_unarchive, R.string.k2go_br_restore_title, R.string.k2go_br_restore_sub, v -> open(BackupJobFragment.MODE_RESTORE))); + // ADFA-4961: returning from a finished op → index-style "returning to Home" countdown + Cancel. + if (sReturnPending) { + sReturnPending = false; + col.addView(buildReturnBar()); + startReturnToHome(); + } + return scroll; } @@ -77,6 +104,79 @@ private void open(String jobMode) { } } + private View buildReturnBar() { + LinearLayout bar = new LinearLayout(requireContext()); + bar.setOrientation(LinearLayout.HORIZONTAL); + bar.setGravity(Gravity.CENTER_VERTICAL); + bar.setBackgroundResource(R.drawable.k2go_info_bg); + bar.setPadding(px(14), px(12), px(14), px(12)); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + lp.topMargin = px(16); + bar.setLayoutParams(lp); + + TextView msg = new TextView(requireContext()); + msg.setText(getString(R.string.k2go_bj_returning)); + msg.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyMedium); + // ADFA-4961: set the color AFTER the appearance — setTextAppearance() overrides textColor, which + // was leaving this line the theme's light default (invisible on the pale info background). + msg.setTextColor(ContextCompat.getColor(requireContext(), R.color.k2go_teal)); + bar.addView(msg, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f)); + + TextView cancel = new TextView(requireContext()); + cancel.setText(getString(R.string.cancel)); + cancel.setTypeface(cancel.getTypeface(), android.graphics.Typeface.BOLD); + cancel.setTextColor(ContextCompat.getColor(requireContext(), R.color.k2go_teal)); + cancel.setPadding(px(12), px(4), px(4), px(4)); + cancel.setOnClickListener(v -> { + returnCancelled = true; + if (readyPoll != null) main.removeCallbacks(readyPoll); + bar.setVisibility(View.GONE); + }); + bar.addView(cancel); + return bar; + } + + /** + * ADFA-4961: mirror the module index — boot the environment (startEnvironment, never the toggle) + * and WAIT for RestReadiness.apiReady() before redirecting, so we never drop the user on a Home that + * is still starting. Cancel keeps them here; a READY_TIMEOUT_MS fallback still goes Home so the user + * is never trapped (Home's boot gate then owns the rest). + */ + private void startReturnToHome() { + returnCancelled = false; + returnStartMs = android.os.SystemClock.elapsedRealtime(); + if (getActivity() instanceof SetupLibraryActivity) { + org.iiab.controller.ServerController sc = ((SetupLibraryActivity) getActivity()).server(); + if (sc != null) sc.startEnvironment(); + } + readyPoll = new Runnable() { + @Override public void run() { + if (returnCancelled || !isAdded()) return; + org.iiab.controller.util.AppExecutors.get().io().execute(() -> { + final boolean up = RestReadiness.apiReady(); + main.post(() -> { + if (returnCancelled || !isAdded()) return; + if (up || android.os.SystemClock.elapsedRealtime() - returnStartMs > READY_TIMEOUT_MS) { + goHome(); // live (or timed out → Home's boot gate takes over) + } else { + main.postDelayed(readyPoll, READY_POLL_MS); + } + }); + }); + } + }; + main.postDelayed(readyPoll, READY_POLL_MS); + } + + private void goHome() { + if (!isAdded()) return; + startActivity(new Intent(requireContext(), LibraryActivity.class) + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP) + .putExtra(LibraryActivity.EXTRA_TAB, R.id.nav_library)); + requireActivity().finish(); + } + private TextView heading(String text, boolean bold, int appearance, int colorRes, int topDp) { TextView t = new TextView(requireContext()); t.setText(text); @@ -90,9 +190,10 @@ private TextView heading(String text, boolean bold, int appearance, int colorRes return t; } - private View card(int titleRes, int subRes, View.OnClickListener onClick) { + private View card(int iconRes, int titleRes, int subRes, View.OnClickListener onClick) { LinearLayout row = new LinearLayout(requireContext()); - row.setOrientation(LinearLayout.VERTICAL); + row.setOrientation(LinearLayout.HORIZONTAL); + row.setGravity(Gravity.CENTER_VERTICAL); row.setBackgroundResource(R.drawable.k2go_card_bg); row.setPadding(px(16), px(16), px(16), px(16)); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( @@ -102,12 +203,23 @@ private View card(int titleRes, int subRes, View.OnClickListener onClick) { row.setClickable(true); row.setOnClickListener(onClick); + ImageView icon = new ImageView(requireContext()); + icon.setImageResource(iconRes); + icon.setColorFilter(ContextCompat.getColor(requireContext(), R.color.k2go_teal)); + LinearLayout.LayoutParams ilp = new LinearLayout.LayoutParams(px(28), px(28)); + ilp.rightMargin = px(14); + row.addView(icon, ilp); + + LinearLayout textCol = new LinearLayout(requireContext()); + textCol.setOrientation(LinearLayout.VERTICAL); + row.addView(textCol, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f)); + TextView t = new TextView(requireContext()); t.setText(getString(titleRes)); t.setTypeface(t.getTypeface(), android.graphics.Typeface.BOLD); t.setTextColor(ContextCompat.getColor(requireContext(), R.color.k2go_ink)); t.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_TitleMedium); - row.addView(t); + textCol.addView(t); TextView sub = new TextView(requireContext()); sub.setText(getString(subRes)); @@ -116,7 +228,12 @@ private View card(int titleRes, int subRes, View.OnClickListener onClick) { LinearLayout.LayoutParams slp = new LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); slp.topMargin = px(4); - row.addView(sub, slp); + textCol.addView(sub, slp); return row; } + + @Override public void onDestroyView() { + if (readyPoll != null) main.removeCallbacks(readyPoll); + super.onDestroyView(); + } } diff --git a/controller/app/src/main/res/drawable/ic_archive.xml b/controller/app/src/main/res/drawable/ic_archive.xml new file mode 100644 index 00000000..8c14e765 --- /dev/null +++ b/controller/app/src/main/res/drawable/ic_archive.xml @@ -0,0 +1,8 @@ + + + + diff --git a/controller/app/src/main/res/drawable/ic_unarchive.xml b/controller/app/src/main/res/drawable/ic_unarchive.xml new file mode 100644 index 00000000..05bafb9a --- /dev/null +++ b/controller/app/src/main/res/drawable/ic_unarchive.xml @@ -0,0 +1,8 @@ + + + + diff --git a/controller/app/src/main/res/layout/fragment_k2go_backup_job.xml b/controller/app/src/main/res/layout/fragment_k2go_backup_job.xml new file mode 100644 index 00000000..baa15a5c --- /dev/null +++ b/controller/app/src/main/res/layout/fragment_k2go_backup_job.xml @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/controller/app/src/main/res/raw/k2go_backup_loop.json b/controller/app/src/main/res/raw/k2go_backup_loop.json new file mode 100644 index 00000000..31c72afc --- /dev/null +++ b/controller/app/src/main/res/raw/k2go_backup_loop.json @@ -0,0 +1 @@ +{"layers": [{"nm": "dot0", "ddd": 0, "ty": 4, "ind": 0, "sr": 1, "ip": 0, "op": 60, "st": 0, "ks": {"a": {"k": [0, 0], "a": 0}, "p": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [492.0, 204]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [475.5, 203.53846153846155]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [459.0, 203.07692307692307]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [442.5, 202.6153846153846]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [426.0, 202.15384615384616]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [409.5, 201.69230769230768]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [393.0, 201.23076923076923]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [376.5, 200.76923076923077]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [360.0, 200.30769230769232]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [343.5, 199.84615384615384]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [327.0, 199.3846153846154]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [310.5, 198.92307692307693]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [294.0, 198.46153846153845]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [277.5, 198]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [261.0, 197.53846153846155]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [244.5, 197.07692307692307]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [228.0, 196.6153846153846]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [211.5, 196.15384615384616]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [206.0, 196]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [206.0, 196]}, {"t": 60, "s": [492.0, 204]}]}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [37.5]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [75]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [70]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [40]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [10]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 60, "s": [0]}]}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}, "ao": 0, "bm": 0, "shapes": [{"ty": "gr", "it": [{"ty": "el", "d": 1, "p": {"k": [0, 0], "a": 0}, "s": {"k": [12, 12], "a": 0}}, {"ty": "fl", "o": {"k": 100, "a": 0}, "c": {"k": [0.18, 0.62, 0.357, 1], "a": 0}}, {"ty": "tr", "a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}]}]}, {"nm": "dot1", "ddd": 0, "ty": 4, "ind": 1, "sr": 1, "ip": 0, "op": 60, "st": 0, "ks": {"a": {"k": [0, 0], "a": 0}, "p": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [244.5, 197.07692307692307]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [228.0, 196.6153846153846]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [211.5, 196.15384615384616]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [206.0, 196]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [206.0, 196]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [492.0, 204]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [475.5, 203.53846153846155]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [459.0, 203.07692307692307]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [442.5, 202.6153846153846]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [426.0, 202.15384615384616]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [409.5, 201.69230769230768]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [393.0, 201.23076923076923]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [376.5, 200.76923076923077]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [360.0, 200.30769230769232]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [343.5, 199.84615384615384]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [327.0, 199.3846153846154]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [310.5, 198.92307692307693]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [294.0, 198.46153846153845]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [277.5, 198]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [261.0, 197.53846153846155]}, {"t": 60, "s": [244.5, 197.07692307692307]}]}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [70]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [40]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [10]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [37.5]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [75]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 60, "s": [70]}]}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}, "ao": 0, "bm": 0, "shapes": [{"ty": "gr", "it": [{"ty": "el", "d": 1, "p": {"k": [0, 0], "a": 0}, "s": {"k": [12, 12], "a": 0}}, {"ty": "fl", "o": {"k": 100, "a": 0}, "c": {"k": [0.949, 0.635, 0.235, 1], "a": 0}}, {"ty": "tr", "a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}]}]}, {"nm": "dot2", "ddd": 0, "ty": 4, "ind": 2, "sr": 1, "ip": 0, "op": 60, "st": 0, "ks": {"a": {"k": [0, 0], "a": 0}, "p": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [327.0, 199.3846153846154]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [310.5, 198.92307692307693]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [294.0, 198.46153846153845]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [277.5, 198]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [261.0, 197.53846153846155]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [244.5, 197.07692307692307]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [228.0, 196.6153846153846]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [211.5, 196.15384615384616]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [206.0, 196]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [206.0, 196]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [492.0, 204]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [475.5, 203.53846153846155]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [459.0, 203.07692307692307]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [442.5, 202.6153846153846]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [426.0, 202.15384615384616]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [409.5, 201.69230769230768]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [393.0, 201.23076923076923]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [376.5, 200.76923076923077]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [360.0, 200.30769230769232]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [343.5, 199.84615384615384]}, {"t": 60, "s": [327.0, 199.3846153846154]}]}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [70]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [40]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [10]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [37.5]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [75]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 60, "s": [100]}]}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}, "ao": 0, "bm": 0, "shapes": [{"ty": "gr", "it": [{"ty": "el", "d": 1, "p": {"k": [0, 0], "a": 0}, "s": {"k": [12, 12], "a": 0}}, {"ty": "fl", "o": {"k": 100, "a": 0}, "c": {"k": [0.769, 0.275, 0.184, 1], "a": 0}}, {"ty": "tr", "a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}]}]}, {"nm": "dot3", "ddd": 0, "ty": 4, "ind": 3, "sr": 1, "ip": 0, "op": 60, "st": 0, "ks": {"a": {"k": [0, 0], "a": 0}, "p": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [409.5, 201.69230769230768]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [393.0, 201.23076923076923]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [376.5, 200.76923076923077]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [360.0, 200.30769230769232]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [343.5, 199.84615384615384]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [327.0, 199.3846153846154]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [310.5, 198.92307692307693]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [294.0, 198.46153846153845]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [277.5, 198]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [261.0, 197.53846153846155]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [244.5, 197.07692307692307]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [228.0, 196.6153846153846]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [211.5, 196.15384615384616]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [206.0, 196]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [206.0, 196]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [492.0, 204]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [475.5, 203.53846153846155]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [459.0, 203.07692307692307]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [442.5, 202.6153846153846]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [426.0, 202.15384615384616]}, {"t": 60, "s": [409.5, 201.69230769230768]}]}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [70]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [40]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [10]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [37.5]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [75]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 60, "s": [100]}]}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}, "ao": 0, "bm": 0, "shapes": [{"ty": "gr", "it": [{"ty": "el", "d": 1, "p": {"k": [0, 0], "a": 0}, "s": {"k": [12, 12], "a": 0}}, {"ty": "fl", "o": {"k": 100, "a": 0}, "c": {"k": [0.055, 0.361, 0.388, 1], "a": 0}}, {"ty": "tr", "a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}]}]}, {"nm": "box", "ddd": 0, "ty": 4, "ind": 0, "sr": 1, "ip": 0, "op": 60, "st": 0, "ks": {"a": {"k": [0, 0], "a": 0}, "p": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0, 0]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0, -5]}, {"t": 60, "s": [0, 0]}]}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}, "ao": 0, "bm": 0, "shapes": [{"nm": "cloud", "ty": "gr", "it": [{"ty": "rc", "p": {"a": 0, "k": [146, 238]}, "s": {"a": 0, "k": [82, 48]}, "r": {"a": 0, "k": 7}}, {"ty": "sh", "ks": {"a": 0, "k": {"c": true, "i": [[0, 0], [0, 0], [0, 0], [0, 0]], "o": [[0, 0], [0, 0], [0, 0], [0, 0]], "v": [[105, 214], [83, 201], [103, 193], [127, 208]]}}}, {"ty": "sh", "ks": {"a": 0, "k": {"c": true, "i": [[0, 0], [0, 0], [0, 0], [0, 0]], "o": [[0, 0], [0, 0], [0, 0], [0, 0]], "v": [[187, 214], [209, 201], [189, 193], [165, 208]]}}}, {"ty": "sh", "ks": {"a": 0, "k": {"c": true, "i": [[0, 0], [0, 0], [0, 0], [0, 0]], "o": [[0, 0], [0, 0], [0, 0], [0, 0]], "v": [[112, 216], [180, 216], [176, 224], [116, 224]]}}}, {"ty": "st", "lc": 2, "lj": 2, "ml": 0, "o": {"k": 100, "a": 0}, "w": {"k": 4, "a": 0}, "c": {"k": [0.054901960784313725, 0.3607843137254902, 0.38823529411764707, 1], "a": 0}}, {"ty": "fl", "o": {"k": 100, "a": 0}, "c": {"k": [0.9372549019607843, 0.9215686274509803, 0.8862745098039215, 1], "a": 0}}, {"ty": "tr", "a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}]}]}, {"nm": "glow", "ddd": 0, "ty": 4, "ind": 4, "sr": 1, "ip": 0, "op": 60, "st": 0, "ks": {"a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [12]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.218847050625474]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.281152949374526]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.281152949374526]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.218847050625474]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [12]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.21884705062547]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.281152949374526]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.28115294937453]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.218847050625477]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [12]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.21884705062547]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.281152949374523]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.28115294937453]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.218847050625477]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [12]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.218847050625467]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.281152949374523]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.28115294937453]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.21884705062548]}, {"t": 60, "s": [12]}]}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}, "ao": 0, "bm": 0, "shapes": [{"ty": "gr", "it": [{"ty": "el", "d": 1, "p": {"k": [146, 230], "a": 0}, "s": {"k": [112, 112], "a": 0}}, {"ty": "fl", "o": {"k": 100, "a": 0}, "c": {"k": [0, 0.745, 0, 1], "a": 0}}, {"ty": "tr", "a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}]}]}], "nm": "k2go-backup-loop.json", "v": "5.5.2", "fr": 30, "ip": 0, "op": 60, "w": 600, "h": 368, "ddd": 0, "assets": []} \ No newline at end of file diff --git a/controller/app/src/main/res/raw/k2go_restore_loop.json b/controller/app/src/main/res/raw/k2go_restore_loop.json new file mode 100644 index 00000000..9442a983 --- /dev/null +++ b/controller/app/src/main/res/raw/k2go_restore_loop.json @@ -0,0 +1 @@ +{"layers": [{"nm": "dot0", "ddd": 0, "ty": 4, "ind": 0, "sr": 1, "ip": 0, "op": 60, "st": 0, "ks": {"a": {"k": [0, 0], "a": 0}, "p": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [206, 204]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [222.5, 203.53846153846155]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [239, 203.07692307692307]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [255.5, 202.6153846153846]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [272, 202.15384615384616]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [288.5, 201.69230769230768]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [305, 201.23076923076923]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [321.5, 200.76923076923077]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [338, 200.30769230769232]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [354.5, 199.84615384615384]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [371, 199.3846153846154]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [387.5, 198.92307692307693]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [404, 198.46153846153845]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [420.5, 198]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [437, 197.53846153846155]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [453.5, 197.07692307692307]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [470, 196.6153846153846]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [486.5, 196.15384615384616]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [492, 196]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [492, 196]}, {"t": 60, "s": [206, 204]}]}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [37.5]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [75]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [70]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [40]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [10]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 60, "s": [0]}]}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}, "ao": 0, "bm": 0, "shapes": [{"ty": "gr", "it": [{"ty": "el", "d": 1, "p": {"k": [0, 0], "a": 0}, "s": {"k": [12, 12], "a": 0}}, {"ty": "fl", "o": {"k": 100, "a": 0}, "c": {"k": [0.18, 0.62, 0.357, 1], "a": 0}}, {"ty": "tr", "a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}]}]}, {"nm": "dot1", "ddd": 0, "ty": 4, "ind": 1, "sr": 1, "ip": 0, "op": 60, "st": 0, "ks": {"a": {"k": [0, 0], "a": 0}, "p": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [453.5, 197.07692307692307]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [470, 196.6153846153846]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [486.5, 196.15384615384616]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [492, 196]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [492, 196]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [206, 204]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [222.5, 203.53846153846155]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [239, 203.07692307692307]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [255.5, 202.6153846153846]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [272, 202.15384615384616]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [288.5, 201.69230769230768]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [305, 201.23076923076923]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [321.5, 200.76923076923077]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [338, 200.30769230769232]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [354.5, 199.84615384615384]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [371, 199.3846153846154]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [387.5, 198.92307692307693]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [404, 198.46153846153845]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [420.5, 198]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [437, 197.53846153846155]}, {"t": 60, "s": [453.5, 197.07692307692307]}]}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [70]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [40]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [10]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [37.5]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [75]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 60, "s": [70]}]}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}, "ao": 0, "bm": 0, "shapes": [{"ty": "gr", "it": [{"ty": "el", "d": 1, "p": {"k": [0, 0], "a": 0}, "s": {"k": [12, 12], "a": 0}}, {"ty": "fl", "o": {"k": 100, "a": 0}, "c": {"k": [0.949, 0.635, 0.235, 1], "a": 0}}, {"ty": "tr", "a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}]}]}, {"nm": "dot2", "ddd": 0, "ty": 4, "ind": 2, "sr": 1, "ip": 0, "op": 60, "st": 0, "ks": {"a": {"k": [0, 0], "a": 0}, "p": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [371, 199.3846153846154]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [387.5, 198.92307692307693]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [404, 198.46153846153845]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [420.5, 198]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [437, 197.53846153846155]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [453.5, 197.07692307692307]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [470, 196.6153846153846]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [486.5, 196.15384615384616]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [492, 196]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [492, 196]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [206, 204]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [222.5, 203.53846153846155]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [239, 203.07692307692307]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [255.5, 202.6153846153846]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [272, 202.15384615384616]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [288.5, 201.69230769230768]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [305, 201.23076923076923]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [321.5, 200.76923076923077]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [338, 200.30769230769232]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [354.5, 199.84615384615384]}, {"t": 60, "s": [371, 199.3846153846154]}]}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [70]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [40]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [10]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [37.5]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [75]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 60, "s": [100]}]}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}, "ao": 0, "bm": 0, "shapes": [{"ty": "gr", "it": [{"ty": "el", "d": 1, "p": {"k": [0, 0], "a": 0}, "s": {"k": [12, 12], "a": 0}}, {"ty": "fl", "o": {"k": 100, "a": 0}, "c": {"k": [0.769, 0.275, 0.184, 1], "a": 0}}, {"ty": "tr", "a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}]}]}, {"nm": "dot3", "ddd": 0, "ty": 4, "ind": 3, "sr": 1, "ip": 0, "op": 60, "st": 0, "ks": {"a": {"k": [0, 0], "a": 0}, "p": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [288.5, 201.69230769230768]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [305, 201.23076923076923]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [321.5, 200.76923076923077]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [338, 200.30769230769232]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [354.5, 199.84615384615384]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [371, 199.3846153846154]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [387.5, 198.92307692307693]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [404, 198.46153846153845]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [420.5, 198]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [437, 197.53846153846155]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [453.5, 197.07692307692307]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [470, 196.6153846153846]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [486.5, 196.15384615384616]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [492, 196]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [492, 196]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [206, 204]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [222.5, 203.53846153846155]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [239, 203.07692307692307]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [255.5, 202.6153846153846]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [272, 202.15384615384616]}, {"t": 60, "s": [288.5, 201.69230769230768]}]}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [70]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [40]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [10]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [37.5]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [75]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [100]}, {"t": 60, "s": [100]}]}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}, "ao": 0, "bm": 0, "shapes": [{"ty": "gr", "it": [{"ty": "el", "d": 1, "p": {"k": [0, 0], "a": 0}, "s": {"k": [12, 12], "a": 0}}, {"ty": "fl", "o": {"k": 100, "a": 0}, "c": {"k": [0.055, 0.361, 0.388, 1], "a": 0}}, {"ty": "tr", "a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}]}]}, {"nm": "box", "ddd": 0, "ty": 4, "ind": 0, "sr": 1, "ip": 0, "op": 60, "st": 0, "ks": {"a": {"k": [0, 0], "a": 0}, "p": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0, 0]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [0, -5]}, {"t": 60, "s": [0, 0]}]}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}, "ao": 0, "bm": 0, "shapes": [{"nm": "cloud", "ty": "gr", "it": [{"ty": "rc", "p": {"a": 0, "k": [146, 238]}, "s": {"a": 0, "k": [82, 48]}, "r": {"a": 0, "k": 7}}, {"ty": "sh", "ks": {"a": 0, "k": {"c": true, "i": [[0, 0], [0, 0], [0, 0], [0, 0]], "o": [[0, 0], [0, 0], [0, 0], [0, 0]], "v": [[105, 214], [83, 201], [103, 193], [127, 208]]}}}, {"ty": "sh", "ks": {"a": 0, "k": {"c": true, "i": [[0, 0], [0, 0], [0, 0], [0, 0]], "o": [[0, 0], [0, 0], [0, 0], [0, 0]], "v": [[187, 214], [209, 201], [189, 193], [165, 208]]}}}, {"ty": "sh", "ks": {"a": 0, "k": {"c": true, "i": [[0, 0], [0, 0], [0, 0], [0, 0]], "o": [[0, 0], [0, 0], [0, 0], [0, 0]], "v": [[112, 216], [180, 216], [176, 224], [116, 224]]}}}, {"ty": "st", "lc": 2, "lj": 2, "ml": 0, "o": {"k": 100, "a": 0}, "w": {"k": 4, "a": 0}, "c": {"k": [0.054901960784313725, 0.3607843137254902, 0.38823529411764707, 1], "a": 0}}, {"ty": "fl", "o": {"k": 100, "a": 0}, "c": {"k": [0.9372549019607843, 0.9215686274509803, 0.8862745098039215, 1], "a": 0}}, {"ty": "tr", "a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}]}]}, {"nm": "glow", "ddd": 0, "ty": 4, "ind": 4, "sr": 1, "ip": 0, "op": 60, "st": 0, "ks": {"a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"a": 1, "k": [{"t": 0, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [12]}, {"t": 3, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.218847050625474]}, {"t": 6, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.281152949374526]}, {"t": 9, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.281152949374526]}, {"t": 12, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.218847050625474]}, {"t": 15, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [12]}, {"t": 18, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.21884705062547]}, {"t": 21, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.281152949374526]}, {"t": 24, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.28115294937453]}, {"t": 27, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.218847050625477]}, {"t": 30, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [12]}, {"t": 33, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.21884705062547]}, {"t": 36, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.281152949374523]}, {"t": 39, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.28115294937453]}, {"t": 42, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.218847050625477]}, {"t": 45, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [12]}, {"t": 48, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.218847050625467]}, {"t": 51, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.281152949374523]}, {"t": 54, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [28.28115294937453]}, {"t": 57, "i": {"x": [1], "y": [1]}, "o": {"x": [0], "y": [0]}, "s": [18.21884705062548]}, {"t": 60, "s": [12]}]}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}, "ao": 0, "bm": 0, "shapes": [{"ty": "gr", "it": [{"ty": "el", "d": 1, "p": {"k": [492, 196], "a": 0}, "s": {"k": [112, 112], "a": 0}}, {"ty": "fl", "o": {"k": 100, "a": 0}, "c": {"k": [0, 0.745, 0, 1], "a": 0}}, {"ty": "tr", "a": {"k": [0, 0], "a": 0}, "p": {"k": [0, 0], "a": 0}, "s": {"k": [100, 100], "a": 0}, "r": {"k": 0, "a": 0}, "o": {"k": 100, "a": 0}, "sk": {"k": 0, "a": 0}, "sa": {"k": 0, "a": 0}}]}]}], "nm": "k2go-restore-loop.json", "v": "5.5.2", "fr": 30, "ip": 0, "op": 60, "w": 600, "h": 368, "ddd": 0, "assets": []} \ No newline at end of file diff --git a/controller/app/src/main/res/values/strings_k2go.xml b/controller/app/src/main/res/values/strings_k2go.xml index 58f514b0..603c49bf 100644 --- a/controller/app/src/main/res/values/strings_k2go.xml +++ b/controller/app/src/main/res/values/strings_k2go.xml @@ -174,7 +174,6 @@ Replace system System restored Restore failed - This is running and can\'t be interrupted — please wait. Backup & restore Keeps a backup or restore running safely in the background Backup & restore @@ -183,6 +182,12 @@ Keeps a device-to-device transfer running Knowledge to Go Transferring between devices — tap to return + Finish + This can take a while + Keep K2Go open. You can leave — it keeps running in the background, and the notification brings you back. + Done — returning to Home… + Backup is running — you can leave; it keeps going and will be ready when you come back. + Restore is running — you can leave; it keeps going and will be ready when you come back. DEVELOPER Network & DNS Use a custom DNS. Off = server defaults.