mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-20 11:41:26 +00:00
Merge branch 'develop' into feature/modular
# Conflicts: # pom.xml # src/main/resources/license/THIRD-PARTY.txt
This commit is contained in:
@@ -23,11 +23,10 @@ module org.cryptomator.desktop {
|
||||
requires org.slf4j;
|
||||
requires org.apache.commons.lang3;
|
||||
requires dagger;
|
||||
requires com.auth0.jwt;
|
||||
|
||||
/* TODO: filename-based modules: */
|
||||
requires static javax.inject; /* ugly dagger/guava crap */
|
||||
requires java.jwt;
|
||||
requires com.fasterxml.jackson.databind; // TODO: tmp fix, waiting for https://github.com/auth0/java-jwt/pull/484
|
||||
requires logback.classic;
|
||||
requires logback.core;
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ public abstract class CommonsModule {
|
||||
private static final int NUM_CORE_BG_THREADS = 6;
|
||||
private static final long BG_THREAD_KEEPALIVE_SECONDS = 60l;
|
||||
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("licensePublicKey")
|
||||
|
||||
@@ -123,8 +123,8 @@ public class Environment {
|
||||
return Stream.empty();
|
||||
} else {
|
||||
Iterable<String> iter = Splitter.on(separator).split(value);
|
||||
Spliterator<String> spliter = Spliterators.spliteratorUnknownSize(iter.iterator(), Spliterator.ORDERED | Spliterator.IMMUTABLE);
|
||||
return StreamSupport.stream(spliter, false);
|
||||
Spliterator<String> spliterator = Spliterators.spliteratorUnknownSize(iter.iterator(), Spliterator.ORDERED | Spliterator.IMMUTABLE);
|
||||
return StreamSupport.stream(spliterator, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,17 +60,17 @@ public class SemVerComparator implements Comparator<String> {
|
||||
final int commonCompCount = Math.min(vComps1.length, vComps2.length);
|
||||
|
||||
for (int i = 0; i < commonCompCount; i++) {
|
||||
int subversionComparisionResult = 0;
|
||||
int subversionComparisonResult = 0;
|
||||
try {
|
||||
final int v1 = Integer.parseInt(vComps1[i]);
|
||||
final int v2 = Integer.parseInt(vComps2[i]);
|
||||
subversionComparisionResult = v1 - v2;
|
||||
subversionComparisonResult = v1 - v2;
|
||||
} catch (NumberFormatException ex) {
|
||||
// ok, lets compare this fragment lexicographically
|
||||
subversionComparisionResult = vComps1[i].compareTo(vComps2[i]);
|
||||
subversionComparisonResult = vComps1[i].compareTo(vComps2[i]);
|
||||
}
|
||||
if (subversionComparisionResult != 0) {
|
||||
return subversionComparisionResult;
|
||||
if (subversionComparisonResult != 0) {
|
||||
return subversionComparisonResult;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public class Settings {
|
||||
public static final int MIN_PORT = 1024;
|
||||
public static final int MAX_PORT = 65535;
|
||||
public static final boolean DEFAULT_ASKED_FOR_UPDATE_CHECK = false;
|
||||
public static final boolean DEFAULT_CHECK_FOR_UDPATES = false;
|
||||
public static final boolean DEFAULT_CHECK_FOR_UPDATES = false;
|
||||
public static final boolean DEFAULT_START_HIDDEN = false;
|
||||
public static final int DEFAULT_PORT = 42427;
|
||||
public static final int DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
|
||||
@@ -46,7 +46,7 @@ public class Settings {
|
||||
|
||||
private final ObservableList<VaultSettings> directories = FXCollections.observableArrayList(VaultSettings::observables);
|
||||
private final BooleanProperty askedForUpdateCheck = new SimpleBooleanProperty(DEFAULT_ASKED_FOR_UPDATE_CHECK);
|
||||
private final BooleanProperty checkForUpdates = new SimpleBooleanProperty(DEFAULT_CHECK_FOR_UDPATES);
|
||||
private final BooleanProperty checkForUpdates = new SimpleBooleanProperty(DEFAULT_CHECK_FOR_UPDATES);
|
||||
private final BooleanProperty startHidden = new SimpleBooleanProperty(DEFAULT_START_HIDDEN);
|
||||
private final IntegerProperty port = new SimpleIntegerProperty(DEFAULT_PORT);
|
||||
private final IntegerProperty numTrayNotifications = new SimpleIntegerProperty(DEFAULT_NUM_TRAY_NOTIFICATIONS);
|
||||
|
||||
@@ -101,7 +101,7 @@ public class SettingsProvider implements Supplier<Settings> {
|
||||
if (settings == null) {
|
||||
return;
|
||||
}
|
||||
final Optional<Path> settingsPath = env.getSettingsPath().findFirst(); // alway save to preferred (first) path
|
||||
final Optional<Path> settingsPath = env.getSettingsPath().findFirst(); // always save to preferred (first) path
|
||||
settingsPath.ifPresent(path -> {
|
||||
Runnable saveCommand = () -> this.save(settings, path);
|
||||
ScheduledFuture<?> scheduledTask = scheduler.schedule(saveCommand, SAVE_DELAY_MS, TimeUnit.MILLISECONDS);
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.util.Random;
|
||||
public class VaultSettings {
|
||||
|
||||
public static final boolean DEFAULT_UNLOCK_AFTER_STARTUP = false;
|
||||
public static final boolean DEFAULT_REAVEAL_AFTER_MOUNT = true;
|
||||
public static final boolean DEFAULT_REVEAL_AFTER_MOUNT = true;
|
||||
public static final boolean DEFAULT_USES_INDIVIDUAL_MOUNTPATH = false;
|
||||
public static final boolean DEFAULT_USES_READONLY_MODE = false;
|
||||
public static final String DEFAULT_MOUNT_FLAGS = "";
|
||||
@@ -47,7 +47,7 @@ public class VaultSettings {
|
||||
private final StringProperty displayName = new SimpleStringProperty();
|
||||
private final StringProperty winDriveLetter = new SimpleStringProperty();
|
||||
private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP);
|
||||
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REAVEAL_AFTER_MOUNT);
|
||||
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REVEAL_AFTER_MOUNT);
|
||||
private final BooleanProperty useCustomMountPath = new SimpleBooleanProperty(DEFAULT_USES_INDIVIDUAL_MOUNTPATH);
|
||||
private final StringProperty customMountPath = new SimpleStringProperty();
|
||||
private final BooleanProperty usesReadOnlyMode = new SimpleBooleanProperty(DEFAULT_USES_READONLY_MODE);
|
||||
|
||||
@@ -44,7 +44,7 @@ class VaultSettingsJsonAdapter {
|
||||
String customMountPath = null;
|
||||
String winDriveLetter = null;
|
||||
boolean unlockAfterStartup = VaultSettings.DEFAULT_UNLOCK_AFTER_STARTUP;
|
||||
boolean revealAfterMount = VaultSettings.DEFAULT_REAVEAL_AFTER_MOUNT;
|
||||
boolean revealAfterMount = VaultSettings.DEFAULT_REVEAL_AFTER_MOUNT;
|
||||
boolean useCustomMountPath = VaultSettings.DEFAULT_USES_INDIVIDUAL_MOUNTPATH;
|
||||
boolean usesReadOnlyMode = VaultSettings.DEFAULT_USES_READONLY_MODE;
|
||||
String mountFlags = VaultSettings.DEFAULT_MOUNT_FLAGS;
|
||||
|
||||
@@ -138,7 +138,7 @@ public class VaultModule {
|
||||
|
||||
// see https://github.com/billziss-gh/winfsp/blob/5d0b10d0b643652c00ebb4704dc2bb28e7244973/src/dll/fuse/fuse_main.c#L53-L62 for syntax guide
|
||||
// see https://github.com/billziss-gh/winfsp/blob/5d0b10d0b643652c00ebb4704dc2bb28e7244973/src/dll/fuse/fuse.c#L295-L319 for options (-o <...>)
|
||||
// see https://github.com/billziss-gh/winfsp/wiki/Frequently-Asked-Questions/5ba00e4be4f5e938eaae6ef1500b331de12dee77 (FUSE 4.) on why the given defaults were choosen
|
||||
// see https://github.com/billziss-gh/winfsp/wiki/Frequently-Asked-Questions/5ba00e4be4f5e938eaae6ef1500b331de12dee77 (FUSE 4.) on why the given defaults were chosen
|
||||
private String getWindowsFuseDefaultMountFlags(StringBinding mountName, ReadOnlyBooleanProperty readOnly) {
|
||||
assert SystemUtils.IS_OS_WINDOWS;
|
||||
StringBuilder flags = new StringBuilder();
|
||||
|
||||
@@ -46,7 +46,7 @@ public class VaultState extends ObservableValueBase<VaultState.Value> implements
|
||||
UNLOCKED,
|
||||
|
||||
/**
|
||||
* Unknown state due to preceeding unrecoverable exceptions.
|
||||
* Unknown state due to preceding unrecoverable exceptions.
|
||||
*/
|
||||
ERROR;
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ public class VaultStats {
|
||||
private final LongProperty bytesPerSecondEncrypted = new SimpleLongProperty();
|
||||
private final LongProperty bytesPerSecondDecrypted = new SimpleLongProperty();
|
||||
private final DoubleProperty cacheHitRate = new SimpleDoubleProperty();
|
||||
private final LongProperty toalBytesRead = new SimpleLongProperty();
|
||||
private final LongProperty toalBytesWritten = new SimpleLongProperty();
|
||||
private final LongProperty totalBytesRead = new SimpleLongProperty();
|
||||
private final LongProperty totalBytesWritten = new SimpleLongProperty();
|
||||
private final LongProperty totalBytesEncrypted = new SimpleLongProperty();
|
||||
private final LongProperty totalBytesDecrypted = new SimpleLongProperty();
|
||||
private final LongProperty filesRead = new SimpleLongProperty();
|
||||
@@ -75,8 +75,8 @@ public class VaultStats {
|
||||
cacheHitRate.set(stats.map(this::getCacheHitRate).orElse(0.0));
|
||||
bytesPerSecondDecrypted.set(stats.map(CryptoFileSystemStats::pollBytesDecrypted).orElse(0L));
|
||||
bytesPerSecondEncrypted.set(stats.map(CryptoFileSystemStats::pollBytesEncrypted).orElse(0L));
|
||||
toalBytesRead.set(stats.map(CryptoFileSystemStats::pollTotalBytesRead).orElse(0L));
|
||||
toalBytesWritten.set(stats.map(CryptoFileSystemStats::pollTotalBytesWritten).orElse(0L));
|
||||
totalBytesRead.set(stats.map(CryptoFileSystemStats::pollTotalBytesRead).orElse(0L));
|
||||
totalBytesWritten.set(stats.map(CryptoFileSystemStats::pollTotalBytesWritten).orElse(0L));
|
||||
totalBytesEncrypted.set(stats.map(CryptoFileSystemStats::pollTotalBytesEncrypted).orElse(0L));
|
||||
totalBytesDecrypted.set(stats.map(CryptoFileSystemStats::pollTotalBytesDecrypted).orElse(0L));
|
||||
var oldAccessCount = filesRead.get() + filesWritten.get();
|
||||
@@ -146,7 +146,7 @@ public class VaultStats {
|
||||
return bytesPerSecondEncrypted;
|
||||
}
|
||||
|
||||
public long getBytesPerSecondEnrypted() {
|
||||
public long getBytesPerSecondEncrypted() {
|
||||
return bytesPerSecondEncrypted.get();
|
||||
}
|
||||
|
||||
@@ -164,13 +164,13 @@ public class VaultStats {
|
||||
return cacheHitRate.get();
|
||||
}
|
||||
|
||||
public LongProperty toalBytesReadProperty() {return toalBytesRead;}
|
||||
public LongProperty totalBytesReadProperty() {return totalBytesRead;}
|
||||
|
||||
public long getTotalBytesRead() { return toalBytesRead.get();}
|
||||
public long getTotalBytesRead() { return totalBytesRead.get();}
|
||||
|
||||
public LongProperty toalBytesWrittenProperty() {return toalBytesWritten;}
|
||||
public LongProperty totalBytesWrittenProperty() {return totalBytesWritten;}
|
||||
|
||||
public long getTotalBytesWritten() { return toalBytesWritten.get();}
|
||||
public long getTotalBytesWritten() { return totalBytesWritten.get();}
|
||||
|
||||
public LongProperty totalBytesEncryptedProperty() {return totalBytesEncrypted;}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Takes a Volume and usess it to mount an unlocked vault
|
||||
* Takes a Volume and uses it to mount an unlocked vault
|
||||
*/
|
||||
public interface Volume {
|
||||
|
||||
@@ -24,7 +24,7 @@ public interface Volume {
|
||||
boolean isSupported();
|
||||
|
||||
/**
|
||||
* Gets the coresponding enum type of the {@link VolumeImpl volume implementation ("VolumeImpl")} that is implemented by this Volume.
|
||||
* Gets the corresponding enum type of the {@link VolumeImpl volume implementation ("VolumeImpl")} that is implemented by this Volume.
|
||||
*
|
||||
* @return the type of implementation as defined by the {@link VolumeImpl VolumeImpl enum}
|
||||
*/
|
||||
|
||||
@@ -67,7 +67,7 @@ public class WebDavVolume implements Volume {
|
||||
throw new IllegalStateException("Mounting requires unlocked WebDAV servlet.");
|
||||
}
|
||||
|
||||
//on windows, prevent an automatic drive letter selection in the upstream library. Either we choose already a specifc one or there is no free.
|
||||
//on windows, prevent an automatic drive letter selection in the upstream library. Either we choose already a specific one or there is no free.
|
||||
Supplier<String> driveLetterSupplier;
|
||||
if (System.getProperty("os.name").toLowerCase().contains("windows") && vaultSettings.winDriveLetter().isEmpty().get()) {
|
||||
driveLetterSupplier = () -> windowsDriveLetters.getAvailableDriveLetter().orElse(null);
|
||||
|
||||
@@ -11,12 +11,12 @@ import java.io.File;
|
||||
*
|
||||
* @param <E> Event type the policy possibly reacts to
|
||||
*/
|
||||
public class LaunchAndSizeBasedTriggerinPolicy<E> extends TriggeringPolicyBase<E> {
|
||||
public class LaunchAndSizeBasedTriggeringPolicy<E> extends TriggeringPolicyBase<E> {
|
||||
|
||||
LaunchBasedTriggeringPolicy<E> launchBasedTriggeringPolicy;
|
||||
SizeBasedTriggeringPolicy<E> sizeBasedTriggeringPolicy;
|
||||
|
||||
public LaunchAndSizeBasedTriggerinPolicy(FileSize threshold) {
|
||||
public LaunchAndSizeBasedTriggeringPolicy(FileSize threshold) {
|
||||
this.launchBasedTriggeringPolicy = new LaunchBasedTriggeringPolicy<>();
|
||||
this.sizeBasedTriggeringPolicy = new SizeBasedTriggeringPolicy<>();
|
||||
sizeBasedTriggeringPolicy.setMaxFileSize(threshold);
|
||||
@@ -85,7 +85,7 @@ public class LoggerModule {
|
||||
appender.setContext(context);
|
||||
appender.setFile(logDir.resolve(LOGFILE_NAME).toString());
|
||||
appender.setEncoder(encoder);
|
||||
LaunchAndSizeBasedTriggerinPolicy triggeringPolicy = new LaunchAndSizeBasedTriggerinPolicy(FileSize.valueOf(LOG_MAX_SIZE));
|
||||
LaunchAndSizeBasedTriggeringPolicy triggeringPolicy = new LaunchAndSizeBasedTriggeringPolicy(FileSize.valueOf(LOG_MAX_SIZE));
|
||||
triggeringPolicy.setContext(context);
|
||||
triggeringPolicy.start();
|
||||
appender.setTriggeringPolicy(triggeringPolicy);
|
||||
|
||||
@@ -62,8 +62,8 @@ public class FxmlLoaderFactory {
|
||||
}
|
||||
Parent root = loader.getRoot();
|
||||
// TODO: discuss if we can remove language-specific stylesheets
|
||||
// List<String> addtionalStyleSheets = Splitter.on(',').omitEmptyStrings().splitToList(resourceBundle.getString("additionalStyleSheets"));
|
||||
// addtionalStyleSheets.forEach(styleSheet -> root.getStylesheets().add("/css/" + styleSheet));
|
||||
// List<String> additionalStyleSheets = Splitter.on(',').omitEmptyStrings().splitToList(resourceBundle.getString("additionalStyleSheets"));
|
||||
// additionalStyleSheets.forEach(styleSheet -> root.getStylesheets().add("/css/" + styleSheet));
|
||||
return sceneFactory.apply(root);
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ public final class WeakBindings {
|
||||
* @param observable The observable
|
||||
* @return a IntegerBinding weakly referenced from the given observable
|
||||
*/
|
||||
public static IntegerBinding bindInterger(ObservableValue<Number> observable) {
|
||||
public static IntegerBinding bindInteger(ObservableValue<Number> observable) {
|
||||
return new IntegerBinding() {
|
||||
{
|
||||
bind(observable);
|
||||
|
||||
@@ -12,8 +12,8 @@ import javafx.scene.layout.StackPane;
|
||||
public class NiceSecurePasswordField extends StackPane {
|
||||
|
||||
private static final String STYLE_CLASS = "nice-secure-password-field";
|
||||
private static final String ICONS_STLYE_CLASS = "icons";
|
||||
private static final String REVEAL_BUTTON_STLYE_CLASS = "reveal-button";
|
||||
private static final String ICONS_STYLE_CLASS = "icons";
|
||||
private static final String REVEAL_BUTTON_STYLE_CLASS = "reveal-button";
|
||||
private static final int ICON_SPACING = 6;
|
||||
private static final double ICON_SIZE = 14.0;
|
||||
|
||||
@@ -30,7 +30,7 @@ public class NiceSecurePasswordField extends StackPane {
|
||||
iconContainer.setAlignment(Pos.CENTER_RIGHT);
|
||||
iconContainer.setMaxWidth(Double.NEGATIVE_INFINITY);
|
||||
iconContainer.setPrefWidth(42); // TODO
|
||||
iconContainer.getStyleClass().add(ICONS_STLYE_CLASS);
|
||||
iconContainer.getStyleClass().add(ICONS_STYLE_CLASS);
|
||||
StackPane.setAlignment(iconContainer, Pos.CENTER_RIGHT);
|
||||
|
||||
capsLockedIcon.setGlyph(FontAwesome5Icon.ARROW_UP);
|
||||
@@ -51,7 +51,7 @@ public class NiceSecurePasswordField extends StackPane {
|
||||
revealPasswordButton.setFocusTraversable(false);
|
||||
revealPasswordButton.visibleProperty().bind(passwordField.focusedProperty());
|
||||
revealPasswordButton.managedProperty().bind(passwordField.focusedProperty());
|
||||
revealPasswordButton.getStyleClass().add(REVEAL_BUTTON_STLYE_CLASS);
|
||||
revealPasswordButton.getStyleClass().add(REVEAL_BUTTON_STYLE_CLASS);
|
||||
|
||||
passwordField.revealPasswordProperty().bind(revealPasswordButton.selectedProperty());
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.scene.control.Label;
|
||||
|
||||
public class ThrougputLabel extends Label {
|
||||
public class ThroughputLabel extends Label {
|
||||
|
||||
private static final long KIBS_THRESHOLD = 1l << 7; // 0.128 kiB/s
|
||||
private static final long MIBS_THRESHOLD = 1l << 19; // 0.512 MiB/s
|
||||
@@ -18,7 +18,7 @@ public class ThrougputLabel extends Label {
|
||||
private final StringProperty mibsFormat = new SimpleStringProperty("%.3f");
|
||||
private final LongProperty bytesPerSecond = new SimpleLongProperty();
|
||||
|
||||
public ThrougputLabel() {
|
||||
public ThroughputLabel() {
|
||||
textProperty().bind(createStringBinding());
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ import javafx.collections.FXCollections;
|
||||
import javafx.concurrent.Worker;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.ListView;
|
||||
import java.time.Duration;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -24,8 +26,7 @@ public class CheckDetailController implements FxController {
|
||||
private final EasyObservableList<DiagnosticResult> results;
|
||||
private final OptionalBinding<Worker.State> taskState;
|
||||
private final Binding<String> taskName;
|
||||
private final Binding<Number> taskDuration;
|
||||
private final ResultListCellFactory resultListCellFactory;
|
||||
private final Binding<String> taskDuration;
|
||||
private final Binding<Boolean> taskRunning;
|
||||
private final Binding<Boolean> taskScheduled;
|
||||
private final Binding<Boolean> taskFinished;
|
||||
@@ -35,17 +36,20 @@ public class CheckDetailController implements FxController {
|
||||
private final Binding<Boolean> taskCancelled;
|
||||
private final Binding<Number> countOfWarnSeverity;
|
||||
private final Binding<Number> countOfCritSeverity;
|
||||
private final ResultListCellFactory resultListCellFactory;
|
||||
private final ResourceBundle resourceBundle;
|
||||
|
||||
public ListView<DiagnosticResult> resultsListView;
|
||||
private Subscription resultSubscription;
|
||||
|
||||
@Inject
|
||||
public CheckDetailController(ObjectProperty<HealthCheckTask> selectedTask, ResultListCellFactory resultListCellFactory) {
|
||||
public CheckDetailController(ObjectProperty<HealthCheckTask> selectedTask, ResultListCellFactory resultListCellFactory, ResourceBundle resourceBundle) {
|
||||
this.resultListCellFactory = resultListCellFactory;
|
||||
this.resourceBundle = resourceBundle;
|
||||
this.results = EasyBind.wrapList(FXCollections.observableArrayList());
|
||||
this.taskState = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::stateProperty);
|
||||
this.taskName = EasyBind.wrapNullable(selectedTask).map(HealthCheckTask::getTitle).orElse("");
|
||||
this.taskDuration = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::durationInMillisProperty).orElse(-1L);
|
||||
this.resultListCellFactory = resultListCellFactory;
|
||||
this.taskDuration = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::durationInMillisProperty).orElse(-1L).map(this::millisToReadAbleDuration);
|
||||
this.taskRunning = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::runningProperty).orElse(false); //TODO: DOES NOT WORK
|
||||
this.taskScheduled = taskState.map(Worker.State.SCHEDULED::equals).orElse(false);
|
||||
this.taskNotStarted = taskState.map(Worker.State.READY::equals).orElse(false);
|
||||
@@ -87,11 +91,11 @@ public class CheckDetailController implements FxController {
|
||||
return taskName;
|
||||
}
|
||||
|
||||
public Number getTaskDuration() {
|
||||
public String getTaskDuration() {
|
||||
return taskDuration.getValue();
|
||||
}
|
||||
|
||||
public Binding<Number> taskDurationProperty() {
|
||||
public Binding<String> taskDurationProperty() {
|
||||
return taskDuration;
|
||||
}
|
||||
|
||||
@@ -167,4 +171,21 @@ public class CheckDetailController implements FxController {
|
||||
return taskCancelled;
|
||||
}
|
||||
|
||||
private String millisToReadAbleDuration(Number millis) {
|
||||
Duration tmp = Duration.ofMillis(millis.longValue());
|
||||
long hours = tmp.toHoursPart();
|
||||
long minutes = tmp.toMinutesPart();
|
||||
long seconds = tmp.toSecondsPart();
|
||||
if (hours != 0) {
|
||||
String hms_format = resourceBundle.getString("health.check.detail.hmsFormat");
|
||||
return String.format(hms_format, hours, minutes, seconds);
|
||||
} else if (minutes != 0) {
|
||||
String ms_format = resourceBundle.getString("health.check.detail.msFormat");
|
||||
return String.format(ms_format, minutes, seconds);
|
||||
} else {
|
||||
String s_format = resourceBundle.getString("health.check.detail.sFormat");
|
||||
return String.format(s_format, seconds);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,35 +4,81 @@ import org.cryptomator.ui.controls.FontAwesome5Icon;
|
||||
import org.cryptomator.ui.controls.FontAwesome5IconView;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.concurrent.Worker;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ContentDisplay;
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.util.Callback;
|
||||
|
||||
class CheckListCell extends ListCell<HealthCheckTask> {
|
||||
|
||||
private final FontAwesome5IconView stateIcon = new FontAwesome5IconView();
|
||||
private final Callback<HealthCheckTask, BooleanProperty> selectedGetter;
|
||||
private final ObjectProperty<State> stateProperty;
|
||||
|
||||
CheckListCell() {
|
||||
private CheckBox checkBox = new CheckBox();
|
||||
private BooleanProperty selectedProperty;
|
||||
|
||||
CheckListCell(Callback<HealthCheckTask, BooleanProperty> selectedGetter, ObservableValue<Boolean> switchIndicator) {
|
||||
this.selectedGetter = selectedGetter;
|
||||
this.stateProperty = new SimpleObjectProperty<>(State.SELECTION);
|
||||
switchIndicator.addListener(this::changeState);
|
||||
setPadding(new Insets(6));
|
||||
setAlignment(Pos.CENTER_LEFT);
|
||||
setContentDisplay(ContentDisplay.LEFT);
|
||||
getStyleClass().add("label");
|
||||
}
|
||||
|
||||
private void changeState(ObservableValue<? extends Boolean> observableValue, boolean oldValue, boolean newValue) {
|
||||
if (newValue) {
|
||||
stateProperty.set(State.RUN);
|
||||
} else {
|
||||
stateProperty.set(State.SELECTION);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateItem(HealthCheckTask item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item != null) {
|
||||
textProperty().bind(item.titleProperty());
|
||||
setText(item.getTitle());
|
||||
}
|
||||
switch (stateProperty.get()) {
|
||||
case SELECTION -> updateItemSelection(item, empty);
|
||||
case RUN -> updateItemRun(item, empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateItemSelection(HealthCheckTask item, boolean empty) {
|
||||
if (!empty) {
|
||||
setGraphic(checkBox);
|
||||
|
||||
if (selectedProperty != null) {
|
||||
checkBox.selectedProperty().unbindBidirectional(selectedProperty);
|
||||
}
|
||||
selectedProperty = selectedGetter.call(item);
|
||||
if (selectedProperty != null) {
|
||||
checkBox.selectedProperty().bindBidirectional(selectedProperty);
|
||||
}
|
||||
} else {
|
||||
setGraphic(null);
|
||||
setText(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateItemRun(HealthCheckTask item, boolean empty) {
|
||||
if (item != null) {
|
||||
item.stateProperty().addListener(this::stateChanged);
|
||||
graphicProperty().bind(Bindings.createObjectBinding(() -> graphicForState(item.getState()),item.stateProperty()));
|
||||
graphicProperty().bind(Bindings.createObjectBinding(() -> graphicForState(item.getState()), item.stateProperty()));
|
||||
stateIcon.setGlyph(glyphForState(item.getState()));
|
||||
} else {
|
||||
textProperty().unbind();
|
||||
graphicProperty().unbind();
|
||||
setGraphic(null);
|
||||
setText(null);
|
||||
@@ -61,4 +107,9 @@ class CheckListCell extends ListCell<HealthCheckTask> {
|
||||
case SUCCEEDED -> FontAwesome5Icon.CHECK;
|
||||
};
|
||||
}
|
||||
|
||||
private enum State {
|
||||
SELECTION,
|
||||
RUN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class CheckListController implements FxController {
|
||||
private final ReportWriter reportWriter;
|
||||
private final ExecutorService executorService;
|
||||
private final ObjectProperty<HealthCheckTask> selectedTask;
|
||||
private final Lazy<ErrorComponent.Builder> errorComponenBuilder;
|
||||
private final Lazy<ErrorComponent.Builder> errorComponentBuilder;
|
||||
private final SimpleObjectProperty<Worker<?>> runningTask;
|
||||
private final Binding<Boolean> running;
|
||||
private final Binding<Boolean> finished;
|
||||
@@ -60,13 +60,13 @@ public class CheckListController implements FxController {
|
||||
|
||||
|
||||
@Inject
|
||||
public CheckListController(@HealthCheckWindow Stage window, Lazy<Collection<HealthCheckTask>> tasks, ReportWriter reportWriteTask, ObjectProperty<HealthCheckTask> selectedTask, ExecutorService executorService, Lazy<ErrorComponent.Builder> errorComponenBuilder) {
|
||||
public CheckListController(@HealthCheckWindow Stage window, Lazy<Collection<HealthCheckTask>> tasks, ReportWriter reportWriteTask, ObjectProperty<HealthCheckTask> selectedTask, ExecutorService executorService, Lazy<ErrorComponent.Builder> errorComponentBuilder) {
|
||||
this.window = window;
|
||||
this.tasks = FXCollections.observableArrayList(tasks.get());
|
||||
this.reportWriter = reportWriteTask;
|
||||
this.executorService = executorService;
|
||||
this.selectedTask = selectedTask;
|
||||
this.errorComponenBuilder = errorComponenBuilder;
|
||||
this.errorComponentBuilder = errorComponentBuilder;
|
||||
this.runningTask = new SimpleObjectProperty<>();
|
||||
this.running = EasyBind.wrapNullable(runningTask).mapObservable(Worker::runningProperty).orElse(false);
|
||||
this.finished = EasyBind.wrapNullable(runningTask).mapObservable(Worker::stateProperty).map(END_STATES::contains).orElse(false);
|
||||
@@ -84,17 +84,7 @@ public class CheckListController implements FxController {
|
||||
@FXML
|
||||
public void initialize() {
|
||||
checksListView.setItems(tasks);
|
||||
checksListView.setCellFactory(CheckBoxListCell.forListView(listPickIndicators::get, new StringConverter<HealthCheckTask>() {
|
||||
@Override
|
||||
public String toString(HealthCheckTask object) {
|
||||
return object.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HealthCheckTask fromString(String string) {
|
||||
return null;
|
||||
}
|
||||
}));
|
||||
checksListView.setCellFactory(view -> new CheckListCell(listPickIndicators::get, showResultScreen));
|
||||
selectedTask.bind(checksListView.getSelectionModel().selectedItemProperty());
|
||||
}
|
||||
|
||||
@@ -115,7 +105,7 @@ public class CheckListController implements FxController {
|
||||
runningTask.set(batchService);
|
||||
showResultScreen.set(true);
|
||||
checksListView.getSelectionModel().select(batch.get(0));
|
||||
checksListView.setCellFactory(view -> new CheckListCell());
|
||||
checksListView.refresh();
|
||||
window.sizeToScene();
|
||||
}
|
||||
|
||||
@@ -131,7 +121,7 @@ public class CheckListController implements FxController {
|
||||
reportWriter.writeReport(tasks);
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to write health check report.", e);
|
||||
errorComponenBuilder.get().cause(e).window(window).returnToScene(window.getScene()).build().showErrorScene();
|
||||
errorComponentBuilder.get().cause(e).window(window).returnToScene(window.getScene()).build().showErrorScene();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ public interface KeyLoadingStrategy extends MasterkeyLoader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Release any ressources or do follow-up tasks after loading a key.
|
||||
* Release any resources or do follow-up tasks after loading a key.
|
||||
*
|
||||
* @param unlockedSuccessfully <code>true</code> if successfully unlocked a vault with the loaded key
|
||||
* @implNote This method might be invoked multiple times, depending on whether multiple attempts to load a key are started.
|
||||
@@ -47,7 +47,7 @@ public interface KeyLoadingStrategy extends MasterkeyLoader {
|
||||
/**
|
||||
* A key loading strategy that will always fail by throwing a {@link MasterkeyLoadingFailedException}.
|
||||
*
|
||||
* @param exception The cause of the failure. If not alreay an {@link MasterkeyLoadingFailedException}, it will get wrapped.
|
||||
* @param exception The cause of the failure. If not already an {@link MasterkeyLoadingFailedException}, it will get wrapped.
|
||||
* @return A new KeyLoadingStrategy that will always fail with an {@link MasterkeyLoadingFailedException}.
|
||||
*/
|
||||
static KeyLoadingStrategy failed(Exception exception) {
|
||||
|
||||
@@ -32,7 +32,7 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
||||
public static final String SCHEME = "masterkeyfile";
|
||||
|
||||
private final Vault vault;
|
||||
private final MasterkeyFileAccess masterkeyFileAcccess;
|
||||
private final MasterkeyFileAccess masterkeyFileAccess;
|
||||
private final Stage window;
|
||||
private final Lazy<Scene> passphraseEntryScene;
|
||||
private final Lazy<Scene> selectMasterkeyFileScene;
|
||||
@@ -45,9 +45,9 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
||||
private boolean wrongPassword;
|
||||
|
||||
@Inject
|
||||
public MasterkeyFileLoadingStrategy(@KeyLoading Vault vault, MasterkeyFileAccess masterkeyFileAcccess, @KeyLoading Stage window, @FxmlScene(FxmlFile.UNLOCK_ENTER_PASSWORD) Lazy<Scene> passphraseEntryScene, @FxmlScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE) Lazy<Scene> selectMasterkeyFileScene, UserInteractionLock<MasterkeyFileLoadingModule.PasswordEntry> passwordEntryLock, UserInteractionLock<MasterkeyFileLoadingModule.MasterkeyFileProvision> masterkeyFileProvisionLock, AtomicReference<char[]> password, AtomicReference<Path> filePath, MasterkeyFileLoadingFinisher finisher) {
|
||||
public MasterkeyFileLoadingStrategy(@KeyLoading Vault vault, MasterkeyFileAccess masterkeyFileAccess, @KeyLoading Stage window, @FxmlScene(FxmlFile.UNLOCK_ENTER_PASSWORD) Lazy<Scene> passphraseEntryScene, @FxmlScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE) Lazy<Scene> selectMasterkeyFileScene, UserInteractionLock<MasterkeyFileLoadingModule.PasswordEntry> passwordEntryLock, UserInteractionLock<MasterkeyFileLoadingModule.MasterkeyFileProvision> masterkeyFileProvisionLock, AtomicReference<char[]> password, AtomicReference<Path> filePath, MasterkeyFileLoadingFinisher finisher) {
|
||||
this.vault = vault;
|
||||
this.masterkeyFileAcccess = masterkeyFileAcccess;
|
||||
this.masterkeyFileAccess = masterkeyFileAccess;
|
||||
this.window = window;
|
||||
this.passphraseEntryScene = passphraseEntryScene;
|
||||
this.selectMasterkeyFileScene = selectMasterkeyFileScene;
|
||||
@@ -68,7 +68,7 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
||||
filePath = getAlternateMasterkeyFilePath();
|
||||
}
|
||||
CharSequence passphrase = getPassphrase();
|
||||
return masterkeyFileAcccess.load(filePath, passphrase);
|
||||
return masterkeyFileAccess.load(filePath, passphrase);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new UnlockCancelledException("Unlock interrupted", e);
|
||||
|
||||
@@ -64,7 +64,7 @@ class AppLaunchEventHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO dedup MainWindowController...
|
||||
// TODO deduplicate MainWindowController...
|
||||
private void addOrRevealVault(Path potentialVaultPath) {
|
||||
assert Platform.isFxApplicationThread();
|
||||
try {
|
||||
|
||||
@@ -22,7 +22,7 @@ import javafx.stage.Window;
|
||||
/**
|
||||
* The sequence of actions performed and checked during lock of a vault.
|
||||
* <p>
|
||||
* This class implements the Task interface, sucht that it can run in the background with some possible forground operations/requests to the ui, without blocking the main app.
|
||||
* This class implements the Task interface, sucht that it can run in the background with some possible foreground operations/requests to the ui, without blocking the main app.
|
||||
* If the task state is
|
||||
* <li>succeeded, the vault was successfully locked;</li>
|
||||
* <li>canceled, the lock was canceled;</li>
|
||||
|
||||
@@ -129,7 +129,7 @@ public class MainWindowTitleController implements FxController {
|
||||
}
|
||||
|
||||
public boolean isShowMinimizeButton() {
|
||||
// always show the minimize button if no tray icon is present OR it is explicitily enabled
|
||||
// always show the minimize button if no tray icon is present OR it is explicitly enabled
|
||||
return !trayMenuInitialized || settings.showMinimizeButton().get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public class AutoCompleter {
|
||||
if (Strings.isNullOrEmpty(prefix)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
int potentialMatchIdx = findIndexOfLexicographicallyPreceeding(0, dictionary.size(), prefix);
|
||||
int potentialMatchIdx = findIndexOfLexicographicallyPreceding(0, dictionary.size(), prefix);
|
||||
if (potentialMatchIdx < dictionary.size()) {
|
||||
String potentialMatch = dictionary.get(potentialMatchIdx);
|
||||
return potentialMatch.startsWith(prefix) ? Optional.of(potentialMatch) : Optional.empty();
|
||||
@@ -48,21 +48,21 @@ public class AutoCompleter {
|
||||
* @param prefix
|
||||
* @return index between [0, dictLen], i.e. index can exceed the upper bounds of {@link #dictionary}.
|
||||
*/
|
||||
private int findIndexOfLexicographicallyPreceeding(int begin, int end, String prefix) {
|
||||
private int findIndexOfLexicographicallyPreceding(int begin, int end, String prefix) {
|
||||
if (begin >= end) {
|
||||
return begin; // this is usually where a binary search ends "unsuccessful"
|
||||
}
|
||||
|
||||
int mid = (begin + end) / 2;
|
||||
String word = dictionary.get(mid);
|
||||
if (prefix.compareTo(word) <= 0) { // prefix preceeds or matches word
|
||||
if (prefix.compareTo(word) <= 0) { // prefix precedes or matches word
|
||||
// proceed in left half
|
||||
assert mid < end;
|
||||
return findIndexOfLexicographicallyPreceeding(0, mid, prefix);
|
||||
return findIndexOfLexicographicallyPreceding(0, mid, prefix);
|
||||
} else {
|
||||
// proceed in right half
|
||||
assert mid >= begin;
|
||||
return findIndexOfLexicographicallyPreceeding(mid + 1, end, prefix);
|
||||
return findIndexOfLexicographicallyPreceding(mid + 1, end, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ class WordEncoder {
|
||||
* @throws IllegalArgumentException If input is not a multiple of three bytes
|
||||
*/
|
||||
public String encodePadded(byte[] input) {
|
||||
Preconditions.checkArgument(input.length % 3 == 0, "input needs to be padded to a multipe of three");
|
||||
Preconditions.checkArgument(input.length % 3 == 0, "input needs to be padded to a multiple of three");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < input.length; i += 3) {
|
||||
byte b1 = input[i];
|
||||
@@ -85,12 +85,12 @@ class WordEncoder {
|
||||
* @throws IllegalArgumentException If the encoded string doesn't consist of a multiple of two words or one of the words is unknown to this encoder.
|
||||
*/
|
||||
public byte[] decode(String encoded) {
|
||||
List<String> splitted = Splitter.on(DELIMITER).omitEmptyStrings().splitToList(Strings.nullToEmpty(encoded));
|
||||
Preconditions.checkArgument(splitted.size() % 2 == 0, "%s needs to be a multiple of two words", encoded);
|
||||
byte[] result = new byte[splitted.size() / 2 * 3];
|
||||
for (int i = 0; i < splitted.size(); i += 2) {
|
||||
String w1 = splitted.get(i);
|
||||
String w2 = splitted.get(i + 1);
|
||||
List<String> split = Splitter.on(DELIMITER).omitEmptyStrings().splitToList(Strings.nullToEmpty(encoded));
|
||||
Preconditions.checkArgument(split.size() % 2 == 0, "%s needs to be a multiple of two words", encoded);
|
||||
byte[] result = new byte[split.size() / 2 * 3];
|
||||
for (int i = 0; i < split.size(); i += 2) {
|
||||
String w1 = split.get(i);
|
||||
String w2 = split.get(i + 1);
|
||||
int firstWordIndex = indices.getOrDefault(w1, -1);
|
||||
int secondWordIndex = indices.getOrDefault(w2, -1);
|
||||
Preconditions.checkArgument(firstWordIndex != -1, "%s not in dictionary", w1);
|
||||
|
||||
@@ -65,8 +65,8 @@ public class VaultStatisticsController implements FxController {
|
||||
this.cacheHitRate = WeakBindings.bindDouble(stats.cacheHitRateProperty());
|
||||
this.cacheHitDegrees = cacheHitRate.multiply(-270);
|
||||
this.cacheHitPercentage = cacheHitRate.multiply(100);
|
||||
this.totalBytesRead = WeakBindings.bindLong(stats.toalBytesReadProperty());
|
||||
this.totalBytesWritten = WeakBindings.bindLong(stats.toalBytesWrittenProperty());
|
||||
this.totalBytesRead = WeakBindings.bindLong(stats.totalBytesReadProperty());
|
||||
this.totalBytesWritten = WeakBindings.bindLong(stats.totalBytesWrittenProperty());
|
||||
this.totalBytesDecrypted = WeakBindings.bindLong(stats.totalBytesDecryptedProperty());
|
||||
this.totalBytesEncrypted = WeakBindings.bindLong(stats.totalBytesEncryptedProperty());
|
||||
this.filesRead = WeakBindings.bindLong(stats.filesRead());
|
||||
@@ -102,7 +102,7 @@ public class VaultStatisticsController implements FxController {
|
||||
this.decryptedBytesRead = readData;
|
||||
this.encryptedBytesWrite = writeData;
|
||||
|
||||
// initialize data once and change value of datapoints later:
|
||||
// initialize data once and change value of data points later:
|
||||
for (int i = 0; i < IO_SAMPLING_STEPS; i++) {
|
||||
decryptedBytesRead.getData().add(new Data<>(i, 0));
|
||||
encryptedBytesWrite.getData().add(new Data<>(i, 0));
|
||||
|
||||
Reference in New Issue
Block a user