* Hide button when not hovering or vault is locked

* localize
This commit is contained in:
Armin Schrenk
2025-02-27 17:25:31 +01:00
parent b76a7d6895
commit 8386183f7a
3 changed files with 55 additions and 22 deletions

View File

@@ -15,7 +15,9 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
@@ -26,6 +28,7 @@ import javafx.geometry.Side;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.HBox;
import java.nio.file.Path;
import java.util.Optional;
import java.util.ResourceBundle;
@@ -46,9 +49,12 @@ public class EventListCellController implements FxController {
private final ObservableValue<String> message;
private final ObservableValue<String> description;
private final ObservableValue<FontAwesome5Icon> icon;
private final BooleanProperty actionsButtonVisible;
@FXML
ContextMenu eventActions;
HBox root;
@FXML
ContextMenu eventActionsMenu;
@FXML
Button eventActionsButton;
@@ -65,13 +71,23 @@ public class EventListCellController implements FxController {
this.message = Bindings.createStringBinding(this::selectMessage, vaultUnlocked, eventMessage);
this.description = Bindings.createStringBinding(this::selectDescription, vaultUnlocked, eventDescription);
this.icon = Bindings.createObjectBinding(this::selectIcon, vaultUnlocked, eventIcon);
this.actionsButtonVisible = new SimpleBooleanProperty();
}
@FXML
public void initialize() {
actionsButtonVisible.bind(Bindings.createBooleanBinding(this::determineActionsButtonVisibility, root.hoverProperty(), eventActionsMenu.showingProperty(), vaultUnlocked));
vaultUnlocked.addListener((_,_,newValue) -> eventActionsMenu.hide());
}
private boolean determineActionsButtonVisibility() {
return vaultUnlocked.getValue() && (eventActionsMenu.isShowing() || root.isHover());
}
public void setEvent(@NotNull VaultEvent item) {
event.set(item);
eventDescription.setValue("Vault " + item.v().getDisplayName());
eventActions.hide();
eventActions.getItems().clear();
eventActionsMenu.hide();
eventActionsMenu.getItems().clear();
addAction("generic.action.dismiss", () -> events.remove(item));
switch (item.actualEvent()) {
case ConflictResolvedEvent fse -> this.adjustToConflictResolvedEvent(fse);
@@ -82,7 +98,8 @@ public class EventListCellController implements FxController {
private void adjustToConflictResolvedEvent(ConflictResolvedEvent cre) {
eventIcon.setValue(FontAwesome5Icon.FILE);
eventMessage.setValue("Resolved conflict, new file is " + cre.resolvedCleartextPath()); //TODO:localize
eventMessage.setValue(cre.resolvedCleartextPath().toString());
eventDescription.setValue(resourceBundle.getString("event.conflictResolved.description"));
if (revealService.isPresent()) {
addAction("event.conflictResolved.showDecrypted", () -> this.showResolvedConflict(cre));
}
@@ -90,15 +107,18 @@ public class EventListCellController implements FxController {
private void adjustToConflictEvent(ConflictResolutionFailedEvent cfe) {
eventIcon.setValue(FontAwesome5Icon.TIMES);
eventMessage.setValue("Failed to resolve conflict for " + cfe.conflictingCiphertextPath()); //TODO:localize
eventMessage.setValue(cfe.canonicalCleartextPath().toString());
eventDescription.setValue(resourceBundle.getString("event.conflict.description"));
if (revealService.isPresent()) {
addAction("event.conflictFailed.showEncrypted", () -> reveal(cfe.conflictingCiphertextPath()));
addAction("event.conflict.showDecrypted", () -> reveal(cfe.canonicalCleartextPath()));
addAction("event.conflict.showEncrypted", () -> reveal(cfe.conflictingCiphertextPath()));
}
}
private void adjustToDecryptionFailedEvent(DecryptionFailedEvent dfe) {
eventIcon.setValue(FontAwesome5Icon.BAN);
eventMessage.setValue("Cannot decrypt " + dfe.ciphertextPath()); //TODO:localize
eventMessage.setValue(dfe.ciphertextPath().toString());
eventDescription.setValue(resourceBundle.getString("event.decryptionFailed.description"));
if (revealService.isPresent()) {
addAction("event.decryptionFailed.showEncrypted", () -> reveal(dfe.ciphertextPath()));
}
@@ -108,7 +128,7 @@ public class EventListCellController implements FxController {
var entry = new MenuItem(resourceBundle.getString(localizationKey));
entry.getStyleClass().addLast("add-vault-menu-item");
entry.setOnAction(_ -> action.run());
eventActions.getItems().addLast(entry);
eventActionsMenu.getItems().addLast(entry);
}
@@ -125,7 +145,7 @@ public class EventListCellController implements FxController {
return eventMessage.getValue();
} else {
var e = event.getValue();
return "Event for " + (e != null ? e.v().getDisplayName() : ""); //TODO: localize
return resourceBundle.getString("event.vaultLocked.message");
}
}
@@ -133,7 +153,7 @@ public class EventListCellController implements FxController {
if (vaultUnlocked.getValue()) {
return eventDescription.getValue();
} else {
return "Unlock the vault to display details."; //TODO: localize
return resourceBundle.getString("event.vaultLocked.description");
}
}
@@ -142,10 +162,10 @@ public class EventListCellController implements FxController {
public void toggleEventActionsMenu() {
var e = event.get();
if (e != null) {
if (eventActions.isShowing()) {
eventActions.hide();
if (eventActionsMenu.isShowing()) {
eventActionsMenu.hide();
} else {
eventActions.show(eventActionsButton, Side.BOTTOM, 0.0, 0.0);
eventActionsMenu.show(eventActionsButton, Side.BOTTOM, 0.0, 0.0);
}
}
}
@@ -165,11 +185,10 @@ public class EventListCellController implements FxController {
revealService.orElseThrow(() -> new IllegalStateException("Function requiring revealService called, but service not available")) //
.reveal(p);
} catch (RevealFailedException e) {
LOG.warn("Failed to show path {}",p, e);
LOG.warn("Failed to show path {}", p, e);
}
}
//-- property accessors --
public ObservableValue<String> messageProperty() {
return message;
@@ -195,4 +214,13 @@ public class EventListCellController implements FxController {
return icon.getValue();
}
public ObservableValue<Boolean> actionsButtonVisibleProperty() {
return actionsButtonVisible;
}
public boolean isActionsButtonVisible() {
return actionsButtonVisible.getValue();
}
}

View File

@@ -14,7 +14,8 @@
prefHeight="60"
prefWidth="200"
spacing="12"
alignment="CENTER_LEFT">
alignment="CENTER_LEFT"
fx:id="root">
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
@@ -26,15 +27,13 @@
<Label styleClass="header-label" text="${controller.message}"/>
<Label styleClass="detail-label" text="${controller.description}" textOverrun="CENTER_ELLIPSIS" />
</VBox>
<Button fx:id="eventActionsButton" contentDisplay="GRAPHIC_ONLY" onAction="#toggleEventActionsMenu">
<Button fx:id="eventActionsButton" contentDisplay="GRAPHIC_ONLY" onAction="#toggleEventActionsMenu" managed="${controller.actionsButtonVisible}" visible="${controller.actionsButtonVisible}">
<graphic>
<FontAwesome5IconView glyph="ELLIPSIS_V" glyphSize="16"/>
</graphic>
</Button>
<fx:define>
<ContextMenu fx:id="eventActions">
<!-- entries are added in the controller -->
</ContextMenu>
<ContextMenu fx:id="eventActionsMenu"/>
</fx:define>
</HBox>

View File

@@ -2,8 +2,14 @@
additionalStyleSheets=
#Test
event.vaultLocked.message=***********
event.vaultLocked.description=Unlock the vault to display details
event.conflictResolved.description=Resolved conflict
event.conflictResolved.showDecrypted=Show decrypted file
event.conflictFailed.showEncrypted=Show encrypted file
event.conflict.description=Cannot resolve conflict.
event.conflict.showDecrypted=Show decrypted, original file
event.conflict.showEncrypted=Show conflicting, encrypted file
event.decryptionFailed.description=Decryption failed.
event.decryptionFailed.showEncrypted=Show encrypted file
# Generics