diff --git a/pom.xml b/pom.xml index 97d01b342..2d43aa712 100644 --- a/pom.xml +++ b/pom.xml @@ -299,6 +299,10 @@ org.apache.maven.plugins maven-surefire-plugin ${mvn-surefire.version} + + + @{argLine} -javaagent:${org.mockito:mockito-core:jar} + org.codehaus.mojo @@ -399,6 +403,12 @@ ${nonModularGroupIds} + + get-mockito-agent-path + + properties + + diff --git a/src/main/java/org/cryptomator/common/Environment.java b/src/main/java/org/cryptomator/common/Environment.java index 0f9396e3b..bc13aa30c 100644 --- a/src/main/java/org/cryptomator/common/Environment.java +++ b/src/main/java/org/cryptomator/common/Environment.java @@ -8,7 +8,6 @@ import org.slf4j.LoggerFactory; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Arrays; import java.util.Optional; import java.util.Set; @@ -166,7 +165,7 @@ public class Environment { private Optional getPath(String propertyName) { String value = System.getProperty(propertyName); - return Optional.ofNullable(value).map(Paths::get); + return Optional.ofNullable(value).map(Path::of); } @VisibleForTesting diff --git a/src/main/java/org/cryptomator/common/ErrorCode.java b/src/main/java/org/cryptomator/common/ErrorCode.java index d75ab97d0..169093104 100644 --- a/src/main/java/org/cryptomator/common/ErrorCode.java +++ b/src/main/java/org/cryptomator/common/ErrorCode.java @@ -77,7 +77,7 @@ public class ErrorCode { public static ErrorCode of(Throwable throwable) { var causalChain = Throwables.getCausalChain(throwable); if (causalChain.size() > 1) { - var rootCause = causalChain.get(causalChain.size() - 1); + var rootCause = causalChain.getLast(); var parentOfRootCause = causalChain.get(causalChain.size() - 2); var rootSpecificFrames = countTopmostFrames(rootCause.getStackTrace(), parentOfRootCause.getStackTrace()); return new ErrorCode(throwable, rootCause, rootSpecificFrames); diff --git a/src/main/java/org/cryptomator/common/SubstitutingProperties.java b/src/main/java/org/cryptomator/common/SubstitutingProperties.java index 3120abde8..4788bcba4 100644 --- a/src/main/java/org/cryptomator/common/SubstitutingProperties.java +++ b/src/main/java/org/cryptomator/common/SubstitutingProperties.java @@ -67,7 +67,7 @@ public class SubstitutingProperties extends PropertiesDecorator { private enum Source { ENV, - PROPS; + PROPS } } diff --git a/src/main/java/org/cryptomator/common/locationpresets/OneDriveWindowsLocationPresetsProvider.java b/src/main/java/org/cryptomator/common/locationpresets/OneDriveWindowsLocationPresetsProvider.java index 467d7785b..21ebef86b 100644 --- a/src/main/java/org/cryptomator/common/locationpresets/OneDriveWindowsLocationPresetsProvider.java +++ b/src/main/java/org/cryptomator/common/locationpresets/OneDriveWindowsLocationPresetsProvider.java @@ -8,9 +8,9 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Path; +import java.time.Duration; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -78,7 +78,7 @@ public final class OneDriveWindowsLocationPresetsProvider implements LocationPre */ @Blocking private static void waitForSuccess(Process process, int timeoutSeconds, String cmdDescription) throws TimeoutException, InterruptedException, CommandFailedException { - boolean exited = process.waitFor(timeoutSeconds, TimeUnit.SECONDS); + boolean exited = process.waitFor(Duration.ofSeconds(timeoutSeconds)); if (!exited) { throw new TimeoutException(cmdDescription + " timed out after " + timeoutSeconds + "s"); } diff --git a/src/main/java/org/cryptomator/common/mount/MountWithinParentUtil.java b/src/main/java/org/cryptomator/common/mount/MountWithinParentUtil.java index b436bc19a..75ba0eb48 100644 --- a/src/main/java/org/cryptomator/common/mount/MountWithinParentUtil.java +++ b/src/main/java/org/cryptomator/common/mount/MountWithinParentUtil.java @@ -90,7 +90,7 @@ public final class MountWithinParentUtil { EMPTY_DIR, - BROKEN_JUNCTION; + BROKEN_JUNCTION } diff --git a/src/main/java/org/cryptomator/common/settings/VaultSettings.java b/src/main/java/org/cryptomator/common/settings/VaultSettings.java index 5112415b4..507af0866 100644 --- a/src/main/java/org/cryptomator/common/settings/VaultSettings.java +++ b/src/main/java/org/cryptomator/common/settings/VaultSettings.java @@ -22,7 +22,6 @@ import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Objects; import java.util.Random; @@ -62,7 +61,7 @@ public class VaultSettings { VaultSettings(VaultSettingsJson json) { this.id = json.id; - this.path = new SimpleObjectProperty<>(this, "path", json.path == null ? null : Paths.get(json.path)); + this.path = new SimpleObjectProperty<>(this, "path", json.path == null ? null : Path.of(json.path)); this.displayName = new SimpleStringProperty(this, "displayName", json.displayName); this.unlockAfterStartup = new SimpleBooleanProperty(this, "unlockAfterStartup", json.unlockAfterStartup); this.revealAfterMount = new SimpleBooleanProperty(this, "revealAfterMount", json.revealAfterMount); diff --git a/src/main/java/org/cryptomator/common/vaults/Vault.java b/src/main/java/org/cryptomator/common/vaults/Vault.java index 64b763aeb..1a44dd3e4 100644 --- a/src/main/java/org/cryptomator/common/vaults/Vault.java +++ b/src/main/java/org/cryptomator/common/vaults/Vault.java @@ -47,7 +47,6 @@ import javafx.beans.property.ReadOnlyStringProperty; import javafx.beans.property.SimpleBooleanProperty; import java.io.IOException; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.ReadOnlyFileSystemException; import java.util.EnumSet; import java.util.Objects; @@ -58,7 +57,7 @@ import java.util.concurrent.atomic.AtomicReference; public class Vault { private static final Logger LOG = LoggerFactory.getLogger(Vault.class); - private static final Path HOME_DIR = Paths.get(SystemUtils.USER_HOME); + private static final Path HOME_DIR = Path.of(SystemUtils.USER_HOME); private static final int UNLIMITED_FILENAME_LENGTH = Integer.MAX_VALUE; private final VaultSettings vaultSettings; diff --git a/src/main/java/org/cryptomator/common/vaults/VaultState.java b/src/main/java/org/cryptomator/common/vaults/VaultState.java index f8b9b412a..5a6ea4108 100644 --- a/src/main/java/org/cryptomator/common/vaults/VaultState.java +++ b/src/main/java/org/cryptomator/common/vaults/VaultState.java @@ -58,7 +58,7 @@ public class VaultState extends ObservableValueBase implements /** * Unknown state due to preceding unrecoverable exceptions. */ - ERROR; + ERROR } private final AtomicReference value; diff --git a/src/main/java/org/cryptomator/launcher/SupportedLanguages.java b/src/main/java/org/cryptomator/launcher/SupportedLanguages.java index 53136e59b..080e433df 100644 --- a/src/main/java/org/cryptomator/launcher/SupportedLanguages.java +++ b/src/main/java/org/cryptomator/launcher/SupportedLanguages.java @@ -34,7 +34,7 @@ public class SupportedLanguages { var collator = Collator.getInstance(preferredLocale); collator.setStrength(Collator.PRIMARY); var sorted = new ArrayList(); - sorted.add(0, null); + sorted.addFirst(null); sorted.add(1, ENGLISH); LANGUAGE_TAGS.stream() // .sorted((a, b) -> collator.compare(Locale.forLanguageTag(a).getDisplayName(), Locale.forLanguageTag(b).getDisplayName())) // diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java index 78a2771df..77f977335 100644 --- a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java +++ b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java @@ -41,7 +41,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Optional; import java.util.ResourceBundle; import java.util.concurrent.ExecutorService; @@ -50,7 +49,7 @@ import java.util.concurrent.ExecutorService; public class CreateNewVaultLocationController implements FxController { private static final Logger LOG = LoggerFactory.getLogger(CreateNewVaultLocationController.class); - private static final Path DEFAULT_CUSTOM_VAULT_PATH = Paths.get(System.getProperty("user.home")); + private static final Path DEFAULT_CUSTOM_VAULT_PATH = Path.of(System.getProperty("user.home")); private static final String TEMP_FILE_PREFIX = ".locationTest.cryptomator"; private final Stage window; diff --git a/src/main/java/org/cryptomator/ui/common/SystemBarUtil.java b/src/main/java/org/cryptomator/ui/common/SystemBarUtil.java index 9faaa60db..a4f74cf47 100644 --- a/src/main/java/org/cryptomator/ui/common/SystemBarUtil.java +++ b/src/main/java/org/cryptomator/ui/common/SystemBarUtil.java @@ -23,7 +23,7 @@ public class SystemBarUtil { /** * OS Bar placed at the bottom screen edge */ - BOTTOM; + BOTTOM } /** diff --git a/src/main/java/org/cryptomator/ui/health/Check.java b/src/main/java/org/cryptomator/ui/health/Check.java index 52bee578c..ff2c18630 100644 --- a/src/main/java/org/cryptomator/ui/health/Check.java +++ b/src/main/java/org/cryptomator/ui/health/Check.java @@ -90,7 +90,7 @@ public class Check { SUCCEEDED, SKIPPED, ERROR, - CANCELLED; + CANCELLED } ObservableList getResults() { diff --git a/src/main/java/org/cryptomator/ui/health/CheckListController.java b/src/main/java/org/cryptomator/ui/health/CheckListController.java index 22ec37b48..e1656f485 100644 --- a/src/main/java/org/cryptomator/ui/health/CheckListController.java +++ b/src/main/java/org/cryptomator/ui/health/CheckListController.java @@ -84,7 +84,7 @@ public class CheckListController implements FxController { checks.filtered(c -> !c.isChosenForExecution()).forEach(c -> c.setState(Check.CheckState.SKIPPED)); checkExecutor.executeBatch(chosenChecks); - checksListView.getSelectionModel().select(chosenChecks.get(0)); + checksListView.getSelectionModel().select(chosenChecks.getFirst()); checksListView.refresh(); window.sizeToScene(); } diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/CheckHostTrustController.java b/src/main/java/org/cryptomator/ui/keyloading/hub/CheckHostTrustController.java index 18bdbfead..aa5ce3c1e 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/CheckHostTrustController.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/CheckHostTrustController.java @@ -6,6 +6,8 @@ import org.cryptomator.common.settings.Settings; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.controls.FontAwesome5Icon; +import org.cryptomator.ui.controls.FontAwesome5IconView; import org.cryptomator.ui.keyloading.KeyLoading; import org.cryptomator.ui.keyloading.KeyLoadingScoped; import org.jetbrains.annotations.VisibleForTesting; @@ -13,14 +15,24 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; +import javafx.animation.PauseTransition; import javafx.application.Platform; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.fxml.FXML; +import javafx.geometry.Pos; +import javafx.scene.Node; import javafx.scene.Scene; -import javafx.scene.text.Text; -import javafx.scene.text.TextFlow; +import javafx.scene.control.Hyperlink; +import javafx.scene.control.Label; +import javafx.scene.control.Tooltip; +import javafx.scene.input.Clipboard; +import javafx.scene.input.ClipboardContent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; import javafx.stage.Stage; +import javafx.util.Duration; import java.net.URI; import java.util.ResourceBundle; import java.util.Set; @@ -35,7 +47,11 @@ public class CheckHostTrustController implements FxController { private static final String CHECK_KEY = "hub.checkHostTrust.message.check"; private static final String ASK_SINGULAR_KEY = "hub.checkHostTrust.message.ask"; private static final String ASK_PLURAL_KEY = "hub.checkHostTrust.message.ask.plural"; + private static final String DESCRIPTION_SINGULAR_KEY = "hub.checkHostTrust.description.ask"; + private static final String DESCRIPTION_PLURAL_KEY = "hub.checkHostTrust.description.ask.plural"; + private static final String COPY_TOOLTIP_KEY = "hub.checkHostTrust.copyBtn.tooltip"; private static final String TRUSTED_CRYPTOMATOR_CLOUD_DOMAIN = ".cryptomator.cloud"; + private static final Duration COPIED_INDICATION_DURATION = Duration.seconds(2); private final Stage window; private final HubConfig hubConfig; @@ -49,9 +65,10 @@ public class CheckHostTrustController implements FxController { private final ResourceBundle resourceBundle; private final SortedSet hostnames; private final StringProperty messageLabel; + private final StringProperty descriptionLabel; @FXML - private TextFlow hostnamesFlow; + private VBox hostnamesBox; @Inject public CheckHostTrustController(@KeyLoading Stage window, // @@ -74,6 +91,7 @@ public class CheckHostTrustController implements FxController { this.resourceBundle = resourceBundle; this.hostnames = new TreeSet<>(); this.messageLabel = new SimpleStringProperty(resourceBundle.getString(CHECK_KEY)); + this.descriptionLabel = new SimpleStringProperty(""); } @FXML @@ -117,12 +135,41 @@ public class CheckHostTrustController implements FxController { } private void renderHostnames() { - hostnamesFlow.getChildren().clear(); + hostnamesBox.getChildren().clear(); for (var hostname : hostnames) { - hostnamesFlow.getChildren().add(new Text(hostname + System.lineSeparator())); + hostnamesBox.getChildren().add(createHostnameRow(hostname)); } - var messageKey = hostnames.size() > 1 ? ASK_PLURAL_KEY : ASK_SINGULAR_KEY; - messageLabel.set(resourceBundle.getString(messageKey)); + var plural = hostnames.size() > 1; + messageLabel.set(resourceBundle.getString(plural ? ASK_PLURAL_KEY : ASK_SINGULAR_KEY)); + descriptionLabel.set(resourceBundle.getString(plural ? DESCRIPTION_PLURAL_KEY : DESCRIPTION_SINGULAR_KEY)); + } + + private Node createHostnameRow(String hostname) { + var label = new Label(hostname); + label.setWrapText(true); + HBox.setHgrow(label, Priority.ALWAYS); + + var icon = new FontAwesome5IconView(); + icon.setGlyph(FontAwesome5Icon.COPY); + var copyLink = new Hyperlink(null, icon); + copyLink.setTooltip(new Tooltip(resourceBundle.getString(COPY_TOOLTIP_KEY))); + copyLink.setAccessibleText(resourceBundle.getString(COPY_TOOLTIP_KEY)); + copyLink.setOnAction(_ -> copyToClipboard(hostname, icon)); + + var row = new HBox(6, label, copyLink); + row.setAlignment(Pos.CENTER_LEFT); + return row; + } + + private void copyToClipboard(String hostname, FontAwesome5IconView icon) { + var clipboardContent = new ClipboardContent(); + clipboardContent.putString(hostname); + Clipboard.getSystemClipboard().setContent(clipboardContent); + + icon.setGlyph(FontAwesome5Icon.CHECK); + var resetIcon = new PauseTransition(COPIED_INDICATION_DURATION); + resetIcon.setOnFinished(_ -> icon.setGlyph(FontAwesome5Icon.COPY)); + resetIcon.play(); } private boolean isConsistentHubConfig() { @@ -176,4 +223,12 @@ public class CheckHostTrustController implements FxController { return messageLabel.get(); } + public StringProperty descriptionLabelProperty() { + return descriptionLabel; + } + + public String getDescriptionLabel() { + return descriptionLabel.get(); + } + } diff --git a/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java b/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java index 2c28d0fb1..84eac0f37 100644 --- a/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java +++ b/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java @@ -153,7 +153,7 @@ public class VaultListController implements FxController { vaults.addListener((ListChangeListener.Change c) -> { while (c.next()) { if (c.wasAdded()) { - Vault anyAddedVault = c.getAddedSubList().get(0); + Vault anyAddedVault = c.getAddedSubList().getFirst(); vaultList.getSelectionModel().select(anyAddedVault); } } diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java index 35f4c15ed..ed1c8535a 100644 --- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java +++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java @@ -217,7 +217,7 @@ public class RecoveryKeyValidateController implements FxController { /** * Recovery key is not a valid key. */ - INVALID; + INVALID } } diff --git a/src/main/java/org/cryptomator/ui/stats/VaultStatisticsController.java b/src/main/java/org/cryptomator/ui/stats/VaultStatisticsController.java index dd294a457..6e3a41ae4 100644 --- a/src/main/java/org/cryptomator/ui/stats/VaultStatisticsController.java +++ b/src/main/java/org/cryptomator/ui/stats/VaultStatisticsController.java @@ -140,9 +140,9 @@ public class VaultStatisticsController implements FxController { long allTimeMaxAccessedFiles = Arrays.stream(maxAccessBuf).max().orElse(0L); // remove oldest value: - decryptedBytesRead.getData().remove(0); - encryptedBytesWrite.getData().remove(0); - accessedFiles.getData().remove(0); + decryptedBytesRead.getData().removeFirst(); + encryptedBytesWrite.getData().removeFirst(); + accessedFiles.getData().removeFirst(); // add latest value: decryptedBytesRead.getData().add(new Data<>(currentStep, decBytes)); diff --git a/src/main/java/org/cryptomator/ui/unlock/UnlockInvalidMountPointController.java b/src/main/java/org/cryptomator/ui/unlock/UnlockInvalidMountPointController.java index 53c358038..eb8e6e4f8 100644 --- a/src/main/java/org/cryptomator/ui/unlock/UnlockInvalidMountPointController.java +++ b/src/main/java/org/cryptomator/ui/unlock/UnlockInvalidMountPointController.java @@ -110,7 +110,7 @@ public class UnlockInvalidMountPointController implements FxController { //TODO Add option to show filesystem, e.g. for ExceptionType.HIDEAWAY_EXISTS SHOW_PREFERENCES, - SHOW_VAULT_OPTIONS; + SHOW_VAULT_OPTIONS } diff --git a/src/main/resources/css/AtkinsonHyperlegibleMono-Regular.ttf b/src/main/resources/css/AtkinsonHyperlegibleMono-Regular.ttf new file mode 100644 index 000000000..157d62eab Binary files /dev/null and b/src/main/resources/css/AtkinsonHyperlegibleMono-Regular.ttf differ diff --git a/src/main/resources/css/dark_theme.css b/src/main/resources/css/dark_theme.css index bb23af18c..f4416282c 100644 --- a/src/main/resources/css/dark_theme.css +++ b/src/main/resources/css/dark_theme.css @@ -20,6 +20,10 @@ src: url('firacode_regular.ttf'); } +@font-face { + src: url('AtkinsonHyperlegibleMono-Regular.ttf'); +} + /******************************************************************************* * * * Root Styling & Colors * @@ -141,6 +145,17 @@ -fx-font-size: 1.1em; } +.hostname-list { + -fx-background-color: CONTROL_BORDER_NORMAL, CONTROL_BG_NORMAL; + -fx-background-insets: 0, 1px; + -fx-background-radius: 4px; + -fx-padding: 6px 8px 6px 8px; +} + +.hostname-list .label { + -fx-font-family: 'Atkinson Hyperlegible Mono'; +} + /******************************************************************************* * * * Glyph Icons * diff --git a/src/main/resources/css/light_theme.css b/src/main/resources/css/light_theme.css index dcbee907f..68e2a099e 100644 --- a/src/main/resources/css/light_theme.css +++ b/src/main/resources/css/light_theme.css @@ -20,6 +20,10 @@ src: url('firacode_regular.ttf'); } +@font-face { + src: url('AtkinsonHyperlegibleMono-Regular.ttf'); +} + /******************************************************************************* * * * Root Styling & Colors * @@ -141,6 +145,17 @@ -fx-font-size: 1.1em; } +.hostname-list { + -fx-background-color: CONTROL_BORDER_NORMAL, CONTROL_BG_NORMAL; + -fx-background-insets: 0, 1px; + -fx-background-radius: 4px; + -fx-padding: 6px 8px 6px 8px; +} + +.hostname-list .label { + -fx-font-family: 'Atkinson Hyperlegible Mono'; +} + /******************************************************************************* * * * Glyph Icons * diff --git a/src/main/resources/fxml/hub_check_host_trust.fxml b/src/main/resources/fxml/hub_check_host_trust.fxml index e93936a93..d124948e2 100644 --- a/src/main/resources/fxml/hub_check_host_trust.fxml +++ b/src/main/resources/fxml/hub_check_host_trust.fxml @@ -11,12 +11,11 @@ - - + - +