diff options
Diffstat (limited to 'app/src/main/java/mygram/droid/SplashActivity.java')
| -rw-r--r-- | app/src/main/java/mygram/droid/SplashActivity.java | 135 |
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); + } +} |
