diff --git a/client/src/main/java/ctbrec/ui/sites/camsoda/CamsodaShowsTab.java b/client/src/main/java/ctbrec/ui/sites/camsoda/CamsodaShowsTab.java deleted file mode 100644 index 7ee78219..00000000 --- a/client/src/main/java/ctbrec/ui/sites/camsoda/CamsodaShowsTab.java +++ /dev/null @@ -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; - } - } -} diff --git a/client/src/main/java/ctbrec/ui/sites/camsoda/CamsodaTabProvider.java b/client/src/main/java/ctbrec/ui/sites/camsoda/CamsodaTabProvider.java index 396fead3..57573c8d 100644 --- a/client/src/main/java/ctbrec/ui/sites/camsoda/CamsodaTabProvider.java +++ b/client/src/main/java/ctbrec/ui/sites/camsoda/CamsodaTabProvider.java @@ -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; }