Add setting to customize the date time format in the GUI
This commit is contained in:
parent
a6e3fcc6e3
commit
38b898f405
|
@ -252,7 +252,7 @@ public class CamrecApplication extends Application {
|
|||
tabPane.getTabs().add(new RecentlyWatchedTab(recorder, sites));
|
||||
}
|
||||
tabPane.getTabs().add(new SettingsTab(sites, recorder));
|
||||
tabPane.getTabs().add(new NewsTab());
|
||||
tabPane.getTabs().add(new NewsTab(config));
|
||||
tabPane.getTabs().add(new DonateTabFx());
|
||||
tabPane.getTabs().add(new HelpTab());
|
||||
tabPane.getTabs().add(new LoggingTab());
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
package ctbrec.ui.controls;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.util.Callback;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class DateTimeCellFactory<T> implements Callback<TableColumn<T, Instant>, TableCell<T, Instant>> {
|
||||
|
||||
private final DateTimeFormatter formatter;
|
||||
|
||||
public DateTimeCellFactory (DateTimeFormatter formatter) {
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableCell<T, Instant> call(TableColumn<T, Instant> param) {
|
||||
return new TableCell<T, Instant>() {
|
||||
|
@ -20,7 +26,6 @@ public class DateTimeCellFactory<T> implements Callback<TableColumn<T, Instant>,
|
|||
setText("");
|
||||
} else {
|
||||
var dateTime = LocalDateTime.ofInstant(item, ZoneId.systemDefault());
|
||||
var formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
|
||||
String formattedDateTime = formatter.format(dateTime);
|
||||
setText(item.equals(Instant.EPOCH) ? "" : formattedDateTime);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import static ctbrec.io.HttpConstants.*;
|
|||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
import ctbrec.Config;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
|
@ -26,10 +27,11 @@ import okhttp3.Request;
|
|||
public class NewsTab extends Tab implements TabSelectionListener {
|
||||
private static final String ACCESS_TOKEN = "a2804d73a89951a22e0f8483a6fcec8943afd88b7ba17c459c095aa9e6f94fd0";
|
||||
private static final String URL = "https://mastodon.cloud/api/v1/accounts/480960/statuses?limit=20&exclude_replies=true";
|
||||
private final Config config;
|
||||
private final VBox layout = new VBox();
|
||||
|
||||
private VBox layout = new VBox();
|
||||
|
||||
public NewsTab() {
|
||||
public NewsTab(Config config) {
|
||||
this.config = config;
|
||||
setText("News");
|
||||
layout.setMaxWidth(800);
|
||||
layout.setAlignment(Pos.CENTER);
|
||||
|
@ -46,11 +48,11 @@ public class NewsTab extends Tab implements TabSelectionListener {
|
|||
var request = new Request.Builder()
|
||||
.url(URL)
|
||||
.header("Authorization", "Bearer " + ACCESS_TOKEN)
|
||||
.header(USER_AGENT, "ctbrec " + CamrecApplication.getVersion().toString())
|
||||
.header(USER_AGENT, "ctbrec " + CamrecApplication.getVersion())
|
||||
.build();
|
||||
try (var response = CamrecApplication.httpClient.execute(request)) {
|
||||
if (response.isSuccessful()) {
|
||||
var body = response.body().string();
|
||||
var body = Objects.requireNonNull(response.body(), "HTTP response body is null").string();
|
||||
if (body.startsWith("[")) {
|
||||
onSuccess(body);
|
||||
} else if (body.startsWith("{")) {
|
||||
|
@ -79,12 +81,12 @@ public class NewsTab extends Tab implements TabSelectionListener {
|
|||
private void onSuccess(String body) throws IOException {
|
||||
var moshi = new Moshi.Builder().build();
|
||||
JsonAdapter<Status[]> statusListAdapter = moshi.adapter(Status[].class);
|
||||
Status[] statusArray = statusListAdapter.fromJson(body);
|
||||
Status[] statusArray = Objects.requireNonNull(statusListAdapter.fromJson(body));
|
||||
Platform.runLater(() -> {
|
||||
layout.getChildren().clear();
|
||||
for (Status status : statusArray) {
|
||||
if (status.getInReplyToId() == null && !Objects.equals("direct", status.getVisibility())) {
|
||||
var stp = new StatusPane(status);
|
||||
var stp = new StatusPane(status, config.getDateTimeFormatter());
|
||||
layout.getChildren().add(stp);
|
||||
VBox.setMargin(stp, new Insets(10));
|
||||
}
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
package ctbrec.ui.news;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.util.Set;
|
||||
|
||||
import ctbrec.io.HtmlParser;
|
||||
import ctbrec.ui.DesktopIntegration;
|
||||
import javafx.collections.ObservableList;
|
||||
|
@ -12,20 +7,20 @@ import javafx.geometry.Insets;
|
|||
import javafx.geometry.Orientation;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollBar;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Set;
|
||||
|
||||
public class StatusPane extends StackPane {
|
||||
|
||||
TextArea content;
|
||||
Button reply;
|
||||
|
||||
public StatusPane(Status status) {
|
||||
public StatusPane(Status status, DateTimeFormatter formatter) {
|
||||
String text = HtmlParser.getText("<div>" + status.getContent() + "</div>", "div");
|
||||
|
||||
content = new TextArea(text);
|
||||
|
@ -35,7 +30,7 @@ public class StatusPane extends StackPane {
|
|||
getChildren().add(content);
|
||||
|
||||
ZonedDateTime createdAt = status.getCreationTime();
|
||||
String creationTime = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.SHORT).format(createdAt);
|
||||
String creationTime = formatter.format(createdAt);
|
||||
var time = new Label(creationTime);
|
||||
time.setStyle("-fx-background-color: -fx-base");
|
||||
time.setOpacity(.7);
|
||||
|
@ -63,18 +58,14 @@ public class StatusPane extends StackPane {
|
|||
protected void layoutChildren() {
|
||||
ObservableList<Node> childrenUnmodifiable = content.getChildrenUnmodifiable();
|
||||
for (Node node : childrenUnmodifiable) {
|
||||
if (node instanceof ScrollPane) {
|
||||
var scrollPane = (ScrollPane) node;
|
||||
if (node instanceof ScrollPane scrollPane) {
|
||||
Set<Node> nodes = scrollPane.lookupAll(".scroll-bar");
|
||||
for (final Node child : nodes) {
|
||||
if (child instanceof ScrollBar) {
|
||||
ScrollBar sb = (ScrollBar) child;
|
||||
if (sb.getOrientation() == Orientation.VERTICAL) {
|
||||
if (sb.isVisible()) {
|
||||
StackPane.setMargin(reply, new Insets(5, 22, 5, 5));
|
||||
} else {
|
||||
StackPane.setMargin(reply, new Insets(5, 5, 5, 5));
|
||||
}
|
||||
if (child instanceof ScrollBar sb && sb.getOrientation() == Orientation.VERTICAL) {
|
||||
if (sb.isVisible()) {
|
||||
StackPane.setMargin(reply, new Insets(5, 22, 5, 5));
|
||||
} else {
|
||||
StackPane.setMargin(reply, new Insets(5, 5, 5, 5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,6 +119,7 @@ public class SettingsTab extends Tab implements TabSelectionListener {
|
|||
private LocalTimeProperty timeoutRecordingStartingAt;
|
||||
private LocalTimeProperty timeoutRecordingEndingAt;
|
||||
private SimpleLongProperty recordUntilDefaultDurationInMinutes;
|
||||
private SimpleStringProperty dateTimeFormat;
|
||||
|
||||
public SettingsTab(List<Site> sites, Recorder recorder) {
|
||||
this.sites = sites;
|
||||
|
@ -189,6 +190,7 @@ public class SettingsTab extends Tab implements TabSelectionListener {
|
|||
timeoutRecordingStartingAt = new LocalTimeProperty(null, "timeoutRecordingStartingAt", settings.timeoutRecordingStartingAt);
|
||||
timeoutRecordingEndingAt = new LocalTimeProperty(null, "timeoutRecordingEndingAt", settings.timeoutRecordingEndingAt);
|
||||
recordUntilDefaultDurationInMinutes = new SimpleLongProperty(null, "recordUntilDefaultDurationInMinutes", settings.recordUntilDefaultDurationInMinutes);
|
||||
dateTimeFormat = new SimpleStringProperty(null, "dateTimeFormat", settings.dateTimeFormat);
|
||||
}
|
||||
|
||||
private void createGui() {
|
||||
|
@ -229,6 +231,7 @@ public class SettingsTab extends Tab implements TabSelectionListener {
|
|||
Group.of("Look & Feel",
|
||||
Setting.of("Colors (Base / Accent)", new ColorSettingsPane(Config.getInstance())).needsRestart(),
|
||||
Setting.of("Font", new FontSettingsPane(this, config)).needsRestart(),
|
||||
Setting.of("Date format (empty = system default)", dateTimeFormat, DATE_FORMATTER_TOOLTIP).needsRestart(),
|
||||
Setting.of("Display stream resolution in overview", determineResolution),
|
||||
Setting.of("Total model count in title", totalModelCountInTitle, "Show the total number of models in the title bar"),
|
||||
Setting.of("Show grid lines in tables", showGridLinesInTables, "Show grid lines in tables").needsRestart(),
|
||||
|
@ -588,5 +591,54 @@ public class SettingsTab extends Tab implements TabSelectionListener {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private static final String DATE_FORMATTER_TOOLTIP = """
|
||||
Leave empty for system default
|
||||
|
||||
Symbol Meaning Presentation Examples
|
||||
------ ------- ------------ -------
|
||||
G era text AD; Anno Domini; A
|
||||
u year year 2004; 04
|
||||
y year-of-era year 2004; 04
|
||||
D day-of-year number 189
|
||||
M/L month-of-year number/text 7; 07; Jul; July; J
|
||||
d day-of-month number 10
|
||||
|
||||
Q/q quarter-of-year number/text 3; 03; Q3; 3rd quarter
|
||||
Y week-based-year year 1996; 96
|
||||
w week-of-week-based-year number 27
|
||||
W week-of-month number 4
|
||||
E day-of-week text Tue; Tuesday; T
|
||||
e/c localized day-of-week number/text 2; 02; Tue; Tuesday; T
|
||||
F week-of-month number 3
|
||||
|
||||
a am-pm-of-day text PM
|
||||
h clock-hour-of-am-pm (1-12) number 12
|
||||
K hour-of-am-pm (0-11) number 0
|
||||
k clock-hour-of-am-pm (1-24) number 0
|
||||
|
||||
H hour-of-day (0-23) number 0
|
||||
m minute-of-hour number 30
|
||||
s second-of-minute number 55
|
||||
S fraction-of-second fraction 978
|
||||
A milli-of-day number 1234
|
||||
n nano-of-second number 987654321
|
||||
N nano-of-day number 1234000000
|
||||
|
||||
V time-zone ID zone-id America/Los_Angeles; Z; -08:30
|
||||
z time-zone name zone-name Pacific Standard Time; PST
|
||||
O localized zone-offset offset-O GMT+8; GMT+08:00; UTC-08:00;
|
||||
X zone-offset 'Z' for zero offset-X Z; -08; -0830; -08:30; -083015; -08:30:15;
|
||||
x zone-offset offset-x +0000; -08; -0830; -08:30; -083015; -08:30:15;
|
||||
Z zone-offset offset-Z +0000; -0800; -08:00;
|
||||
|
||||
p pad next pad modifier 1
|
||||
|
||||
' escape for text delimiter
|
||||
'' single quote literal '
|
||||
[ optional section start
|
||||
] optional section end
|
||||
# reserved for future use
|
||||
{ reserved for future use
|
||||
} reserved for future use
|
||||
""";
|
||||
}
|
||||
|
|
|
@ -147,8 +147,8 @@ public class RecentlyWatchedTab extends Tab implements ShutdownListener {
|
|||
|
||||
TableColumn<PlayerStartedEvent, Instant> timestamp = createTableColumn("Timestamp", 150, idx);
|
||||
timestamp.setId("timestamp");
|
||||
timestamp.setCellValueFactory(cdf -> new SimpleObjectProperty<Instant>(cdf.getValue().getTimestamp()));
|
||||
timestamp.setCellFactory(new DateTimeCellFactory<>());
|
||||
timestamp.setCellValueFactory(cdf -> new SimpleObjectProperty<>(cdf.getValue().getTimestamp()));
|
||||
timestamp.setCellFactory(new DateTimeCellFactory<>(config.getDateTimeFormatter()));
|
||||
timestamp.setEditable(false);
|
||||
timestamp.setSortType(SortType.DESCENDING);
|
||||
table.getColumns().add(timestamp);
|
||||
|
|
|
@ -128,7 +128,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener, Shutdown
|
|||
var instant = cdf.getValue().getStartDate();
|
||||
return new SimpleObjectProperty<>(instant);
|
||||
});
|
||||
date.setCellFactory(new DateTimeCellFactory<>());
|
||||
date.setCellFactory(new DateTimeCellFactory<>(config.getDateTimeFormatter()));
|
||||
date.setPrefWidth(200);
|
||||
TableColumn<JavaFxRecording, String> status = new TableColumn<>("Status");
|
||||
status.setId("status");
|
||||
|
|
|
@ -315,7 +315,7 @@ public abstract class AbstractRecordedModelsTab extends Tab implements TabSelect
|
|||
|
||||
protected void addAddedTimestampColumn(int columnIdx) {
|
||||
TableColumn<JavaFxModel, Instant> tc = addTableColumn("addedTimestamp", "added at", columnIdx, 400);
|
||||
tc.setCellFactory(new DateTimeCellFactory<>());
|
||||
tc.setCellFactory(new DateTimeCellFactory<>(config.getDateTimeFormatter()));
|
||||
tc.setCellValueFactory(param -> new SimpleObjectProperty<>(param.getValue().getAddedTimestamp()));
|
||||
tc.setPrefWidth(150);
|
||||
tc.setEditable(false);
|
||||
|
|
|
@ -124,7 +124,7 @@ public class RecordedModelsTab extends AbstractRecordedModelsTab implements TabS
|
|||
table.getColumns().add(priority);
|
||||
TableColumn<JavaFxModel, Instant> lastSeen = new TableColumn<>("last seen");
|
||||
lastSeen.setCellValueFactory(cdf -> cdf.getValue().lastSeenProperty());
|
||||
lastSeen.setCellFactory(new DateTimeCellFactory<>());
|
||||
lastSeen.setCellFactory(new DateTimeCellFactory<>(config.getDateTimeFormatter()));
|
||||
lastSeen.setPrefWidth(150);
|
||||
lastSeen.setEditable(false);
|
||||
lastSeen.setId("lastSeen");
|
||||
|
@ -134,7 +134,7 @@ public class RecordedModelsTab extends AbstractRecordedModelsTab implements TabS
|
|||
table.getColumns().add(lastSeen);
|
||||
TableColumn<JavaFxModel, Instant> lastRecorded = new TableColumn<>("last recorded");
|
||||
lastRecorded.setCellValueFactory(cdf -> cdf.getValue().lastRecordedProperty());
|
||||
lastRecorded.setCellFactory(new DateTimeCellFactory<>());
|
||||
lastRecorded.setCellFactory(new DateTimeCellFactory<>(config.getDateTimeFormatter()));
|
||||
lastRecorded.setPrefWidth(150);
|
||||
lastRecorded.setEditable(false);
|
||||
lastRecorded.setId("lastRecorded");
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
package ctbrec;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.*;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import ctbrec.Settings.SplitStrategy;
|
||||
import ctbrec.io.*;
|
||||
import ctbrec.recorder.postprocessing.DeleteTooShort;
|
||||
import ctbrec.recorder.postprocessing.PostProcessor;
|
||||
import ctbrec.recorder.postprocessing.RemoveKeepFile;
|
||||
import ctbrec.recorder.postprocessing.Script;
|
||||
import ctbrec.sites.Site;
|
||||
import ctbrec.sites.cam4.Cam4Model;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -13,34 +24,13 @@ import java.time.LocalDateTime;
|
|||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
|
||||
import ctbrec.Settings.SplitStrategy;
|
||||
import ctbrec.io.FileJsonAdapter;
|
||||
import ctbrec.io.LocalTimeJsonAdapter;
|
||||
import ctbrec.io.ModelJsonAdapter;
|
||||
import ctbrec.io.PostProcessorJsonAdapter;
|
||||
import ctbrec.io.UuidJSonAdapter;
|
||||
import ctbrec.recorder.postprocessing.DeleteTooShort;
|
||||
import ctbrec.recorder.postprocessing.PostProcessor;
|
||||
import ctbrec.recorder.postprocessing.RemoveKeepFile;
|
||||
import ctbrec.recorder.postprocessing.Script;
|
||||
import ctbrec.sites.Site;
|
||||
import ctbrec.sites.cam4.Cam4Model;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.nio.file.StandardOpenOption.*;
|
||||
|
||||
// TODO don't use singleton pattern
|
||||
public class Config {
|
||||
|
@ -305,6 +295,15 @@ public class Config {
|
|||
return context;
|
||||
}
|
||||
|
||||
public DateTimeFormatter getDateTimeFormatter() {
|
||||
var dtf = getSettings().dateTimeFormat;
|
||||
if (StringUtil.isNotBlank(dtf)) {
|
||||
return DateTimeFormatter.ofPattern(dtf);
|
||||
} else {
|
||||
return DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
|
||||
}
|
||||
}
|
||||
|
||||
public String getModelNotes(Model m) {
|
||||
return Config.getInstance().getSettings().modelNotes.getOrDefault(m.getUrl(), "");
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package ctbrec;
|
|||
|
||||
import java.io.File;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -66,6 +67,7 @@ public class Settings {
|
|||
public int concurrentRecordings = 0;
|
||||
public boolean confirmationForDangerousActions = false;
|
||||
public String contactsheetTimestampLook = "font=sans-serif:fontcolor=white:fontsize=60:box=1:boxcolor=black@0.5:boxborderw=5";
|
||||
public String dateTimeFormat = "";
|
||||
public int defaultPriority = 50;
|
||||
public boolean determineResolution = false;
|
||||
public List<String> disabledSites = new ArrayList<>();
|
||||
|
|
Loading…
Reference in New Issue