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.
This commit is contained in:
parent
705b04b0da
commit
378d3954b0
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<Tab> getTabs(Scene scene) {
|
||||
List<Tab> 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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<Tab> getTabs(Scene scene) {
|
||||
final String BASE_URI = chaturbate.getBaseUrl();
|
||||
List<Tab> 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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,4 +8,5 @@ import javafx.scene.control.Tab;
|
|||
public abstract class TabProvider {
|
||||
|
||||
public abstract List<Tab> getTabs(Scene scene);
|
||||
public abstract Tab getFollowedTab();
|
||||
}
|
||||
|
|
|
@ -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<Boolean> 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() {
|
||||
|
|
|
@ -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<Integer> 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<ThumbCell> 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<ThumbCell> selection, boolean start) {
|
||||
for (ThumbCell thumbCell : selection) {
|
||||
thumbCell.startStopAction(start);
|
||||
|
|
Loading…
Reference in New Issue