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:
0xboobface 2018-11-13 01:01:49 +01:00
parent 705b04b0da
commit 378d3954b0
13 changed files with 154 additions and 23 deletions

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;
}
}

View File

@ -8,4 +8,5 @@ import javafx.scene.control.Tab;
public abstract class TabProvider {
public abstract List<Tab> getTabs(Scene scene);
public abstract Tab getFollowedTab();
}

View File

@ -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() {

View File

@ -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);