mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-17 18:21:26 +00:00
Merge branch 'develop' into feature/#1228-forcedUnmountDialog
This commit is contained in:
16
.github/ISSUE_TEMPLATE/bug.md
vendored
16
.github/ISSUE_TEMPLATE/bug.md
vendored
@@ -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 -->
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -89,4 +89,8 @@ abstract class FxApplicationModule {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Provides
|
||||
static QuitComponent provideQuitComponent(QuitComponent.Builder builder) {
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user