Prechádzať zdrojové kódy

Added animation to unlock dialog

Sebastian Stenzel 5 rokov pred
rodič
commit
357d63f398

+ 1 - 0
main/ui/src/main/java/org/cryptomator/ui/mainwindow/WelcomeController.java

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

+ 72 - 0
main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java

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

+ 1 - 1
main/ui/src/main/resources/fxml/addvault_welcome.fxml

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

+ 1 - 1
main/ui/src/main/resources/fxml/preferences_about.fxml

@@ -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}"/>

+ 32 - 5
main/ui/src/main/resources/fxml/unlock.fxml

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

+ 1 - 1
main/ui/src/main/resources/fxml/vault_detail_welcome.fxml

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


BIN
main/ui/src/main/resources/img/bot/arm-l@2x.png


BIN
main/ui/src/main/resources/img/bot/arm-r.png


BIN
main/ui/src/main/resources/img/bot/arm-r@2x.png


BIN
main/ui/src/main/resources/img/bot/body.png


BIN
main/ui/src/main/resources/img/bot/body@2x.png


main/ui/src/main/resources/img/bot.png → main/ui/src/main/resources/img/bot/bot.png


main/ui/src/main/resources/img/bot@2x.png → main/ui/src/main/resources/img/bot/bot@2x.png


BIN
main/ui/src/main/resources/img/bot/face.png


BIN
main/ui/src/main/resources/img/bot/face@2x.png


BIN
main/ui/src/main/resources/img/bot/legs.png


BIN
main/ui/src/main/resources/img/bot/legs@2x.png