Remove CamSoda shows tab
This commit is contained in:
parent
8be632a708
commit
c515ce7b2a
|
@ -1,296 +0,0 @@
|
|||
package ctbrec.ui.sites.camsoda;
|
||||
|
||||
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.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ctbrec.GlobalThreadPool;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.sites.camsoda.Camsoda;
|
||||
import ctbrec.ui.AutosizeAlert;
|
||||
import ctbrec.ui.DesktopIntegration;
|
||||
import ctbrec.ui.SiteUiFactory;
|
||||
import ctbrec.ui.tabs.TabSelectionListener;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ProgressIndicator;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TitledPane;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.FontWeight;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class CamsodaShowsTab extends Tab implements TabSelectionListener {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CamsodaShowsTab.class);
|
||||
|
||||
private Camsoda camsoda;
|
||||
private Recorder recorder;
|
||||
private GridPane showList;
|
||||
|
||||
public CamsodaShowsTab(Camsoda camsoda, Recorder recorder) {
|
||||
this.camsoda = camsoda;
|
||||
this.recorder = recorder;
|
||||
createGui();
|
||||
}
|
||||
|
||||
private void createGui() {
|
||||
showList = new GridPane();
|
||||
showList.setPadding(new Insets(5));
|
||||
showList.setHgap(5);
|
||||
showList.setVgap(5);
|
||||
var progressIndicator = new ProgressIndicator();
|
||||
progressIndicator.setPrefSize(100, 100);
|
||||
setContent(progressIndicator);
|
||||
setClosable(false);
|
||||
setText("Shows");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selected() {
|
||||
Task<List<ShowBox>> task = new Task<List<ShowBox>>() {
|
||||
@Override
|
||||
protected List<ShowBox> call() throws Exception {
|
||||
return loadShows();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
super.done();
|
||||
Platform.runLater(() -> {
|
||||
try {
|
||||
List<ShowBox> boxes = get();
|
||||
showList.getChildren().clear();
|
||||
var index = 0;
|
||||
for (ShowBox showBox : boxes) {
|
||||
showList.add(showBox, index % 2, index++ / 2);
|
||||
GridPane.setMargin(showBox, new Insets(20, 20, 0, 20));
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
LOG.error("Couldn't load upcoming camsoda shows", e);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Couldn't load upcoming camsoda shows", e);
|
||||
}
|
||||
setContent(new ScrollPane(showList));
|
||||
});
|
||||
}
|
||||
};
|
||||
GlobalThreadPool.submit(task);
|
||||
}
|
||||
|
||||
private List<ShowBox> loadShows() throws IOException {
|
||||
String url = camsoda.getBaseUrl() + "/api/v1/user/model_shows";
|
||||
Request req = new Request.Builder().url(url).build();
|
||||
try(var response = camsoda.getHttpClient().execute(req)) {
|
||||
if (response.isSuccessful()) {
|
||||
var json = new JSONObject(response.body().string());
|
||||
if (json.optInt("success") == 1) {
|
||||
List<ShowBox> boxes = new ArrayList<>();
|
||||
var results = json.getJSONArray("results");
|
||||
for (var i = 0; i < results.length(); i++) {
|
||||
var result = results.getJSONObject(i);
|
||||
var modelUrl = camsoda.getBaseUrl() + result.getString("url");
|
||||
var name = modelUrl.substring(modelUrl.lastIndexOf('/') + 1);
|
||||
var model = camsoda.createModel(name);
|
||||
ZonedDateTime startTime = parseUtcTime(result.getString("start"));
|
||||
ZonedDateTime endTime = parseUtcTime(result.getString("end"));
|
||||
boxes.add(new ShowBox(model, startTime, endTime));
|
||||
}
|
||||
return boxes;
|
||||
} else {
|
||||
LOG.error("Couldn't load upcoming camsoda shows. Unexpected response: {}", json);
|
||||
showErrorDialog("Oh no!", "Couldn't load upcoming CamSoda shows", "Got an unexpected response from server");
|
||||
}
|
||||
} else {
|
||||
showErrorDialog("Oh no!", "Couldn't load upcoming CamSoda shows", "Got an unexpected response from server");
|
||||
LOG.error("Couldn't load upcoming camsoda shows: {} {}", response.code(), response.message());
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private ZonedDateTime parseUtcTime(String string) {
|
||||
var formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
||||
var ta = formatter.parse(string.replace(" UTC", ""));
|
||||
var instant = Instant.from(ta);
|
||||
return ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deselected() {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
private void showErrorDialog(String title, String head, String msg) {
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new AutosizeAlert(Alert.AlertType.ERROR, getTabPane().getScene());
|
||||
alert.setTitle(title);
|
||||
alert.setHeaderText(head);
|
||||
alert.setContentText(msg);
|
||||
alert.showAndWait();
|
||||
});
|
||||
}
|
||||
|
||||
private class ShowBox extends TitledPane {
|
||||
|
||||
BorderPane root = new BorderPane();
|
||||
int thumbSize = 200;
|
||||
|
||||
public ShowBox(Model model, ZonedDateTime startTime, ZonedDateTime endTime) {
|
||||
setText(model.getName());
|
||||
setPrefHeight(268);
|
||||
setContent(root);
|
||||
|
||||
var thumb = new ImageView();
|
||||
thumb.setPreserveRatio(true);
|
||||
thumb.setFitHeight(thumbSize);
|
||||
loadImage(model, thumb);
|
||||
root.setLeft(new ProgressIndicator());
|
||||
BorderPane.setMargin(thumb, new Insets(10, 30, 10, 10));
|
||||
|
||||
var formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.MEDIUM);
|
||||
var grid = new GridPane();
|
||||
|
||||
grid.add(createLabel("Start", true), 0, 0);
|
||||
grid.add(createLabel(formatter.format(startTime), false), 1, 0);
|
||||
grid.add(createLabel("End", true), 0, 1);
|
||||
grid.add(createLabel(formatter.format(endTime), false), 1, 1);
|
||||
var recordButton = new Button("Record Model");
|
||||
recordButton.setTooltip(new Tooltip(recordButton.getText()));
|
||||
recordButton.setOnAction(evt -> recordModel(model));
|
||||
grid.add(recordButton, 1, 2);
|
||||
GridPane.setMargin(recordButton, new Insets(10));
|
||||
var follow = new Button("Follow");
|
||||
follow.setTooltip(new Tooltip(follow.getText()));
|
||||
follow.setOnAction(evt -> follow(model));
|
||||
grid.add(follow, 1, 3);
|
||||
GridPane.setMargin(follow, new Insets(10));
|
||||
var openInBrowser = new Button("Open in Browser");
|
||||
openInBrowser.setTooltip(new Tooltip(openInBrowser.getText()));
|
||||
openInBrowser.setOnAction(evt -> DesktopIntegration.open(model.getUrl()));
|
||||
grid.add(openInBrowser, 1, 4);
|
||||
GridPane.setMargin(openInBrowser, new Insets(10));
|
||||
root.setCenter(grid);
|
||||
loadImage(model, thumb);
|
||||
|
||||
recordButton.minWidthProperty().bind(openInBrowser.widthProperty());
|
||||
follow.minWidthProperty().bind(openInBrowser.widthProperty());
|
||||
}
|
||||
|
||||
private void follow(Model model) {
|
||||
setCursor(Cursor.WAIT);
|
||||
GlobalThreadPool.submit(() -> {
|
||||
try {
|
||||
SiteUiFactory.getUi(model.getSite()).login();
|
||||
model.follow();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Couldn't follow model {}", model, e);
|
||||
showErrorDialog("Oh no!", "Couldn't follow model", e.getMessage());
|
||||
} finally {
|
||||
Platform.runLater(() -> setCursor(Cursor.DEFAULT));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void recordModel(Model model) {
|
||||
setCursor(Cursor.WAIT);
|
||||
GlobalThreadPool.submit(() -> {
|
||||
try {
|
||||
recorder.addModel(model);
|
||||
} catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | IOException e) {
|
||||
showErrorDialog("Oh no!", "Couldn't add model to the recorder", "Recorder error: " + e.getMessage());
|
||||
} finally {
|
||||
Platform.runLater(() -> setCursor(Cursor.DEFAULT));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadImage(Model model, ImageView thumb) {
|
||||
GlobalThreadPool.submit(() -> {
|
||||
try {
|
||||
String url = camsoda.getBaseUrl() + "/api/v1/user/" + model.getName();
|
||||
var detailRequest = new Request.Builder().url(url).build();
|
||||
try (Response resp = camsoda.getHttpClient().execute(detailRequest)) {
|
||||
if (resp.isSuccessful()) {
|
||||
parseImageUrl(resp.body().string()).ifPresent(imageUrl -> updateImageView(thumb, imageUrl));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Couldn't load model details", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateImageView(ImageView view, String imageUrl) {
|
||||
Platform.runLater(() -> {
|
||||
var img = new Image(imageUrl, 1000, thumbSize, true, true, true);
|
||||
img.progressProperty().addListener((ChangeListener<Number>) (observable, oldValue, newValue) -> {
|
||||
if (newValue.doubleValue() == 1.0) {
|
||||
view.setImage(img);
|
||||
root.setLeft(view);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private Optional<String> parseImageUrl(String body) {
|
||||
var json = new JSONObject(body);
|
||||
if (json.optBoolean("status") && json.has("user")) {
|
||||
var user = json.getJSONObject("user");
|
||||
if (user.has("settings")) {
|
||||
var settings = user.getJSONObject("settings");
|
||||
String imageUrl;
|
||||
if (Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
||||
imageUrl = getClass().getResource("/image_not_found.png").toString();
|
||||
} else {
|
||||
if (settings.has("offline_picture")) {
|
||||
imageUrl = settings.getString("offline_picture");
|
||||
} else {
|
||||
imageUrl = "https:" + user.getString("thumb");
|
||||
}
|
||||
}
|
||||
return Optional.of(imageUrl);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private Node createLabel(String string, boolean bold) {
|
||||
var label = new Label(string);
|
||||
label.setPadding(new Insets(10));
|
||||
var def = Font.getDefault();
|
||||
label.setFont(Font.font(def.getFamily(), bold ? FontWeight.BOLD : FontWeight.NORMAL, 16));
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,7 +40,6 @@ public class CamsodaTabProvider implements TabProvider {
|
|||
followedTab.setRecorder(recorder);
|
||||
followedTab.setScene(scene);
|
||||
tabs.add(followedTab);
|
||||
tabs.add(new CamsodaShowsTab(camsoda, recorder));
|
||||
return tabs;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue