Hook up migration window

This commit is contained in:
Sebastian Stenzel
2019-09-06 15:26:01 +02:00
parent cb4717b770
commit f35f04851e
12 changed files with 259 additions and 4 deletions

View File

@@ -68,6 +68,7 @@ public class Vault {
private final BooleanBinding locked;
private final BooleanBinding processing;
private final BooleanBinding unlocked;
private final BooleanBinding needsMigration;
private final ObjectBinding<Path> accessPoint;
private volatile Volume volume;
@@ -85,6 +86,7 @@ public class Vault {
this.locked = Bindings.createBooleanBinding(this::isLocked, state);
this.processing = Bindings.createBooleanBinding(this::isProcessing, state);
this.unlocked = Bindings.createBooleanBinding(this::isUnlocked, state);
this.needsMigration = Bindings.createBooleanBinding(this::isNeedsMigration, state);
this.accessPoint = Bindings.createObjectBinding(this::getAccessPoint, state);
}
@@ -215,6 +217,14 @@ public class Vault {
public boolean isUnlocked() {
return state.get() == VaultState.UNLOCKED;
}
public BooleanBinding needsMigrationProperty() {
return needsMigration;
}
public boolean isNeedsMigration() {
return state.get() == VaultState.NEEDS_MIGRATION;
}
public StringBinding displayableNameProperty() {
return displayableName;

View File

@@ -9,6 +9,7 @@ public enum FxmlFile {
ADDVAULT_SUCCESS("/fxml/addvault_success.fxml"), //
CHANGEPASSWORD("/fxml/changepassword.fxml"), //
MAIN_WINDOW("/fxml/main_window.fxml"), //
MIGRATION_START("/fxml/migration_start.fxml"), //
PREFERENCES("/fxml/preferences.fxml"), //
QUIT("/fxml/quit.fxml"), //
REMOVE_VAULT("/fxml/remove_vault.fxml"), //

View File

@@ -12,6 +12,7 @@ public enum FontAwesome5Icon {
EXCLAMATION_TRIANGLE("\uF071"), //
EYE("\uF06E"), //
EYE_SLASH("\uF070"), //
FILE_IMPORT("\uF56F"), //
FOLDER_OPEN("\uF07C"), //
HDD("\uF0A0"), //
KEY("\uF084"), //

View File

@@ -17,6 +17,7 @@ import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.migration.MigrationComponent;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
import org.cryptomator.ui.wrongfilealert.WrongFileAlertComponent;
@@ -27,7 +28,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.ResourceBundle;
@Module(subcomponents = {AddVaultWizardComponent.class, RemoveVaultComponent.class, VaultOptionsComponent.class, WrongFileAlertComponent.class})
@Module(subcomponents = {AddVaultWizardComponent.class, MigrationComponent.class, RemoveVaultComponent.class, VaultOptionsComponent.class, WrongFileAlertComponent.class})
abstract class MainWindowModule {
@Provides

View File

@@ -13,6 +13,7 @@ import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.Tasks;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import org.cryptomator.ui.fxapp.FxApplication;
import org.cryptomator.ui.migration.MigrationComponent;
import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
import org.fxmisc.easybind.EasyBind;
import org.slf4j.Logger;
@@ -32,15 +33,17 @@ public class VaultDetailController implements FxController {
private final ExecutorService executor;
private final FxApplication application;
private final VaultOptionsComponent.Builder vaultOptionsWindow;
private final MigrationComponent.Builder vaultMigrationWindow;
@Inject
VaultDetailController(ObjectProperty<Vault> vault, ExecutorService executor, FxApplication application, VaultOptionsComponent.Builder vaultOptionsWindow) {
VaultDetailController(ObjectProperty<Vault> vault, ExecutorService executor, FxApplication application, VaultOptionsComponent.Builder vaultOptionsWindow, MigrationComponent.Builder vaultMigrationWindow) {
this.vault = vault;
this.glyph = EasyBind.select(vault).selectObject(Vault::stateProperty).map(this::getGlyphForVaultState).orElse(FontAwesome5Icon.EXCLAMATION_TRIANGLE);
this.executor = executor;
this.application = application;
this.vaultOptionsWindow = vaultOptionsWindow;
this.anyVaultSelected = vault.isNotNull();
this.vaultMigrationWindow = vaultMigrationWindow;
}
private FontAwesome5Icon getGlyphForVaultState(VaultState state) {
@@ -83,12 +86,17 @@ public class VaultDetailController implements FxController {
}
@FXML
public void revealStorageLocation(ActionEvent actionEvent) {
public void showVaultMigrator() {
vaultMigrationWindow.vault(vault.get()).build().showMigrationWindow();
}
@FXML
public void revealStorageLocation() {
application.getHostServices().showDocument(vault.get().getPath().toUri().toString());
}
@FXML
public void revealAccessLocation(ActionEvent actionEvent) {
public void revealAccessLocation() {
try {
vault.get().reveal();
} catch (Volume.VolumeException e) {

View File

@@ -0,0 +1,38 @@
package org.cryptomator.ui.migration;
import dagger.BindsInstance;
import dagger.Lazy;
import dagger.Subcomponent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
@MigrationScoped
@Subcomponent(modules = {MigrationModule.class})
public interface MigrationComponent {
@MigrationWindow
Stage window();
@FxmlScene(FxmlFile.MIGRATION_START)
Lazy<Scene> scene();
default Stage showMigrationWindow() {
Stage stage = window();
stage.setScene(scene().get());
stage.show();
return stage;
}
@Subcomponent.Builder
interface Builder {
@BindsInstance
Builder vault(@MigrationWindow Vault vault);
MigrationComponent build();
}
}

View File

@@ -0,0 +1,71 @@
package org.cryptomator.ui.migration;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.cryptomator.ui.common.FXMLLoaderFactory;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.mainwindow.MainWindow;
import javax.inject.Named;
import javax.inject.Provider;
import java.util.Map;
import java.util.Optional;
import java.util.ResourceBundle;
@Module
abstract class MigrationModule {
@Provides
@MigrationWindow
@MigrationScoped
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, ResourceBundle resourceBundle) {
return new FXMLLoaderFactory(factories, resourceBundle);
}
@Provides
@MigrationWindow
@MigrationScoped
static Stage provideStage(@MainWindow Stage owner, ResourceBundle resourceBundle, @Named("windowIcon") Optional<Image> windowIcon) {
Stage stage = new Stage();
stage.setTitle(resourceBundle.getString("unlock.title"));
stage.setResizable(false);
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(owner);
windowIcon.ifPresent(stage.getIcons()::add);
return stage;
}
@Provides
@FxmlScene(FxmlFile.MIGRATION_START)
@MigrationScoped
static Scene provideMigrationStartScene(@MigrationWindow FXMLLoaderFactory fxmlLoaders, @MigrationWindow Stage window) {
Scene scene = fxmlLoaders.createScene("/fxml/migration_start.fxml"); // TODO rename fxml file
KeyCombination cmdW = new KeyCodeCombination(KeyCode.W, KeyCombination.SHORTCUT_DOWN);
scene.getAccelerators().put(cmdW, window::close);
return scene;
}
// ------------------
@Binds
@IntoMap
@FxControllerKey(MigrationStartController.class)
abstract FxController bindMigrationStartController(MigrationStartController controller);
}

View File

@@ -0,0 +1,13 @@
package org.cryptomator.ui.migration;
import javax.inject.Scope;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
@interface MigrationScoped {
}

View File

@@ -0,0 +1,46 @@
package org.cryptomator.ui.migration;
import dagger.Lazy;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import javax.inject.Inject;
@MigrationScoped
public class MigrationStartController implements FxController {
private final Stage window;
private final Vault vault;
private final Lazy<Scene> successScene;
@Inject
public MigrationStartController(@MigrationWindow Stage window, @MigrationWindow Vault vault, @FxmlScene(FxmlFile.MIGRATION_START) Lazy<Scene> successScene) {
this.window = window;
this.vault = vault;
this.successScene = successScene;
}
public void initialize() {
}
@FXML
public void cancel() {
window.close();
}
@FXML
public void proceed() {
}
/* Getter/Setter */
public Vault getVault() {
return vault;
}
}

View File

@@ -0,0 +1,14 @@
package org.cryptomator.ui.migration;
import javax.inject.Qualifier;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface MigrationWindow {
}

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import org.cryptomator.ui.controls.FormattedLabel?>
<VBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.cryptomator.ui.migration.MigrationStartController"
minWidth="400"
maxWidth="400"
minHeight="145"
spacing="12">
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<HBox spacing="12" alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
<StackPane alignment="CENTER" HBox.hgrow="NEVER">
<Circle styleClass="glyph-icon-primary" radius="24"/>
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="FILE_IMPORT" glyphSize="24"/>
</StackPane>
<VBox spacing="6" HBox.hgrow="ALWAYS">
<FormattedLabel format="TODO Your vault &quot;%s&quot; needs to be updated to a newer format. Before proceeding, make sure there is no pending synchronization affecting this vault." arg1="${controller.vault.displayableName}" wrapText="true" />
<CheckBox fx:id="confirmSyncDone" text="TODO Yes, my vault is fully synced"/>
</VBox>
</HBox>
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
<ButtonBar buttonMinWidth="120" buttonOrder="+CX">
<buttons>
<Button text="%generic.button.done" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#cancel"/>
<Button text="%generic.button.next" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#proceed" disable="${!confirmSyncDone.selected}"/>
</buttons>
</ButtonBar>
</VBox>
</children>
</VBox>

View File

@@ -87,6 +87,13 @@
</Button>
</VBox>
<!-- TODO we might want to split this fxml file into one file per vault state -->
<Button styleClass="button-large" text="TODO Upgrade Vault" minWidth="120" onAction="#showVaultMigrator" visible="${controller.vault.needsMigration}">
<graphic>
<FontAwesome5IconView glyph="FILE_IMPORT" glyphSize="15"/>
</graphic>
</Button>
<Region VBox.vgrow="ALWAYS"/>
<VBox spacing="6" visible="${controller.vault.unlocked}" managed="${controller.vault.unlocked}">