Feature: revamp health workflow init (#1695)

* Add health tab to vault options:
* health tool is started from there
* health tool closes old Window and creates new one
* added info and remarks about health tool
* adds confirmation checkbox before starting health tool
* close vault options window when starting health workflow
* Remove AutoLock tab, move options to general tab

Co-authored-by: Snyk bot <snyk-bot@snyk.io>
Co-authored-by: Tobias Hagemann <tobias.hagemann@skymatic.de>
Co-authored-by: Sebastian Stenzel <sebastian.stenzel@skymatic.de >
This commit is contained in:
Armin Schrenk
2021-06-29 09:57:45 +02:00
committed by GitHub
parent c6aceb3e59
commit a96115ecd6
15 changed files with 153 additions and 105 deletions

View File

@@ -39,7 +39,7 @@ public enum FontAwesome5Icon {
REDO("\uF01E"), //
SEARCH("\uF002"), //
SPINNER("\uF110"), //
STOPWATCH("\uF2F2"), //
STETHOSCOPE("\uF0f1"), //
SYNC("\uF021"), //
TIMES("\uF00D"), //
TRASH("\uF1F8"), //

View File

@@ -7,6 +7,7 @@ import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import javax.inject.Named;
import javafx.scene.Scene;
import javafx.stage.Stage;
@@ -17,6 +18,9 @@ public interface HealthCheckComponent {
@HealthCheckWindow
Stage window();
@Named("windowToClose")
Stage windowToClose();
@FxmlScene(FxmlFile.HEALTH_START)
Lazy<Scene> scene();
@@ -24,6 +28,7 @@ public interface HealthCheckComponent {
Stage stage = window();
stage.setScene(scene().get());
stage.show();
windowToClose().close();
return stage;
}
@@ -33,6 +38,9 @@ public interface HealthCheckComponent {
@BindsInstance
Builder vault(@HealthCheckWindow Vault vault);
@BindsInstance
Builder windowToClose(@Named("windowToClose") Stage window);
HealthCheckComponent build();
}

View File

@@ -19,6 +19,8 @@ import org.cryptomator.ui.keyloading.KeyLoadingComponent;
import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
import org.cryptomator.ui.mainwindow.MainWindow;
import javax.annotation.Nullable;
import javax.inject.Named;
import javax.inject.Provider;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
@@ -86,10 +88,10 @@ abstract class HealthCheckModule {
@HealthCheckScoped
static Stage provideStage(StageFactory factory, @MainWindow Stage owner, ResourceBundle resourceBundle, ChangeListener<Boolean> showingListener) {
Stage stage = factory.create();
stage.setTitle(resourceBundle.getString("health.title"));
stage.setResizable(true);
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(owner);
stage.setTitle(resourceBundle.getString("health.title"));
stage.setResizable(true);
stage.showingProperty().addListener(showingListener); // bind masterkey lifecycle to window
return stage;
}

View File

@@ -1,51 +0,0 @@
package org.cryptomator.ui.vaultoptions;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.controls.NumericTextField;
import javax.inject.Inject;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.util.StringConverter;
@VaultOptionsScoped
public class AutoLockVaultOptionsController implements FxController {
private final Vault vault;
public CheckBox lockAfterTimeCheckbox;
public NumericTextField lockTimeInMinutesTextField;
@Inject
AutoLockVaultOptionsController(@VaultOptionsWindow Vault vault) {
this.vault = vault;
}
@FXML
public void initialize() {
lockAfterTimeCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().autoLockWhenIdle());
Bindings.bindBidirectional(lockTimeInMinutesTextField.textProperty(), vault.getVaultSettings().autoLockIdleSeconds(), new IdleTimeSecondsConverter());
}
private static class IdleTimeSecondsConverter extends StringConverter<Number> {
@Override
public String toString(Number seconds) {
int minutes = seconds.intValue() / 60; // int-truncate
return Integer.toString(minutes);
}
@Override
public Number fromString(String string) {
try {
int minutes = Integer.valueOf(string);
return minutes * 60;
} catch (NumberFormatException e) {
return 0;
}
}
}
}

View File

@@ -3,10 +3,11 @@ package org.cryptomator.ui.vaultoptions;
import org.cryptomator.common.settings.WhenUnlocked;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.health.HealthCheckComponent;
import org.cryptomator.ui.controls.NumericTextField;
import javax.inject.Inject;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ChoiceBox;
@@ -23,18 +24,18 @@ public class GeneralVaultOptionsController implements FxController {
private final Stage window;
private final Vault vault;
private final HealthCheckComponent.Builder healthCheckWindow;
private final ResourceBundle resourceBundle;
public TextField vaultName;
public CheckBox unlockOnStartupCheckbox;
public ChoiceBox<WhenUnlocked> actionAfterUnlockChoiceBox;
public CheckBox lockAfterTimeCheckbox;
public NumericTextField lockTimeInMinutesTextField;
@Inject
GeneralVaultOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, HealthCheckComponent.Builder healthCheckWindow, ResourceBundle resourceBundle) {
GeneralVaultOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, ResourceBundle resourceBundle) {
this.window = window;
this.vault = vault;
this.healthCheckWindow = healthCheckWindow;
this.resourceBundle = resourceBundle;
}
@@ -47,6 +48,8 @@ public class GeneralVaultOptionsController implements FxController {
actionAfterUnlockChoiceBox.getItems().addAll(WhenUnlocked.values());
actionAfterUnlockChoiceBox.valueProperty().bindBidirectional(vault.getVaultSettings().actionAfterUnlock());
actionAfterUnlockChoiceBox.setConverter(new WhenUnlockedConverter(resourceBundle));
lockAfterTimeCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().autoLockWhenIdle());
Bindings.bindBidirectional(lockTimeInMinutesTextField.textProperty(), vault.getVaultSettings().autoLockIdleSeconds(), new IdleTimeSecondsConverter());
}
private void trimVaultNameOnFocusLoss(Observable observable, Boolean wasFocussed, Boolean isFocussed) {
@@ -64,12 +67,6 @@ public class GeneralVaultOptionsController implements FxController {
}
}
@FXML
public void showHealthCheck() {
healthCheckWindow.vault(vault).build().showHealthCheckWindow();
}
private static class WhenUnlockedConverter extends StringConverter<WhenUnlocked> {
private final ResourceBundle resourceBundle;
@@ -89,4 +86,22 @@ public class GeneralVaultOptionsController implements FxController {
}
}
private static class IdleTimeSecondsConverter extends StringConverter<Number> {
@Override
public String toString(Number seconds) {
int minutes = seconds.intValue() / 60; // int-truncate
return Integer.toString(minutes);
}
@Override
public Number fromString(String string) {
try {
int minutes = Integer.valueOf(string);
return minutes * 60;
} catch (NumberFormatException e) {
return 0;
}
}
}
}

View File

@@ -0,0 +1,30 @@
package org.cryptomator.ui.vaultoptions;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.health.HealthCheckComponent;
import javax.inject.Inject;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.stage.Stage;
@VaultOptionsScoped
public class HealthVaultOptionsController implements FxController {
@Inject
public HealthVaultOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, HealthCheckComponent.Builder healthCheckWindow) {
this.window = window;
this.vault = vault;
this.healthCheckWindow = healthCheckWindow;
}
@FXML
public void startHealthCheck(ActionEvent event) {
healthCheckWindow.vault(vault).windowToClose(window).build().showHealthCheckWindow();
}
private final Stage window;
private final Vault vault;
private final HealthCheckComponent.Builder healthCheckWindow;
}

View File

@@ -23,7 +23,11 @@ public enum SelectedVaultOptionsTab {
/**
* Show Auto-Lock tab
*
*/
AUTOLOCK,
/**
* Show health tab
*/
HEALTH;
}

View File

@@ -24,6 +24,7 @@ public class VaultOptionsController implements FxController {
public Tab mountTab;
public Tab keyTab;
public Tab autoLockTab;
public Tab healthTab;
@Inject
VaultOptionsController(@VaultOptionsWindow Stage window, ObjectProperty<SelectedVaultOptionsTab> selectedTabProperty) {
@@ -49,6 +50,7 @@ public class VaultOptionsController implements FxController {
case MOUNT -> mountTab;
case KEY -> keyTab;
case AUTOLOCK -> autoLockTab;
case HEALTH -> healthTab;
};
}

View File

@@ -86,7 +86,6 @@ abstract class VaultOptionsModule {
@Binds
@IntoMap
@FxControllerKey(AutoLockVaultOptionsController.class)
abstract FxController bindAutoLockVaultOptionsController(AutoLockVaultOptionsController controller);
@FxControllerKey(HealthVaultOptionsController.class)
abstract FxController bindHealthOptionsController(HealthVaultOptionsController controller);
}

View File

@@ -17,7 +17,6 @@
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<Label text="%health.start.introduction" wrapText="true"/>
<!-- TODO: combine the two below labels to one and bind the properties accordingly or, preferably think about a new flow -->
<Label text="%health.start.configInvalid" visible="${controller.invalidConfig}" managed="${controller.invalidConfig}" wrapText="true" contentDisplay="LEFT">

View File

@@ -36,12 +36,12 @@
<fx:include source="/fxml/vault_options_masterkey.fxml"/>
</content>
</Tab>
<Tab fx:id="autoLockTab" id="AUTOLOCK" text="%vaultOptions.autoLock">
<Tab fx:id="healthTab" id="HEALTH" text="%vaultOptions.health">
<graphic>
<FontAwesome5IconView glyph="STOPWATCH"/>
<FontAwesome5IconView glyph="STETHOSCOPE"/>
</graphic>
<content>
<fx:include source="/fxml/vault_options_autolock.fxml"/>
<fx:include source="/fxml/vault_options_health.fxml"/>
</content>
</Tab>
</tabs>

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import org.cryptomator.ui.controls.FormattedLabel?>
<?import org.cryptomator.ui.controls.NumericTextField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Text?>
<?import javafx.scene.text.TextFlow?>
<VBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.vaultoptions.AutoLockVaultOptionsController"
spacing="6">
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<TextFlow styleClass="text-flow" prefWidth="-Infinity">
<CheckBox text="%vaultOptions.autoLock.lockAfterTimePart1" fx:id="lockAfterTimeCheckbox"/>
<Text text=" "/>
<NumericTextField fx:id="lockTimeInMinutesTextField" prefWidth="50"/>
<Text text=" "/>
<FormattedLabel format="%vaultOptions.autoLock.lockAfterTimePart2"/>
</TextFlow>
</children>
</VBox>

View File

@@ -8,6 +8,10 @@
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.text.TextFlow?>
<?import javafx.scene.text.Text?>
<?import org.cryptomator.ui.controls.NumericTextField?>
<?import org.cryptomator.ui.controls.FormattedLabel?>
<VBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.vaultoptions.GeneralVaultOptionsController"
@@ -21,12 +25,19 @@
<TextField fx:id="vaultName"/>
</HBox>
<TextFlow styleClass="text-flow" prefWidth="-Infinity">
<CheckBox text="%vaultOptions.general.autoLock.lockAfterTimePart1" fx:id="lockAfterTimeCheckbox"/>
<Text text=" "/>
<NumericTextField fx:id="lockTimeInMinutesTextField" prefWidth="50"/>
<Text text=" "/>
<FormattedLabel format="%vaultOptions.general.autoLock.lockAfterTimePart2"/>
</TextFlow>
<CheckBox text="%vaultOptions.general.unlockAfterStartup" fx:id="unlockOnStartupCheckbox"/>
<HBox spacing="6" alignment="CENTER_LEFT">
<Label text="%vaultOptions.general.actionAfterUnlock"/>
<ChoiceBox fx:id="actionAfterUnlockChoiceBox"/>
</HBox>
<Button text="%vaultOptions.general.healthBtn" onAction="#showHealthCheck"/>
</children>
</VBox>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.shape.Box?>
<?import javafx.scene.Group?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.collections.ObservableList?>
<?import javafx.collections.FXCollections?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.CheckBox?>
<VBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.vaultoptions.HealthVaultOptionsController"
spacing="6">
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<Label text="%vaultOptions.health.introduction" wrapText="true"/>
<Label text="%vaultOptions.health.remarks" wrapText="true"/>
<GridPane >
<padding>
<Insets left="6"/>
</padding>
<columnConstraints>
<ColumnConstraints minWidth="20" halignment="LEFT"/>
<ColumnConstraints fillWidth="true"/>
</columnConstraints>
<rowConstraints>
<RowConstraints valignment="TOP"/>
<RowConstraints valignment="TOP"/>
<RowConstraints valignment="TOP"/>
</rowConstraints>
<Label text="1." GridPane.rowIndex="0" GridPane.columnIndex="0" />
<Label text="%vaultOptions.health.remarkSync" wrapText="true" GridPane.rowIndex="0" GridPane.columnIndex="1" />
<Label text="2." GridPane.rowIndex="1" GridPane.columnIndex="0" />
<Label text="%vaultOptions.health.remarkFix" wrapText="true" GridPane.rowIndex="1" GridPane.columnIndex="1" />
<Label text="3." GridPane.rowIndex="2" GridPane.columnIndex="0" />
<Label text="%vaultOptions.health.remarkBackup" wrapText="true" GridPane.rowIndex="2" GridPane.columnIndex="1" />
</GridPane>
<CheckBox text="%vaultOptions.health.affirmation" fx:id="affirmationBox"/>
<Button text="%vaultOptions.health.startBtn" disable="${!affirmationBox.selected}" onAction="#startHealthCheck"/>
</children>
</VBox>

View File

@@ -148,7 +148,6 @@ migration.impossible.moreInfo=The vault can still be opened with an older versio
# Health Check
health.title=Vault Health Check
health.start.introduction=The Vault Health Check is a collection of checks to detect and possibly fix problems in the internal structure of your vault. Please note, that not all problems are fixable. You need the vault password to perform the checks.
health.start.configValid=Reading and parsing vault configuration file was successful. Proceed to select checks.
health.start.configInvalid=Error while reading and parsing the vault configuration file.
health.checkList.header=Available Health Checks
@@ -304,12 +303,13 @@ wrongFileAlert.link=For further assistance, visit
## General
vaultOptions.general=General
vaultOptions.general.vaultName=Vault Name
vaultOptions.general.autoLock.lockAfterTimePart1=Lock when idle for
vaultOptions.general.autoLock.lockAfterTimePart2=minutes
vaultOptions.general.unlockAfterStartup=Unlock vault when starting Cryptomator
vaultOptions.general.actionAfterUnlock=After successful unlock
vaultOptions.general.actionAfterUnlock.ignore=Do nothing
vaultOptions.general.actionAfterUnlock.reveal=Reveal Drive
vaultOptions.general.actionAfterUnlock.ask=Ask
vaultOptions.general.healthBtn=Start Health Check
## Mount
vaultOptions.mount=Mounting
vaultOptions.mount.readonly=Read-Only
@@ -328,10 +328,16 @@ vaultOptions.masterkey.forgetSavedPasswordBtn=Forget Saved Password
vaultOptions.masterkey.recoveryKeyExplanation=A recovery key is your only means to restore access to a vault if you lose your password.
vaultOptions.masterkey.showRecoveryKeyBtn=Display Recovery Key
vaultOptions.masterkey.recoverPasswordBtn=Recover Password
## Auto Lock
vaultOptions.autoLock=Auto-Lock
vaultOptions.autoLock.lockAfterTimePart1=Lock when idle for
vaultOptions.autoLock.lockAfterTimePart2=minutes
## Health
vaultOptions.health=Health Check
vaultOptions.health.startBtn=Start Health Check
vaultOptions.health.introduction=Health Check is a collection of checks to detect and possibly fix problems in the internal structure of your vault.
vaultOptions.health.remarks=Please keep in mind:
vaultOptions.health.remarkSync=Incomplete synchronisation causes most problems. Ensure that every device is completely synced.
vaultOptions.health.remarkFix=Not all problems can be fixed.
vaultOptions.health.remarkBackup=If data is corrupted, only a backup can help.
vaultOptions.health.affirmation=I have read and understood the above information.
# Recovery Key
recoveryKey.title=Recovery Key