aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/mygram/droid/SplashActivity.java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/mygram/droid/SplashActivity.java')
-rw-r--r--app/src/main/java/mygram/droid/SplashActivity.java135
1 files changed, 135 insertions, 0 deletions
diff --git a/app/src/main/java/mygram/droid/SplashActivity.java b/app/src/main/java/mygram/droid/SplashActivity.java
new file mode 100644
index 0000000..ed94488
--- /dev/null
+++ b/app/src/main/java/mygram/droid/SplashActivity.java
@@ -0,0 +1,135 @@
+/*
+ * mygram-droid: Android TV client for Foldergram.
+ * Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+package mygram.droid;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.text.InputType;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import org.json.JSONObject;
+
+/**
+ * Gate shown on every start and return to the app: the PIN prompt when a PIN
+ * is set, then a wait while Foldergram indexes, which makes it unusably slow.
+ */
+public final class SplashActivity extends Activity {
+ private static final long POLL_MS = 5000;
+ private final Handler handler = new Handler(Looper.getMainLooper());
+ private final Runnable poll = this::checkScan;
+ private LinearLayout box;
+ private TextView status;
+
+ @Override
+ protected void onCreate(Bundle state) {
+ super.onCreate(state);
+ box = Ui.column(this);
+ ImageView logo = new ImageView(this);
+ logo.setImageResource(R.drawable.ic_launcher);
+ logo.setContentDescription("mygram");
+ int s = Ui.dp(this, 96);
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(s, s);
+ lp.bottomMargin = Ui.dp(this, 24);
+ box.addView(logo, lp);
+ setContentView(box);
+ if (Prefs.hasPin())
+ askPin();
+ else
+ checkScan();
+ }
+
+ private void askPin() {
+ EditText pin = Ui.field(this, "PIN", InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
+ box.addView(pin);
+ View ok = Ui.iconButton(this, R.drawable.ic_check, "Unlock", v -> {
+ if (Prefs.checkPin(pin.getText().toString())) {
+ box.removeViews(1, box.getChildCount() - 1);
+ checkScan();
+ } else {
+ pin.setText("");
+ Toast.makeText(this, "Wrong PIN", Toast.LENGTH_SHORT).show();
+ }
+ });
+ box.addView(ok);
+ // The keyboard's done key unlocks; the D-pad cannot leave the keyboard.
+ pin.setOnEditorActionListener((v, action, event) -> ok.performClick());
+ pin.requestFocus();
+ }
+
+ /** Waits while the library is being indexed; lets the user in once it is idle. */
+ private void checkScan() {
+ if (Prefs.server() == null) { // first run: setup comes next
+ done();
+ return;
+ }
+ Api.async(() -> Api.call("GET", "/scan-progress"), o -> {
+ if (isDestroyed())
+ return;
+ if (!o.optBoolean("isScanning")) {
+ done();
+ return;
+ }
+ showScan(o);
+ handler.postDelayed(poll, POLL_MS);
+ }, e -> {
+ if (isDestroyed())
+ return;
+ if (status == null)
+ done(); // unreachable at the first check: Home reports it with Retry
+ else
+ handler.postDelayed(poll, POLL_MS); // mid-scan the server is slow; keep waiting
+ });
+ }
+
+ private void showScan(JSONObject o) {
+ if (status == null) {
+ box.addView(new ProgressBar(this));
+ box.addView(Ui.text(this, "Library is indexing", 24));
+ status = Ui.text(this, "", 16);
+ box.addView(status);
+ }
+ String msg = Post.str(o, "currentPhaseMessage");
+ if (msg == null)
+ msg = o.optString("phase");
+ int done = o.optInt("processedDerivativeJobs"), total = o.optInt("queuedDerivativeJobs");
+ status.setText(total > 0 ? msg + " " + done + " / " + total : msg);
+ }
+
+ private void done() {
+ App.locked = false;
+ finish();
+ }
+
+ /** Back leaves the app instead of revealing the screen underneath. */
+ @Override
+ @SuppressWarnings("deprecation") // no predictive back on this TV; onBackPressed still fires
+ public void onBackPressed() {
+ finishAffinity();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ handler.removeCallbacksAndMessages(null);
+ }
+}