From 378d3954b00ff67b9d6afa280be0f0e7a4fa0adf Mon Sep 17 00:00:00 2001 From: 0xboobface <0xboobface@gmail.com> Date: Tue, 13 Nov 2018 01:01:49 +0100 Subject: [PATCH] Add animation for following a model The preview of the model is animated to move to the followd tab on the left side. This should help to understand, what happened and that it happened. --- .../java/ctbrec/sites/bonga/BongaCams.java | 7 +- .../sites/bonga/BongaCamsTabProvider.java | 9 ++- src/main/java/ctbrec/sites/cam4/Cam4.java | 6 +- .../ctbrec/sites/cam4/Cam4TabProvider.java | 8 +- .../java/ctbrec/sites/camsoda/Camsoda.java | 6 +- .../sites/camsoda/CamsodaTabProvider.java | 8 +- .../ctbrec/sites/chaturbate/Chaturbate.java | 6 +- .../chaturbate/ChaturbateTabProvider.java | 13 ++- .../java/ctbrec/sites/mfc/MyFreeCams.java | 6 +- .../sites/mfc/MyFreeCamsTabProvider.java | 8 +- src/main/java/ctbrec/ui/TabProvider.java | 1 + src/main/java/ctbrec/ui/ThumbCell.java | 19 ++++- src/main/java/ctbrec/ui/ThumbOverviewTab.java | 80 +++++++++++++++++-- 13 files changed, 154 insertions(+), 23 deletions(-) diff --git a/src/main/java/ctbrec/sites/bonga/BongaCams.java b/src/main/java/ctbrec/sites/bonga/BongaCams.java index 5cea832c..f5e51a7d 100644 --- a/src/main/java/ctbrec/sites/bonga/BongaCams.java +++ b/src/main/java/ctbrec/sites/bonga/BongaCams.java @@ -21,8 +21,8 @@ public class BongaCams extends AbstractSite { public static final String BASE_URL = "https://bongacams.com"; private BongaCamsHttpClient httpClient; - private Recorder recorder; + private BongaCamsTabProvider tabProvider; @Override public String getName() { @@ -46,7 +46,10 @@ public class BongaCams extends AbstractSite { @Override public TabProvider getTabProvider() { - return new BongaCamsTabProvider(recorder, this); + if(tabProvider == null) { + tabProvider = new BongaCamsTabProvider(recorder, this); + } + return tabProvider; } @Override diff --git a/src/main/java/ctbrec/sites/bonga/BongaCamsTabProvider.java b/src/main/java/ctbrec/sites/bonga/BongaCamsTabProvider.java index 5a5bf55a..d54420dc 100644 --- a/src/main/java/ctbrec/sites/bonga/BongaCamsTabProvider.java +++ b/src/main/java/ctbrec/sites/bonga/BongaCamsTabProvider.java @@ -14,6 +14,7 @@ public class BongaCamsTabProvider extends TabProvider { private BongaCams bongaCams; private Recorder recorder; + private Tab friendsTab; public BongaCamsTabProvider(Recorder recorder, BongaCams bongaCams) { this.recorder = recorder; @@ -52,11 +53,17 @@ public class BongaCamsTabProvider extends TabProvider { // friends url = BongaCams.BASE_URL + "/tools/listing_v3.php?livetab=friends&online_only=true&offset="; updateService = new BongaCamsUpdateService(bongaCams, url); - tabs.add(createTab("Friends", updateService)); + friendsTab = createTab("Friends", updateService); + tabs.add(friendsTab); return tabs; } + @Override + public Tab getFollowedTab() { + return friendsTab; + } + private Tab createTab(String title, PaginatedScheduledService updateService) { ThumbOverviewTab tab = new ThumbOverviewTab(title, updateService, bongaCams); tab.setRecorder(recorder); diff --git a/src/main/java/ctbrec/sites/cam4/Cam4.java b/src/main/java/ctbrec/sites/cam4/Cam4.java index 7533f96e..1ac2c7f3 100644 --- a/src/main/java/ctbrec/sites/cam4/Cam4.java +++ b/src/main/java/ctbrec/sites/cam4/Cam4.java @@ -20,6 +20,7 @@ public class Cam4 extends AbstractSite { private HttpClient httpClient; private Recorder recorder; + private Cam4TabProvider tabProvider; @Override public String getName() { @@ -43,7 +44,10 @@ public class Cam4 extends AbstractSite { @Override public TabProvider getTabProvider() { - return new Cam4TabProvider(this, recorder); + if(tabProvider == null) { + tabProvider = new Cam4TabProvider(this, recorder); + } + return tabProvider; } @Override diff --git a/src/main/java/ctbrec/sites/cam4/Cam4TabProvider.java b/src/main/java/ctbrec/sites/cam4/Cam4TabProvider.java index 62136129..fc8d0acf 100644 --- a/src/main/java/ctbrec/sites/cam4/Cam4TabProvider.java +++ b/src/main/java/ctbrec/sites/cam4/Cam4TabProvider.java @@ -13,6 +13,7 @@ public class Cam4TabProvider extends TabProvider { private Cam4 cam4; private Recorder recorder; + private Cam4FollowedTab followed; public Cam4TabProvider(Cam4 cam4, Recorder recorder) { this.cam4 = cam4; @@ -28,13 +29,18 @@ public class Cam4TabProvider extends TabProvider { tabs.add(createTab("Couples", cam4.getBaseUrl() + "/directoryResults?online=true&broadcastType=male_group&broadcastType=female_group&broadcastType=male_female_group&orderBy=MOST_VIEWERS")); tabs.add(createTab("HD", cam4.getBaseUrl() + "/directoryResults?online=true&hd=true&orderBy=MOST_VIEWERS")); - Cam4FollowedTab followed = new Cam4FollowedTab(cam4); + followed = new Cam4FollowedTab(cam4); followed.setRecorder(recorder); tabs.add(followed); return tabs; } + @Override + public Tab getFollowedTab() { + return followed; + } + private Tab createTab(String name, String url) { Cam4UpdateService updateService = new Cam4UpdateService(url, false, cam4); ThumbOverviewTab tab = new ThumbOverviewTab(name, updateService, cam4); diff --git a/src/main/java/ctbrec/sites/camsoda/Camsoda.java b/src/main/java/ctbrec/sites/camsoda/Camsoda.java index c405b336..1ae7f00c 100644 --- a/src/main/java/ctbrec/sites/camsoda/Camsoda.java +++ b/src/main/java/ctbrec/sites/camsoda/Camsoda.java @@ -19,6 +19,7 @@ public class Camsoda extends AbstractSite { public static final String BASE_URI = "https://www.camsoda.com"; private Recorder recorder; private HttpClient httpClient; + private CamsodaTabProvider tabProvider; @Override public String getName() { @@ -47,7 +48,10 @@ public class Camsoda extends AbstractSite { @Override public TabProvider getTabProvider() { - return new CamsodaTabProvider(this, recorder); + if(tabProvider == null) { + tabProvider = new CamsodaTabProvider(this, recorder); + } + return tabProvider; } @Override diff --git a/src/main/java/ctbrec/sites/camsoda/CamsodaTabProvider.java b/src/main/java/ctbrec/sites/camsoda/CamsodaTabProvider.java index 9aa552a7..7ac423a6 100644 --- a/src/main/java/ctbrec/sites/camsoda/CamsodaTabProvider.java +++ b/src/main/java/ctbrec/sites/camsoda/CamsodaTabProvider.java @@ -15,17 +15,18 @@ public class CamsodaTabProvider extends TabProvider { private Camsoda camsoda; private Recorder recorder; + CamsodaFollowedTab followedTab; public CamsodaTabProvider(Camsoda camsoda, Recorder recorder) { this.camsoda = camsoda; this.recorder = recorder; + followedTab = new CamsodaFollowedTab("Followed", camsoda); } @Override public List getTabs(Scene scene) { List tabs = new ArrayList<>(); tabs.add(createTab("Online", BASE_URI + "/api/v1/browse/online")); - CamsodaFollowedTab followedTab = new CamsodaFollowedTab("Followed", camsoda); followedTab.setRecorder(recorder); followedTab.setScene(scene); tabs.add(followedTab); @@ -33,6 +34,11 @@ public class CamsodaTabProvider extends TabProvider { return tabs; } + @Override + public Tab getFollowedTab() { + return followedTab; + } + private Tab createTab(String title, String url) { CamsodaUpdateService updateService = new CamsodaUpdateService(url, false, camsoda); ThumbOverviewTab tab = new ThumbOverviewTab(title, updateService, camsoda); diff --git a/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java b/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java index d06b37b4..4c2dfd13 100644 --- a/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java +++ b/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java @@ -45,6 +45,7 @@ public class Chaturbate extends AbstractSite { public static final String REGISTRATION_LINK = BASE_URI + "/in/?track=default&tour=g4pe&campaign=55vTi"; private Recorder recorder; private ChaturbateHttpClient httpClient; + private ChaturbateTabProvider tabProvider; @Override public void init() throws IOException { @@ -68,7 +69,10 @@ public class Chaturbate extends AbstractSite { @Override public TabProvider getTabProvider() { - return new ChaturbateTabProvider(this, recorder); + if(tabProvider == null) { + tabProvider = new ChaturbateTabProvider(this, recorder); + } + return tabProvider; } @Override diff --git a/src/main/java/ctbrec/sites/chaturbate/ChaturbateTabProvider.java b/src/main/java/ctbrec/sites/chaturbate/ChaturbateTabProvider.java index ccf19691..3d01dd7d 100644 --- a/src/main/java/ctbrec/sites/chaturbate/ChaturbateTabProvider.java +++ b/src/main/java/ctbrec/sites/chaturbate/ChaturbateTabProvider.java @@ -1,5 +1,7 @@ package ctbrec.sites.chaturbate; +import static ctbrec.sites.chaturbate.Chaturbate.*; + import java.util.ArrayList; import java.util.List; @@ -13,28 +15,33 @@ public class ChaturbateTabProvider extends TabProvider { private Chaturbate chaturbate; private Recorder recorder; + private ChaturbateFollowedTab followedTab; public ChaturbateTabProvider(Chaturbate chaturbate, Recorder recorder) { this.chaturbate = chaturbate; this.recorder = recorder; + this.followedTab = new ChaturbateFollowedTab("Followed", BASE_URI + "/followed-cams/", chaturbate); } @Override public List getTabs(Scene scene) { - final String BASE_URI = chaturbate.getBaseUrl(); List tabs = new ArrayList<>(); tabs.add(createTab("Featured", BASE_URI + "/")); tabs.add(createTab("Female", BASE_URI + "/female-cams/")); tabs.add(createTab("Male", BASE_URI + "/male-cams/")); tabs.add(createTab("Couples", BASE_URI + "/couple-cams/")); tabs.add(createTab("Trans", BASE_URI + "/trans-cams/")); - ChaturbateFollowedTab followedTab = new ChaturbateFollowedTab("Followed", BASE_URI + "/followed-cams/", chaturbate); - followedTab.setRecorder(recorder); followedTab.setScene(scene); + followedTab.setRecorder(recorder); tabs.add(followedTab); return tabs; } + @Override + public Tab getFollowedTab() { + return followedTab; + } + private Tab createTab(String title, String url) { ChaturbateUpdateService updateService = new ChaturbateUpdateService(url, false, chaturbate); ThumbOverviewTab tab = new ThumbOverviewTab(title, updateService, chaturbate); diff --git a/src/main/java/ctbrec/sites/mfc/MyFreeCams.java b/src/main/java/ctbrec/sites/mfc/MyFreeCams.java index 1d857810..3c9cc2d4 100644 --- a/src/main/java/ctbrec/sites/mfc/MyFreeCams.java +++ b/src/main/java/ctbrec/sites/mfc/MyFreeCams.java @@ -21,6 +21,7 @@ public class MyFreeCams extends AbstractSite { private Recorder recorder; private MyFreeCamsClient client; private MyFreeCamsHttpClient httpClient; + private MyFreeCamsTabProvider tabProvider; @Override public void init() throws IOException { @@ -56,7 +57,10 @@ public class MyFreeCams extends AbstractSite { @Override public TabProvider getTabProvider() { - return new MyFreeCamsTabProvider(client, recorder, this); + if(tabProvider == null) { + tabProvider = new MyFreeCamsTabProvider(client, recorder, this); + } + return tabProvider; } @Override diff --git a/src/main/java/ctbrec/sites/mfc/MyFreeCamsTabProvider.java b/src/main/java/ctbrec/sites/mfc/MyFreeCamsTabProvider.java index da2310c7..5035c28d 100644 --- a/src/main/java/ctbrec/sites/mfc/MyFreeCamsTabProvider.java +++ b/src/main/java/ctbrec/sites/mfc/MyFreeCamsTabProvider.java @@ -15,6 +15,7 @@ import javafx.util.Duration; public class MyFreeCamsTabProvider extends TabProvider { private Recorder recorder; private MyFreeCams myFreeCams; + private MyFreeCamsFriendsTab friends; public MyFreeCamsTabProvider(MyFreeCamsClient client, Recorder recorder, MyFreeCams myFreeCams) { this.recorder = recorder; @@ -31,7 +32,7 @@ public class MyFreeCamsTabProvider extends TabProvider { updateService.setPeriod(new Duration(TimeUnit.SECONDS.toMillis(10))); tabs.add(online); - ThumbOverviewTab friends = new MyFreeCamsFriendsTab(myFreeCams); + friends = new MyFreeCamsFriendsTab(myFreeCams); friends.setRecorder(recorder); tabs.add(friends); @@ -50,4 +51,9 @@ public class MyFreeCamsTabProvider extends TabProvider { return tabs; } + + @Override + public Tab getFollowedTab() { + return friends; + } } diff --git a/src/main/java/ctbrec/ui/TabProvider.java b/src/main/java/ctbrec/ui/TabProvider.java index 2f760081..d755590f 100644 --- a/src/main/java/ctbrec/ui/TabProvider.java +++ b/src/main/java/ctbrec/ui/TabProvider.java @@ -8,4 +8,5 @@ import javafx.scene.control.Tab; public abstract class TabProvider { public abstract List getTabs(Scene scene); + public abstract Tab getFollowedTab(); } diff --git a/src/main/java/ctbrec/ui/ThumbCell.java b/src/main/java/ctbrec/ui/ThumbCell.java index 1865844b..1a58e37d 100644 --- a/src/main/java/ctbrec/ui/ThumbCell.java +++ b/src/main/java/ctbrec/ui/ThumbCell.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.function.Function; @@ -282,6 +283,10 @@ public class ThumbCell extends StackPane { } } + Image getImage() { + return iv.getImage(); + } + private Transition changeColor(Shape shape, Color from, Color to) { FillTransition transition = new FillTransition(ANIMATION_DURATION, from, to); transition.setShape(shape); @@ -417,13 +422,15 @@ public class ThumbCell extends StackPane { }).start(); } - void follow(boolean follow) { + CompletableFuture follow(boolean follow) { setCursor(Cursor.WAIT); - new Thread(() -> { + return CompletableFuture.supplyAsync(() -> { try { if(follow) { boolean followed = model.follow(); - if(!followed) { + if(followed) { + return true; + } else { Platform.runLater(() -> { Alert alert = new AutosizeAlert(Alert.AlertType.ERROR); alert.setTitle("Error"); @@ -431,11 +438,13 @@ public class ThumbCell extends StackPane { alert.setContentText(""); alert.showAndWait(); }); + return false; } } else { boolean unfollowed = model.unfollow(); if(unfollowed) { Platform.runLater(() -> thumbCellList.remove(ThumbCell.this)); + return true; } else { Platform.runLater(() -> { Alert alert = new AutosizeAlert(Alert.AlertType.ERROR); @@ -444,6 +453,7 @@ public class ThumbCell extends StackPane { alert.setContentText(""); alert.showAndWait(); }); + return false; } } } catch (Exception e1) { @@ -455,10 +465,11 @@ public class ThumbCell extends StackPane { alert.setContentText("I/O error while following/unfollowing model " + model.getName() + ": " + e1.getLocalizedMessage()); alert.showAndWait(); }); + return false; } finally { setCursor(Cursor.DEFAULT); } - }).start(); + }); } public Model getModel() { diff --git a/src/main/java/ctbrec/ui/ThumbOverviewTab.java b/src/main/java/ctbrec/ui/ThumbOverviewTab.java index b7e8a7f2..752c555b 100644 --- a/src/main/java/ctbrec/ui/ThumbOverviewTab.java +++ b/src/main/java/ctbrec/ui/ThumbOverviewTab.java @@ -32,12 +32,20 @@ import ctbrec.recorder.Recorder; import ctbrec.sites.Site; import ctbrec.sites.mfc.MyFreeCamsClient; import ctbrec.sites.mfc.MyFreeCamsModel; +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.collections.ObservableList; import javafx.concurrent.Worker.State; import javafx.concurrent.WorkerStateEvent; import javafx.event.EventHandler; import javafx.geometry.Insets; +import javafx.geometry.Pos; import javafx.scene.Node; +import javafx.scene.Parent; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.ComboBox; @@ -46,8 +54,10 @@ import javafx.scene.control.Label; import javafx.scene.control.MenuItem; import javafx.scene.control.ScrollPane; 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.Clipboard; import javafx.scene.input.ClipboardContent; import javafx.scene.input.ContextMenuEvent; @@ -56,6 +66,8 @@ import javafx.scene.input.MouseEvent; import javafx.scene.layout.BorderPane; import javafx.scene.layout.FlowPane; import javafx.scene.layout.HBox; +import javafx.scene.layout.StackPane; +import javafx.scene.transform.Transform; import javafx.util.Duration; public class ThumbOverviewTab extends Tab implements TabSelectionListener { @@ -82,6 +94,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { private volatile boolean updatesSuspended = false; ContextMenu popup; Site site; + StackPane root = new StackPane(); private ComboBox thumbWidth; @@ -170,11 +183,13 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { bottomPane.setLeft(pagination); bottomPane.setRight(thumbSizeSelector); - BorderPane root = new BorderPane(); - root.setPadding(new Insets(5)); - root.setTop(search); - root.setCenter(scrollPane); - root.setBottom(bottomPane); + BorderPane borderPane = new BorderPane(); + borderPane.setPadding(new Insets(5)); + borderPane.setTop(search); + borderPane.setCenter(scrollPane); + borderPane.setBottom(bottomPane); + + root.getChildren().add(borderPane); setContent(root); } @@ -427,13 +442,66 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { protected void follow(List selection, boolean follow) { for (ThumbCell thumbCell : selection) { - thumbCell.follow(follow); + thumbCell.follow(follow).thenAccept((success) -> { + if(follow && success) { + showAddToFollowedAnimation(thumbCell); + } + }); } if(!follow) { selectedThumbCells.clear(); } } + private void showAddToFollowedAnimation(ThumbCell thumbCell) { + Platform.runLater(() -> { + Transform tx = thumbCell.getLocalToParentTransform(); + ImageView iv = new ImageView(); + iv.setFitWidth(thumbCell.getWidth()); + root.getChildren().add(iv); + StackPane.setAlignment(iv, Pos.TOP_LEFT); + iv.setImage(thumbCell.getImage()); + double scrollPaneTopLeft = scrollPane.getVvalue() * (grid.getHeight() - scrollPane.getViewportBounds().getHeight()); + double offsetInViewPort = tx.getTy() - scrollPaneTopLeft; + int duration = 500; + TranslateTransition translate = new TranslateTransition(Duration.millis(duration), iv); + translate.setFromX(0); + translate.setFromY(0); + translate.setByX(-tx.getTx() - 200); + translate.setByY(-offsetInViewPort + getFollowedTabYPosition()); + StackPane.setMargin(iv, new Insets(offsetInViewPort, 0, 0, tx.getTx())); + translate.setInterpolator(Interpolator.EASE_BOTH); + FadeTransition fade = new FadeTransition(Duration.millis(duration), iv); + fade.setFromValue(1); + fade.setToValue(.3); + ScaleTransition scale = new ScaleTransition(Duration.millis(duration), iv); + scale.setToX(0.1); + scale.setToY(0.1); + ParallelTransition pt = new ParallelTransition(translate, scale); + pt.play(); + pt.setOnFinished((evt) -> { + root.getChildren().remove(iv); + }); + }); + } + + private double getFollowedTabYPosition() { + Tab followedTab = site.getTabProvider().getFollowedTab(); + TabPane tabPane = getTabPane(); + int idx = tabPane.getTabs().indexOf(followedTab); + for (Node node : tabPane.getChildrenUnmodifiable()) { + Parent p = (Parent) node; + for (Node child : p.getChildrenUnmodifiable()) { + if(child.getStyleClass().contains("headers-region")) { + Parent tabContainer = (Parent) child; + Node tab = tabContainer.getChildrenUnmodifiable().get(tabContainer.getChildrenUnmodifiable().size() - idx - 1); + return tab.getLayoutX() - 85; + } + } + } + return 0; + } + private void startStopAction(List selection, boolean start) { for (ThumbCell thumbCell : selection) { thumbCell.startStopAction(start);