Add model group context menu
This commit is contained in:
parent
0c4f37f950
commit
0d0311fbfc
|
@ -40,6 +40,10 @@ public class AddToGroupAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void execute() {
|
public void execute() {
|
||||||
|
execute(() -> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Runnable callback) {
|
||||||
source.setCursor(Cursor.WAIT);
|
source.setCursor(Cursor.WAIT);
|
||||||
try {
|
try {
|
||||||
var dialog = new AddModelGroupDialog();
|
var dialog = new AddModelGroupDialog();
|
||||||
|
@ -66,6 +70,7 @@ public class AddToGroupAction {
|
||||||
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException e) {
|
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException e) {
|
||||||
Dialogs.showError(source.getScene(), "Add model to group", "Saving model group failed", e);
|
Dialogs.showError(source.getScene(), "Add model to group", "Saving model group failed", e);
|
||||||
} finally {
|
} finally {
|
||||||
|
callback.run();
|
||||||
source.setCursor(Cursor.DEFAULT);
|
source.setCursor(Cursor.DEFAULT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package ctbrec.ui.action;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.ModelGroup;
|
import ctbrec.ModelGroup;
|
||||||
|
@ -36,6 +37,10 @@ public class EditGroupAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void execute() {
|
public void execute() {
|
||||||
|
execute(m -> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute(Consumer<Model> callback) {
|
||||||
source.setCursor(Cursor.WAIT);
|
source.setCursor(Cursor.WAIT);
|
||||||
try {
|
try {
|
||||||
var dialog = new EditModelGroupDialog(model);
|
var dialog = new EditModelGroupDialog(model);
|
||||||
|
@ -56,6 +61,7 @@ public class EditGroupAction {
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Dialogs.showError(source.getScene(), DIALOG_TITLE, "Editing model group failed", e);
|
Dialogs.showError(source.getScene(), DIALOG_TITLE, "Editing model group failed", e);
|
||||||
} finally {
|
} finally {
|
||||||
|
Optional.ofNullable(callback).ifPresent(c -> c.accept(model));
|
||||||
source.setCursor(Cursor.DEFAULT);
|
source.setCursor(Cursor.DEFAULT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,6 +108,7 @@ public class EditGroupAction {
|
||||||
urlList = FXCollections.observableList(modelGroup.getModelUrls());
|
urlList = FXCollections.observableList(modelGroup.getModelUrls());
|
||||||
urlList.addListener((ListChangeListener<String>) change -> urls = new ArrayList<>(urlList));
|
urlList.addListener((ListChangeListener<String>) change -> urls = new ArrayList<>(urlList));
|
||||||
urlListView = new ListView<>(urlList);
|
urlListView = new ListView<>(urlList);
|
||||||
|
urlListView.setPrefWidth(600);
|
||||||
GridPane.setHgrow(urlListView, Priority.ALWAYS);
|
GridPane.setHgrow(urlListView, Priority.ALWAYS);
|
||||||
|
|
||||||
var row = 0;
|
var row = 0;
|
||||||
|
|
|
@ -1,21 +1,33 @@
|
||||||
package ctbrec.ui.action;
|
package ctbrec.ui.action;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ctbrec.GlobalThreadPool;
|
import ctbrec.GlobalThreadPool;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
|
import ctbrec.ui.controls.Dialogs;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.scene.Cursor;
|
import javafx.scene.Cursor;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
|
|
||||||
public class ModelMassEditAction {
|
public class ModelMassEditAction {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ModelMassEditAction.class);
|
||||||
|
|
||||||
protected List<? extends Model> models;
|
protected List<? extends Model> models;
|
||||||
protected Consumer<Model> action;
|
protected Consumer<Model> action;
|
||||||
protected Node source;
|
protected Node source;
|
||||||
|
|
||||||
|
protected ModelMassEditAction() {
|
||||||
|
}
|
||||||
|
|
||||||
protected ModelMassEditAction(Node source, List<? extends Model> models) {
|
protected ModelMassEditAction(Node source, List<? extends Model> models) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.models = models;
|
this.models = models;
|
||||||
|
@ -32,14 +44,36 @@ public class ModelMassEditAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void execute(Consumer<Model> callback) {
|
public void execute(Consumer<Model> callback) {
|
||||||
Consumer<Model> cb = Objects.requireNonNull(callback, "Callback is null, call execute() instead");
|
|
||||||
source.setCursor(Cursor.WAIT);
|
|
||||||
for (Model model : models) {
|
|
||||||
GlobalThreadPool.submit(() -> {
|
GlobalThreadPool.submit(() -> {
|
||||||
|
Platform.runLater(() -> source.setCursor(Cursor.WAIT));
|
||||||
|
Consumer<Model> cb = Objects.requireNonNull(callback, "Callback is null, call execute() instead");
|
||||||
|
List<Future<?>> futures = new LinkedList<>();
|
||||||
|
for (Model model : getModels()) {
|
||||||
|
futures.add(GlobalThreadPool.submit(() -> {
|
||||||
action.accept(model);
|
action.accept(model);
|
||||||
cb.accept(model);
|
cb.accept(model);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
Exception ex = null;
|
||||||
|
for (Future<?> future : futures) {
|
||||||
|
try {
|
||||||
|
future.get();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
ex = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ex != null) {
|
||||||
|
LOG.error("Error while executing model mass edit", ex);
|
||||||
|
Dialogs.showError(source.getScene(), "Error", "Error while execution action", ex);
|
||||||
|
}
|
||||||
Platform.runLater(() -> source.setCursor(Cursor.DEFAULT));
|
Platform.runLater(() -> source.setCursor(Cursor.DEFAULT));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected List<Model> getModels() {
|
||||||
|
return (List<Model>) models;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package ctbrec.ui.action;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
import ctbrec.ModelGroup;
|
||||||
|
import ctbrec.recorder.Recorder;
|
||||||
|
import ctbrec.ui.controls.Dialogs;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
|
||||||
|
public class PauseGroupAction extends ModelMassEditAction {
|
||||||
|
|
||||||
|
private Recorder recorder;
|
||||||
|
private Model model;
|
||||||
|
|
||||||
|
public PauseGroupAction(Node source, Recorder recorder, Model model) {
|
||||||
|
super.source = source;
|
||||||
|
this.recorder = recorder;
|
||||||
|
this.model = model;
|
||||||
|
|
||||||
|
action = m -> {
|
||||||
|
try {
|
||||||
|
recorder.suspendRecording(m);
|
||||||
|
} catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
|
||||||
|
Platform.runLater(() -> Dialogs.showError(source.getScene(), "Couldn't pause model", "Pausing recording of " + m.getName() + " failed", e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<Model> getModels() {
|
||||||
|
Optional<ModelGroup> optionalGroup = recorder.getModelGroup(model);
|
||||||
|
if (optionalGroup.isPresent()) {
|
||||||
|
ModelGroup group = optionalGroup.get();
|
||||||
|
return recorder.getModels().stream() //
|
||||||
|
.filter(m -> group.getModelUrls().contains(m.getUrl())) //
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
} else {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package ctbrec.ui.action;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
import ctbrec.ModelGroup;
|
||||||
|
import ctbrec.recorder.Recorder;
|
||||||
|
import ctbrec.ui.controls.Dialogs;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
|
||||||
|
public class ResumeGroupAction extends ModelMassEditAction {
|
||||||
|
|
||||||
|
private Recorder recorder;
|
||||||
|
private Model model;
|
||||||
|
|
||||||
|
public ResumeGroupAction(Node source, Recorder recorder, Model model) {
|
||||||
|
super.source = source;
|
||||||
|
this.recorder = recorder;
|
||||||
|
this.model = model;
|
||||||
|
|
||||||
|
action = m -> {
|
||||||
|
try {
|
||||||
|
recorder.resumeRecording(m);
|
||||||
|
} catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
|
||||||
|
Platform.runLater(() -> Dialogs.showError(source.getScene(), "Couldn't resume model", "Resuming recording of " + m.getName() + " failed", e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<Model> getModels() {
|
||||||
|
Optional<ModelGroup> optionalGroup = recorder.getModelGroup(model);
|
||||||
|
if (optionalGroup.isPresent()) {
|
||||||
|
ModelGroup group = optionalGroup.get();
|
||||||
|
return recorder.getModels().stream() //
|
||||||
|
.filter(m -> group.getModelUrls().contains(m.getUrl())) //
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
} else {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package ctbrec.ui.action;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
import ctbrec.ModelGroup;
|
||||||
|
import ctbrec.recorder.Recorder;
|
||||||
|
import ctbrec.ui.controls.Dialogs;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
|
||||||
|
public class StopGroupAction extends ModelMassEditAction {
|
||||||
|
|
||||||
|
private Recorder recorder;
|
||||||
|
private Model model;
|
||||||
|
|
||||||
|
public StopGroupAction(Node source, Recorder recorder, Model model) {
|
||||||
|
super.source = source;
|
||||||
|
this.recorder = recorder;
|
||||||
|
this.model = model;
|
||||||
|
|
||||||
|
action = m -> {
|
||||||
|
try {
|
||||||
|
recorder.stopRecording(m);
|
||||||
|
} catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
|
||||||
|
Platform.runLater(() -> Dialogs.showError(source.getScene(), "Couldn't stop model", "Stopping recording of " + m.getName() + " failed", e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<Model> getModels() {
|
||||||
|
Optional<ModelGroup> optionalGroup = recorder.getModelGroup(model);
|
||||||
|
if (optionalGroup.isPresent()) {
|
||||||
|
ModelGroup group = optionalGroup.get();
|
||||||
|
return recorder.getModels().stream() //
|
||||||
|
.filter(m -> group.getModelUrls().contains(m.getUrl())) //
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
} else {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package ctbrec.ui.action;
|
||||||
|
|
||||||
|
import static ctbrec.ui.controls.Dialogs.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
import ctbrec.event.EventBusHolder;
|
||||||
|
import ctbrec.ui.SiteUiFactory;
|
||||||
|
import ctbrec.ui.TipDialog;
|
||||||
|
import javafx.scene.Cursor;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
|
||||||
|
public class TipAction {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(TipAction.class);
|
||||||
|
|
||||||
|
private Model model;
|
||||||
|
private Node source;
|
||||||
|
|
||||||
|
public TipAction(Model model, Node source) {
|
||||||
|
this.model = model;
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void execute() {
|
||||||
|
source.setCursor(Cursor.WAIT);
|
||||||
|
try {
|
||||||
|
var site = model.getSite();
|
||||||
|
var tipDialog = new TipDialog(source.getScene(), site);
|
||||||
|
tipDialog.showAndWait();
|
||||||
|
String tipText = tipDialog.getResult();
|
||||||
|
if (tipText != null) {
|
||||||
|
var df = new DecimalFormat("0.##");
|
||||||
|
try {
|
||||||
|
Number tokens = df.parse(tipText);
|
||||||
|
SiteUiFactory.getUi(site).login();
|
||||||
|
model.receiveTip(tokens.doubleValue());
|
||||||
|
Map<String, Object> event = new HashMap<>();
|
||||||
|
event.put("event", "tokens.sent");
|
||||||
|
event.put("amount", tokens.doubleValue());
|
||||||
|
EventBusHolder.BUS.post(event);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOG.error("An error occurred while sending tip", ex);
|
||||||
|
showError(source.getScene(), "Couldn't send tip", "An error occurred while sending tip:", ex);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
showError(source.getScene(), "Couldn't send tip", "You entered an invalid amount of tokens", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
source.setCursor(Cursor.DEFAULT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package ctbrec.ui.menu;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
import ctbrec.recorder.Recorder;
|
||||||
|
import ctbrec.ui.action.EditGroupAction;
|
||||||
|
import ctbrec.ui.action.PauseGroupAction;
|
||||||
|
import ctbrec.ui.action.ResumeGroupAction;
|
||||||
|
import ctbrec.ui.action.StopGroupAction;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.Menu;
|
||||||
|
import javafx.scene.control.MenuItem;
|
||||||
|
|
||||||
|
public class ModelGroupMenuBuilder {
|
||||||
|
|
||||||
|
private Model model;
|
||||||
|
private Recorder recorder;
|
||||||
|
private Node source;
|
||||||
|
private Consumer<Model> callback;
|
||||||
|
|
||||||
|
public ModelGroupMenuBuilder model(Model model) {
|
||||||
|
this.model = Objects.requireNonNull(model, "Model cannot be null");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelGroupMenuBuilder recorder(Recorder recorder) {
|
||||||
|
this.recorder = Objects.requireNonNull(recorder, "Recorder cannot be null");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelGroupMenuBuilder node(Node source) {
|
||||||
|
this.source = Objects.requireNonNull(source, "Node cannot be null");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModelGroupMenuBuilder callback(Consumer<Model> callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Menu build() {
|
||||||
|
Objects.requireNonNull(model, "Model has to be set");
|
||||||
|
Objects.requireNonNull(recorder, "Recorder has to be set");
|
||||||
|
Objects.requireNonNull(source, "Node has to be set");
|
||||||
|
|
||||||
|
var menu = new Menu("Group");
|
||||||
|
|
||||||
|
var editGroup = new MenuItem("Edit group");
|
||||||
|
editGroup.setOnAction(e -> new EditGroupAction(source, recorder, model).execute(callback));
|
||||||
|
|
||||||
|
var resumeAllOfGroup = new MenuItem("Resume all");
|
||||||
|
resumeAllOfGroup.setOnAction(e -> new ResumeGroupAction(source, recorder, model).execute(callback));
|
||||||
|
|
||||||
|
var pauseAllOfGroup = new MenuItem("Pause all");
|
||||||
|
pauseAllOfGroup.setOnAction(e -> new PauseGroupAction(source, recorder, model).execute(callback));
|
||||||
|
|
||||||
|
var stopAllOfGroup = new MenuItem("Remove all");
|
||||||
|
stopAllOfGroup.setOnAction(e -> new StopGroupAction(source, recorder, model).execute(callback));
|
||||||
|
|
||||||
|
menu.getItems().addAll(editGroup, resumeAllOfGroup, pauseAllOfGroup, stopAllOfGroup);
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
}
|
|
@ -614,7 +614,7 @@ public class ThumbCell extends StackPane {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void update() {
|
protected void update() {
|
||||||
model.setSuspended(recorder.isSuspended(model));
|
model.setSuspended(recorder.isSuspended(model));
|
||||||
model.setMarkedForLaterRecording(recorder.isMarkedForLaterRecording(model));
|
model.setMarkedForLaterRecording(recorder.isMarkedForLaterRecording(model));
|
||||||
setRecording(recorder.isTracked(model));
|
setRecording(recorder.isTracked(model));
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
package ctbrec.ui.tabs;
|
package ctbrec.ui.tabs;
|
||||||
|
|
||||||
import static ctbrec.ui.controls.Dialogs.*;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.text.DecimalFormat;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -30,7 +27,6 @@ import ctbrec.Config;
|
||||||
import ctbrec.GlobalThreadPool;
|
import ctbrec.GlobalThreadPool;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.ModelGroup;
|
import ctbrec.ModelGroup;
|
||||||
import ctbrec.event.EventBusHolder;
|
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.sites.Site;
|
import ctbrec.sites.Site;
|
||||||
import ctbrec.sites.mfc.MyFreeCamsClient;
|
import ctbrec.sites.mfc.MyFreeCamsClient;
|
||||||
|
@ -38,18 +34,18 @@ import ctbrec.sites.mfc.MyFreeCamsModel;
|
||||||
import ctbrec.ui.AutosizeAlert;
|
import ctbrec.ui.AutosizeAlert;
|
||||||
import ctbrec.ui.DesktopIntegration;
|
import ctbrec.ui.DesktopIntegration;
|
||||||
import ctbrec.ui.SiteUiFactory;
|
import ctbrec.ui.SiteUiFactory;
|
||||||
import ctbrec.ui.TipDialog;
|
|
||||||
import ctbrec.ui.TokenLabel;
|
import ctbrec.ui.TokenLabel;
|
||||||
import ctbrec.ui.action.AddToGroupAction;
|
import ctbrec.ui.action.AddToGroupAction;
|
||||||
import ctbrec.ui.action.EditGroupAction;
|
|
||||||
import ctbrec.ui.action.IgnoreModelsAction;
|
import ctbrec.ui.action.IgnoreModelsAction;
|
||||||
import ctbrec.ui.action.OpenRecordingsDir;
|
import ctbrec.ui.action.OpenRecordingsDir;
|
||||||
import ctbrec.ui.action.SetStopDateAction;
|
import ctbrec.ui.action.SetStopDateAction;
|
||||||
|
import ctbrec.ui.action.TipAction;
|
||||||
import ctbrec.ui.controls.CustomMouseBehaviorContextMenu;
|
import ctbrec.ui.controls.CustomMouseBehaviorContextMenu;
|
||||||
import ctbrec.ui.controls.FasterVerticalScrollPaneSkin;
|
import ctbrec.ui.controls.FasterVerticalScrollPaneSkin;
|
||||||
import ctbrec.ui.controls.SearchBox;
|
import ctbrec.ui.controls.SearchBox;
|
||||||
import ctbrec.ui.controls.SearchPopover;
|
import ctbrec.ui.controls.SearchPopover;
|
||||||
import ctbrec.ui.controls.SearchPopoverTreeList;
|
import ctbrec.ui.controls.SearchPopoverTreeList;
|
||||||
|
import ctbrec.ui.menu.ModelGroupMenuBuilder;
|
||||||
import javafx.animation.FadeTransition;
|
import javafx.animation.FadeTransition;
|
||||||
import javafx.animation.Interpolator;
|
import javafx.animation.Interpolator;
|
||||||
import javafx.animation.ParallelTransition;
|
import javafx.animation.ParallelTransition;
|
||||||
|
@ -80,7 +76,6 @@ import javafx.scene.control.ProgressIndicator;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.control.SeparatorMenuItem;
|
import javafx.scene.control.SeparatorMenuItem;
|
||||||
import javafx.scene.control.Tab;
|
import javafx.scene.control.Tab;
|
||||||
import javafx.scene.control.TabPane;
|
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
import javafx.scene.control.Tooltip;
|
import javafx.scene.control.Tooltip;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
|
@ -96,7 +91,6 @@ import javafx.scene.layout.FlowPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.Priority;
|
import javafx.scene.layout.Priority;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.transform.Transform;
|
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
|
||||||
public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
|
@ -249,7 +243,6 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
thumbSizeSelector.getChildren().add(thumbWidth);
|
thumbSizeSelector.getChildren().add(thumbWidth);
|
||||||
BorderPane.setMargin(thumbSizeSelector, new Insets(5));
|
BorderPane.setMargin(thumbSizeSelector, new Insets(5));
|
||||||
|
|
||||||
|
|
||||||
BorderPane bottomPane = new BorderPane();
|
BorderPane bottomPane = new BorderPane();
|
||||||
bottomPane.setLeft(pagination);
|
bottomPane.setLeft(pagination);
|
||||||
bottomPane.setRight(thumbSizeSelector);
|
bottomPane.setRight(thumbSizeSelector);
|
||||||
|
@ -281,7 +274,6 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
changePageTo(page);
|
changePageTo(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void previousPage() {
|
private void previousPage() {
|
||||||
int page = updateService.getPage();
|
int page = updateService.getPage();
|
||||||
page = Math.max(1, --page);
|
page = Math.max(1, --page);
|
||||||
|
@ -362,9 +354,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
|
|
||||||
private List<Model> filterIgnoredModels(List<Model> models) {
|
private List<Model> filterIgnoredModels(List<Model> models) {
|
||||||
List<String> ignored = Config.getInstance().getSettings().ignoredModels;
|
List<String> ignored = Config.getInstance().getSettings().ignoredModels;
|
||||||
return models.stream()
|
return models.stream().filter(m -> !ignored.contains(m.getUrl())).collect(Collectors.toList());
|
||||||
.filter(m -> !ignored.contains(m.getUrl()))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateGrid(List<? extends Model> models) {
|
protected void updateGrid(List<? extends Model> models) {
|
||||||
|
@ -397,7 +387,8 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
for (Model model : models) {
|
for (Model model : models) {
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (Node node : nodes) { // NOSONAR
|
for (Node node : nodes) { // NOSONAR
|
||||||
if (!(node instanceof ThumbCell)) continue;
|
if (!(node instanceof ThumbCell))
|
||||||
|
continue;
|
||||||
ThumbCell cell = (ThumbCell) node;
|
ThumbCell cell = (ThumbCell) node;
|
||||||
if (cell.getModel().equals(model)) {
|
if (cell.getModel().equals(model)) {
|
||||||
found = true;
|
found = true;
|
||||||
|
@ -433,7 +424,8 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
private void removeModelsMissingInUpdate(ObservableList<Node> nodes, List<? extends Model> models) {
|
private void removeModelsMissingInUpdate(ObservableList<Node> nodes, List<? extends Model> models) {
|
||||||
for (Iterator<Node> iterator = nodes.iterator(); iterator.hasNext();) {
|
for (Iterator<Node> iterator = nodes.iterator(); iterator.hasNext();) {
|
||||||
Node node = iterator.next();
|
Node node = iterator.next();
|
||||||
if (!(node instanceof ThumbCell)) continue;
|
if (!(node instanceof ThumbCell))
|
||||||
|
continue;
|
||||||
ThumbCell cell = (ThumbCell) node;
|
ThumbCell cell = (ThumbCell) node;
|
||||||
if (!models.contains(cell.getModel())) {
|
if (!models.contains(cell.getModel())) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
|
@ -469,14 +461,6 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
return newCell;
|
return newCell;
|
||||||
}
|
}
|
||||||
|
|
||||||
// private ContextMenu createContextMenu(ThumbCell cell) {
|
|
||||||
// return new ModelContextMenu.Builder()
|
|
||||||
// .model(cell.getModel())
|
|
||||||
// .node(grid)
|
|
||||||
// .recorder(recorder)
|
|
||||||
// .build();
|
|
||||||
// }
|
|
||||||
|
|
||||||
private ContextMenu createContextMenu(ThumbCell cell) {
|
private ContextMenu createContextMenu(ThumbCell cell) {
|
||||||
var model = cell.getModel();
|
var model = cell.getModel();
|
||||||
boolean modelIsTrackedByRecorder = recorder.isTracked(model);
|
boolean modelIsTrackedByRecorder = recorder.isTracked(model);
|
||||||
|
@ -507,16 +491,15 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
resume.setOnAction(e -> pauseResumeAction(getSelectedThumbCells(cell), false));
|
resume.setOnAction(e -> pauseResumeAction(getSelectedThumbCells(cell), false));
|
||||||
var pauseResume = recorder.isSuspended(model) ? resume : pause;
|
var pauseResume = recorder.isSuspended(model) ? resume : pause;
|
||||||
|
|
||||||
|
var addToGroup = new MenuItem("Add to group");
|
||||||
|
addToGroup.setOnAction(e -> new AddToGroupAction(this.getContent(), recorder, model).execute());
|
||||||
|
var groupSubMenu = new ModelGroupMenuBuilder().model(model).recorder(recorder).node(grid).build();
|
||||||
|
|
||||||
var follow = new MenuItem("Follow");
|
var follow = new MenuItem("Follow");
|
||||||
follow.setOnAction(e -> follow(getSelectedThumbCells(cell), true));
|
follow.setOnAction(e -> follow(getSelectedThumbCells(cell), true));
|
||||||
var unfollow = new MenuItem("Unfollow");
|
var unfollow = new MenuItem("Unfollow");
|
||||||
unfollow.setOnAction(e -> follow(getSelectedThumbCells(cell), false));
|
unfollow.setOnAction(e -> follow(getSelectedThumbCells(cell), false));
|
||||||
|
|
||||||
var addToGroup = new MenuItem("Add to group");
|
|
||||||
addToGroup.setOnAction(e -> addToGroup(model));
|
|
||||||
var editGroup = new MenuItem("Edit group");
|
|
||||||
editGroup.setOnAction(e -> editGroup(model));
|
|
||||||
|
|
||||||
var ignore = new MenuItem("Ignore");
|
var ignore = new MenuItem("Ignore");
|
||||||
ignore.setOnAction(e -> ignore(getSelectedThumbCells(cell)));
|
ignore.setOnAction(e -> ignore(getSelectedThumbCells(cell)));
|
||||||
|
|
||||||
|
@ -542,6 +525,8 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
} else {
|
} else {
|
||||||
contextMenu.getItems().addAll(recordUntil, addPaused, addRemoveBookmark);
|
contextMenu.getItems().addAll(recordUntil, addPaused, addRemoveBookmark);
|
||||||
}
|
}
|
||||||
|
Optional<ModelGroup> modelGroup = recorder.getModelGroup(model);
|
||||||
|
contextMenu.getItems().add(modelGroup.isEmpty() ? addToGroup : groupSubMenu);
|
||||||
contextMenu.getItems().add(new SeparatorMenuItem());
|
contextMenu.getItems().add(new SeparatorMenuItem());
|
||||||
if (site.supportsFollow()) {
|
if (site.supportsFollow()) {
|
||||||
var followOrUnFollow = (this instanceof FollowedTab) ? unfollow : follow;
|
var followOrUnFollow = (this instanceof FollowedTab) ? unfollow : follow;
|
||||||
|
@ -551,8 +536,6 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
if (site.supportsTips()) {
|
if (site.supportsTips()) {
|
||||||
contextMenu.getItems().add(sendTip);
|
contextMenu.getItems().add(sendTip);
|
||||||
}
|
}
|
||||||
Optional<ModelGroup> modelGroup = recorder.getModelGroup(model);
|
|
||||||
contextMenu.getItems().add(modelGroup.isEmpty() ? addToGroup : editGroup);
|
|
||||||
contextMenu.getItems().addAll(copyUrl, openInBrowser, ignore, refresh, openRecDir);
|
contextMenu.getItems().addAll(copyUrl, openInBrowser, ignore, refresh, openRecDir);
|
||||||
if (model instanceof MyFreeCamsModel && Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
if (model instanceof MyFreeCamsModel && Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
||||||
var debug = new MenuItem("debug");
|
var debug = new MenuItem("debug");
|
||||||
|
@ -563,14 +546,6 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
return contextMenu;
|
return contextMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void editGroup(Model model) {
|
|
||||||
new EditGroupAction(this.getContent(), recorder, model).execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addToGroup(Model model) {
|
|
||||||
new AddToGroupAction(this.getContent(), recorder, model).execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void recordLater(List<ThumbCell> list, boolean recordLater) {
|
private void recordLater(List<ThumbCell> list, boolean recordLater) {
|
||||||
for (ThumbCell cell : list) {
|
for (ThumbCell cell : list) {
|
||||||
cell.recordLater(recordLater);
|
cell.recordLater(recordLater);
|
||||||
|
@ -593,9 +568,9 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check, if other cells are selected, too. in that case, we have to disable menu items, which make sense only for
|
/*
|
||||||
* single selections. but only do that, if the popup has been triggered on a selected cell. otherwise remove the
|
* check, if other cells are selected, too. in that case, we have to disable menu items, which make sense only for single selections. but only do that, if
|
||||||
* selection and show the normal menu
|
* the popup has been triggered on a selected cell. otherwise remove the selection and show the normal menu
|
||||||
*/
|
*/
|
||||||
private void configureItemsForSelection(ThumbCell cell, MenuItem openInPlayer, MenuItem copyUrl, MenuItem sendTip) {
|
private void configureItemsForSelection(ThumbCell cell, MenuItem openInPlayer, MenuItem copyUrl, MenuItem sendTip) {
|
||||||
if (selectedThumbCells.size() > 1 || selectedThumbCells.size() == 1 && selectedThumbCells.get(0) != cell) {
|
if (selectedThumbCells.size() > 1 || selectedThumbCells.size() == 1 && selectedThumbCells.get(0) != cell) {
|
||||||
|
@ -612,46 +587,24 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private MenuItem createOpenInBrowser(ThumbCell cell) {
|
private MenuItem createOpenInBrowser(ThumbCell cell) {
|
||||||
MenuItem openInBrowser = new MenuItem("Open in browser");
|
var openInBrowser = new MenuItem("Open in browser");
|
||||||
openInBrowser.setOnAction(e -> DesktopIntegration.open(cell.getModel().getUrl()));
|
openInBrowser.setOnAction(e -> DesktopIntegration.open(cell.getModel().getUrl()));
|
||||||
return openInBrowser;
|
return openInBrowser;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MenuItem createCopyUrlMenuItem(ThumbCell cell) {
|
private MenuItem createCopyUrlMenuItem(ThumbCell cell) {
|
||||||
MenuItem copyUrl = new MenuItem("Copy URL");
|
var copyUrl = new MenuItem("Copy URL");
|
||||||
copyUrl.setOnAction(e -> {
|
copyUrl.setOnAction(e -> {
|
||||||
final Clipboard clipboard = Clipboard.getSystemClipboard();
|
final var content = new ClipboardContent();
|
||||||
final ClipboardContent content = new ClipboardContent();
|
|
||||||
content.putString(cell.getModel().getUrl());
|
content.putString(cell.getModel().getUrl());
|
||||||
clipboard.setContent(content);
|
Clipboard.getSystemClipboard().setContent(content);
|
||||||
});
|
});
|
||||||
return copyUrl;
|
return copyUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MenuItem createTipMenuItem(ThumbCell cell) {
|
private MenuItem createTipMenuItem(ThumbCell cell) {
|
||||||
MenuItem sendTip = new MenuItem("Send Tip");
|
var sendTip = new MenuItem("Send Tip");
|
||||||
sendTip.setOnAction(e -> {
|
sendTip.setOnAction(e -> new TipAction(cell.getModel(), cell));
|
||||||
TipDialog tipDialog = new TipDialog(getTabPane().getScene(), site);
|
|
||||||
tipDialog.showAndWait();
|
|
||||||
String tipText = tipDialog.getResult();
|
|
||||||
if(tipText != null) {
|
|
||||||
DecimalFormat df = new DecimalFormat("0.##");
|
|
||||||
try {
|
|
||||||
Number tokens = df.parse(tipText);
|
|
||||||
SiteUiFactory.getUi(site).login();
|
|
||||||
cell.getModel().receiveTip(tokens.doubleValue());
|
|
||||||
Map<String, Object> event = new HashMap<>();
|
|
||||||
event.put("event", "tokens.sent");
|
|
||||||
event.put("amount", tokens.doubleValue());
|
|
||||||
EventBusHolder.BUS.post(event);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
LOG.error("An error occurred while sending tip", ex);
|
|
||||||
showError(getTabPane().getScene(), "Couldn't send tip", "An error occurred while sending tip:", ex);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
showError(getTabPane().getScene(), "Couldn't send tip", "You entered an invalid amount of tokens", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
sendTip.setDisable(!site.credentialsAvailable());
|
sendTip.setDisable(!site.credentialsAvailable());
|
||||||
return sendTip;
|
return sendTip;
|
||||||
}
|
}
|
||||||
|
@ -679,15 +632,12 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
|
|
||||||
protected void ignore(List<ThumbCell> selection) {
|
protected void ignore(List<ThumbCell> selection) {
|
||||||
Map<Model, ThumbCell> thumbcells = new HashMap<>();
|
Map<Model, ThumbCell> thumbcells = new HashMap<>();
|
||||||
List<Model> selectedModels = selection.stream()
|
List<Model> selectedModels = selection.stream().map(tc -> {
|
||||||
.map(tc -> {
|
|
||||||
thumbcells.put(tc.getModel(), tc);
|
thumbcells.put(tc.getModel(), tc);
|
||||||
return tc;
|
return tc;
|
||||||
})
|
}).map(ThumbCell::getModel).collect(Collectors.toList());
|
||||||
.map(ThumbCell::getModel)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
new IgnoreModelsAction(grid, selectedModels, recorder, false).execute(m -> {
|
new IgnoreModelsAction(grid, selectedModels, recorder, false).execute(m -> {
|
||||||
ThumbCell thumbCell = thumbcells.get(m);
|
var thumbCell = thumbcells.get(m);
|
||||||
grid.getChildren().remove(thumbCell);
|
grid.getChildren().remove(thumbCell);
|
||||||
selectedThumbCells.remove(thumbCell);
|
selectedThumbCells.remove(thumbCell);
|
||||||
});
|
});
|
||||||
|
@ -695,40 +645,40 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
|
|
||||||
private void showAddToFollowedAnimation(ThumbCell thumbCell) {
|
private void showAddToFollowedAnimation(ThumbCell thumbCell) {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
Transform tx = thumbCell.getLocalToParentTransform();
|
var tx = thumbCell.getLocalToParentTransform();
|
||||||
ImageView iv = new ImageView();
|
var iv = new ImageView();
|
||||||
iv.setFitWidth(thumbCell.getWidth());
|
iv.setFitWidth(thumbCell.getWidth());
|
||||||
root.getChildren().add(iv);
|
root.getChildren().add(iv);
|
||||||
StackPane.setAlignment(iv, Pos.TOP_LEFT);
|
StackPane.setAlignment(iv, Pos.TOP_LEFT);
|
||||||
iv.setImage(thumbCell.getImage());
|
iv.setImage(thumbCell.getImage());
|
||||||
double scrollPaneTopLeft = scrollPane.getVvalue() * (grid.getHeight() - scrollPane.getViewportBounds().getHeight());
|
double scrollPaneTopLeft = scrollPane.getVvalue() * (grid.getHeight() - scrollPane.getViewportBounds().getHeight());
|
||||||
double offsetInViewPort = tx.getTy() - scrollPaneTopLeft;
|
double offsetInViewPort = tx.getTy() - scrollPaneTopLeft;
|
||||||
int duration = 500;
|
var duration = 500;
|
||||||
TranslateTransition translate = new TranslateTransition(Duration.millis(duration), iv);
|
var translate = new TranslateTransition(Duration.millis(duration), iv);
|
||||||
translate.setFromX(0);
|
translate.setFromX(0);
|
||||||
translate.setFromY(0);
|
translate.setFromY(0);
|
||||||
translate.setByX(-tx.getTx() - 200);
|
translate.setByX(-tx.getTx() - 200);
|
||||||
TabProvider tabProvider = SiteUiFactory.getUi(site).getTabProvider();
|
var tabProvider = SiteUiFactory.getUi(site).getTabProvider();
|
||||||
Tab followedTab = tabProvider.getFollowedTab();
|
var followedTab = tabProvider.getFollowedTab();
|
||||||
translate.setByY(-offsetInViewPort + getFollowedTabYPosition(followedTab));
|
translate.setByY(-offsetInViewPort + getFollowedTabYPosition(followedTab));
|
||||||
StackPane.setMargin(iv, new Insets(offsetInViewPort, 0, 0, tx.getTx()));
|
StackPane.setMargin(iv, new Insets(offsetInViewPort, 0, 0, tx.getTx()));
|
||||||
translate.setInterpolator(Interpolator.EASE_BOTH);
|
translate.setInterpolator(Interpolator.EASE_BOTH);
|
||||||
FadeTransition fade = new FadeTransition(Duration.millis(duration), iv);
|
var fade = new FadeTransition(Duration.millis(duration), iv);
|
||||||
fade.setFromValue(1);
|
fade.setFromValue(1);
|
||||||
fade.setToValue(.3);
|
fade.setToValue(.3);
|
||||||
ScaleTransition scale = new ScaleTransition(Duration.millis(duration), iv);
|
var scale = new ScaleTransition(Duration.millis(duration), iv);
|
||||||
scale.setToX(0.1);
|
scale.setToX(0.1);
|
||||||
scale.setToY(0.1);
|
scale.setToY(0.1);
|
||||||
ParallelTransition pt = new ParallelTransition(translate, scale);
|
var pt = new ParallelTransition(translate, scale);
|
||||||
pt.play();
|
pt.play();
|
||||||
pt.setOnFinished(evt -> root.getChildren().remove(iv));
|
pt.setOnFinished(evt -> root.getChildren().remove(iv));
|
||||||
FollowTabBlinkTransition blink = new FollowTabBlinkTransition(followedTab);
|
var blink = new FollowTabBlinkTransition(followedTab);
|
||||||
blink.play();
|
blink.play();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getFollowedTabYPosition(Tab followedTab) {
|
private double getFollowedTabYPosition(Tab followedTab) {
|
||||||
TabPane tabPane = getTabPane();
|
var tabPane = getTabPane();
|
||||||
int idx = Math.max(0, tabPane.getTabs().indexOf(followedTab));
|
int idx = Math.max(0, tabPane.getTabs().indexOf(followedTab));
|
||||||
for (Node node : tabPane.getChildrenUnmodifiable()) {
|
for (Node node : tabPane.getChildrenUnmodifiable()) {
|
||||||
Parent p = (Parent) node;
|
Parent p = (Parent) node;
|
||||||
|
@ -806,8 +756,10 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
|
|
||||||
void filter() {
|
void filter() {
|
||||||
filteredThumbCells.sort((c1, c2) -> {
|
filteredThumbCells.sort((c1, c2) -> {
|
||||||
if (c1.getIndex() < c2.getIndex()) return -1;
|
if (c1.getIndex() < c2.getIndex())
|
||||||
if (c1.getIndex() > c2.getIndex()) return 1;
|
return -1;
|
||||||
|
if (c1.getIndex() > c2.getIndex())
|
||||||
|
return 1;
|
||||||
return c1.getModel().getName().compareTo(c2.getModel().getName());
|
return c1.getModel().getName().compareTo(c2.getModel().getName());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -990,6 +942,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int threadCounter = 0;
|
private static int threadCounter = 0;
|
||||||
|
|
||||||
private static ThreadFactory createThreadFactory() {
|
private static ThreadFactory createThreadFactory() {
|
||||||
return r -> {
|
return r -> {
|
||||||
Thread t = new Thread(r);
|
Thread t = new Thread(r);
|
||||||
|
|
|
@ -38,7 +38,6 @@ import ctbrec.ui.PreviewPopupHandler;
|
||||||
import ctbrec.ui.StreamSourceSelectionDialog;
|
import ctbrec.ui.StreamSourceSelectionDialog;
|
||||||
import ctbrec.ui.action.AddToGroupAction;
|
import ctbrec.ui.action.AddToGroupAction;
|
||||||
import ctbrec.ui.action.CheckModelAccountAction;
|
import ctbrec.ui.action.CheckModelAccountAction;
|
||||||
import ctbrec.ui.action.EditGroupAction;
|
|
||||||
import ctbrec.ui.action.EditNotesAction;
|
import ctbrec.ui.action.EditNotesAction;
|
||||||
import ctbrec.ui.action.FollowAction;
|
import ctbrec.ui.action.FollowAction;
|
||||||
import ctbrec.ui.action.IgnoreModelsAction;
|
import ctbrec.ui.action.IgnoreModelsAction;
|
||||||
|
@ -57,6 +56,7 @@ import ctbrec.ui.controls.Dialogs;
|
||||||
import ctbrec.ui.controls.SearchBox;
|
import ctbrec.ui.controls.SearchBox;
|
||||||
import ctbrec.ui.controls.autocomplete.AutoFillTextField;
|
import ctbrec.ui.controls.autocomplete.AutoFillTextField;
|
||||||
import ctbrec.ui.controls.autocomplete.ObservableListSuggester;
|
import ctbrec.ui.controls.autocomplete.ObservableListSuggester;
|
||||||
|
import ctbrec.ui.menu.ModelGroupMenuBuilder;
|
||||||
import ctbrec.ui.tabs.TabSelectionListener;
|
import ctbrec.ui.tabs.TabSelectionListener;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
@ -75,6 +75,7 @@ import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.ContextMenu;
|
import javafx.scene.control.ContextMenu;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.Menu;
|
||||||
import javafx.scene.control.MenuItem;
|
import javafx.scene.control.MenuItem;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.control.SelectionMode;
|
import javafx.scene.control.SelectionMode;
|
||||||
|
@ -154,7 +155,6 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
scrollPane.setFitToWidth(true);
|
scrollPane.setFitToWidth(true);
|
||||||
BorderPane.setMargin(scrollPane, new Insets(5));
|
BorderPane.setMargin(scrollPane, new Insets(5));
|
||||||
|
|
||||||
|
|
||||||
table.setEditable(true);
|
table.setEditable(true);
|
||||||
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||||||
var previewPopupHandler = new PreviewPopupHandler(table);
|
var previewPopupHandler = new PreviewPopupHandler(table);
|
||||||
|
@ -286,8 +286,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
HBox.setHgrow(model, Priority.ALWAYS);
|
HBox.setHgrow(model, Priority.ALWAYS);
|
||||||
model.setPromptText("e.g. MyFreeCams:ModelName or an URL like https://chaturbate.com/modelname/");
|
model.setPromptText("e.g. MyFreeCams:ModelName or an URL like https://chaturbate.com/modelname/");
|
||||||
model.onActionHandler(this::addModel);
|
model.onActionHandler(this::addModel);
|
||||||
model.setTooltip(new Tooltip("To add a model enter SiteName:ModelName\n" +
|
model.setTooltip(new Tooltip("To add a model enter SiteName:ModelName\n" + "press ENTER to confirm a suggested site name"));
|
||||||
"press ENTER to confirm a suggested site name"));
|
|
||||||
BorderPane.setMargin(addModelBox, new Insets(5));
|
BorderPane.setMargin(addModelBox, new Insets(5));
|
||||||
addModelButton.setOnAction(this::addModel);
|
addModelButton.setOnAction(this::addModel);
|
||||||
addModelButton.setPadding(new Insets(5));
|
addModelButton.setPadding(new Insets(5));
|
||||||
|
@ -303,8 +302,8 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
checkModelAccountExistance.setPadding(new Insets(5));
|
checkModelAccountExistance.setPadding(new Insets(5));
|
||||||
checkModelAccountExistance.setTooltip(new Tooltip("Go over all model URLs and check, if the account still exists"));
|
checkModelAccountExistance.setTooltip(new Tooltip("Go over all model URLs and check, if the account still exists"));
|
||||||
HBox.setMargin(checkModelAccountExistance, new Insets(0, 0, 0, 20));
|
HBox.setMargin(checkModelAccountExistance, new Insets(0, 0, 0, 20));
|
||||||
checkModelAccountExistance.setOnAction(evt -> new CheckModelAccountAction(checkModelAccountExistance, recorder)
|
checkModelAccountExistance
|
||||||
.execute(Predicate.not(Model::isMarkedForLaterRecording)));
|
.setOnAction(evt -> new CheckModelAccountAction(checkModelAccountExistance, recorder).execute(Predicate.not(Model::isMarkedForLaterRecording)));
|
||||||
|
|
||||||
var filterContainer = new HBox();
|
var filterContainer = new HBox();
|
||||||
filterContainer.setSpacing(0);
|
filterContainer.setSpacing(0);
|
||||||
|
@ -591,11 +590,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
LOG.trace("Updating recorded models");
|
LOG.trace("Updating recorded models");
|
||||||
List<Recording> recordings = recorder.getRecordings();
|
List<Recording> recordings = recorder.getRecordings();
|
||||||
List<Model> onlineModels = recorder.getOnlineModels();
|
List<Model> onlineModels = recorder.getOnlineModels();
|
||||||
return recorder.getModels()
|
return recorder.getModels().stream().filter(Predicate.not(Model::isMarkedForLaterRecording)).map(JavaFxModel::new).peek(fxm -> { // NOSONAR
|
||||||
.stream()
|
|
||||||
.filter(Predicate.not(Model::isMarkedForLaterRecording))
|
|
||||||
.map(JavaFxModel::new)
|
|
||||||
.peek(fxm -> { // NOSONAR
|
|
||||||
for (Recording recording : recordings) {
|
for (Recording recording : recordings) {
|
||||||
if (recording.getStatus() == RECORDING && Objects.equals(recording.getModel(), fxm)) {
|
if (recording.getStatus() == RECORDING && Objects.equals(recording.getModel(), fxm)) {
|
||||||
fxm.setRecordingProperty(true);
|
fxm.setRecordingProperty(true);
|
||||||
|
@ -609,8 +604,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}).collect(Collectors.toList());
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -684,9 +678,8 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
openRecDir.setOnAction(e -> new OpenRecordingsDir(table, selectedModels.get(0)).execute());
|
openRecDir.setOnAction(e -> new OpenRecordingsDir(table, selectedModels.get(0)).execute());
|
||||||
|
|
||||||
var addToGroup = new MenuItem("Add to group");
|
var addToGroup = new MenuItem("Add to group");
|
||||||
addToGroup.setOnAction(e -> addToGroup(selectedModels.get(0)));
|
addToGroup.setOnAction(e -> new AddToGroupAction(this.getContent(), recorder, selectedModels.get(0)).execute(() -> table.refresh()));
|
||||||
var editGroup = new MenuItem("Edit group");
|
var groupSubMenu = createModelGroupMenu(selectedModels);
|
||||||
editGroup.setOnAction(e -> editGroup(selectedModels.get(0)));
|
|
||||||
|
|
||||||
ContextMenu menu = new CustomMouseBehaviorContextMenu(stop, recordLater);
|
ContextMenu menu = new CustomMouseBehaviorContextMenu(stop, recordLater);
|
||||||
if (selectedModels.size() == 1) {
|
if (selectedModels.size() == 1) {
|
||||||
|
@ -699,7 +692,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
menu.getItems().addAll(resumeRecording, pauseRecording);
|
menu.getItems().addAll(resumeRecording, pauseRecording);
|
||||||
}
|
}
|
||||||
Optional<ModelGroup> modelGroup = recorder.getModelGroup(selectedModels.get(0));
|
Optional<ModelGroup> modelGroup = recorder.getModelGroup(selectedModels.get(0));
|
||||||
menu.getItems().add(modelGroup.isEmpty() ? addToGroup : editGroup);
|
menu.getItems().add(modelGroup.isEmpty() ? addToGroup : groupSubMenu);
|
||||||
menu.getItems().addAll(copyUrl, openInPlayer, openInBrowser, openRecDir, switchStreamSource, follow, notes, ignore);
|
menu.getItems().addAll(copyUrl, openInPlayer, openInBrowser, openRecDir, switchStreamSource, follow, notes, ignore);
|
||||||
|
|
||||||
if (selectedModels.size() > 1) {
|
if (selectedModels.size() > 1) {
|
||||||
|
@ -713,14 +706,13 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addToGroup(Model model) {
|
private Menu createModelGroupMenu(ObservableList<JavaFxModel> selectedModels) {
|
||||||
new AddToGroupAction(this.getContent(), recorder, model).execute();
|
return new ModelGroupMenuBuilder() //
|
||||||
table.refresh();
|
.model(selectedModels.get(0)) //
|
||||||
}
|
.recorder(recorder) //
|
||||||
|
.node(table) //
|
||||||
private void editGroup(Model model) {
|
.callback(m -> table.refresh()) //
|
||||||
new EditGroupAction(this.getContent(), recorder, model).execute();
|
.build();
|
||||||
table.refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setStopDate(JavaFxModel model) {
|
private void setStopDate(JavaFxModel model) {
|
||||||
|
@ -818,13 +810,10 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
private void recordLater(List<JavaFxModel> selectedModels) {
|
private void recordLater(List<JavaFxModel> selectedModels) {
|
||||||
boolean confirmed = stopAction(selectedModels);
|
boolean confirmed = stopAction(selectedModels);
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
List<Model> models = selectedModels.stream()
|
List<Model> models = selectedModels.stream().map(JavaFxModel::getDelegate).map(m -> {
|
||||||
.map(JavaFxModel::getDelegate)
|
|
||||||
.map(m -> {
|
|
||||||
m.setMarkedForLaterRecording(true);
|
m.setMarkedForLaterRecording(true);
|
||||||
return m;
|
return m;
|
||||||
})
|
}).collect(Collectors.toList());
|
||||||
.collect(Collectors.toList());
|
|
||||||
new StartRecordingAction(table, models, recorder).execute();
|
new StartRecordingAction(table, models, recorder).execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue