Added animation to unlock dialog
@@ -42,4 +42,5 @@ public class WelcomeController implements FxController {
|
||||
public boolean isNoVaultPresent() {
|
||||
return noVaultPresent.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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}"/>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
BIN
main/ui/src/main/resources/img/bot/arm-l.png
Normal file
|
After Width: | Height: | Size: 568 B |
BIN
main/ui/src/main/resources/img/bot/arm-l@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
main/ui/src/main/resources/img/bot/arm-r.png
Normal file
|
After Width: | Height: | Size: 572 B |
BIN
main/ui/src/main/resources/img/bot/arm-r@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
main/ui/src/main/resources/img/bot/body.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
main/ui/src/main/resources/img/bot/body@2x.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
BIN
main/ui/src/main/resources/img/bot/face.png
Normal file
|
After Width: | Height: | Size: 508 B |
BIN
main/ui/src/main/resources/img/bot/face@2x.png
Normal file
|
After Width: | Height: | Size: 937 B |
BIN
main/ui/src/main/resources/img/bot/legs.png
Normal file
|
After Width: | Height: | Size: 648 B |
BIN
main/ui/src/main/resources/img/bot/legs@2x.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |