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