diff --git a/client/src/main/java/ctbrec/ui/CamrecApplication.java b/client/src/main/java/ctbrec/ui/CamrecApplication.java index 94edea00..c5df0f6e 100644 --- a/client/src/main/java/ctbrec/ui/CamrecApplication.java +++ b/client/src/main/java/ctbrec/ui/CamrecApplication.java @@ -63,12 +63,12 @@ import ctbrec.ui.settings.SettingsTab; import ctbrec.ui.tabs.DonateTabFx; import ctbrec.ui.tabs.HelpTab; import ctbrec.ui.tabs.RecentlyWatchedTab; -import ctbrec.ui.tabs.RecordedTab; import ctbrec.ui.tabs.RecordingsTab; import ctbrec.ui.tabs.SiteTab; import ctbrec.ui.tabs.TabSelectionListener; import ctbrec.ui.tabs.UpdateTab; import ctbrec.ui.tabs.logging.LoggingTab; +import ctbrec.ui.tabs.recorded.RecordedTab; import javafx.application.Application; import javafx.application.HostServices; import javafx.application.Platform; diff --git a/client/src/main/java/ctbrec/ui/Icon.java b/client/src/main/java/ctbrec/ui/Icon.java new file mode 100644 index 00000000..2f55c911 --- /dev/null +++ b/client/src/main/java/ctbrec/ui/Icon.java @@ -0,0 +1,18 @@ +package ctbrec.ui; + +public enum Icon { + + GROUP_16(Icon.class.getResource("/16/users.png").toExternalForm()), + CHECK_16(Icon.class.getResource("/16/check-small.png").toExternalForm()), + CLOCK_16(Icon.class.getResource("/16/clock.png").toExternalForm()); + + private String url; + + private Icon(String url) { + this.url = url; + } + + public String url() { + return url; + } +} diff --git a/client/src/main/java/ctbrec/ui/JavaFxModel.java b/client/src/main/java/ctbrec/ui/JavaFxModel.java index 05a4f32b..c76bc9ee 100644 --- a/client/src/main/java/ctbrec/ui/JavaFxModel.java +++ b/client/src/main/java/ctbrec/ui/JavaFxModel.java @@ -22,15 +22,13 @@ import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; /** * Just a wrapper for Model, which augments it with JavaFX value binding properties, so that UI widgets get updated proeprly */ public class JavaFxModel implements Model { - private transient StringProperty onlineProperty = new SimpleStringProperty(); - private transient StringProperty recordingProperty = new SimpleStringProperty(); + private transient BooleanProperty onlineProperty = new SimpleBooleanProperty(); + private transient BooleanProperty recordingProperty = new SimpleBooleanProperty(); private transient BooleanProperty pausedProperty = new SimpleBooleanProperty(); private transient SimpleIntegerProperty priorityProperty = new SimpleIntegerProperty(); private transient SimpleObjectProperty lastSeenProperty = new SimpleObjectProperty<>(); @@ -105,14 +103,22 @@ public class JavaFxModel implements Model { return delegate.toString(); } - public StringProperty getOnlineProperty() { + public BooleanProperty getOnlineProperty() { return onlineProperty; } - public StringProperty getRecordingProperty() { + public void setOnlineProperty(boolean online) { + this.onlineProperty.set(online); + } + + public BooleanProperty getRecordingProperty() { return recordingProperty; } + public void setRecordingProperty(boolean recording) { + this.recordingProperty.setValue(recording); + } + public BooleanProperty getPausedProperty() { return pausedProperty; } diff --git a/client/src/main/java/ctbrec/ui/action/AddToGroupAction.java b/client/src/main/java/ctbrec/ui/action/AddToGroupAction.java index db2a5c86..0a285db4 100644 --- a/client/src/main/java/ctbrec/ui/action/AddToGroupAction.java +++ b/client/src/main/java/ctbrec/ui/action/AddToGroupAction.java @@ -41,7 +41,7 @@ public class AddToGroupAction { public void execute() { source.setCursor(Cursor.WAIT); try { - var dialog = new ModelGroupDialog(); + var dialog = new AddModelGroupDialog(); boolean ok = Dialogs.showCustomInput(source.getScene(), "Add model to group", dialog.getMainPane()); dialog.requestFocus(); if (ok) { @@ -70,7 +70,7 @@ public class AddToGroupAction { } } - private static class ModelGroupDialog { + private static class AddModelGroupDialog { private ComboBox comboBox; private TextField editor; private ObservableListSuggester suggester; diff --git a/client/src/main/java/ctbrec/ui/action/EditGroupAction.java b/client/src/main/java/ctbrec/ui/action/EditGroupAction.java new file mode 100644 index 00000000..c60a0cfb --- /dev/null +++ b/client/src/main/java/ctbrec/ui/action/EditGroupAction.java @@ -0,0 +1,161 @@ +package ctbrec.ui.action; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import ctbrec.Config; +import ctbrec.Model; +import ctbrec.ModelGroup; +import ctbrec.recorder.Recorder; +import ctbrec.ui.controls.Dialogs; +import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javafx.scene.Cursor; +import javafx.scene.Node; +import javafx.scene.control.Button; +import javafx.scene.control.ListView; +import javafx.scene.control.TextField; +import javafx.scene.control.Tooltip; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; + +public class EditGroupAction { + + private static final String DIALOG_TITLE = "Edit model group"; + + private Node source; + private Model model; + private Recorder recorder; + + public EditGroupAction(Node source, Recorder recorder, Model model) { + this.source = source; + this.recorder = recorder; + this.model = model; + } + + public void execute() { + source.setCursor(Cursor.WAIT); + try { + var dialog = new EditModelGroupDialog(model); + boolean ok = Dialogs.showCustomInput(source.getScene(), DIALOG_TITLE, dialog); + if (ok) { + var group = dialog.getModelGroup(); + group.setName(dialog.getGroupName()); + group.getModelUrls().clear(); + group.getModelUrls().addAll(dialog.getUrls()); + recorder.saveModelGroup(group); + } + } catch (Exception e) { + Dialogs.showError(source.getScene(), DIALOG_TITLE, "Editing model group failed", e); + } finally { + source.setCursor(Cursor.DEFAULT); + } + } + + private static class EditModelGroupDialog extends GridPane { + private TextField groupName; + private ListView urlListView; + private ObservableList urlList; + private ModelGroup modelGroup; + private List urls; + + public EditModelGroupDialog(Model model) { + Optional optionalModelGroup = Config.getInstance().getModelGroup(model); + if (optionalModelGroup.isPresent()) { + modelGroup = optionalModelGroup.get(); + urls = new ArrayList<>(modelGroup.getModelUrls()); + createGui(modelGroup); + } else { + Dialogs.showError(getScene(), DIALOG_TITLE, "No group found for model", null); + } + } + + public ModelGroup getModelGroup() { + return modelGroup; + } + + public List getUrls() { + return urls; + } + + public String getGroupName() { + return groupName.getText(); + } + + void createGui(ModelGroup modelGroup) { + setHgap(5); + vgapProperty().bind(hgapProperty()); + + groupName = new TextField(modelGroup.getName()); + Button up = createUpButton(); + Button down = createDownButton(); + Button remove = createRemoveButton(); + var buttons = new VBox(3, up, down, remove); + urlList = FXCollections.observableList(modelGroup.getModelUrls()); + urlList.addListener((ListChangeListener) change -> { + urls = new ArrayList<>(urlList); + }); + urlListView = new ListView<>(urlList); + GridPane.setHgrow(urlListView, Priority.ALWAYS); + + var row = 0; + add(groupName, 0, row++); + add(urlListView, 0, row); + add(buttons, 1, row); + + urlListView.getSelectionModel().selectedIndexProperty().addListener((obs, oldV, newV) -> { + var idx = newV.intValue(); + boolean noSelection = idx == -1; + up.setDisable(noSelection || idx == 0); + down.setDisable(noSelection || idx == urlList.size() - 1); + remove.setDisable(noSelection); + }); + } + + private Button createUpButton() { + var button = createButton("\u25B4", "Move step up"); + button.setOnAction(evt -> { + int idx = urlListView.getSelectionModel().getSelectedIndex(); + String selectedItem = urlListView.getSelectionModel().getSelectedItem(); + urlList.remove(idx); + urlList.add(idx - 1, selectedItem); + urlListView.getSelectionModel().select(idx - 1); + }); + return button; + } + + private Button createDownButton() { + var button = createButton("\u25BE", "Move step down"); + button.setOnAction(evt -> { + int idx = urlListView.getSelectionModel().getSelectedIndex(); + String selectedItem = urlListView.getSelectionModel().getSelectedItem(); + urlList.remove(idx); + urlList.add(idx + 1, selectedItem); + urlListView.getSelectionModel().select(idx + 1); + }); + return button; + } + + private Button createRemoveButton() { + var button = createButton("-", "Remove selected step"); + button.setOnAction(evt -> { + String selectedItem = urlListView.getSelectionModel().getSelectedItem(); + if (selectedItem != null) { + urlList.remove(selectedItem); + } + }); + return button; + } + + private Button createButton(String text, String tooltip) { + var b = new Button(text); + b.setTooltip(new Tooltip(tooltip)); + b.setDisable(true); + b.setPrefSize(32, 32); + return b; + } + } +} diff --git a/client/src/main/java/ctbrec/ui/controls/Dialogs.java b/client/src/main/java/ctbrec/ui/controls/Dialogs.java index 3de44bb5..1e5292ec 100644 --- a/client/src/main/java/ctbrec/ui/controls/Dialogs.java +++ b/client/src/main/java/ctbrec/ui/controls/Dialogs.java @@ -56,7 +56,7 @@ public class Dialogs { } alert.setContentText(content); if (parent != null) { - Stage stage = (Stage) alert.getDialogPane().getScene().getWindow(); + var stage = (Stage) alert.getDialogPane().getScene().getWindow(); stage.getScene().getStylesheets().addAll(parent.getStylesheets()); } alert.showAndWait(); @@ -77,18 +77,18 @@ public class Dialogs { dialog.initModality(Modality.APPLICATION_MODAL); dialog.setResizable(true); InputStream icon = Dialogs.class.getResourceAsStream("/icon.png"); - Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow(); + var stage = (Stage) dialog.getDialogPane().getScene().getWindow(); stage.getIcons().add(new Image(icon)); if (parent != null) { stage.getScene().getStylesheets().addAll(parent.getStylesheets()); } - GridPane grid = new GridPane(); + var grid = new GridPane(); grid.setHgap(10); grid.setVgap(10); grid.setPadding(new Insets(20, 150, 10, 10)); - TextArea notes = new TextArea(text); + var notes = new TextArea(text); notes.setPrefRowCount(3); grid.add(notes, 0, 0); dialog.getDialogPane().setContent(grid); @@ -112,7 +112,7 @@ public class Dialogs { dialog.initModality(Modality.APPLICATION_MODAL); dialog.setResizable(true); InputStream icon = Dialogs.class.getResourceAsStream("/icon.png"); - Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow(); + var stage = (Stage) dialog.getDialogPane().getScene().getWindow(); stage.getIcons().add(new Image(icon)); if (parent != null) { stage.getScene().getStylesheets().addAll(parent.getStylesheets()); @@ -123,7 +123,7 @@ public class Dialogs { } public static boolean showConfirmDialog(String title, String message, String header, Scene parent) { - AutosizeAlert confirm = new AutosizeAlert(AlertType.CONFIRMATION, message, parent, YES, NO); + var confirm = new AutosizeAlert(AlertType.CONFIRMATION, message, parent, YES, NO); confirm.setTitle(title); confirm.setHeaderText(header); confirm.showAndWait(); @@ -131,8 +131,8 @@ public class Dialogs { } public static ButtonType showShutdownDialog(Scene parent) { - String message = "There are recordings in progress"; - AutosizeAlert confirm = new AutosizeAlert(AlertType.CONFIRMATION, "", parent, YES, FINISH, NO); + var message = "There are recordings in progress"; + var confirm = new AutosizeAlert(AlertType.CONFIRMATION, "", parent, YES, FINISH, NO); confirm.setTitle("Shutdown"); confirm.setHeaderText(message); ((Button) confirm.getDialogPane().lookupButton(ButtonType.YES)).setText("Shutdown Now"); @@ -146,7 +146,7 @@ public class Dialogs { } public static Optional showModelGroupSelectionDialog(Scene parent, Model model) { - GridPane dialogPane = new GridPane(); + var dialogPane = new GridPane(); Set modelGroups = Config.getInstance().getSettings().modelGroups; ObservableList comboBoxModel = FXCollections.observableArrayList(modelGroups); ComboBox comboBox = new ComboBox<>(comboBoxModel); @@ -165,7 +165,7 @@ public class Dialogs { existingGroup.get().add(model); return existingGroup; } else { - ModelGroup group = new ModelGroup(); + var group = new ModelGroup(); group.setId(UUID.randomUUID()); group.setName(text); group.add(model); diff --git a/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java b/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java index d7748246..073fe677 100644 --- a/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java +++ b/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java @@ -41,6 +41,7 @@ import ctbrec.ui.SiteUiFactory; import ctbrec.ui.TipDialog; import ctbrec.ui.TokenLabel; import ctbrec.ui.action.AddToGroupAction; +import ctbrec.ui.action.EditGroupAction; import ctbrec.ui.action.IgnoreModelsAction; import ctbrec.ui.action.OpenRecordingsDir; import ctbrec.ui.action.SetStopDateAction; @@ -469,57 +470,57 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { } private ContextMenu createContextMenu(ThumbCell cell) { - Model model = cell.getModel(); + var model = cell.getModel(); boolean modelIsTrackedByRecorder = recorder.isTracked(model); - MenuItem openInPlayer = new MenuItem("Open in Player"); + var openInPlayer = new MenuItem("Open in Player"); openInPlayer.setOnAction(e -> startPlayer(getSelectedThumbCells(cell))); - MenuItem start = new MenuItem("Start Recording"); + var start = new MenuItem("Start Recording"); start.setOnAction(e -> startStopAction(getSelectedThumbCells(cell), true)); - MenuItem stop = new MenuItem("Stop Recording"); + var stop = new MenuItem("Stop Recording"); stop.setOnAction(e -> startStopAction(getSelectedThumbCells(cell), false)); - MenuItem startStop = recorder.isTracked(model) ? stop : start; + var startStop = recorder.isTracked(model) ? stop : start; - MenuItem recordUntil = new MenuItem("Start Recording Until"); + var recordUntil = new MenuItem("Start Recording Until"); recordUntil.setOnAction(e -> startRecordingWithTimeLimit(getSelectedThumbCells(cell))); - MenuItem addPaused = new MenuItem("Add in paused state"); + var addPaused = new MenuItem("Add in paused state"); addPaused.setOnAction(e -> addPaused(getSelectedThumbCells(cell))); - MenuItem recordLater = new MenuItem("Record Later"); + var recordLater = new MenuItem("Record Later"); recordLater.setOnAction(e -> recordLater(getSelectedThumbCells(cell), true)); - MenuItem removeRecordLater = new MenuItem("Forget Model"); + var removeRecordLater = new MenuItem("Forget Model"); removeRecordLater.setOnAction(e -> recordLater(getSelectedThumbCells(cell), false)); - MenuItem addRemoveBookmark = recorder.isMarkedForLaterRecording(model) ? removeRecordLater : recordLater; + var addRemoveBookmark = recorder.isMarkedForLaterRecording(model) ? removeRecordLater : recordLater; - MenuItem pause = new MenuItem("Pause Recording"); + var pause = new MenuItem("Pause Recording"); pause.setOnAction(e -> pauseResumeAction(getSelectedThumbCells(cell), true)); - MenuItem resume = new MenuItem("Resume Recording"); + var resume = new MenuItem("Resume Recording"); resume.setOnAction(e -> pauseResumeAction(getSelectedThumbCells(cell), false)); - MenuItem pauseResume = recorder.isSuspended(model) ? resume : pause; + var pauseResume = recorder.isSuspended(model) ? resume : pause; - MenuItem follow = new MenuItem("Follow"); + var follow = new MenuItem("Follow"); follow.setOnAction(e -> follow(getSelectedThumbCells(cell), true)); - MenuItem unfollow = new MenuItem("Unfollow"); + var unfollow = new MenuItem("Unfollow"); unfollow.setOnAction(e -> follow(getSelectedThumbCells(cell), false)); - MenuItem addToGroup = new MenuItem("Add to group"); + var addToGroup = new MenuItem("Add to group"); addToGroup.setOnAction(e -> addToGroup(model)); - MenuItem editGroup = new MenuItem("Edit group"); + var editGroup = new MenuItem("Edit group"); editGroup.setOnAction(e -> editGroup(model)); - MenuItem ignore = new MenuItem("Ignore"); + var ignore = new MenuItem("Ignore"); ignore.setOnAction(e -> ignore(getSelectedThumbCells(cell))); - MenuItem refresh = new MenuItem("Refresh Overview"); + var refresh = new MenuItem("Refresh Overview"); refresh.setOnAction(e -> refresh()); - MenuItem openRecDir = new MenuItem("Open recording directory"); + var openRecDir = new MenuItem("Open recording directory"); openRecDir.setOnAction(e -> new OpenRecordingsDir(cell, model).execute()); - MenuItem copyUrl = createCopyUrlMenuItem(cell); - MenuItem openInBrowser = createOpenInBrowser(cell); - MenuItem sendTip = createTipMenuItem(cell); + var copyUrl = createCopyUrlMenuItem(cell); + var openInBrowser = createOpenInBrowser(cell); + var sendTip = createTipMenuItem(cell); configureItemsForSelection(cell, openInPlayer, copyUrl, sendTip); @@ -535,7 +536,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { } contextMenu.getItems().add(new SeparatorMenuItem()); if (site.supportsFollow()) { - MenuItem followOrUnFollow = (this instanceof FollowedTab) ? unfollow : follow; + var followOrUnFollow = (this instanceof FollowedTab) ? unfollow : follow; followOrUnFollow.setDisable(!site.credentialsAvailable()); contextMenu.getItems().add(followOrUnFollow); } @@ -546,7 +547,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { contextMenu.getItems().add(modelGroup.isEmpty() ? addToGroup : editGroup); contextMenu.getItems().addAll(copyUrl, openInBrowser, ignore, refresh, openRecDir); if (model instanceof MyFreeCamsModel && Objects.equals(System.getenv("CTBREC_DEV"), "1")) { - MenuItem debug = new MenuItem("debug"); + var debug = new MenuItem("debug"); debug.setOnAction(e -> MyFreeCamsClient.getInstance().getSessionState(model)); contextMenu.getItems().add(debug); } @@ -555,6 +556,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { } private void editGroup(Model model) { + new EditGroupAction(this.getContent(), recorder, model).execute(); } private void addToGroup(Model model) { diff --git a/client/src/main/java/ctbrec/ui/tabs/recorded/ClickableTableCell.java b/client/src/main/java/ctbrec/ui/tabs/recorded/ClickableTableCell.java new file mode 100644 index 00000000..85262a0f --- /dev/null +++ b/client/src/main/java/ctbrec/ui/tabs/recorded/ClickableTableCell.java @@ -0,0 +1,21 @@ +package ctbrec.ui.tabs.recorded; + +import ctbrec.ui.JavaFxModel; +import ctbrec.ui.action.PlayAction; +import javafx.scene.control.TableCell; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; + +public class ClickableTableCell extends TableCell { + + public ClickableTableCell() { + addEventFilter(MouseEvent.MOUSE_CLICKED, event -> { + if (event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 2) { + JavaFxModel selectedModel = getTableView().getSelectionModel().getSelectedItem(); + if(selectedModel != null) { + new PlayAction(getTableView(), selectedModel).execute(); + } + } + }); + } +} diff --git a/client/src/main/java/ctbrec/ui/tabs/recorded/IconTableCell.java b/client/src/main/java/ctbrec/ui/tabs/recorded/IconTableCell.java new file mode 100644 index 00000000..cd7884f9 --- /dev/null +++ b/client/src/main/java/ctbrec/ui/tabs/recorded/IconTableCell.java @@ -0,0 +1,47 @@ +package ctbrec.ui.tabs.recorded; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import ctbrec.ui.Icon; +import javafx.scene.control.Tooltip; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; + +public class IconTableCell extends ClickableTableCell { + + protected String tooltip; + protected HBox iconRow; + private Map icons; + + public IconTableCell(Map icons) { + this.icons = Objects.requireNonNullElse(icons, new HashMap<>()); + iconRow = new HBox(3); + } + + protected void show(Icon iconName) { + var imageView = icons.get(iconName); + if (imageView != null) { + iconRow.getChildren().remove(imageView); + iconRow.getChildren().add(imageView); + } + } + + protected void hide(Icon iconName) { + var imageView = icons.get(iconName); + if (imageView != null) { + iconRow.getChildren().remove(imageView); + } + } + + @Override + protected void updateItem(T value, boolean empty) { + if (tooltip != null) { + setTooltip(new Tooltip(tooltip)); + } else { + setTooltip(null); + } + setGraphic(iconRow); + } +} diff --git a/client/src/main/java/ctbrec/ui/tabs/recorded/ModelNameTableCell.java b/client/src/main/java/ctbrec/ui/tabs/recorded/ModelNameTableCell.java new file mode 100644 index 00000000..4f9120f3 --- /dev/null +++ b/client/src/main/java/ctbrec/ui/tabs/recorded/ModelNameTableCell.java @@ -0,0 +1,40 @@ +package ctbrec.ui.tabs.recorded; + +import static ctbrec.ui.Icon.*; + +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import ctbrec.Config; +import ctbrec.Model; +import ctbrec.ModelGroup; +import javafx.scene.image.ImageView; + +public class ModelNameTableCell extends IconTableCell { + + public ModelNameTableCell() { + super(Map.of(GROUP_16, new ImageView(GROUP_16.url()))); + } + + @Override + protected void updateItem(String item, boolean empty) { + setText(null); + tooltip = null; + hide(GROUP_16); + + if (item != null && !empty) { + setText(item); + Model m = getTableView().getItems().get(getTableRow().getIndex()); + Optional optionalGroup = Config.getInstance().getModelGroup(m); + if (optionalGroup.isPresent()) { + ModelGroup group = optionalGroup.get(); + setText(group.getName() + " (aka " + item + ')'); + show(GROUP_16); + tooltip = group.getModelUrls().size() + " models:\n"; + tooltip += group.getModelUrls().stream().collect(Collectors.joining("\n")); + } + } + super.updateItem(item, empty); + } +} diff --git a/client/src/main/java/ctbrec/ui/tabs/recorded/OnlineTableCell.java b/client/src/main/java/ctbrec/ui/tabs/recorded/OnlineTableCell.java new file mode 100644 index 00000000..fb535162 --- /dev/null +++ b/client/src/main/java/ctbrec/ui/tabs/recorded/OnlineTableCell.java @@ -0,0 +1,32 @@ +package ctbrec.ui.tabs.recorded; + +import static ctbrec.ui.Icon.*; + +import java.util.Map; + +import com.google.common.base.Objects; + +import javafx.scene.image.ImageView; + +public class OnlineTableCell extends IconTableCell { + + public OnlineTableCell() { + super(Map.of(CHECK_16, new ImageView(CHECK_16.url()))); + } + + @Override + protected void updateItem(Boolean value, boolean empty) { + if (!empty) { + if (Objects.equal(value, Boolean.TRUE)) { + show(CHECK_16); + tooltip = "Online"; + } else { + hide(CHECK_16); + tooltip = null; + } + } else { + tooltip = null; + } + super.updateItem(value, empty); + } +} diff --git a/client/src/main/java/ctbrec/ui/tabs/RecordLaterTab.java b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordLaterTab.java similarity index 99% rename from client/src/main/java/ctbrec/ui/tabs/RecordLaterTab.java rename to client/src/main/java/ctbrec/ui/tabs/recorded/RecordLaterTab.java index 59a7266e..f7a2148e 100644 --- a/client/src/main/java/ctbrec/ui/tabs/RecordLaterTab.java +++ b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordLaterTab.java @@ -1,4 +1,4 @@ -package ctbrec.ui.tabs; +package ctbrec.ui.tabs.recorded; import java.io.IOException; import java.security.InvalidKeyException; @@ -37,6 +37,7 @@ import ctbrec.ui.controls.Dialogs; import ctbrec.ui.controls.SearchBox; import ctbrec.ui.controls.autocomplete.AutoFillTextField; import ctbrec.ui.controls.autocomplete.ObservableListSuggester; +import ctbrec.ui.tabs.TabSelectionListener; import javafx.application.Platform; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringPropertyBase; diff --git a/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordedModelsTab.java similarity index 89% rename from client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java rename to client/src/main/java/ctbrec/ui/tabs/recorded/RecordedModelsTab.java index b0da6346..e3bf2a74 100644 --- a/client/src/main/java/ctbrec/ui/tabs/RecordedModelsTab.java +++ b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordedModelsTab.java @@ -1,16 +1,11 @@ -package ctbrec.ui.tabs; +package ctbrec.ui.tabs.recorded; import static ctbrec.Recording.State.*; -import static ctbrec.ui.UnicodeEmoji.*; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.time.Instant; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.FormatStyle; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -31,6 +26,7 @@ import org.slf4j.LoggerFactory; import ctbrec.Config; import ctbrec.Model; +import ctbrec.ModelGroup; import ctbrec.Recording; import ctbrec.StringUtil; import ctbrec.recorder.Recorder; @@ -40,7 +36,9 @@ import ctbrec.ui.DesktopIntegration; import ctbrec.ui.JavaFxModel; import ctbrec.ui.PreviewPopupHandler; import ctbrec.ui.StreamSourceSelectionDialog; +import ctbrec.ui.action.AddToGroupAction; import ctbrec.ui.action.CheckModelAccountAction; +import ctbrec.ui.action.EditGroupAction; import ctbrec.ui.action.EditNotesAction; import ctbrec.ui.action.FollowAction; import ctbrec.ui.action.IgnoreModelsAction; @@ -59,6 +57,7 @@ import ctbrec.ui.controls.Dialogs; import ctbrec.ui.controls.SearchBox; import ctbrec.ui.controls.autocomplete.AutoFillTextField; import ctbrec.ui.controls.autocomplete.ObservableListSuggester; +import ctbrec.ui.tabs.TabSelectionListener; import javafx.application.Platform; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringPropertyBase; @@ -157,7 +156,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { table.setEditable(true); table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); - PreviewPopupHandler previewPopupHandler = new PreviewPopupHandler(table); + var previewPopupHandler = new PreviewPopupHandler(table); table.setRowFactory(tableview -> { TableRow row = new TableRow<>(); row.addEventHandler(MouseEvent.ANY, previewPopupHandler); @@ -174,7 +173,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { TableColumn name = new TableColumn<>("Model"); name.setPrefWidth(200); name.setCellValueFactory(new PropertyValueFactory<>("displayName")); - name.setCellFactory(new ClickableCellFactory<>()); + name.setCellFactory(param -> new ModelNameTableCell()); name.setEditable(false); name.setId("name"); TableColumn url = new TableColumn<>("URL"); @@ -183,15 +182,16 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { url.setPrefWidth(400); url.setEditable(false); url.setId("url"); - TableColumn online = new TableColumn<>("Online"); + TableColumn online = new TableColumn<>("Online"); online.setCellValueFactory(cdf -> cdf.getValue().getOnlineProperty()); + online.setCellFactory(param -> new OnlineTableCell()); online.setPrefWidth(100); online.setEditable(false); online.setId("online"); online.setStyle(STYLE_ALIGN_CENTER); - TableColumn recording = new TableColumn<>("Recording"); + TableColumn recording = new TableColumn<>("Recording"); recording.setCellValueFactory(cdf -> cdf.getValue().getRecordingProperty()); - recording.setCellFactory(tc -> new RecordingCell()); + recording.setCellFactory(tc -> new RecordingTableCell()); recording.setPrefWidth(100); recording.setEditable(false); recording.setId("recording"); @@ -272,7 +272,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { scrollPane.setContent(table); - HBox addModelBox = new HBox(5); + var addModelBox = new HBox(5); modelLabel.setPadding(new Insets(5, 0, 0, 0)); ObservableList suggestions = FXCollections.observableArrayList(); sites.forEach(site -> suggestions.add(site.getClass().getSimpleName())); @@ -302,7 +302,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { checkModelAccountExistance.setOnAction(evt -> new CheckModelAccountAction(checkModelAccountExistance, recorder) .execute(Predicate.not(Model::isMarkedForLaterRecording))); - HBox filterContainer = new HBox(); + var filterContainer = new HBox(); filterContainer.setSpacing(0); filterContainer.setPadding(new Insets(0)); filterContainer.setAlignment(Pos.CENTER_RIGHT); @@ -326,7 +326,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { filterContainer.getChildren().add(filter); addModelBox.getChildren().add(filterContainer); - BorderPane root = new BorderPane(); + var root = new BorderPane(); root.setPadding(new Insets(5)); root.setTop(addModelBox); root.setCenter(scrollPane); @@ -338,7 +338,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { private void jumpToNextModel(KeyCode code) { if (!table.getItems().isEmpty() && (code.isLetterKey() || code.isDigitKey())) { // determine where to start looking for the next model - int startAt = 0; + var startAt = 0; if (table.getSelectionModel().getSelectedIndex() >= 0) { startAt = table.getSelectionModel().getSelectedIndex() + 1; if (startAt >= table.getItems().size()) { @@ -346,7 +346,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { } } - String c = code.getChar().toLowerCase(); + var c = code.getChar().toLowerCase(); int i = startAt; do { JavaFxModel current = table.getItems().get(i); @@ -378,7 +378,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { private void updatePriority(JavaFxModel model, int priority) { try { if (priority < 0 || priority > 100) { - String msg = "Priority has to be between 0 and 100"; + var msg = "Priority has to be between 0 and 100"; Dialogs.showError(table.getScene(), "Invalid value", msg, null); } else { model.setPriority(priority); @@ -404,7 +404,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { private void addModelByUrl(String url) { for (Site site : sites) { - Model newModel = site.createModelFromUrl(url); + var newModel = site.createModelFromUrl(url); if (newModel != null) { try { recorder.addModel(newModel); @@ -431,7 +431,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { for (Site site : sites) { if (Objects.equals(siteName.toLowerCase(), site.getClass().getSimpleName().toLowerCase())) { try { - Model m = site.createModel(modelName); + var m = site.createModel(modelName); recorder.addModel(m); } catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) { Dialogs.showError(getTabPane().getScene(), "Couldn't add model", "The model " + modelName + " could not be added:", e1); @@ -548,18 +548,18 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { String[] tokens = filter.split(" "); observableModels.addAll(filteredModels); filteredModels.clear(); - for (int i = 0; i < table.getItems().size(); i++) { - StringBuilder sb = new StringBuilder(); + for (var i = 0; i < table.getItems().size(); i++) { + var sb = new StringBuilder(); for (TableColumn tc : table.getColumns()) { Object cellData = tc.getCellData(i); if (cellData != null) { - String content = cellData.toString(); + var content = cellData.toString(); sb.append(content).append(' '); } } - String searchText = sb.toString(); + var searchText = sb.toString(); - boolean tokensMissing = false; + var tokensMissing = false; for (String token : tokens) { if (!searchText.toLowerCase().contains(token.toLowerCase())) { tokensMissing = true; @@ -594,18 +594,14 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { .peek(fxm -> { // NOSONAR for (Recording recording : recordings) { if(recording.getStatus() == RECORDING && Objects.equals(recording.getModel(), fxm)){ - String recordingValue = HEAVY_CHECK_MARK; - if(!Objects.equals(recording.getModel().getRecordUntil(), Instant.ofEpochMilli(Model.RECORD_INDEFINITELY))) { - recordingValue += ' ' + CLOCK; - } - fxm.getRecordingProperty().set(recordingValue); + fxm.setRecordingProperty(true); break; } } for (Model onlineModel : onlineModels) { if(Objects.equals(onlineModel, fxm)) { - fxm.getOnlineProperty().set(HEAVY_CHECK_MARK); + fxm.setOnlineProperty(true); break; } } @@ -616,7 +612,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { } }; ExecutorService executor = Executors.newSingleThreadExecutor(r -> { - Thread t = new Thread(r); + var t = new Thread(r); t.setDaemon(true); t.setName("RecordedModelsTab UpdateService"); return t; @@ -645,44 +641,49 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { if (selectedModels.isEmpty()) { return null; } - MenuItem stop = new MenuItem("Remove Model"); + var stop = new MenuItem("Remove Model"); stop.setOnAction(e -> stopAction(selectedModels)); - MenuItem recordLater = new MenuItem("Record Later"); + var recordLater = new MenuItem("Record Later"); recordLater.setOnAction(e -> recordLater(selectedModels)); - MenuItem copyUrl = new MenuItem("Copy URL"); + var copyUrl = new MenuItem("Copy URL"); copyUrl.setOnAction(e -> { Model selected = selectedModels.get(0); - final Clipboard clipboard = Clipboard.getSystemClipboard(); - final ClipboardContent content = new ClipboardContent(); + final var clipboard = Clipboard.getSystemClipboard(); + final var content = new ClipboardContent(); content.putString(selected.getUrl()); clipboard.setContent(content); }); - MenuItem pauseRecording = new MenuItem("Pause Recording"); + var pauseRecording = new MenuItem("Pause Recording"); pauseRecording.setOnAction(e -> pauseRecording(selectedModels)); - MenuItem resumeRecording = new MenuItem("Resume Recording"); + var resumeRecording = new MenuItem("Resume Recording"); resumeRecording.setOnAction(e -> resumeRecording(selectedModels)); - MenuItem stopRecordingAt = new MenuItem("Stop Recording at Date"); + var stopRecordingAt = new MenuItem("Stop Recording at Date"); stopRecordingAt.setOnAction(e -> setStopDate(selectedModels.get(0))); - MenuItem removeTimeLimit = new MenuItem("Remove Time Limit"); + var removeTimeLimit = new MenuItem("Remove Time Limit"); removeTimeLimit.setOnAction(e -> removeTimeLimit(selectedModels.get(0))); - MenuItem openInBrowser = new MenuItem("Open in Browser"); + var openInBrowser = new MenuItem("Open in Browser"); openInBrowser.setOnAction(e -> DesktopIntegration.open(selectedModels.get(0).getUrl())); - MenuItem openInPlayer = new MenuItem("Open in Player"); + var openInPlayer = new MenuItem("Open in Player"); openInPlayer.setOnAction(e -> openInPlayer(selectedModels.get(0))); - MenuItem switchStreamSource = new MenuItem("Switch resolution"); + var switchStreamSource = new MenuItem("Switch resolution"); switchStreamSource.setOnAction(e -> switchStreamSource(selectedModels.get(0))); - MenuItem follow = new MenuItem("Follow"); + var follow = new MenuItem("Follow"); follow.setOnAction(e -> follow(selectedModels)); follow.setDisable(!selectedModels.stream().allMatch(m -> m.getSite().supportsFollow() && m.getSite().credentialsAvailable())); - MenuItem ignore = new MenuItem("Ignore"); + var ignore = new MenuItem("Ignore"); ignore.setOnAction(e -> ignore(selectedModels)); - MenuItem notes = new MenuItem("Notes"); + var notes = new MenuItem("Notes"); notes.setOnAction(e -> notes(selectedModels)); - MenuItem openRecDir = new MenuItem("Open recording directory"); + var openRecDir = new MenuItem("Open recording directory"); openRecDir.setOnAction(e -> new OpenRecordingsDir(table, selectedModels.get(0)).execute()); + var addToGroup = new MenuItem("Add to group"); + addToGroup.setOnAction(e -> addToGroup(selectedModels.get(0))); + var editGroup = new MenuItem("Edit group"); + editGroup.setOnAction(e -> editGroup(selectedModels.get(0))); + ContextMenu menu = new CustomMouseBehaviorContextMenu(stop, recordLater); if (selectedModels.size() == 1) { menu.getItems().add(selectedModels.get(0).isSuspended() ? resumeRecording : pauseRecording); @@ -693,6 +694,8 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { } else { menu.getItems().addAll(resumeRecording, pauseRecording); } + Optional modelGroup = Config.getInstance().getModelGroup(selectedModels.get(0)); + menu.getItems().add(modelGroup.isEmpty() ? addToGroup : editGroup); menu.getItems().addAll(copyUrl, openInPlayer, openInBrowser, openRecDir, switchStreamSource, follow, notes, ignore); if (selectedModels.size() > 1) { @@ -706,6 +709,16 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { return menu; } + private void addToGroup(Model model) { + new AddToGroupAction(this.getContent(), recorder, model).execute(); + table.refresh(); + } + + private void editGroup(Model model) { + new EditGroupAction(this.getContent(), recorder, model).execute(); + table.refresh(); + } + private void setStopDate(JavaFxModel model) { new SetStopDateAction(table, model.getDelegate(), recorder) // .execute() // @@ -735,7 +748,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { } private void switchStreamSource(JavaFxModel fxModel) { - String couldntSwitchHeaderText = "Couldn't switch stream resolution"; + var couldntSwitchHeaderText = "Couldn't switch stream resolution"; try { if (!fxModel.isOnline(true)) { @@ -781,7 +794,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { } private boolean stopAction(List selectedModels) { - boolean confirmed = true; + var confirmed = true; if (Config.getInstance().getSettings().confirmationForDangerousActions) { int n = selectedModels.size(); String plural = n > 1 ? "s" : ""; @@ -829,9 +842,9 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { Config.getInstance().getSettings().recordedModelsSortType = col.getSortType().toString(); } int columns = table.getColumns().size(); - double[] columnWidths = new double[columns]; - String[] columnIds = new String[columns]; - for (int i = 0; i < columnWidths.length; i++) { + var columnWidths = new double[columns]; + var columnIds = new String[columns]; + for (var i = 0; i < columnWidths.length; i++) { columnWidths[i] = table.getColumns().get(i).getWidth(); columnIds[i] = table.getColumns().get(i).getId(); } @@ -862,8 +875,8 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { private void restoreColumnOrder() { String[] columnIds = Config.getInstance().getSettings().recordedModelsColumnIds; ObservableList> columns = table.getColumns(); - for (int i = 0; i < columnIds.length; i++) { - for (int j = 0; j < table.getColumns().size(); j++) { + for (var i = 0; i < columnIds.length; i++) { + for (var j = 0; j < table.getColumns().size(); j++) { if(Objects.equals(columnIds[i], columns.get(j).getId())) { TableColumn col = columns.get(j); columns.remove(j); // NOSONAR @@ -876,7 +889,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { private void restoreColumnWidths() { double[] columnWidths = Config.getInstance().getSettings().recordedModelsColumnWidths; if (columnWidths != null && columnWidths.length == table.getColumns().size()) { - for (int i = 0; i < columnWidths.length; i++) { + for (var i = 0; i < columnWidths.length; i++) { table.getColumns().get(i).setPrefWidth(columnWidths[i]); } } @@ -930,25 +943,4 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { return tableCell; } } - - private class RecordingCell extends TableCell { - @Override - protected void updateItem(String value, boolean empty) { - super.updateItem(value, empty); - if (value == null) { - setTooltip(null); - setText(null); - } else { - Model m = getTableView().getItems().get(getTableRow().getIndex()); - if (m.isRecordingTimeLimited()) { - Tooltip tooltip = new Tooltip(); - DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT); - ZonedDateTime zonedDateTime = m.getRecordUntil().atZone(ZoneId.systemDefault()); - tooltip.setText("Recording until " + dtf.format(zonedDateTime)); - setTooltip(tooltip); - } - setText(value); - } - } - } } diff --git a/client/src/main/java/ctbrec/ui/tabs/RecordedTab.java b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordedTab.java similarity index 96% rename from client/src/main/java/ctbrec/ui/tabs/RecordedTab.java rename to client/src/main/java/ctbrec/ui/tabs/recorded/RecordedTab.java index 38a112d4..547fdd33 100644 --- a/client/src/main/java/ctbrec/ui/tabs/RecordedTab.java +++ b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordedTab.java @@ -1,10 +1,11 @@ -package ctbrec.ui.tabs; +package ctbrec.ui.tabs.recorded; import java.util.List; import ctbrec.recorder.Recorder; import ctbrec.sites.Site; import ctbrec.ui.ShutdownListener; +import ctbrec.ui.tabs.TabSelectionListener; import javafx.beans.value.ChangeListener; import javafx.geometry.Side; import javafx.scene.control.Tab; diff --git a/client/src/main/java/ctbrec/ui/tabs/recorded/RecordingTableCell.java b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordingTableCell.java new file mode 100644 index 00000000..ffd35375 --- /dev/null +++ b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordingTableCell.java @@ -0,0 +1,47 @@ +package ctbrec.ui.tabs.recorded; + +import static ctbrec.ui.Icon.*; + +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.Map; +import java.util.Objects; + +import ctbrec.Model; +import ctbrec.SubsequentAction; +import javafx.scene.image.ImageView; + +public class RecordingTableCell extends IconTableCell { + + public RecordingTableCell() { + super(Map.of( // + CHECK_16, new ImageView(CHECK_16.url()), // + CLOCK_16, new ImageView(CLOCK_16.url()))); + } + + @Override + protected void updateItem(Boolean value, boolean empty) { + tooltip = null; + hide(CHECK_16); + hide(CLOCK_16); + if (value == null || empty) { + return; + } + + if (Objects.equals(value, Boolean.TRUE)) { + show(CHECK_16); + tooltip = "Recording"; + } + + Model m = getTableView().getItems().get(getTableRow().getIndex()); + if (m.isRecordingTimeLimited()) { + show(CLOCK_16); + var dtf = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT); + var zonedDateTime = m.getRecordUntil().atZone(ZoneId.systemDefault()); + String action = m.getRecordUntilSubsequentAction() == SubsequentAction.PAUSE ? "Pause" : "Remove"; + tooltip = action + " at " + dtf.format(zonedDateTime); + } + super.updateItem(value, empty); + } +} \ No newline at end of file diff --git a/client/src/main/resources/16/check-circle.png b/client/src/main/resources/16/check-circle.png new file mode 100644 index 00000000..2c3c1024 Binary files /dev/null and b/client/src/main/resources/16/check-circle.png differ diff --git a/client/src/main/resources/16/check-small.png b/client/src/main/resources/16/check-small.png new file mode 100644 index 00000000..c3b7d245 Binary files /dev/null and b/client/src/main/resources/16/check-small.png differ diff --git a/client/src/main/resources/16/check.png b/client/src/main/resources/16/check.png new file mode 100644 index 00000000..36b0bc8f Binary files /dev/null and b/client/src/main/resources/16/check.png differ diff --git a/client/src/main/resources/16/clock.png b/client/src/main/resources/16/clock.png new file mode 100644 index 00000000..00c9e221 Binary files /dev/null and b/client/src/main/resources/16/clock.png differ diff --git a/client/src/main/resources/16/users.png b/client/src/main/resources/16/users.png new file mode 100644 index 00000000..cb1ce703 Binary files /dev/null and b/client/src/main/resources/16/users.png differ diff --git a/client/src/main/resources/32/check-circle.png b/client/src/main/resources/32/check-circle.png new file mode 100644 index 00000000..5687d94e Binary files /dev/null and b/client/src/main/resources/32/check-circle.png differ diff --git a/client/src/main/resources/32/check-small.png b/client/src/main/resources/32/check-small.png new file mode 100644 index 00000000..540010a1 Binary files /dev/null and b/client/src/main/resources/32/check-small.png differ diff --git a/client/src/main/resources/32/check-small.svg b/client/src/main/resources/32/check-small.svg new file mode 100644 index 00000000..2980ea7a --- /dev/null +++ b/client/src/main/resources/32/check-small.svg @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/client/src/main/resources/32/check.png b/client/src/main/resources/32/check.png new file mode 100644 index 00000000..bc8b618b Binary files /dev/null and b/client/src/main/resources/32/check.png differ diff --git a/client/src/main/resources/32/clock.png b/client/src/main/resources/32/clock.png new file mode 100644 index 00000000..a7ad0f32 Binary files /dev/null and b/client/src/main/resources/32/clock.png differ diff --git a/client/src/main/resources/32/users.png b/client/src/main/resources/32/users.png new file mode 100644 index 00000000..fe71827c Binary files /dev/null and b/client/src/main/resources/32/users.png differ diff --git a/client/src/main/resources/buymeacoffee-round.png b/client/src/main/resources/buymeacoffee-round.png deleted file mode 100644 index 341a0f8e..00000000 Binary files a/client/src/main/resources/buymeacoffee-round.png and /dev/null differ diff --git a/client/src/main/resources/kofi-round.png b/client/src/main/resources/kofi-round.png deleted file mode 100644 index 412a0a66..00000000 Binary files a/client/src/main/resources/kofi-round.png and /dev/null differ diff --git a/client/src/main/resources/kofi-round600.png b/client/src/main/resources/kofi-round600.png deleted file mode 100644 index 995171ea..00000000 Binary files a/client/src/main/resources/kofi-round600.png and /dev/null differ diff --git a/client/src/main/resources/patreon-round.png b/client/src/main/resources/patreon-round.png deleted file mode 100644 index 22c9edac..00000000 Binary files a/client/src/main/resources/patreon-round.png and /dev/null differ diff --git a/client/src/main/resources/paypal-round.png b/client/src/main/resources/paypal-round.png deleted file mode 100644 index 481490ea..00000000 Binary files a/client/src/main/resources/paypal-round.png and /dev/null differ diff --git a/common/src/main/java/ctbrec/Settings.java b/common/src/main/java/ctbrec/Settings.java index c0402eaf..81de026f 100644 --- a/common/src/main/java/ctbrec/Settings.java +++ b/common/src/main/java/ctbrec/Settings.java @@ -106,6 +106,7 @@ public class Settings { public String mfcPassword = ""; public String mfcUsername = ""; public boolean minimizeToTray = false; + @Deprecated public int minimumLengthInSeconds = 0; public long minimumSpaceLeftInBytes = 0; public Map modelNotes = new HashMap<>();