mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-21 20:21:27 +00:00
Added an additional layer of abstraction to error reports
Fixed var names Added abstract base class for controllers Added base interface for error components Added base interface for error component builders Generified scene providers Made GenericError classes and InvalidMountPointException classes depend on those base interfaces/classes
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
package org.cryptomator.ui.error;
|
||||
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class AbstractErrorController implements FxController {
|
||||
|
||||
protected final Stage window;
|
||||
protected final Scene returnScene;
|
||||
|
||||
public AbstractErrorController(@ErrorReport Stage window, @ErrorReport @Nullable Scene returnScene) {
|
||||
this.returnScene = returnScene;
|
||||
this.window = window;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void back() {
|
||||
if (this.returnScene != null) {
|
||||
this.window.setScene(this.returnScene);
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
this.window.close();
|
||||
}
|
||||
|
||||
public boolean isReturnScenePresent() {
|
||||
return this.returnScene != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.cryptomator.ui.error;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Named;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public interface ErrorComponentBase {
|
||||
|
||||
@ErrorReport
|
||||
Stage window();
|
||||
|
||||
@Named("errorScene")
|
||||
Scene errorScene();
|
||||
|
||||
@ErrorReport
|
||||
Throwable cause();
|
||||
|
||||
@ErrorReport
|
||||
@Nullable
|
||||
Scene previousScene();
|
||||
|
||||
default void showErrorScene() {
|
||||
if (Platform.isFxApplicationThread()) {
|
||||
show();
|
||||
} else {
|
||||
Platform.runLater(this::show);
|
||||
}
|
||||
}
|
||||
|
||||
private void show() {
|
||||
Stage stage = window();
|
||||
stage.setScene(errorScene());
|
||||
stage.show();
|
||||
}
|
||||
|
||||
interface BuilderBase<B, C> {
|
||||
|
||||
@BindsInstance
|
||||
B window(@ErrorReport Stage window);
|
||||
|
||||
@BindsInstance
|
||||
B cause(@ErrorReport Throwable cause);
|
||||
|
||||
@BindsInstance
|
||||
B returnToScene(@ErrorReport @Nullable Scene returnScene);
|
||||
|
||||
C build();
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,11 @@
|
||||
package org.cryptomator.ui.error;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
@@ -30,23 +26,16 @@ abstract class ErrorModule {
|
||||
|
||||
@Provides
|
||||
@Named("stackTrace")
|
||||
static String provideStackTrace(Throwable cause) {
|
||||
static String provideStackTrace(@ErrorReport Throwable cause) {
|
||||
// TODO deduplicate VaultDetailUnknownErrorController.java
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
cause.printStackTrace(new PrintStream(baos));
|
||||
return baos.toString(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(GenericErrorController.class)
|
||||
abstract FxController bindErrorController(GenericErrorController controller);
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.GENERIC_ERROR)
|
||||
static Scene provideErrorScene(FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.GENERIC_ERROR);
|
||||
@Named("errorScene")
|
||||
static Scene provideErrorScene(FxmlLoaderFactory fxmlLoaders, @ErrorReport FxmlFile file) {
|
||||
return fxmlLoaders.createScene(file);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.cryptomator.ui.error;
|
||||
|
||||
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 ErrorReport {
|
||||
|
||||
}
|
||||
@@ -1,51 +1,32 @@
|
||||
package org.cryptomator.ui.error;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.Subcomponent;
|
||||
import dagger.multibindings.IntoMap;
|
||||
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 javax.annotation.Nullable;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@Subcomponent(modules = {ErrorModule.class})
|
||||
public interface GenericErrorComponent {
|
||||
|
||||
Stage window();
|
||||
|
||||
@FxmlScene(FxmlFile.GENERIC_ERROR)
|
||||
Scene scene();
|
||||
|
||||
default void showErrorScene() {
|
||||
if (Platform.isFxApplicationThread()) {
|
||||
show();
|
||||
} else {
|
||||
Platform.runLater(this::show);
|
||||
}
|
||||
}
|
||||
|
||||
private void show() {
|
||||
Stage stage = window();
|
||||
stage.setScene(scene());
|
||||
stage.show();
|
||||
}
|
||||
@Subcomponent(modules = {ErrorModule.class, GenericErrorComponent.GenericErrorModule.class})
|
||||
public interface GenericErrorComponent extends ErrorComponentBase {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
interface Builder extends BuilderBase<Builder, GenericErrorComponent> { /* Handled by base interface */ }
|
||||
|
||||
@BindsInstance
|
||||
Builder cause(Throwable cause);
|
||||
@Module
|
||||
abstract class GenericErrorModule {
|
||||
|
||||
@BindsInstance
|
||||
Builder window(Stage window);
|
||||
|
||||
@BindsInstance
|
||||
Builder returnToScene(@Nullable Scene previousScene);
|
||||
|
||||
GenericErrorComponent build();
|
||||
@Provides
|
||||
@ErrorReport
|
||||
static FxmlFile provideFxmlFile() {
|
||||
return FxmlFile.GENERIC_ERROR;
|
||||
}
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(GenericErrorController.class)
|
||||
abstract FxController bindController(GenericErrorController controller);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,24 @@
|
||||
package org.cryptomator.ui.error;
|
||||
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class GenericErrorController implements FxController {
|
||||
public class GenericErrorController extends AbstractErrorController {
|
||||
|
||||
private final String stackTrace;
|
||||
private final Scene previousScene;
|
||||
private final Stage window;
|
||||
|
||||
@Inject
|
||||
GenericErrorController(@Named("stackTrace") String stackTrace, @Nullable Scene previousScene, Stage window) {
|
||||
GenericErrorController(@ErrorReport Stage window, @ErrorReport @Nullable Scene previousScene, @Named("stackTrace") String stackTrace) {
|
||||
super(window, previousScene);
|
||||
this.stackTrace = stackTrace;
|
||||
this.previousScene = previousScene;
|
||||
this.window = window;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void back() {
|
||||
if (previousScene != null) {
|
||||
window.setScene(previousScene);
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public boolean isPreviousScenePresent() {
|
||||
return previousScene != null;
|
||||
}
|
||||
|
||||
public String getStackTrace() {
|
||||
return stackTrace;
|
||||
return this.stackTrace;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.cryptomator.ui.error;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.Subcomponent;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.unlock.UnlockInvalidMountPointController;
|
||||
import org.cryptomator.ui.unlock.UnlockScoped;
|
||||
|
||||
@Subcomponent(modules = {ErrorModule.class, InvalidMountPointExceptionComponent.InvalidMountPointExceptionModule.class})
|
||||
@UnlockScoped
|
||||
public interface InvalidMountPointExceptionComponent extends ErrorComponentBase {
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder extends BuilderBase<Builder, InvalidMountPointExceptionComponent> {
|
||||
|
||||
@BindsInstance
|
||||
Builder vault(@ErrorReport Vault vault);
|
||||
|
||||
}
|
||||
|
||||
@Module
|
||||
abstract class InvalidMountPointExceptionModule {
|
||||
|
||||
@Provides
|
||||
@ErrorReport
|
||||
static FxmlFile provideFxmlFile() {
|
||||
return FxmlFile.UNLOCK_INVALID_MOUNT_POINT;
|
||||
}
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(UnlockInvalidMountPointController.class)
|
||||
abstract FxController bindController(UnlockInvalidMountPointController controller);
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,9 @@ import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.ui.error.GenericErrorComponent;
|
||||
import org.cryptomator.ui.common.StageFactory;
|
||||
import org.cryptomator.ui.error.GenericErrorComponent;
|
||||
import org.cryptomator.ui.error.InvalidMountPointExceptionComponent;
|
||||
import org.cryptomator.ui.lock.LockComponent;
|
||||
import org.cryptomator.ui.mainwindow.MainWindowComponent;
|
||||
import org.cryptomator.ui.preferences.PreferencesComponent;
|
||||
@@ -26,8 +27,8 @@ import java.io.UncheckedIOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Module(includes = {UpdateCheckerModule.class}, subcomponents = {MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class, LockComponent.class, QuitComponent.class, GenericErrorComponent.class})
|
||||
abstract class FxApplicationModule {
|
||||
@Module(includes = {UpdateCheckerModule.class}, subcomponents = {MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class, LockComponent.class, QuitComponent.class, GenericErrorComponent.class, InvalidMountPointExceptionComponent.class})
|
||||
public abstract class FxApplicationModule {
|
||||
|
||||
@Provides
|
||||
@Named("windowIcons")
|
||||
|
||||
@@ -1,49 +1,38 @@
|
||||
package org.cryptomator.ui.unlock;
|
||||
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.vaults.MountPointRequirement;
|
||||
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 org.cryptomator.ui.error.AbstractErrorController;
|
||||
import org.cryptomator.ui.error.ErrorReport;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
//At the current point in time only the CustomMountPointChooser may cause this window to be shown.
|
||||
@UnlockScoped
|
||||
public class UnlockInvalidMountPointController implements FxController {
|
||||
public class UnlockInvalidMountPointController extends AbstractErrorController {
|
||||
|
||||
private final Stage window;
|
||||
private final Lazy<Scene> unlockScene;
|
||||
private final Vault vault;
|
||||
|
||||
@Inject
|
||||
UnlockInvalidMountPointController(@UnlockWindow Stage window, @FxmlScene(FxmlFile.UNLOCK) Lazy<Scene> unlockScene, @UnlockWindow Vault vault) {
|
||||
this.window = window;
|
||||
this.unlockScene = unlockScene;
|
||||
UnlockInvalidMountPointController(@ErrorReport Stage window, @ErrorReport @Nullable Scene previousScene, @ErrorReport Vault vault) {
|
||||
super(window, previousScene);
|
||||
this.vault = vault;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void back() {
|
||||
window.setScene(unlockScene.get());
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public String getMountPoint() {
|
||||
return vault.getVaultSettings().getCustomMountPath().orElse("AUTO");
|
||||
return this.vault.getVaultSettings().getCustomMountPath().orElse("AUTO");
|
||||
}
|
||||
|
||||
public boolean getMustExist() {
|
||||
MountPointRequirement requirement = vault.getVolume().orElseThrow(() -> new IllegalStateException("Invalid Mountpoint without a Volume?!")).getMountPointRequirement();
|
||||
MountPointRequirement requirement = this.vault.getVolume().orElseThrow(() -> new IllegalStateException("Invalid Mountpoint without a Volume?!")).getMountPointRequirement();
|
||||
assert requirement != MountPointRequirement.NONE; //An invalid MountPoint with no required MountPoint doesn't seem sensible
|
||||
assert requirement != MountPointRequirement.PARENT_OPT_MOUNT_POINT; //Not implemented anywhere (yet)
|
||||
|
||||
return requirement == MountPointRequirement.EMPTY_MOUNT_POINT;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -130,10 +130,4 @@ abstract class UnlockModule {
|
||||
@IntoMap
|
||||
@FxControllerKey(UnlockSuccessController.class)
|
||||
abstract FxController bindUnlockSuccessController(UnlockSuccessController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(UnlockInvalidMountPointController.class)
|
||||
abstract FxController bindUnlockInvalidMountPointController(UnlockInvalidMountPointController controller);
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,6 @@ import java.lang.annotation.RetentionPolicy;
|
||||
@Scope
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface UnlockScoped {
|
||||
public @interface UnlockScoped {
|
||||
|
||||
}
|
||||
|
||||
@@ -10,11 +10,12 @@ import org.cryptomator.common.vaults.Volume.VolumeException;
|
||||
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
|
||||
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
||||
import org.cryptomator.ui.common.Animations;
|
||||
import org.cryptomator.ui.error.GenericErrorComponent;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.UserInteractionLock;
|
||||
import org.cryptomator.ui.common.VaultService;
|
||||
import org.cryptomator.ui.error.GenericErrorComponent;
|
||||
import org.cryptomator.ui.error.InvalidMountPointExceptionComponent;
|
||||
import org.cryptomator.ui.unlock.UnlockModule.PasswordEntry;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -56,11 +57,11 @@ public class UnlockWorkflow extends Task<Boolean> {
|
||||
private final KeychainManager keychain;
|
||||
private final Lazy<Scene> unlockScene;
|
||||
private final Lazy<Scene> successScene;
|
||||
private final Lazy<Scene> invalidMountPointScene;
|
||||
private final GenericErrorComponent.Builder genericErrorBuilder;
|
||||
private final InvalidMountPointExceptionComponent.Builder invalidMountPointExceptionBuilder;
|
||||
|
||||
@Inject
|
||||
UnlockWorkflow(@UnlockWindow Stage window, @UnlockWindow Vault vault, VaultService vaultService, AtomicReference<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<PasswordEntry> passwordEntryLock, KeychainManager keychain, @FxmlScene(FxmlFile.UNLOCK) Lazy<Scene> unlockScene, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT) Lazy<Scene> invalidMountPointScene, GenericErrorComponent.Builder genericErrorBuilder) {
|
||||
UnlockWorkflow(@UnlockWindow Stage window, @UnlockWindow Vault vault, VaultService vaultService, AtomicReference<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<PasswordEntry> passwordEntryLock, KeychainManager keychain, @FxmlScene(FxmlFile.UNLOCK) Lazy<Scene> unlockScene, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene, GenericErrorComponent.Builder genericErrorBuilder, InvalidMountPointExceptionComponent.Builder invalidMountPointExceptionBuilder) {
|
||||
this.window = window;
|
||||
this.vault = vault;
|
||||
this.vaultService = vaultService;
|
||||
@@ -71,8 +72,8 @@ public class UnlockWorkflow extends Task<Boolean> {
|
||||
this.keychain = keychain;
|
||||
this.unlockScene = unlockScene;
|
||||
this.successScene = successScene;
|
||||
this.invalidMountPointScene = invalidMountPointScene;
|
||||
this.genericErrorBuilder = genericErrorBuilder;
|
||||
this.invalidMountPointExceptionBuilder = invalidMountPointExceptionBuilder;
|
||||
|
||||
setOnFailed(event -> {
|
||||
Throwable throwable = event.getSource().getException();
|
||||
@@ -172,26 +173,23 @@ public class UnlockWorkflow extends Task<Boolean> {
|
||||
} else {
|
||||
LOG.error("Unlock failed. Mountpoint doesn't exist (needs to be a folder): {}", cause.getMessage());
|
||||
}
|
||||
showInvalidMountPointScene();
|
||||
showInvalidMountPointScene(cause);
|
||||
return;
|
||||
} else if (cause instanceof FileAlreadyExistsException) {
|
||||
LOG.error("Unlock failed. Mountpoint already exists: {}", cause.getMessage());
|
||||
showInvalidMountPointScene();
|
||||
showInvalidMountPointScene(cause);
|
||||
return;
|
||||
} else if (cause instanceof DirectoryNotEmptyException) {
|
||||
LOG.error("Unlock failed. Mountpoint not an empty directory: {}", cause.getMessage());
|
||||
showInvalidMountPointScene();
|
||||
showInvalidMountPointScene(cause);
|
||||
return;
|
||||
} else {
|
||||
handleGenericError(impExc);
|
||||
}
|
||||
}
|
||||
|
||||
private void showInvalidMountPointScene() {
|
||||
Platform.runLater(() -> {
|
||||
window.setScene(invalidMountPointScene.get());
|
||||
window.show();
|
||||
});
|
||||
private void showInvalidMountPointScene(Throwable e) {
|
||||
invalidMountPointExceptionBuilder.cause(e).window(window).returnToScene(window.getScene()).vault(vault).build().showErrorScene();
|
||||
}
|
||||
|
||||
private void handleGenericError(Throwable e) {
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="B+C">
|
||||
<buttons>
|
||||
<Button text="%generic.button.back" ButtonBar.buttonData="BACK_PREVIOUS" onAction="#back" visible="${controller.previousScenePresent}"/>
|
||||
<Button text="%generic.button.back" ButtonBar.buttonData="BACK_PREVIOUS" onAction="#back" visible="${controller.returnScenePresent}"/>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" onAction="#close"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
|
||||
Reference in New Issue
Block a user