feat(hobbs-organizer): v1.3.0 photo gallery + Shield photo app 1.1, slideshow 15s
- /photo/gallery: D-pad grid, OK opens full screen, arrows browse, Back returns - 400px gallery tiles cached per photo (sync + uploads) - com.dayline.photos 1.1: launcher tile opens the gallery, takes remote input, Back steps through WebView history; screensaver unchanged - slideshow interval 20s -> 15s (live settings) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E9NnVEico3WvFxLyjy1iW3
This commit is contained in:
+2
-2
@@ -16,8 +16,8 @@ android {
|
||||
applicationId "com.dayline.photos"
|
||||
minSdk 26
|
||||
targetSdk 35
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
versionCode 2
|
||||
versionName "1.1"
|
||||
buildConfigField "String", "DEFAULT_URL", "\"http://192.168.86.100:8340/photo\""
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -5,7 +5,7 @@ import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
/** Launcher tile: the photo frame, full screen, screen kept on. Back exits. */
|
||||
/** Launcher tile: the photo gallery (remote-driven grid), full screen, screen kept on. Back steps back, then exits. */
|
||||
public final class PhotoActivity extends Activity {
|
||||
private PhotoFrameView frame;
|
||||
|
||||
@@ -13,9 +13,10 @@ public final class PhotoActivity extends Activity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
frame = new PhotoFrameView(this);
|
||||
frame = new PhotoFrameView(this, "/gallery", true);
|
||||
setContentView(frame.view());
|
||||
hideSystemUi();
|
||||
frame.view().requestFocus();
|
||||
frame.load();
|
||||
}
|
||||
|
||||
@@ -25,6 +26,13 @@ public final class PhotoActivity extends Activity {
|
||||
if (hasFocus) hideSystemUi();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void onBackPressed() {
|
||||
if (frame != null && frame.goBack()) return;
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void hideSystemUi() {
|
||||
getWindow().getDecorView().setSystemUiVisibility(
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ public final class PhotoDreamService extends DreamService {
|
||||
setInteractive(false);
|
||||
setFullscreen(true);
|
||||
setScreenBright(true);
|
||||
frame = new PhotoFrameView(this);
|
||||
frame = new PhotoFrameView(this, "", false);
|
||||
setContentView(frame.view());
|
||||
}
|
||||
|
||||
|
||||
+35
-7
@@ -22,8 +22,9 @@ import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* A locked-down full-screen WebView showing the organizer's /photo page.
|
||||
* Shared by the launcher activity and the screen saver.
|
||||
* A locked-down full-screen WebView showing the organizer's photo pages.
|
||||
* Shared by the launcher activity (interactive gallery, /photo/gallery) and the screen saver
|
||||
* (non-interactive slideshow, /photo).
|
||||
*/
|
||||
final class PhotoFrameView {
|
||||
private static final long RETRY_MS = 30_000;
|
||||
@@ -34,17 +35,26 @@ final class PhotoFrameView {
|
||||
private final String url;
|
||||
private final String origin;
|
||||
private boolean destroyed;
|
||||
/** Set by load(): the next finished page becomes the bottom of the Back stack. */
|
||||
private boolean clearHistoryWhenLoaded;
|
||||
|
||||
/**
|
||||
* @param subPath appended to the configured photo URL (e.g. "/gallery"), or "" for the slideshow
|
||||
* @param interactive true to take remote (D-pad) input; the screen saver passes false
|
||||
*/
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
PhotoFrameView(Context context) {
|
||||
url = configuredUrl(context);
|
||||
PhotoFrameView(Context context, String subPath, boolean interactive) {
|
||||
String base = configuredUrl(context);
|
||||
while (base.endsWith("/")) base = base.substring(0, base.length() - 1);
|
||||
url = base + subPath;
|
||||
Uri parsed = Uri.parse(url);
|
||||
origin = parsed.getScheme() + "://" + parsed.getAuthority();
|
||||
|
||||
WebView.setWebContentsDebuggingEnabled(false);
|
||||
webView = new WebView(context);
|
||||
webView.setBackgroundColor(Color.BLACK);
|
||||
webView.setFocusable(false);
|
||||
webView.setFocusable(interactive);
|
||||
webView.setFocusableInTouchMode(interactive);
|
||||
|
||||
WebSettings settings = webView.getSettings();
|
||||
settings.setJavaScriptEnabled(true);
|
||||
@@ -58,7 +68,7 @@ final class PhotoFrameView {
|
||||
settings.setLoadWithOverviewMode(true);
|
||||
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_NEVER_ALLOW);
|
||||
settings.setMediaPlaybackRequiresUserGesture(true);
|
||||
settings.setUserAgentString(settings.getUserAgentString() + " HobbsPhotoFrame/1.0");
|
||||
settings.setUserAgentString(settings.getUserAgentString() + " HobbsPhotoFrame/" + BuildConfig.VERSION_NAME);
|
||||
CookieManager.getInstance().setAcceptCookie(false);
|
||||
|
||||
webView.setWebChromeClient(new WebChromeClient());
|
||||
@@ -68,6 +78,15 @@ final class PhotoFrameView {
|
||||
return !sameOrigin(request.getUrl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String finishedUrl) {
|
||||
// Drop the "waiting for server" page (and anything before it) from the Back stack.
|
||||
if (clearHistoryWhenLoaded && finishedUrl != null && finishedUrl.startsWith(origin)) {
|
||||
clearHistoryWhenLoaded = false;
|
||||
view.clearHistory();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedSslError(WebView view, SslErrorHandler sslHandler, SslError error) {
|
||||
sslHandler.cancel();
|
||||
@@ -88,7 +107,16 @@ final class PhotoFrameView {
|
||||
}
|
||||
|
||||
void load() {
|
||||
if (!destroyed) webView.loadUrl(url);
|
||||
if (destroyed) return;
|
||||
clearHistoryWhenLoaded = true;
|
||||
webView.loadUrl(url);
|
||||
}
|
||||
|
||||
/** Back key: step back inside the pages (e.g. close a full-screen photo). False = nothing left, exit. */
|
||||
boolean goBack() {
|
||||
if (destroyed || !webView.canGoBack()) return false;
|
||||
webView.goBack();
|
||||
return true;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
|
||||
Reference in New Issue
Block a user