Merge branch 'develop' into feature/#1228-forcedUnmountDialog

This commit is contained in:
Sebastian Stenzel
2020-12-07 17:55:29 +01:00
committed by GitHub
14 changed files with 95 additions and 48 deletions

View File

@@ -5,8 +5,11 @@ labels: type:bug
---
<!--
⚠️⚠️⚠️ READ CAREFULLY ⚠️⚠️⚠️
**************************************
* *
* ⚠️⚠️⚠️ READ CAREFULLY ⚠️⚠️⚠️ *
* *
**************************************
Do you want to ask a QUESTION? Are you looking for SUPPORT?
We're happy to help you via our support channels! Please read: https://github.com/cryptomator/cryptomator/blob/develop/SUPPORT.md
@@ -14,7 +17,14 @@ By filing an issue, you are expected to comply with our code of conduct: https:/
Of course, we also expect you to search for existing similar issues first! ;) https://github.com/cryptomator/cryptomator/issues?q=
⚠️ IMPORTANT: If you don't stick to this template, the issue will get closed. To proof that you read this, please remove the X from the following line:
⚠️ IMPORTANT: If you don't stick to this template, the issue will get closed.
*****************************************************************************
* *
* To proof that you read this, please remove the X from the line below: *
* *
*****************************************************************************
-->
<!-- oooXooo -->

View File

@@ -28,7 +28,7 @@ class MacVolumeMountChooser implements MountPointChooser {
@Override
public Optional<Path> chooseMountPoint(Volume caller) {
return Optional.of(VOLUME_PATH).map(dir -> this.helper.chooseTemporaryMountPoint(this.vaultSettings, dir));
return Optional.of(helper.chooseTemporaryMountPoint(vaultSettings, VOLUME_PATH));
}
@Override

View File

@@ -20,11 +20,10 @@ import java.util.Optional;
class MountPointHelper {
public static Logger LOG = LoggerFactory.getLogger(MountPointHelper.class);
private static final int MAX_TMPMOUNTPOINT_CREATION_RETRIES = 10;
private final Optional<Path> tmpMountPointDir;
private volatile boolean alreadyChecked = false;
private volatile boolean unmountDebrisCleared = false;
@Inject
public MountPointHelper(Environment env) {
@@ -55,13 +54,13 @@ class MountPointHelper {
}
public synchronized void clearIrregularUnmountDebrisIfNeeded() {
if (alreadyChecked || tmpMountPointDir.isEmpty()) {
return; //nuthin to do
if (unmountDebrisCleared || tmpMountPointDir.isEmpty()) {
return; // nothing to do
}
if (Files.exists(tmpMountPointDir.get(), LinkOption.NOFOLLOW_LINKS)) {
clearIrregularUnmountDebris(tmpMountPointDir.get());
}
alreadyChecked = true;
unmountDebrisCleared = true;
}
private void clearIrregularUnmountDebris(Path dirContainingMountPoints) {
@@ -92,7 +91,7 @@ class MountPointHelper {
} catch (IOException e) {
LOG.warn("Unable to perform cleanup of mountpoint dir {}.", dirContainingMountPoints, e);
} finally {
alreadyChecked = true;
unmountDebrisCleared = true;
}
}

View File

@@ -20,7 +20,8 @@ public abstract class AbstractVolume implements Volume {
}
protected Path determineMountPoint() throws InvalidMountPointException {
for (var chooser : Iterables.filter(choosers, c -> c.isApplicable(this))) {
var applicableChoosers = Iterables.filter(choosers, c -> c.isApplicable(this));
for (var chooser : applicableChoosers) {
Optional<Path> chosenPath = chooser.chooseMountPoint(this);
if (chosenPath.isEmpty()) { // chooser couldn't find a feasible mountpoint
continue;
@@ -29,7 +30,7 @@ public abstract class AbstractVolume implements Volume {
this.usedChooser = chooser;
return chosenPath.get();
}
throw new InvalidMountPointException("No feasible MountPoint found!");
throw new InvalidMountPointException(String.format("No feasible MountPoint found by choosers: %s", applicableChoosers));
}
protected void cleanupMountPoint() {

View File

@@ -13,7 +13,6 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.SortedSet;
import java.util.concurrent.ExecutorService;
public class DokanyVolume extends AbstractVolume {
@@ -42,7 +41,6 @@ public class DokanyVolume extends AbstractVolume {
@Override
public void mount(CryptoFileSystem fs, String mountFlags) throws InvalidMountPointException, VolumeException {
this.mountPoint = determineMountPoint();
String mountName = vaultSettings.mountName().get();
try {
this.mount = mountFactory.mount(fs.getPath("/"), mountPoint, vaultSettings.mountName().get(), FS_TYPE_NAME, mountFlags.strip());
} catch (MountFailedException e) {
@@ -62,8 +60,18 @@ public class DokanyVolume extends AbstractVolume {
}
@Override
public void unmount() {
mount.close();
public void unmount() throws VolumeException {
try {
mount.unmount();
} catch (IllegalStateException e) {
throw new VolumeException("Unmount Failed.", e);
}
cleanupMountPoint();
}
@Override
public void unmountForced() {
mount.close(); //TODO: with next dokany-nio-release, change this to unmountForced()
cleanupMountPoint();
}

View File

@@ -1,6 +1,5 @@
package org.cryptomator.ui.addvaultwizard;
import com.tobiasdiez.easybind.EasyBind;
import dagger.Lazy;
import org.cryptomator.ui.common.ErrorComponent;
import org.cryptomator.ui.common.FxController;
@@ -84,11 +83,11 @@ public class CreateNewVaultLocationController implements FxController {
public void initialize() {
predefinedLocationToggler.selectedToggleProperty().addListener(this::togglePredefinedLocation);
usePresetPath.bind(predefinedLocationToggler.selectedToggleProperty().isNotEqualTo(customRadioButton));
EasyBind.subscribe(vaultPath, this::vaultPathDidChange);
vaultPath.addListener(this::vaultPathDidChange);
}
private void vaultPathDidChange(Path newValue) {
if (newValue != null && !Files.notExists(newValue)) {
private void vaultPathDidChange(@SuppressWarnings("unused") ObservableValue<? extends Path> observable, @SuppressWarnings("unused") Path oldValue, Path newValue) {
if (!Files.notExists(newValue)) {
warningText.set(resourceBundle.getString("addvaultwizard.new.fileAlreadyExists"));
} else {
warningText.set(null);

View File

@@ -1,6 +1,5 @@
package org.cryptomator.ui.fxapp;
import com.tobiasdiez.easybind.EasyBind;
import dagger.Lazy;
import org.cryptomator.common.LicenseHolder;
import org.cryptomator.common.settings.Settings;
@@ -41,9 +40,9 @@ public class FxApplication extends Application {
private final Settings settings;
private final Lazy<MainWindowComponent> mainWindow;
private final Lazy<PreferencesComponent> preferencesWindow;
private final Lazy<QuitComponent> quitWindow;
private final Provider<UnlockComponent.Builder> unlockWindowBuilderProvider;
private final Provider<LockComponent.Builder> lockWindowBuilderProvider;
private final Provider<QuitComponent.Builder> quitWindowBuilderProvider;
private final Optional<TrayIntegrationProvider> trayIntegration;
private final Optional<UiAppearanceProvider> appearanceProvider;
private final VaultService vaultService;
@@ -52,13 +51,13 @@ public class FxApplication extends Application {
private final UiAppearanceListener systemInterfaceThemeListener = this::systemInterfaceThemeChanged;
@Inject
FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, Provider<UnlockComponent.Builder> unlockWindowBuilderProvider, Provider<LockComponent.Builder> lockWindowBuilderProvider, Provider<QuitComponent.Builder> quitWindowBuilderProvider, Optional<TrayIntegrationProvider> trayIntegration, Optional<UiAppearanceProvider> appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet<Stage> visibleStages) {
FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, Provider<UnlockComponent.Builder> unlockWindowBuilderProvider, Provider<LockComponent.Builder> lockWindowBuilderProvider, Lazy<QuitComponent> quitWindow, Optional<TrayIntegrationProvider> trayIntegration, Optional<UiAppearanceProvider> appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet<Stage> visibleStages) {
this.settings = settings;
this.mainWindow = mainWindow;
this.preferencesWindow = preferencesWindow;
this.unlockWindowBuilderProvider = unlockWindowBuilderProvider;
this.lockWindowBuilderProvider = lockWindowBuilderProvider;
this.quitWindowBuilderProvider = quitWindowBuilderProvider;
this.quitWindow = quitWindow;
this.trayIntegration = trayIntegration;
this.appearanceProvider = appearanceProvider;
this.vaultService = vaultService;
@@ -70,7 +69,7 @@ public class FxApplication extends Application {
LOG.trace("FxApplication.start()");
Platform.setImplicitExit(false);
EasyBind.subscribe(hasVisibleStages, this::hasVisibleStagesChanged);
hasVisibleStages.addListener(this::hasVisibleStagesChanged);
settings.theme().addListener(this::appThemeChanged);
loadSelectedStyleSheet(settings.theme().get());
@@ -81,7 +80,7 @@ public class FxApplication extends Application {
throw new UnsupportedOperationException("Use start() instead.");
}
private void hasVisibleStagesChanged(boolean newValue) {
private void hasVisibleStagesChanged(@SuppressWarnings("unused") ObservableValue<? extends Boolean> observableValue, @SuppressWarnings("unused") boolean oldValue, boolean newValue) {
if (newValue) {
trayIntegration.ifPresent(TrayIntegrationProvider::restoredFromTray);
} else {
@@ -119,7 +118,7 @@ public class FxApplication extends Application {
public void showQuitWindow(QuitResponse response) {
Platform.runLater(() -> {
quitWindowBuilderProvider.get().quitResponse(response).build().showQuitWindow();
quitWindow.get().showQuitWindow(response);
LOG.debug("Showing QuitWindow");
});
}

View File

@@ -89,4 +89,8 @@ abstract class FxApplicationModule {
return builder.build();
}
@Provides
static QuitComponent provideQuitComponent(QuitComponent.Builder builder) {
return builder.build();
}
}

View File

@@ -1,6 +1,5 @@
package org.cryptomator.ui.mainwindow;
import com.tobiasdiez.easybind.EasyBind;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent;
@@ -13,6 +12,7 @@ import javax.inject.Inject;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
@@ -41,7 +41,7 @@ public class VaultListController implements FxController {
this.removeVault = removeVault;
this.noVaultSelected = selectedVault.isNull();
this.emptyVaultList = Bindings.isEmpty(vaults);
EasyBind.subscribe(selectedVault, this::selectedVaultDidChange);
selectedVault.addListener(this::selectedVaultDidChange);
}
public void initialize() {
@@ -58,10 +58,11 @@ public class VaultListController implements FxController {
});
}
private void selectedVaultDidChange(Vault newValue) {
if (newValue != null) {
VaultListManager.redetermineVaultState(newValue);
private void selectedVaultDidChange(@SuppressWarnings("unused") ObservableValue<? extends Vault> observableValue, @SuppressWarnings("unused") Vault oldValue, Vault newValue) {
if (newValue == null) {
return;
}
VaultListManager.redetermineVaultState(newValue);
}
@FXML

View File

@@ -1,5 +1,6 @@
package org.cryptomator.ui.preferences;
import com.google.common.base.CharMatcher;
import org.cryptomator.common.LicenseHolder;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.UiTheme;
@@ -10,6 +11,7 @@ import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextFormatter;
@PreferencesScoped
public class DonationKeyPreferencesController implements FxController {
@@ -32,6 +34,15 @@ public class DonationKeyPreferencesController implements FxController {
public void initialize() {
donationKeyField.setText(licenseHolder.getLicenseKey().orElse(null));
donationKeyField.textProperty().addListener(this::registrationKeyChanged);
donationKeyField.setTextFormatter(new TextFormatter<>(this::checkVaultNameLength));
}
private TextFormatter.Change checkVaultNameLength(TextFormatter.Change change) {
if (change.isContentChange()) {
var strippedText = CharMatcher.whitespace().removeFrom(change.getText());
change.setText(strippedText);
}
return change;
}
private void registrationKeyChanged(@SuppressWarnings("unused") ObservableValue<? extends String> observable, @SuppressWarnings("unused") String oldValue, String newValue) {

View File

@@ -5,7 +5,6 @@
*******************************************************************************/
package org.cryptomator.ui.quit;
import dagger.BindsInstance;
import dagger.Lazy;
import dagger.Subcomponent;
import org.cryptomator.ui.common.FxmlFile;
@@ -25,7 +24,10 @@ public interface QuitComponent {
@FxmlScene(FxmlFile.QUIT)
Lazy<Scene> scene();
default Stage showQuitWindow() {
QuitController controller();
default Stage showQuitWindow(QuitResponse response) {
controller().updateQuitRequest(response);
Stage stage = window();
stage.setScene(scene().get());
stage.show();
@@ -36,9 +38,6 @@ public interface QuitComponent {
@Subcomponent.Builder
interface Builder {
@BindsInstance
Builder quitResponse(QuitResponse response);
QuitComponent build();
}

View File

@@ -16,6 +16,8 @@ import javafx.stage.Stage;
import java.awt.desktop.QuitResponse;
import java.util.Collection;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@QuitScoped
@@ -24,26 +26,40 @@ public class QuitController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(QuitController.class);
private final Stage window;
private final QuitResponse response;
private final ObservableList<Vault> unlockedVaults;
private final ExecutorService executorService;
private final VaultService vaultService;
private final AtomicReference<QuitResponse> quitResponse = new AtomicReference<>();
public Button lockAndQuitButton;
@Inject
QuitController(@QuitWindow Stage window, QuitResponse response, ObservableList<Vault> vaults, ExecutorService executorService, VaultService vaultService) {
QuitController(@QuitWindow Stage window, ObservableList<Vault> vaults, ExecutorService executorService, VaultService vaultService) {
this.window = window;
this.response = response;
this.unlockedVaults = vaults.filtered(Vault::isUnlocked);
this.executorService = executorService;
this.vaultService = vaultService;
window.setOnCloseRequest(windowEvent -> cancel());
}
public void updateQuitRequest(QuitResponse newResponse) {
var oldResponse = quitResponse.getAndSet(newResponse);
if (oldResponse != null) {
oldResponse.cancelQuit();
}
}
private void respondToQuitRequest(Consumer<QuitResponse> action) {
var response = quitResponse.getAndSet(null);
if (response != null) {
action.accept(response);
}
}
@FXML
public void cancel() {
LOG.info("Quitting application canceled by user.");
window.close();
response.cancelQuit();
respondToQuitRequest(QuitResponse::cancelQuit);
}
@FXML
@@ -56,16 +72,16 @@ public class QuitController implements FxController {
LOG.info("Locked {}", lockAllTask.getValue().stream().map(Vault::getDisplayName).collect(Collectors.joining(", ")));
if (unlockedVaults.isEmpty()) {
window.close();
response.performQuit();
respondToQuitRequest(QuitResponse::performQuit);
}
});
lockAllTask.setOnFailed(evt -> {
LOG.warn("Locking failed", lockAllTask.getException());
lockAndQuitButton.setDisable(false);
lockAndQuitButton.setContentDisplay(ContentDisplay.TEXT_ONLY);
// TODO: show force lock or force quit scene (and DO NOT cancelQuit() here!)
// see https://github.com/cryptomator/cryptomator/blob/1.4.16/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java#L151-L163
response.cancelQuit();
// TODO: show force lock or force quit scene (and DO NOT cancelQuit() here!) (see https://github.com/cryptomator/cryptomator/pull/1416)
window.close();
respondToQuitRequest(QuitResponse::cancelQuit);
});
executorService.execute(lockAllTask);
}

View File

@@ -43,7 +43,7 @@ abstract class QuitModule {
@Provides
@FxmlScene(FxmlFile.QUIT)
@QuitScoped
static Scene provideUnlockScene(@QuitWindow FXMLLoaderFactory fxmlLoaders) {
static Scene provideQuitScene(@QuitWindow FXMLLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene("/fxml/quit.fxml");
}

View File

@@ -39,7 +39,7 @@ public class GeneralVaultOptionsController implements FxController {
public void initialize() {
vaultName.textProperty().set(vault.getVaultSettings().displayName().get());
vaultName.focusedProperty().addListener(this::trimVaultNameOnFocusLoss);
vaultName.setTextFormatter(new TextFormatter<>(this::checkVaultNameLength));
vaultName.setTextFormatter(new TextFormatter<>(this::removeWhitespaces));
unlockOnStartupCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().unlockAfterStartup());
actionAfterUnlockChoiceBox.getItems().addAll(WhenUnlocked.values());
actionAfterUnlockChoiceBox.valueProperty().bindBidirectional(vault.getVaultSettings().actionAfterUnlock());
@@ -53,7 +53,7 @@ public class GeneralVaultOptionsController implements FxController {
}
}
private TextFormatter.Change checkVaultNameLength(TextFormatter.Change change) {
private TextFormatter.Change removeWhitespaces(TextFormatter.Change change) {
if (change.isContentChange() && change.getControlNewText().length() > VAULTNAME_TRUNCATE_THRESHOLD) {
return null; // reject any change that would lead to a text exceeding threshold
} else {