diff --git a/client/src/main/java/ctbrec/ui/controls/PausedIndicator.java b/client/src/main/java/ctbrec/ui/controls/PausedIndicator.java deleted file mode 100644 index 482d8d08..00000000 --- a/client/src/main/java/ctbrec/ui/controls/PausedIndicator.java +++ /dev/null @@ -1,34 +0,0 @@ -package ctbrec.ui.controls; - -import ctbrec.ui.PauseIcon; -import javafx.scene.Cursor; -import javafx.scene.control.Tooltip; -import javafx.scene.layout.StackPane; -import javafx.scene.paint.Color; -import javafx.scene.paint.Paint; -import javafx.scene.shape.Rectangle; - -public class PausedIndicator extends StackPane { - - private PauseIcon pausedIcon; - private Rectangle clickPanel; - - public PausedIndicator(int size, Color color) { - setMaxSize(size, size); - - pausedIcon = new PauseIcon(color, size); - pausedIcon.setVisible(false); - clickPanel = new Rectangle(size, size); - clickPanel.setCursor(Cursor.HAND); - clickPanel.setFill(Paint.valueOf("#00000000")); - getChildren().add(pausedIcon); - getChildren().add(clickPanel); - - pausedIcon.visibleProperty().bindBidirectional(visibleProperty()); - clickPanel.onMouseClickedProperty().bindBidirectional(onMouseClickedProperty()); - - Tooltip tooltip = new Tooltip("Resume Recording"); - Tooltip.install(clickPanel, tooltip); - } -} - diff --git a/client/src/main/java/ctbrec/ui/controls/RecordingIndicator.java b/client/src/main/java/ctbrec/ui/controls/RecordingIndicator.java new file mode 100644 index 00000000..ed07aa1b --- /dev/null +++ b/client/src/main/java/ctbrec/ui/controls/RecordingIndicator.java @@ -0,0 +1,37 @@ +package ctbrec.ui.controls; + +import javafx.scene.Cursor; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.StackPane; +import javafx.scene.paint.Paint; +import javafx.scene.shape.Rectangle; + +public class RecordingIndicator extends StackPane { + + private ImageView icon; + private Rectangle clickPanel; + + public RecordingIndicator(int size) { + setMaxSize(size, size); + + icon = new ImageView(); + icon.setVisible(false); + icon.prefHeight(size); + icon.prefWidth(size); + icon.maxHeight(size); + icon.maxWidth(size); + clickPanel = new Rectangle(size, size); + clickPanel.setCursor(Cursor.HAND); + clickPanel.setFill(Paint.valueOf("#00000000")); + getChildren().add(icon); + getChildren().add(clickPanel); + + icon.visibleProperty().bindBidirectional(visibleProperty()); + } + + public void setImage(Image img) { + icon.setImage(img); + } +} + diff --git a/client/src/main/java/ctbrec/ui/tabs/ThumbCell.java b/client/src/main/java/ctbrec/ui/tabs/ThumbCell.java index 3899e3d1..1c6455b9 100644 --- a/client/src/main/java/ctbrec/ui/tabs/ThumbCell.java +++ b/client/src/main/java/ctbrec/ui/tabs/ThumbCell.java @@ -31,7 +31,7 @@ import ctbrec.ui.SiteUiFactory; import ctbrec.ui.StreamSourceSelectionDialog; import ctbrec.ui.action.PlayAction; import ctbrec.ui.controls.Dialogs; -import ctbrec.ui.controls.PausedIndicator; +import ctbrec.ui.controls.RecordingIndicator; import ctbrec.ui.controls.StreamPreview; import javafx.animation.FadeTransition; import javafx.animation.FillTransition; @@ -51,6 +51,7 @@ import javafx.scene.control.ContextMenu; import javafx.scene.control.Tooltip; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +import javafx.scene.input.MouseEvent; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.paint.Paint; @@ -72,6 +73,11 @@ public class ThumbCell extends StackPane { private static final Logger LOG = LoggerFactory.getLogger(ThumbCell.class); private static final Duration ANIMATION_DURATION = new Duration(250); + private static Image imgRecordIndicator = new Image(ThumbCell.class.getResource("/media-record-16.png").toExternalForm()); + private static Image imgPauseIndicator = new Image(ThumbCell.class.getResource("/media-playback-pause-16.png").toExternalForm()); + private static Image imgBookmarkIndicator = new Image(ThumbCell.class.getResource("/bookmark-new-16.png").toExternalForm()); + + private ModelRecordingState modelRecordingState = ModelRecordingState.NOT; private Model model; private StreamPreview streamPreview; private ImageView iv; @@ -85,8 +91,8 @@ public class ThumbCell extends StackPane { private Text topic; private Text resolutionTag; private Recorder recorder; - private Circle recordingIndicator; - private PausedIndicator pausedIndicator; + private RecordingIndicator recordingIndicator; + private Tooltip recordingIndicatorTooltip; private StackPane previewTrigger; private int index = 0; ContextMenu popup; @@ -178,22 +184,15 @@ public class ThumbCell extends StackPane { StackPane.setMargin(resolutionTag, new Insets(2, 4, 2, 2)); getChildren().add(resolutionTag); - recordingIndicator = new Circle(8); - recordingIndicator.setFill(colorRecording); + recordingIndicator = new RecordingIndicator(16); recordingIndicator.setCursor(Cursor.HAND); - recordingIndicator.setOnMouseClicked(e -> pauseResumeAction(true)); - Tooltip tooltip = new Tooltip("Pause Recording"); - Tooltip.install(recordingIndicator, tooltip); + recordingIndicator.setOnMouseClicked(this::recordingInidicatorClicked); + recordingIndicatorTooltip = new Tooltip("Pause Recording"); + Tooltip.install(recordingIndicator, recordingIndicatorTooltip); StackPane.setMargin(recordingIndicator, new Insets(3)); StackPane.setAlignment(recordingIndicator, Pos.TOP_LEFT); getChildren().add(recordingIndicator); - pausedIndicator = new PausedIndicator(16, colorRecording); - pausedIndicator.setOnMouseClicked(e -> pauseResumeAction(false)); - StackPane.setMargin(pausedIndicator, new Insets(3)); - StackPane.setAlignment(pausedIndicator, Pos.TOP_LEFT); - getChildren().add(pausedIndicator); - if (Config.getInstance().getSettings().livePreviews) { getChildren().add(createPreviewTrigger()); } @@ -231,6 +230,21 @@ public class ThumbCell extends StackPane { update(); } + private void recordingInidicatorClicked(MouseEvent evt) { + switch(modelRecordingState) { + case RECORDING: + pauseResumeAction(true); + break; + case PAUSED: + pauseResumeAction(false); + break; + case BOOKMARKED: + recordLater(false); + break; + default: + } + } + private Node createPreviewTrigger() { int s = 32; previewTrigger = new StackPane(); @@ -293,7 +307,6 @@ public class ThumbCell extends StackPane { streamPreview.stop(); } recordingIndicator.setVisible(!visible); - pausedIndicator.setVisible(!visible); if (!visible) { updateRecordingIndicator(); } @@ -445,17 +458,32 @@ public class ThumbCell extends StackPane { c = mouseHovering ? colorHighlight : colorNormal; } nameBackground.setFill(c); - updateRecordingIndicator(); } private void updateRecordingIndicator() { if (recording) { - recordingIndicator.setVisible(!model.isSuspended()); - pausedIndicator.setVisible(model.isSuspended()); + recordingIndicator.setVisible(true); + if (model.isSuspended()) { + modelRecordingState = ModelRecordingState.PAUSED; + recordingIndicator.setImage(imgPauseIndicator); + recordingIndicatorTooltip.setText("Resume Recording"); + } else { + modelRecordingState = ModelRecordingState.RECORDING; + recordingIndicator.setImage(imgRecordIndicator); + recordingIndicatorTooltip.setText("Pause Recording"); + } } else { - recordingIndicator.setVisible(false); - pausedIndicator.setVisible(false); + if (model.isMarkedForLaterRecording()) { + recordingIndicator.setVisible(true); + modelRecordingState = ModelRecordingState.BOOKMARKED; + recordingIndicator.setImage(imgBookmarkIndicator); + recordingIndicatorTooltip.setText("Forget Model"); + } else { + recordingIndicator.setVisible(false); + modelRecordingState = ModelRecordingState.NOT; + recordingIndicator.setImage(null); + } } } @@ -562,9 +590,9 @@ public class ThumbCell extends StackPane { }); } - void recordLater() { - model.setMarkedForLaterRecording(true); - startStopAction(true); + void recordLater(boolean recordLater) { + model.setMarkedForLaterRecording(recordLater); + startStopAction(recordLater); } public Model getModel() { @@ -577,7 +605,6 @@ public class ThumbCell extends StackPane { this.model.setPreview(model.getPreview()); this.model.setTags(model.getTags()); this.model.setUrl(model.getUrl()); - this.model.setSuspended(recorder.isSuspended(model)); update(); } @@ -591,9 +618,11 @@ public class ThumbCell extends StackPane { private void update() { model.setSuspended(recorder.isSuspended(model)); + model.setMarkedForLaterRecording(recorder.isMarkedForLaterRecording(model)); setRecording(recorder.isTracked(model)); + updateRecordingIndicator(); setImage(model.getPreview()); - String txt = recording ? " " : ""; + String txt = (modelRecordingState != ModelRecordingState.NOT) ? " " : ""; txt += model.getDescription() != null ? model.getDescription() : ""; topic.setText(txt); @@ -693,4 +722,11 @@ public class ThumbCell extends StackPane { model.setMarkedForLaterRecording(false); startStopAction(true); } + + private enum ModelRecordingState { + RECORDING, + PAUSED, + BOOKMARKED, + NOT + } } diff --git a/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java b/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java index ae0a1b9b..25bd867d 100644 --- a/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java +++ b/client/src/main/java/ctbrec/ui/tabs/ThumbOverviewTab.java @@ -1,5 +1,31 @@ package ctbrec.ui.tabs; +import static ctbrec.ui.controls.Dialogs.*; + +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import ctbrec.Config; import ctbrec.Model; import ctbrec.event.EventBusHolder; @@ -7,12 +33,24 @@ import ctbrec.recorder.Recorder; import ctbrec.sites.Site; import ctbrec.sites.mfc.MyFreeCamsClient; import ctbrec.sites.mfc.MyFreeCamsModel; -import ctbrec.ui.*; +import ctbrec.ui.AutosizeAlert; +import ctbrec.ui.DesktopIntegration; +import ctbrec.ui.SiteUiFactory; +import ctbrec.ui.TipDialog; +import ctbrec.ui.TokenLabel; import ctbrec.ui.action.IgnoreModelsAction; import ctbrec.ui.action.OpenRecordingsDir; import ctbrec.ui.action.SetStopDateAction; -import ctbrec.ui.controls.*; -import javafx.animation.*; +import ctbrec.ui.controls.CustomMouseBehaviorContextMenu; +import ctbrec.ui.controls.FasterVerticalScrollPaneSkin; +import ctbrec.ui.controls.SearchBox; +import ctbrec.ui.controls.SearchPopover; +import ctbrec.ui.controls.SearchPopoverTreeList; +import javafx.animation.FadeTransition; +import javafx.animation.Interpolator; +import javafx.animation.ParallelTransition; +import javafx.animation.ScaleTransition; +import javafx.animation.TranslateTransition; import javafx.application.Platform; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -28,24 +66,34 @@ import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Node; import javafx.scene.Parent; -import javafx.scene.control.*; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.ComboBox; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.Label; +import javafx.scene.control.MenuItem; +import javafx.scene.control.ProgressIndicator; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.SeparatorMenuItem; +import javafx.scene.control.Tab; +import javafx.scene.control.TabPane; +import javafx.scene.control.TextField; +import javafx.scene.control.Tooltip; import javafx.scene.image.ImageView; -import javafx.scene.input.*; -import javafx.scene.layout.*; +import javafx.scene.input.Clipboard; +import javafx.scene.input.ClipboardContent; +import javafx.scene.input.ContextMenuEvent; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.StackPane; import javafx.scene.transform.Transform; import javafx.util.Duration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.net.SocketTimeoutException; -import java.text.DecimalFormat; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; - -import static ctbrec.ui.controls.Dialogs.showError; public class ThumbOverviewTab extends Tab implements TabSelectionListener { private static final Logger LOG = LoggerFactory.getLogger(ThumbOverviewTab.class); @@ -441,7 +489,10 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { MenuItem addPaused = new MenuItem("Add in paused state"); addPaused.setOnAction(e -> addPaused(getSelectedThumbCells(cell))); MenuItem recordLater = new MenuItem("Record Later"); - recordLater.setOnAction(e -> recordLater(getSelectedThumbCells(cell))); + recordLater.setOnAction(e -> recordLater(getSelectedThumbCells(cell), true)); + MenuItem removeRecordLater = new MenuItem("Forget Model"); + removeRecordLater.setOnAction(e -> recordLater(getSelectedThumbCells(cell), false)); + MenuItem addRemoveBookmark = recorder.isMarkedForLaterRecording(model) ? removeRecordLater : recordLater; MenuItem pause = new MenuItem("Pause Recording"); pause.setOnAction(e -> pauseResumeAction(getSelectedThumbCells(cell), true)); @@ -476,10 +527,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { if (modelIsTrackedByRecorder) { contextMenu.getItems().addAll(pauseResume, recordLater); } else { - contextMenu.getItems().addAll(recordUntil, addPaused); - if (!recorder.isMarkedForLaterRecording(model)) { - contextMenu.getItems().add(recordLater); - } + contextMenu.getItems().addAll(recordUntil, addPaused, addRemoveBookmark); } contextMenu.getItems().add(new SeparatorMenuItem()); if (site.supportsFollow()) { @@ -500,9 +548,9 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { return contextMenu; } - private void recordLater(List list) { + private void recordLater(List list, boolean recordLater) { for (ThumbCell cell : list) { - cell.recordLater(); + cell.recordLater(recordLater); } } diff --git a/client/src/main/resources/bookmark-new-16.png b/client/src/main/resources/bookmark-new-16.png new file mode 100644 index 00000000..d50f515a Binary files /dev/null and b/client/src/main/resources/bookmark-new-16.png differ diff --git a/client/src/main/resources/bookmark-new.png b/client/src/main/resources/bookmark-new.png new file mode 100644 index 00000000..90b9daad Binary files /dev/null and b/client/src/main/resources/bookmark-new.png differ diff --git a/client/src/main/resources/media-playback-pause-16.png b/client/src/main/resources/media-playback-pause-16.png new file mode 100644 index 00000000..91c5549f Binary files /dev/null and b/client/src/main/resources/media-playback-pause-16.png differ diff --git a/client/src/main/resources/media-playback-pause.png b/client/src/main/resources/media-playback-pause.png new file mode 100644 index 00000000..9d486a08 Binary files /dev/null and b/client/src/main/resources/media-playback-pause.png differ diff --git a/client/src/main/resources/media-record-16.png b/client/src/main/resources/media-record-16.png new file mode 100644 index 00000000..aec3241b Binary files /dev/null and b/client/src/main/resources/media-record-16.png differ diff --git a/client/src/main/resources/media-record.png b/client/src/main/resources/media-record.png new file mode 100644 index 00000000..b4a507cb Binary files /dev/null and b/client/src/main/resources/media-record.png differ