mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-09-20 15:04:23 +00:00
Merge branch 'master' of https://github.com/totalvoidness/cryptomator
This commit is contained in:
@@ -16,12 +16,15 @@ import java.util.ResourceBundle;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.Parent;
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.control.ContextMenu;
|
||||||
import javafx.scene.control.ListCell;
|
import javafx.scene.control.ListCell;
|
||||||
import javafx.scene.control.ListView;
|
import javafx.scene.control.ListView;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
@@ -44,6 +47,9 @@ public class MainController implements Initializable, InitializationListener, Un
|
|||||||
|
|
||||||
private Stage stage;
|
private Stage stage;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private ContextMenu directoryContextMenu;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private HBox rootPane;
|
private HBox rootPane;
|
||||||
|
|
||||||
@@ -58,9 +64,11 @@ public class MainController implements Initializable, InitializationListener, Un
|
|||||||
@Override
|
@Override
|
||||||
public void initialize(URL url, ResourceBundle rb) {
|
public void initialize(URL url, ResourceBundle rb) {
|
||||||
this.rb = rb;
|
this.rb = rb;
|
||||||
|
|
||||||
|
final ObservableList<Directory> items = FXCollections.observableList(Settings.load().getDirectories());
|
||||||
|
directoryList.setItems(items);
|
||||||
directoryList.setCellFactory(this::createDirecoryListCell);
|
directoryList.setCellFactory(this::createDirecoryListCell);
|
||||||
directoryList.getSelectionModel().getSelectedItems().addListener(this::selectedDirectoryDidChange);
|
directoryList.getSelectionModel().getSelectedItems().addListener(this::selectedDirectoryDidChange);
|
||||||
directoryList.getItems().addAll(Settings.load().getDirectories());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@@ -70,22 +78,38 @@ public class MainController implements Initializable, InitializationListener, Un
|
|||||||
if (file != null && file.canWrite()) {
|
if (file != null && file.canWrite()) {
|
||||||
final Directory dir = new Directory(file.toPath());
|
final Directory dir = new Directory(file.toPath());
|
||||||
directoryList.getItems().add(dir);
|
directoryList.getItems().add(dir);
|
||||||
Settings.load().getDirectories().clear();
|
|
||||||
Settings.load().getDirectories().addAll(directoryList.getItems());
|
|
||||||
directoryList.getSelectionModel().selectLast();
|
directoryList.getSelectionModel().selectLast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListCell<Directory> createDirecoryListCell(ListView<Directory> param) {
|
private ListCell<Directory> createDirecoryListCell(ListView<Directory> param) {
|
||||||
return new DirectoryListCell();
|
final DirectoryListCell cell = new DirectoryListCell();
|
||||||
|
cell.setContextMenu(directoryContextMenu);
|
||||||
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectedDirectoryDidChange(ListChangeListener.Change<? extends Directory> change) {
|
private void selectedDirectoryDidChange(ListChangeListener.Change<? extends Directory> change) {
|
||||||
final Directory selectedDir = directoryList.getSelectionModel().getSelectedItem();
|
final Directory selectedDir = directoryList.getSelectionModel().getSelectedItem();
|
||||||
stage.setTitle(selectedDir.getName());
|
if (selectedDir == null) {
|
||||||
showDirectory(selectedDir);
|
stage.setTitle(rb.getString("app.name"));
|
||||||
|
showWelcomeView();
|
||||||
|
} else {
|
||||||
|
stage.setTitle(selectedDir.getName());
|
||||||
|
showDirectory(selectedDir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void didClickRemoveSelectedEntry(ActionEvent e) {
|
||||||
|
final Directory selectedDir = directoryList.getSelectionModel().getSelectedItem();
|
||||||
|
directoryList.getItems().remove(selectedDir);
|
||||||
|
directoryList.getSelectionModel().clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ****************************************
|
||||||
|
// Subcontroller for right panel
|
||||||
|
// ****************************************
|
||||||
|
|
||||||
private void showDirectory(Directory directory) {
|
private void showDirectory(Directory directory) {
|
||||||
try {
|
try {
|
||||||
if (directory.isUnlocked()) {
|
if (directory.isUnlocked()) {
|
||||||
@@ -100,10 +124,6 @@ public class MainController implements Initializable, InitializationListener, Un
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ****************************************
|
|
||||||
// Subcontroller for right panel
|
|
||||||
// ****************************************
|
|
||||||
|
|
||||||
private <T> T showView(String fxml) {
|
private <T> T showView(String fxml) {
|
||||||
try {
|
try {
|
||||||
final FXMLLoader loader = new FXMLLoader(getClass().getResource(fxml), rb);
|
final FXMLLoader loader = new FXMLLoader(getClass().getResource(fxml), rb);
|
||||||
@@ -116,6 +136,10 @@ public class MainController implements Initializable, InitializationListener, Un
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showWelcomeView() {
|
||||||
|
this.showView("/welcome.fxml");
|
||||||
|
}
|
||||||
|
|
||||||
private void showInitializeView(Directory directory) {
|
private void showInitializeView(Directory directory) {
|
||||||
final InitializeController ctrl = showView("/initialize.fxml");
|
final InitializeController ctrl = showView("/initialize.fxml");
|
||||||
ctrl.setDirectory(directory);
|
ctrl.setDirectory(directory);
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class UnlockController implements Initializable {
|
|||||||
// ****************************************
|
// ****************************************
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected void didClickUnlockButton(ActionEvent event) {
|
private void didClickUnlockButton(ActionEvent event) {
|
||||||
final String masterKeyFileName = usernameBox.getValue() + Aes256Cryptor.MASTERKEY_FILE_EXT;
|
final String masterKeyFileName = usernameBox.getValue() + Aes256Cryptor.MASTERKEY_FILE_EXT;
|
||||||
final Path masterKeyPath = directory.getPath().resolve(masterKeyFileName);
|
final Path masterKeyPath = directory.getPath().resolve(masterKeyFileName);
|
||||||
final CharSequence password = passwordField.getCharacters();
|
final CharSequence password = passwordField.getCharacters();
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class UnlockedController implements Initializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
protected void closeVault(ActionEvent event) {
|
private void didClickCloseVault(ActionEvent event) {
|
||||||
directory.unmount();
|
directory.unmount();
|
||||||
directory.stopServer();
|
directory.stopServer();
|
||||||
directory.setUnlocked(false);
|
directory.setUnlocked(false);
|
||||||
@@ -82,7 +82,7 @@ public class UnlockedController implements Initializable {
|
|||||||
|
|
||||||
private class IoSamplingAnimationHandler implements EventHandler<ActionEvent> {
|
private class IoSamplingAnimationHandler implements EventHandler<ActionEvent> {
|
||||||
|
|
||||||
private static final double BYTES_TO_MEGABYTES_FACTOR = IO_SAMPLING_INTERVAL / 1024.0 / 1024.0;
|
private static final double BYTES_TO_MEGABYTES_FACTOR = 1.0 / IO_SAMPLING_INTERVAL / 1024.0 / 1024.0;
|
||||||
private final CryptorIOSampling sampler;
|
private final CryptorIOSampling sampler;
|
||||||
private final Series<Number, Number> decryptedBytes;
|
private final Series<Number, Number> decryptedBytes;
|
||||||
private final Series<Number, Number> encryptedBytes;
|
private final Series<Number, Number> encryptedBytes;
|
||||||
|
|||||||
@@ -1,19 +1,55 @@
|
|||||||
package org.cryptomator.ui.controls;
|
package org.cryptomator.ui.controls;
|
||||||
|
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.scene.control.ContentDisplay;
|
||||||
import javafx.scene.control.ListCell;
|
import javafx.scene.control.ListCell;
|
||||||
|
import javafx.scene.control.Tooltip;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.paint.Paint;
|
||||||
|
import javafx.scene.shape.Circle;
|
||||||
|
|
||||||
import org.cryptomator.ui.model.Directory;
|
import org.cryptomator.ui.model.Directory;
|
||||||
|
|
||||||
public class DirectoryListCell extends ListCell<Directory> {
|
public class DirectoryListCell extends ListCell<Directory> implements ChangeListener<Boolean> {
|
||||||
|
|
||||||
|
// TODO: fancy graphics instead of circles ;-)
|
||||||
|
private final Circle statusIndicator = new Circle(3.0);
|
||||||
|
|
||||||
|
public DirectoryListCell() {
|
||||||
|
setGraphic(statusIndicator);
|
||||||
|
setGraphicTextGap(12.0);
|
||||||
|
setContentDisplay(ContentDisplay.LEFT);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateItem(Directory item, boolean empty) {
|
protected void updateItem(Directory item, boolean empty) {
|
||||||
|
final Directory oldItem = super.getItem();
|
||||||
|
if (oldItem != null) {
|
||||||
|
oldItem.unlockedProperty().removeListener(this);
|
||||||
|
}
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
setText(null);
|
setText(null);
|
||||||
|
setTooltip(null);
|
||||||
|
statusIndicator.setVisible(false);
|
||||||
} else {
|
} else {
|
||||||
setText(item.getName());
|
setText(item.getName());
|
||||||
|
setTooltip(new Tooltip(item.getPath().toString()));
|
||||||
|
statusIndicator.setVisible(true);
|
||||||
|
item.unlockedProperty().addListener(this);
|
||||||
|
updateStatusIndicator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
|
||||||
|
updateStatusIndicator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateStatusIndicator() {
|
||||||
|
final Paint statusColor = getItem().isUnlocked() ? Color.LIME : Color.RED;
|
||||||
|
statusIndicator.setFill(statusColor);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import java.io.Serializable;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.cryptomator.crypto.Cryptor;
|
import org.cryptomator.crypto.Cryptor;
|
||||||
import org.cryptomator.crypto.SamplingDecorator;
|
import org.cryptomator.crypto.SamplingDecorator;
|
||||||
@@ -29,8 +32,9 @@ public class Directory implements Serializable {
|
|||||||
|
|
||||||
private final WebDAVServer server = new WebDAVServer();
|
private final WebDAVServer server = new WebDAVServer();
|
||||||
private final Cryptor cryptor = SamplingDecorator.decorate(new Aes256Cryptor());
|
private final Cryptor cryptor = SamplingDecorator.decorate(new Aes256Cryptor());
|
||||||
|
private final ObjectProperty<Boolean> unlocked = new SimpleObjectProperty<Boolean>(this, "unlocked", Boolean.FALSE);
|
||||||
private final Path path;
|
private final Path path;
|
||||||
private boolean unlocked;
|
// private boolean unlocked;
|
||||||
private String unmountCommand;
|
private String unmountCommand;
|
||||||
private final Runnable shutdownTask = new ShutdownTask();
|
private final Runnable shutdownTask = new ShutdownTask();
|
||||||
|
|
||||||
@@ -103,12 +107,16 @@ public class Directory implements Serializable {
|
|||||||
return cryptor;
|
return cryptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUnlocked() {
|
public ObjectProperty<Boolean> unlockedProperty() {
|
||||||
return unlocked;
|
return unlocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isUnlocked() {
|
||||||
|
return unlocked.get();
|
||||||
|
}
|
||||||
|
|
||||||
public void setUnlocked(boolean unlocked) {
|
public void setUnlocked(boolean unlocked) {
|
||||||
this.unlocked = unlocked;
|
this.unlocked.set(unlocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebDAVServer getServer() {
|
public WebDAVServer getServer() {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang3.SystemUtils;
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
import org.cryptomator.ui.model.Directory;
|
import org.cryptomator.ui.model.Directory;
|
||||||
@@ -54,7 +54,7 @@ public class Settings implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<Directory> directories;
|
private List<Directory> directories;
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
private Settings() {
|
private Settings() {
|
||||||
@@ -96,14 +96,14 @@ public class Settings implements Serializable {
|
|||||||
|
|
||||||
/* Getter/Setter */
|
/* Getter/Setter */
|
||||||
|
|
||||||
public Collection<Directory> getDirectories() {
|
public List<Directory> getDirectories() {
|
||||||
if (directories == null) {
|
if (directories == null) {
|
||||||
directories = new ArrayList<>();
|
directories = new ArrayList<>();
|
||||||
}
|
}
|
||||||
return directories;
|
return directories;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDirectories(Collection<Directory> directories) {
|
public void setDirectories(List<Directory> directories) {
|
||||||
this.directories = directories;
|
this.directories = directories;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,11 @@
|
|||||||
|
|
||||||
app.name=Cryptomator
|
app.name=Cryptomator
|
||||||
|
|
||||||
|
# main.fxml
|
||||||
|
main.directoryList.contextMenu.remove=Remove from list
|
||||||
|
main.directoryList.contextMenu.addUser=Add user
|
||||||
|
main.directoryList.contextMenu.changePassword=Change password
|
||||||
|
|
||||||
|
|
||||||
# welcome.fxml
|
# welcome.fxml
|
||||||
welcome.welcomeLabel=Welcome to Cryptomator
|
welcome.welcomeLabel=Welcome to Cryptomator
|
||||||
|
|||||||
@@ -14,13 +14,23 @@
|
|||||||
<?import javafx.scene.layout.Pane?>
|
<?import javafx.scene.layout.Pane?>
|
||||||
<?import javafx.scene.control.ToolBar?>
|
<?import javafx.scene.control.ToolBar?>
|
||||||
<?import javafx.scene.control.Button?>
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.ContextMenu?>
|
||||||
|
<?import javafx.scene.control.MenuItem?>
|
||||||
|
|
||||||
<HBox fx:id="rootPane" prefHeight="400.0" prefWidth="600.0" fx:controller="org.cryptomator.ui.MainController" xmlns:fx="http://javafx.com/fxml">
|
<HBox fx:id="rootPane" prefHeight="400.0" prefWidth="600.0" fx:controller="org.cryptomator.ui.MainController" xmlns:fx="http://javafx.com/fxml">
|
||||||
|
|
||||||
<fx:define>
|
<fx:define>
|
||||||
<fx:include fx:id="welcomeView" source="welcome.fxml" />
|
<fx:include fx:id="welcomeView" source="welcome.fxml" />
|
||||||
|
<ContextMenu fx:id="directoryContextMenu">
|
||||||
|
<items>
|
||||||
|
<MenuItem text="%main.directoryList.contextMenu.remove" onAction="#didClickRemoveSelectedEntry" />
|
||||||
|
<!-- TODO: -->
|
||||||
|
<MenuItem text="%main.directoryList.contextMenu.addUser" disable="true" />
|
||||||
|
<MenuItem text="%main.directoryList.contextMenu.changePassword" disable="true" />
|
||||||
|
</items>
|
||||||
|
</ContextMenu>
|
||||||
</fx:define>
|
</fx:define>
|
||||||
|
|
||||||
<children>
|
<children>
|
||||||
<VBox prefWidth="200.0">
|
<VBox prefWidth="200.0">
|
||||||
<children>
|
<children>
|
||||||
@@ -34,7 +44,7 @@
|
|||||||
</VBox>
|
</VBox>
|
||||||
<Pane fx:id="contentPane">
|
<Pane fx:id="contentPane">
|
||||||
<children>
|
<children>
|
||||||
<fx:reference source="welcomeView"/>
|
<fx:reference source="welcomeView" />
|
||||||
</children>
|
</children>
|
||||||
</Pane>
|
</Pane>
|
||||||
</children>
|
</children>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
<Label fx:id="messageLabel" GridPane.rowIndex="0" GridPane.columnIndex="0" GridPane.columnSpan="2" />
|
<Label fx:id="messageLabel" GridPane.rowIndex="0" GridPane.columnIndex="0" GridPane.columnSpan="2" />
|
||||||
|
|
||||||
<!-- Row 1 -->
|
<!-- Row 1 -->
|
||||||
<Button text="%unlocked.button.lock" defaultButton="true" GridPane.rowIndex="1" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="RIGHT" prefWidth="150.0" onAction="#closeVault" focusTraversable="false"/>
|
<Button text="%unlocked.button.lock" defaultButton="true" GridPane.rowIndex="1" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="RIGHT" prefWidth="150.0" onAction="#didClickCloseVault" focusTraversable="false"/>
|
||||||
|
|
||||||
<!-- Row 2 -->
|
<!-- Row 2 -->
|
||||||
<LineChart fx:id="ioGraph" GridPane.rowIndex="2" GridPane.columnIndex="0" GridPane.columnSpan="2" animated="false" createSymbols="false" prefHeight="300.0" legendVisible="true" legendSide="BOTTOM" verticalZeroLineVisible="false" verticalGridLinesVisible="false" horizontalGridLinesVisible="true">
|
<LineChart fx:id="ioGraph" GridPane.rowIndex="2" GridPane.columnIndex="0" GridPane.columnSpan="2" animated="false" createSymbols="false" prefHeight="300.0" legendVisible="true" legendSide="BOTTOM" verticalZeroLineVisible="false" verticalGridLinesVisible="false" horizontalGridLinesVisible="true">
|
||||||
|
|||||||
Reference in New Issue
Block a user