diff --git a/README.md b/README.md index 9f0a0e0a1..d2bf39f29 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![cryptomator](cryptomator.png)](https://cryptomator.org/) -[![Build](https://github.com/cryptomator/cryptomator/workflows/Build/badge.svg)](https://github.com/cryptomator/cryptomator/actions?query=workflow%3ABuild) +[![Build](https://github.com/cryptomator/cryptomator/workflows/Build/badge.svg)](https://github.com/cryptomator/cryptomator/actions/workflows/build.yml?query=branch%3Adevelop) [![Known Vulnerabilities](https://snyk.io/test/github/cryptomator/cryptomator/badge.svg)](https://snyk.io/test/github/cryptomator/cryptomator) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=cryptomator_cryptomator&metric=alert_status)](https://sonarcloud.io/dashboard?id=cryptomator_cryptomator) [![Mastodon](https://img.shields.io/mastodon/follow/176112?domain=mastodon.online&style=flat)](https://mastodon.online/@cryptomator) diff --git a/pom.xml b/pom.xml index e6f1e96e4..1735b728f 100644 --- a/pom.xml +++ b/pom.xml @@ -61,7 +61,7 @@ 26.0.1 - 12.0.1 + 12.1.0 0.8.12 2.5.0 1.4.0 diff --git a/src/main/java/org/cryptomator/ui/fxapp/AutoUnlocker.java b/src/main/java/org/cryptomator/ui/fxapp/AutoUnlocker.java index 719071ed2..65bc080ca 100644 --- a/src/main/java/org/cryptomator/ui/fxapp/AutoUnlocker.java +++ b/src/main/java/org/cryptomator/ui/fxapp/AutoUnlocker.java @@ -43,8 +43,8 @@ public class AutoUnlocker { private CompletionStage unlockSequentially(Stream vaultStream) { // this is an attempt to run all the unlock workflows sequentially, i.e. start the next workflow only after completing/failing the previous workflow. return vaultStream.filter(Vault::isLocked).reduce(CompletableFuture.completedFuture(null), - (prevUnlock, nextVault) -> prevUnlock.thenCompose(unused -> appWindows.startUnlockWorkflow(nextVault, null)), - (prevUnlock, nextUnlock) -> nextUnlock.exceptionally(e -> null) // we don't care here about the exception, logged elsewhere + (prevUnlock, nextVault) -> prevUnlock.thenCompose(_ -> appWindows.startUnlockWorkflow(nextVault, null)), + (_, nextUnlock) -> nextUnlock.exceptionally(_ -> null) // we don't care here about the exception, logged elsewhere ); } diff --git a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationWindows.java b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationWindows.java index 162874dce..c8a870fd8 100644 --- a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationWindows.java +++ b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationWindows.java @@ -6,6 +6,7 @@ import org.cryptomator.common.vaults.Vault; import org.cryptomator.common.vaults.VaultState; import org.cryptomator.integrations.tray.TrayIntegrationProvider; import org.cryptomator.ui.dialogs.Dialogs; +import org.cryptomator.ui.dialogs.SimpleDialog; import org.cryptomator.ui.error.ErrorComponent; import org.cryptomator.ui.eventview.EventViewComponent; import org.cryptomator.ui.lock.LockComponent; @@ -97,17 +98,17 @@ public class FxApplicationWindows { // register preferences shortcut if (desktop.isSupported(Desktop.Action.APP_PREFERENCES)) { - desktop.setPreferencesHandler(evt -> showPreferencesWindow(SelectedPreferencesTab.ANY)); + desktop.setPreferencesHandler(_ -> showPreferencesWindow(SelectedPreferencesTab.ANY)); } // register preferences shortcut if (desktop.isSupported(Desktop.Action.APP_ABOUT)) { - desktop.setAboutHandler(evt -> showPreferencesWindow(SelectedPreferencesTab.ABOUT)); + desktop.setAboutHandler(_ -> showPreferencesWindow(SelectedPreferencesTab.ABOUT)); } // register app reopen listener if (desktop.isSupported(Desktop.Action.APP_EVENT_REOPENED)) { - desktop.addAppEventListener((AppReopenedListener) e -> showMainWindow()); + desktop.addAppEventListener((AppReopenedListener) _ -> showMainWindow()); } // observe visible windows @@ -139,11 +140,12 @@ public class FxApplicationWindows { } public CompletionStage showVaultOptionsWindow(Vault vault, SelectedVaultOptionsTab tab) { - return showMainWindow().thenApplyAsync((window) -> vaultOptionsWindow.create(vault).showVaultOptionsWindow(tab), Platform::runLater).whenComplete(this::reportErrors); + return showMainWindow().thenApplyAsync(_ -> vaultOptionsWindow.create(vault).showVaultOptionsWindow(tab), Platform::runLater) // + .whenComplete(this::reportErrors); } public void showQuitWindow(QuitResponse response, boolean forced) { - CompletableFuture.runAsync(() -> quitWindowBuilder.build().showQuitWindow(response,forced), Platform::runLater); + CompletableFuture.runAsync(() -> quitWindowBuilder.build().showQuitWindow(response, forced), Platform::runLater); } public void showUpdateReminderWindow() { @@ -151,13 +153,14 @@ public class FxApplicationWindows { } public void showDokanySupportEndWindow() { - CompletableFuture.runAsync(() -> dialogs.prepareDokanySupportEndDialog( - mainWindow.get().window(), - stage -> { - showPreferencesWindow(SelectedPreferencesTab.VOLUME); - stage.close(); - } - ).build().showAndWait(), Platform::runLater); + CompletableFuture.runAsync(() -> createDokanySupportEndDialog().showAndWait(), Platform::runLater); + } + + private SimpleDialog createDokanySupportEndDialog() { + return dialogs.prepareDokanySupportEndDialog(mainWindow.get().window(), stage -> { + showPreferencesWindow(SelectedPreferencesTab.VOLUME); + stage.close(); + }).build(); } public CompletionStage startUnlockWorkflow(Vault vault, @Nullable Stage owner) { @@ -166,8 +169,7 @@ public class FxApplicationWindows { LOG.debug("Start unlock workflow for {}", vault.getDisplayName()); return unlockWorkflowFactory.create(vault, owner).unlockWorkflow(); }, Platform::runLater) // - .thenAcceptAsync(UnlockWorkflow::run, executor) - .exceptionally(e -> { + .thenAcceptAsync(UnlockWorkflow::run, executor).exceptionally(e -> { showErrorWindow(e, owner == null ? primaryStage : owner, null); return null; }); diff --git a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java index b80804f2e..fa1b441d9 100644 --- a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java +++ b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java @@ -1,6 +1,7 @@ package org.cryptomator.ui.mainwindow; import dagger.Binds; +import dagger.Lazy; import dagger.Module; import dagger.Provides; import dagger.multibindings.IntoMap; @@ -14,9 +15,11 @@ import org.cryptomator.ui.common.FxmlScene; import org.cryptomator.ui.common.StageFactory; import org.cryptomator.ui.common.StageInitializer; import org.cryptomator.ui.error.ErrorComponent; +import org.cryptomator.ui.fxapp.FxApplicationTerminator; import org.cryptomator.ui.fxapp.PrimaryStage; import org.cryptomator.ui.migration.MigrationComponent; import org.cryptomator.ui.stats.VaultStatisticsComponent; +import org.cryptomator.ui.traymenu.TrayMenuComponent; import org.cryptomator.ui.wrongfilealert.WrongFileAlertComponent; import javax.inject.Named; @@ -35,11 +38,19 @@ abstract class MainWindowModule { @Provides @MainWindow @MainWindowScoped - static Stage provideMainWindow(@PrimaryStage Stage stage, StageInitializer initializer) { + static Stage provideMainWindow(@PrimaryStage Stage stage, StageInitializer initializer, FxApplicationTerminator terminator, Lazy trayMenu) { initializer.accept(stage); stage.setTitle("Cryptomator"); stage.setMinWidth(650); stage.setMinHeight(498); + stage.setOnCloseRequest(e -> { + if (!trayMenu.get().isInitialized()) { + terminator.terminate(); + e.consume(); + } else { + stage.close(); + } + }); return stage; } diff --git a/src/main/java/org/cryptomator/ui/preferences/UpdatesPreferencesController.java b/src/main/java/org/cryptomator/ui/preferences/UpdatesPreferencesController.java index afa05cc8c..f5a72290f 100644 --- a/src/main/java/org/cryptomator/ui/preferences/UpdatesPreferencesController.java +++ b/src/main/java/org/cryptomator/ui/preferences/UpdatesPreferencesController.java @@ -19,6 +19,8 @@ import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; import javafx.scene.control.CheckBox; import javafx.scene.control.ContentDisplay; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; @@ -32,7 +34,10 @@ import java.util.ResourceBundle; @PreferencesScoped public class UpdatesPreferencesController implements FxController { - private static final String DOWNLOADS_URI = "https://cryptomator.org/downloads"; + private static final String DOWNLOADS_URI_TEMPLATE = "https://cryptomator.org/downloads/" // + + "?utm_source=cryptomator-desktop" // + + "&utm_medium=update-notification&" // + + "utm_campaign=app-update-%s"; private final Application application; private final Environment environment; @@ -50,6 +55,7 @@ public class UpdatesPreferencesController implements FxController { private final BooleanProperty upToDateLabelVisible = new SimpleBooleanProperty(false); private final DateTimeFormatter formatter; private final BooleanBinding upToDate; + private final String downloadsUri; /* FXML */ public CheckBox checkForUpdatesCheckbox; @@ -65,12 +71,13 @@ public class UpdatesPreferencesController implements FxController { this.latestVersion = updateChecker.latestVersionProperty(); this.lastSuccessfulUpdateCheck = updateChecker.lastSuccessfulUpdateCheckProperty(); this.timeDifferenceMessage = Bindings.createStringBinding(this::getTimeDifferenceMessage, lastSuccessfulUpdateCheck); - this.currentVersion = updateChecker.getCurrentVersion(); + this.currentVersion = environment.getAppVersion(); this.updateAvailable = updateChecker.updateAvailableProperty(); this.formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault()); this.upToDate = updateChecker.updateCheckStateProperty().isEqualTo(UpdateChecker.UpdateCheckState.CHECK_SUCCESSFUL).and(latestVersion.isEqualTo(currentVersion)); this.checkFailed = updateChecker.checkFailedProperty(); this.lastUpdateCheckMessage = Bindings.createStringBinding(this::getLastUpdateCheckMessage, lastSuccessfulUpdateCheck); + this.downloadsUri = DOWNLOADS_URI_TEMPLATE.formatted(URLEncoder.encode(currentVersion, StandardCharsets.US_ASCII)); } public void initialize() { @@ -93,7 +100,7 @@ public class UpdatesPreferencesController implements FxController { @FXML public void visitDownloadsPage() { - application.getHostServices().showDocument(DOWNLOADS_URI); + application.getHostServices().showDocument(downloadsUri); } @FXML