fix image preview and add option for automatically stop auto screenshoting when idle
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package dev.photosync.client;
|
||||
|
||||
import dev.photosync.core.capture.CameraPose;
|
||||
import dev.photosync.core.capture.CaptureOrigin;
|
||||
import dev.photosync.core.capture.CapturedScreenshot;
|
||||
import dev.photosync.core.config.AutoCaptureSettings;
|
||||
@@ -9,6 +10,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -23,6 +25,11 @@ import java.util.function.Supplier;
|
||||
*
|
||||
* <p>Off by default, and it stays off until the player says otherwise: silently
|
||||
* filling someone's screenshots folder is not a feature.
|
||||
*
|
||||
* <p>When it is on, a cycle is skipped if the camera has not moved for a whole
|
||||
* interval, because that shot would be the previous one again. The condition is
|
||||
* "has not moved since the last capture", expressed as a duration so that it
|
||||
* survives the player wandering off and coming back to the same spot.
|
||||
*/
|
||||
@Slf4j
|
||||
public final class AutoCapture {
|
||||
@@ -36,6 +43,10 @@ public final class AutoCapture {
|
||||
private long nextCaptureMillis;
|
||||
private boolean capturing;
|
||||
|
||||
/** The last view that differed from the one before it, and when it arrived. */
|
||||
private CameraPose restingPose;
|
||||
private long movedAtMillis;
|
||||
|
||||
public AutoCapture(GameContext game, ScreenshotService screenshots,
|
||||
Supplier<AutoCaptureSettings> settings, Consumer<CapturedScreenshot> sink) {
|
||||
this.game = game;
|
||||
@@ -51,11 +62,15 @@ public final class AutoCapture {
|
||||
// Disarmed, so switching the feature on never fires immediately --
|
||||
// it always waits a full interval first.
|
||||
nextCaptureMillis = 0;
|
||||
restingPose = null;
|
||||
return;
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
long interval = current.intervalSeconds() * 1000L;
|
||||
// Every tick, so that stillness is measured over the whole interval
|
||||
// rather than sampled at its two ends.
|
||||
observePose(now);
|
||||
if (nextCaptureMillis == 0) {
|
||||
nextCaptureMillis = now + interval;
|
||||
return;
|
||||
@@ -75,11 +90,47 @@ public final class AutoCapture {
|
||||
// where it is and the shot happens as soon as it closes.
|
||||
return;
|
||||
}
|
||||
if (current.skipWhenStill() && stillFor(interval, now)) {
|
||||
// The view is the one the last screenshot already has. Skip this
|
||||
// cycle and arm the next: the moment the player moves, the timer
|
||||
// resumes on its own, so nothing has to be re-enabled.
|
||||
log.debug("Skipping an automatic capture: the view has not changed in {}s",
|
||||
current.intervalSeconds());
|
||||
nextCaptureMillis = now + interval;
|
||||
return;
|
||||
}
|
||||
|
||||
nextCaptureMillis = now + interval;
|
||||
take(current.fileNameSuffix());
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes where the camera is, and when it last went somewhere new.
|
||||
*
|
||||
* <p>The comparison is against the last pose that <em>differed</em> rather
|
||||
* than against the previous tick, so a player drifting slowly -- in water, on
|
||||
* a boat, turning by a pixel at a time -- still counts as moving once the
|
||||
* movement adds up, instead of being called still forever.
|
||||
*/
|
||||
private void observePose(long now) {
|
||||
Optional<CameraPose> pose = game.cameraPose();
|
||||
if (pose.isEmpty()) {
|
||||
// No world, or no player in it yet. Nothing to compare, and stillness
|
||||
// is not claimed against a view that does not exist.
|
||||
restingPose = null;
|
||||
return;
|
||||
}
|
||||
if (restingPose == null || pose.get().movedFrom(restingPose)) {
|
||||
restingPose = pose.get();
|
||||
movedAtMillis = now;
|
||||
}
|
||||
}
|
||||
|
||||
/** True once the view has been the same for a full capture cycle. */
|
||||
private boolean stillFor(long millis, long now) {
|
||||
return restingPose != null && now - movedAtMillis >= millis;
|
||||
}
|
||||
|
||||
private void take(String suffix) {
|
||||
capturing = true;
|
||||
screenshots.capture(suffix).whenComplete((file, failure) -> {
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
"photosync.browse.failed": "Could not load the timeline",
|
||||
"photosync.browse.empty": "Nothing here yet",
|
||||
"photosync.browse.page_failed": "Could not load these photos",
|
||||
"photosync.browse.opening": "Loading...",
|
||||
"photosync.browse.opening": "Loading the full photo...",
|
||||
"photosync.browse.open_failed": "Could not load this photo",
|
||||
"photosync.browse.open_failed.hint": "Close and open it again to retry.",
|
||||
"photosync.browse.close_hint": "Esc to close",
|
||||
"photosync.browse.status": "%s photos in %s days",
|
||||
|
||||
@@ -82,6 +84,8 @@
|
||||
"photosync.settings.suffix": "Name suffix",
|
||||
"photosync.settings.only_in_world": "Only while in a world",
|
||||
"photosync.settings.skip_when_screen_open": "Skip while a screen is open",
|
||||
"photosync.settings.skip_when_still": "Skip if you have not moved",
|
||||
"photosync.settings.skip_when_still.detail": "Skips a cycle when the view has not changed since the last automatic screenshot.",
|
||||
|
||||
"photosync.settings.notify": "Show messages in the corner",
|
||||
"photosync.settings.notify.detail": "One line, bottom left, for a moment.",
|
||||
|
||||
Reference in New Issue
Block a user