Added animation to unlock dialog

This commit is contained in:
Sebastian Stenzel
2020-05-14 09:03:13 +02:00
parent e594bf208d
commit 357d63f398
18 changed files with 108 additions and 8 deletions

View File

@@ -42,4 +42,5 @@ public class WelcomeController implements FxController {
public boolean isNoVaultPresent() {
return noVaultPresent.get();
}
}

View File

@@ -1,5 +1,10 @@
package org.cryptomator.ui.unlock;
import javafx.animation.Animation;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.ObjectBinding;
@@ -9,7 +14,11 @@ import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.image.ImageView;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import javafx.util.Duration;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.ui.common.FxController;
@@ -42,8 +51,15 @@ public class UnlockController implements FxController {
private final ObjectBinding<ContentDisplay> unlockButtonContentDisplay;
private final BooleanBinding userInteractionDisabled;
private final BooleanProperty unlockButtonDisabled;
public NiceSecurePasswordField passwordField;
public CheckBox savePasswordCheckbox;
public ImageView face;
public ImageView leftArm;
public ImageView rightArm;
public ImageView legs;
public ImageView body;
public Animation unlockAnimation;
@Inject
public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, AtomicReference<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<UnlockModule.PasswordEntry> passwordEntryLock, ForgetPasswordComponent.Builder forgetPassword, Optional<KeychainManager> keychain) {
@@ -60,12 +76,51 @@ public class UnlockController implements FxController {
this.unlockButtonDisabled = new SimpleBooleanProperty();
}
@FXML
public void initialize() {
savePasswordCheckbox.setSelected(savedPassword.isPresent());
if (password.get() != null) {
passwordField.setPassword(password.get());
}
unlockButtonDisabled.bind(userInteractionDisabled.or(passwordField.textProperty().isEmpty()));
var leftArmTranslation = new Translate(24, 0);
var leftArmRotation = new Rotate(60, 16, 30, 0);
var leftArmRetracted = new KeyValue(leftArmTranslation.xProperty(), 24);
var leftArmExtended = new KeyValue(leftArmTranslation.xProperty(), 0.0);
var leftArmHorizontal = new KeyValue(leftArmRotation.angleProperty(), 60, Interpolator.EASE_OUT);
var leftArmHanging = new KeyValue(leftArmRotation.angleProperty(), 0);
leftArm.getTransforms().setAll(leftArmTranslation, leftArmRotation);
var rightArmTranslation = new Translate(-24, 0);
var rightArmRotation = new Rotate(60, 48, 30, 0);
var rightArmRetracted = new KeyValue(rightArmTranslation.xProperty(), -24);
var rightArmExtended = new KeyValue(rightArmTranslation.xProperty(), 0.0);
var rightArmHorizontal = new KeyValue(rightArmRotation.angleProperty(), -60);
var rightArmHanging = new KeyValue(rightArmRotation.angleProperty(), 0, Interpolator.EASE_OUT);
rightArm.getTransforms().setAll(rightArmTranslation, rightArmRotation);
var legsRetractedY = new KeyValue(legs.scaleYProperty(), 0);
var legsExtendedY = new KeyValue(legs.scaleYProperty(), 1, Interpolator.EASE_OUT);
var legsRetractedX = new KeyValue(legs.scaleXProperty(), 0);
var legsExtendedX = new KeyValue(legs.scaleXProperty(), 1, Interpolator.EASE_OUT);
legs.setScaleY(0);
legs.setScaleX(0);
var faceHidden = new KeyValue(face.opacityProperty(), 0.0);
var faceVisible = new KeyValue(face.opacityProperty(), 1.0, Interpolator.LINEAR);
face.setOpacity(0);
unlockAnimation = new Timeline(
new KeyFrame(Duration.ZERO, leftArmRetracted, leftArmHorizontal, rightArmRetracted, rightArmHorizontal, legsRetractedY, legsRetractedX, faceHidden),
new KeyFrame(Duration.millis(200), leftArmExtended, leftArmHorizontal, rightArmRetracted, rightArmHorizontal),
new KeyFrame(Duration.millis(400), leftArmExtended, leftArmHanging, rightArmExtended, rightArmHorizontal),
new KeyFrame(Duration.millis(600), leftArmExtended, leftArmHanging, rightArmExtended, rightArmHanging),
new KeyFrame(Duration.millis(800), legsExtendedY, legsExtendedX, faceHidden),
new KeyFrame(Duration.millis(1000), faceVisible)
);
passwordEntryLock.awaitingInteraction().addListener(observable -> stopUnlockAnimation());
}
@FXML
@@ -88,6 +143,23 @@ public class UnlockController implements FxController {
Arrays.fill(oldPw, ' ');
}
passwordEntryLock.interacted(UnlockModule.PasswordEntry.PASSWORD_ENTERED);
startUnlockAnimation();
}
private void startUnlockAnimation() {
leftArm.setVisible(true);
rightArm.setVisible(true);
legs.setVisible(true);
face.setVisible(true);
unlockAnimation.playFromStart();
}
private void stopUnlockAnimation() {
unlockAnimation.stop();
leftArm.setVisible(false);
rightArm.setVisible(false);
legs.setVisible(false);
face.setVisible(false);
}
/* Save Password */

View File

@@ -21,7 +21,7 @@
<Region VBox.vgrow="ALWAYS"/>
<ImageView VBox.vgrow="ALWAYS" fitHeight="128" preserveRatio="true" smooth="true" cache="true">
<Image url="/img/bot.png"/>
<Image url="/img/bot/bot.png"/>
</ImageView>
<Region VBox.vgrow="ALWAYS"/>

View File

@@ -18,7 +18,7 @@
<children>
<HBox spacing="12" VBox.vgrow="NEVER">
<ImageView VBox.vgrow="ALWAYS" fitHeight="64" preserveRatio="true" smooth="true" cache="true">
<Image url="/img/bot.png"/>
<Image url="/img/bot/bot.png"/>
</ImageView>
<VBox spacing="3" HBox.hgrow="ALWAYS" alignment="CENTER_LEFT">
<FormattedLabel styleClass="label-large" format="Cryptomator %s" arg1="${controller.applicationVersion}"/>

View File

@@ -5,6 +5,10 @@
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.ProgressIndicator?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import org.cryptomator.ui.controls.FormattedLabel?>
<?import org.cryptomator.ui.controls.NiceSecurePasswordField?>
@@ -19,11 +23,34 @@
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<VBox spacing="6">
<FormattedLabel format="%unlock.passwordPrompt" arg1="${controller.vault.displayableName}" wrapText="true"/>
<NiceSecurePasswordField fx:id="passwordField" disable="${controller.userInteractionDisabled}"/>
<CheckBox fx:id="savePasswordCheckbox" text="%unlock.savePassword" onAction="#didClickSavePasswordCheckbox" disable="${controller.userInteractionDisabled}" visible="${controller.keychainAccessAvailable}"/>
</VBox>
<HBox spacing="12" VBox.vgrow="ALWAYS">
<StackPane alignment="CENTER" HBox.hgrow="NEVER">
<ImageView VBox.vgrow="ALWAYS" fitWidth="64" preserveRatio="true" smooth="true" cache="true" fx:id="face" visible="false">
<Image url="/img/bot/face.png"/>
</ImageView>
<ImageView VBox.vgrow="ALWAYS" fitWidth="64" preserveRatio="true" smooth="true" cache="true" fx:id="leftArm" visible="false">
<Image url="/img/bot/arm-l.png"/>
</ImageView>
<ImageView VBox.vgrow="ALWAYS" fitWidth="64" preserveRatio="true" smooth="true" cache="true" fx:id="rightArm" visible="false">
<Image url="/img/bot/arm-r.png"/>
</ImageView>
<ImageView VBox.vgrow="ALWAYS" fitWidth="64" preserveRatio="true" smooth="true" cache="true" fx:id="legs" visible="false">
<Image url="/img/bot/legs.png"/>
</ImageView>
<ImageView VBox.vgrow="ALWAYS" fitWidth="64" preserveRatio="true" smooth="true" cache="true" fx:id="body">
<Image url="/img/bot/body.png"/>
</ImageView>
</StackPane>
<VBox spacing="6" HBox.hgrow="ALWAYS">
<FormattedLabel format="%unlock.passwordPrompt" arg1="${controller.vault.displayableName}" wrapText="true"/>
<NiceSecurePasswordField fx:id="passwordField" disable="${controller.userInteractionDisabled}"/>
<CheckBox fx:id="savePasswordCheckbox" text="%unlock.savePassword" onAction="#didClickSavePasswordCheckbox" disable="${controller.userInteractionDisabled}" visible="${controller.keychainAccessAvailable}"/>
</VBox>
</HBox>
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">

View File

@@ -11,8 +11,8 @@
spacing="24">
<children>
<ImageView VBox.vgrow="ALWAYS" fitHeight="128" preserveRatio="true" smooth="true" cache="true">
<Image url="/img/bot/bot.png"/>
</ImageView>
<Image url="/img/bot.png"/>
<TextFlow styleClass="text-flow" prefWidth="-Infinity" visible="${controller.noVaultPresent}" managed="${controller.noVaultPresent}">
<Text text="%main.vaultDetail.welcomeOnboarding"/>

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB