From cd4cb7089656455f70a659e9dc4826096e16a869 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Fri, 27 Sep 2019 21:44:24 +0200 Subject: [PATCH] show progress during vault migration (ugly prototype) --- .../ui/migration/MigrationRunController.java | 68 ++++++++++++++++++- .../main/resources/fxml/migration_run.fxml | 3 + .../fxml/vault_detail_needsmigration.fxml | 5 +- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java index b7e0d6eaa..181876d2f 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java @@ -7,8 +7,13 @@ import javafx.animation.Timeline; import javafx.beans.binding.Bindings; import javafx.beans.binding.ObjectBinding; import javafx.beans.property.BooleanProperty; +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.value.WritableValue; +import javafx.concurrent.ScheduledService; +import javafx.concurrent.Task; import javafx.fxml.FXML; import javafx.scene.Scene; import javafx.scene.control.ContentDisplay; @@ -17,6 +22,7 @@ import javafx.util.Duration; import org.cryptomator.common.vaults.Vault; import org.cryptomator.common.vaults.VaultState; import org.cryptomator.cryptofs.migration.Migrators; +import org.cryptomator.cryptofs.migration.api.MigrationProgressListener; import org.cryptomator.cryptofs.migration.api.NoApplicableMigratorException; import org.cryptomator.cryptolib.api.InvalidPassphraseException; import org.cryptomator.keychain.KeychainAccess; @@ -39,6 +45,7 @@ public class MigrationRunController implements FxController { private static final Logger LOG = LoggerFactory.getLogger(MigrationRunController.class); private static final String MASTERKEY_FILENAME = "masterkey.cryptomator"; // TODO: deduplicate constant declared in multiple classes + private static final Duration MIGRATION_PROGRESS_UPDATE_INTERVAL = Duration.millis(25); private final Stage window; private final Vault vault; @@ -48,6 +55,9 @@ public class MigrationRunController implements FxController { private final Lazy successScene; private final ObjectBinding migrateButtonContentDisplay; private final BooleanProperty migrationButtonDisabled; + private final DoubleProperty migrationProgress; + private final ScheduledService migrationProgressObservationService; + private volatile double volatileMigrationProgress = -1.0; public NiceSecurePasswordField passwordField; @Inject @@ -60,6 +70,10 @@ public class MigrationRunController implements FxController { this.successScene = successScene; this.migrateButtonContentDisplay = Bindings.createObjectBinding(this::getMigrateButtonContentDisplay, vault.stateProperty()); this.migrationButtonDisabled = new SimpleBooleanProperty(); + this.migrationProgress = new SimpleDoubleProperty(volatileMigrationProgress); + this.migrationProgressObservationService = new MigrationProgressObservationService(); + migrationProgressObservationService.setExecutor(executor); + migrationProgressObservationService.setPeriod(MIGRATION_PROGRESS_UPDATE_INTERVAL); } public void initialize() { @@ -79,17 +93,18 @@ public class MigrationRunController implements FxController { LOG.info("Migrating vault {}", vault.getPath()); CharSequence password = passwordField.getCharacters(); vault.setState(VaultState.PROCESSING); + migrationProgressObservationService.start(); Tasks.create(() -> { Migrators migrators = Migrators.get(); - migrators.migrate(vault.getPath(), MASTERKEY_FILENAME, password); + migrators.migrate(vault.getPath(), MASTERKEY_FILENAME, password, this::migrationProgressChanged); return migrators.needsMigration(vault.getPath(), MASTERKEY_FILENAME); }).onSuccess(needsAnotherMigration -> { + LOG.info("Migration of '{}' succeeded.", vault.getDisplayableName()); if (needsAnotherMigration) { vault.setState(VaultState.NEEDS_MIGRATION); } else { vault.setState(VaultState.LOCKED); passwordField.swipe(); - LOG.info("Migration of '{}' succeeded.", vault.getDisplayableName()); window.setScene(successScene.get()); } }).onError(InvalidPassphraseException.class, e -> { @@ -105,9 +120,29 @@ public class MigrationRunController implements FxController { LOG.error("Migration failed for technical reasons.", e); vault.setState(VaultState.ERROR); // TODO show generic error screen + }).andFinally(() -> { + migrationProgressObservationService.cancel(); + migrationProgressObservationService.reset(); }).runOnce(executor); } + // Called by a background task. We can not directly modify observable properties from here + private void migrationProgressChanged(MigrationProgressListener.ProgressState state, double progress) { + switch (state) { + case INITIALIZING: + volatileMigrationProgress = -1.0; + break; + case MIGRATING: + volatileMigrationProgress = progress; + break; + case FINALIZING: + volatileMigrationProgress = 1.0; + break; + default: + throw new IllegalStateException("Unexpted state " + state); + } + } + private void loadStoredPassword() { assert keychainAccess.isPresent(); char[] storedPw = null; @@ -126,6 +161,27 @@ public class MigrationRunController implements FxController { } } + // Sets migrationProgress to volatileMigrationProgress at its configured interval + private class MigrationProgressObservationService extends ScheduledService { + + @Override + protected Task createTask() { + return new Task<>() { + @Override + protected Double call() { + return volatileMigrationProgress; + } + }; + } + + @Override + protected void succeeded() { + assert getValue() != null; + migrationProgress.set(getValue()); + super.succeeded(); + } + } + /* Animations */ private void shakeWindow() { @@ -180,4 +236,12 @@ public class MigrationRunController implements FxController { } } + public ReadOnlyDoubleProperty migrationProgressProperty() { + return migrationProgress; + } + + public double getMigrationProgress() { + return migrationProgress.get(); + } + } diff --git a/main/ui/src/main/resources/fxml/migration_run.fxml b/main/ui/src/main/resources/fxml/migration_run.fxml index 16cf87611..a932b449f 100644 --- a/main/ui/src/main/resources/fxml/migration_run.fxml +++ b/main/ui/src/main/resources/fxml/migration_run.fxml @@ -23,6 +23,9 @@ + + + diff --git a/main/ui/src/main/resources/fxml/vault_detail_needsmigration.fxml b/main/ui/src/main/resources/fxml/vault_detail_needsmigration.fxml index b0a78f5c8..1c5e9721f 100644 --- a/main/ui/src/main/resources/fxml/vault_detail_needsmigration.fxml +++ b/main/ui/src/main/resources/fxml/vault_detail_needsmigration.fxml @@ -2,7 +2,6 @@ - - -