From 19d2f1d0979696eccdd7d8b2f94d80af6d6dda47 Mon Sep 17 00:00:00 2001 From: abedurftig Date: Mon, 19 Jan 2026 23:12:24 +0100 Subject: [PATCH 1/3] Display document dateCreated and dateLastModified in document details Added date properties to ApplicationModel that are populated when a document is selected and cleared when selection is cleared. The dates are displayed in the document details panel using the existing date format pattern. Fixes smartfiles-we7 Co-Authored-By: Claude Opus 4.5 --- .beads/issues.jsonl | 2 +- .../dev/arne/smartfiles/app/ApplicationModel.java | 9 +++++++++ .../smartfiles/app/ApplicationViewBuilder.java | 10 ++++++++++ .../arne/smartfiles/app/ApplicationModelTest.java | 15 +++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 7714881..ae4965c 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -25,7 +25,7 @@ {"id":"smartfiles-u4i","title":"Apply consistent tag styling between filter and document views","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-11T21:49:21.617484+01:00","created_by":"abedurftig","updated_at":"2026-01-11T21:53:15.289719+01:00","closed_at":"2026-01-11T21:53:15.289719+01:00","close_reason":"Closed"} {"id":"smartfiles-vap","title":"Missing Platform.runLater in ApplicationInteractor event handlers","description":"In ApplicationInteractor.java, most event handlers correctly use Platform.runLater() to update the model on the JavaFX Application Thread. However, two handlers do not:\n\n- handleDocumentTagAddedEvent (line 49-51) calls model.updateDocumentTags() directly\n- handleArchiveEntryAddedEvent (line 61-64) calls model.addDocumentFromArchiveEntry() directly\n\nSince Spring events can be published from any thread, these could cause UI updates from non-FX threads, leading to race conditions or crashes.\n\n**Fix:** Wrap these calls in Platform.runLater().","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-01-15T22:32:45.051937+01:00","created_by":"abedurftig","updated_at":"2026-01-16T20:58:09.470451+01:00","closed_at":"2026-01-16T20:58:09.470451+01:00","close_reason":"Closed"} {"id":"smartfiles-w73","title":"Maven compiler plugin source/target mismatch","description":"In pom.xml, the properties define java.version=25 and maven.compiler.source/target=25, but the maven-compiler-plugin configuration explicitly sets source=22 and target=22 (lines 129-130), contradicting the properties.\n\n**Fix:** Remove explicit source/target from plugin config to use the property values, or update to match.","status":"closed","priority":2,"issue_type":"bug","created_at":"2026-01-15T22:36:17.931659+01:00","created_by":"abedurftig","updated_at":"2026-01-16T21:17:57.858516+01:00","closed_at":"2026-01-16T21:17:57.858516+01:00","close_reason":"Closed"} -{"id":"smartfiles-we7","title":"Display document details dateLastModified and dateCreated in the document details","description":"Display the dateCreated and dateLastModified of the selected document in the document details in the bottom right.","status":"open","priority":2,"issue_type":"feature","created_at":"2026-01-07T21:31:02.161058+01:00","created_by":"abedurftig","updated_at":"2026-01-07T21:32:30.284216+01:00"} +{"id":"smartfiles-we7","title":"Display document details dateLastModified and dateCreated in the document details","description":"Display the dateCreated and dateLastModified of the selected document in the document details in the bottom right.","status":"in_progress","priority":2,"issue_type":"feature","created_at":"2026-01-07T21:31:02.161058+01:00","created_by":"abedurftig","updated_at":"2026-01-19T23:07:46.174507+01:00"} {"id":"smartfiles-wyr","title":"Window size and position not persisted","description":"The application starts with fixed dimensions (1024x768) and does not save/restore window size or position. This is a user experience issue as preferences are lost on restart.\n\n**File:** SmartFilesApp.java (lines 22-23)\n\n**Fix:** Save window bounds to settings on close, restore on startup.","status":"open","priority":4,"issue_type":"feature","created_at":"2026-01-15T22:37:37.871391+01:00","created_by":"abedurftig","updated_at":"2026-01-15T22:37:37.871391+01:00"} {"id":"smartfiles-yes","title":"Theme change event handler inconsistent with threading pattern","description":"handleLightThemeActivatedSettingsChangedEvent (lines 57-59) modifies the model directly without Platform.runLater(). While the theme toggle is likely called from the UI thread, the pattern should be consistent for safety.\n\n**Fix:** Wrap in Platform.runLater() for consistency with other handlers.","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-15T22:36:52.962703+01:00","created_by":"abedurftig","updated_at":"2026-01-16T20:58:09.473652+01:00","closed_at":"2026-01-16T20:58:09.473652+01:00","close_reason":"Closed"} {"id":"smartfiles-yo2","title":"APP_EXECUTOR thread pool never shutdown on exit","description":"ApplicationViewBuilder.APP_EXECUTOR is a static CachedThreadPool that is never shut down when the application exits. This can prevent clean JVM shutdown and leak threads.\n\n**File:** ApplicationViewBuilder.java (line 39)\n\n**Fix:** Register a shutdown hook or use Spring's @PreDestroy to call APP_EXECUTOR.shutdown() on application exit.","status":"open","priority":2,"issue_type":"bug","created_at":"2026-01-15T22:35:36.312096+01:00","created_by":"abedurftig","updated_at":"2026-01-15T22:35:36.312096+01:00"} diff --git a/src/main/java/dev/arne/smartfiles/app/ApplicationModel.java b/src/main/java/dev/arne/smartfiles/app/ApplicationModel.java index 4469915..1b8aeea 100644 --- a/src/main/java/dev/arne/smartfiles/app/ApplicationModel.java +++ b/src/main/java/dev/arne/smartfiles/app/ApplicationModel.java @@ -11,6 +11,7 @@ import lombok.Getter; import lombok.Setter; +import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Set; import java.util.UUID; @@ -19,7 +20,11 @@ @Setter public class ApplicationModel { + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("MMM d, yyyy 'at' HH:mm"); + private final StringProperty selectedDocumentNameProperty = new SimpleStringProperty(null); + private final StringProperty documentDateCreatedProperty = new SimpleStringProperty(""); + private final StringProperty documentDateLastModifiedProperty = new SimpleStringProperty(""); private final BooleanProperty lightModeActivated = new SimpleBooleanProperty(false); private final ObservableList documentsList = FXCollections.observableArrayList(); private final FilteredList filteredDocuments = new FilteredList<>(documentsList, _ -> true); @@ -80,6 +85,8 @@ public void setSelectedDocument(ArchiveEntry selectedDocument) { selectedDocumentProperty.setValue(selectedDocument); selectedDocumentNameProperty.setValue(selectedDocument.getName()); descriptionProperty.setValue(selectedDocument.getSummary()); + documentDateCreatedProperty.setValue(selectedDocument.getDateCreated().format(DATE_FORMATTER)); + documentDateLastModifiedProperty.setValue(selectedDocument.getDateLastModified().format(DATE_FORMATTER)); updateDocumentTags(); } @@ -136,6 +143,8 @@ public void clearSelectedDocument() { selectedDocumentProperty.setValue(null); selectedDocumentNameProperty.setValue(null); descriptionProperty.setValue(""); + documentDateCreatedProperty.setValue(""); + documentDateLastModifiedProperty.setValue(""); tagsProperty.clear(); } } diff --git a/src/main/java/dev/arne/smartfiles/app/ApplicationViewBuilder.java b/src/main/java/dev/arne/smartfiles/app/ApplicationViewBuilder.java index 3d07090..416f971 100644 --- a/src/main/java/dev/arne/smartfiles/app/ApplicationViewBuilder.java +++ b/src/main/java/dev/arne/smartfiles/app/ApplicationViewBuilder.java @@ -255,6 +255,16 @@ private VBox createRightBottom() { vBox.getChildren().add(createAreaLabel("Document details")); + var dateCreatedLabel = new Label(); + dateCreatedLabel.textProperty().bind(model.getDocumentDateCreatedProperty().map(d -> d.isEmpty() ? "" : "Created: " + d)); + dateCreatedLabel.getStyleClass().add("sf-footer-label"); + vBox.getChildren().add(dateCreatedLabel); + + var dateModifiedLabel = new Label(); + dateModifiedLabel.textProperty().bind(model.getDocumentDateLastModifiedProperty().map(d -> d.isEmpty() ? "" : "Modified: " + d)); + dateModifiedLabel.getStyleClass().add("sf-footer-label"); + vBox.getChildren().add(dateModifiedLabel); + descriptionField = new TextField(); descriptionField.setPromptText("Click to add description"); descriptionField.textProperty().bindBidirectional(model.getDescriptionProperty()); diff --git a/src/test/java/dev/arne/smartfiles/app/ApplicationModelTest.java b/src/test/java/dev/arne/smartfiles/app/ApplicationModelTest.java index 4eedee3..3ea5410 100644 --- a/src/test/java/dev/arne/smartfiles/app/ApplicationModelTest.java +++ b/src/test/java/dev/arne/smartfiles/app/ApplicationModelTest.java @@ -230,9 +230,24 @@ void clearSelectedDocument_clearsAllSelectionProperties() { assertNull(model.getSelectedDocumentProperty().get()); assertNull(model.getSelectedDocumentNameProperty().get()); assertEquals("", model.getDescriptionProperty().get()); + assertEquals("", model.getDocumentDateCreatedProperty().get()); + assertEquals("", model.getDocumentDateLastModifiedProperty().get()); assertTrue(model.getTagsProperty().isEmpty()); } + @Test + void setSelectedDocument_setsDateProperties() { + var entry = createTestEntry("test.pdf", "Description"); + entry.setDateCreated(LocalDateTime.of(2024, 6, 15, 14, 30)); + entry.setDateLastModified(LocalDateTime.of(2024, 12, 25, 9, 0)); + model.getDocumentsList().add(entry); + + model.setSelectedDocument(entry); + + assertEquals("Jun 15, 2024 at 14:30", model.getDocumentDateCreatedProperty().get()); + assertEquals("Dec 25, 2024 at 09:00", model.getDocumentDateLastModifiedProperty().get()); + } + private ArchiveEntry createTestEntry(String name, String summary) { var entry = new ArchiveEntry(); entry.setId(UUID.randomUUID()); From 095f4a9027dc8866dc651c80a1ec357c7d08e0c0 Mon Sep 17 00:00:00 2001 From: abedurftig Date: Mon, 19 Jan 2026 23:19:51 +0100 Subject: [PATCH 2/3] Fix modified date not updating after description change When a document's description is updated, the dateLastModified property is now refreshed to reflect the change immediately in the UI. Co-Authored-By: Claude Opus 4.5 --- .../java/dev/arne/smartfiles/app/ApplicationModel.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/dev/arne/smartfiles/app/ApplicationModel.java b/src/main/java/dev/arne/smartfiles/app/ApplicationModel.java index 1b8aeea..76514aa 100644 --- a/src/main/java/dev/arne/smartfiles/app/ApplicationModel.java +++ b/src/main/java/dev/arne/smartfiles/app/ApplicationModel.java @@ -101,6 +101,14 @@ public void updateDescription(String description) { if (selectedDocument != null) { selectedDocument.setSummary(description); refreshDocumentInList(selectedDocument); + refreshDocumentDateLastModified(); + } + } + + private void refreshDocumentDateLastModified() { + var selectedDocument = selectedDocumentProperty.get(); + if (selectedDocument != null) { + documentDateLastModifiedProperty.setValue(selectedDocument.getDateLastModified().format(DATE_FORMATTER)); } } From b8d13718b953eb60bbb90bd81760ed693b8e4b0c Mon Sep 17 00:00:00 2001 From: abedurftig Date: Mon, 19 Jan 2026 23:21:17 +0100 Subject: [PATCH 3/3] Update lastModified date when adding tags Added entry.updateLastModified() call in ArchiveServiceImpl.addTag() and refreshDocumentDateLastModified() call in ApplicationModel.updateDocumentTags() so the modified date is updated in both the model and UI when tags are added. Co-Authored-By: Claude Opus 4.5 --- src/main/java/dev/arne/smartfiles/app/ApplicationModel.java | 1 + .../dev/arne/smartfiles/core/service/ArchiveServiceImpl.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/dev/arne/smartfiles/app/ApplicationModel.java b/src/main/java/dev/arne/smartfiles/app/ApplicationModel.java index 76514aa..d6192ea 100644 --- a/src/main/java/dev/arne/smartfiles/app/ApplicationModel.java +++ b/src/main/java/dev/arne/smartfiles/app/ApplicationModel.java @@ -93,6 +93,7 @@ public void setSelectedDocument(ArchiveEntry selectedDocument) { public void updateDocumentTags() { tagsProperty.removeIf(_ -> true); tagsProperty.addAll(selectedDocumentProperty.get().getTags()); + refreshDocumentDateLastModified(); } public void updateDescription(String description) { diff --git a/src/main/java/dev/arne/smartfiles/core/service/ArchiveServiceImpl.java b/src/main/java/dev/arne/smartfiles/core/service/ArchiveServiceImpl.java index 69f3531..5dac031 100644 --- a/src/main/java/dev/arne/smartfiles/core/service/ArchiveServiceImpl.java +++ b/src/main/java/dev/arne/smartfiles/core/service/ArchiveServiceImpl.java @@ -87,6 +87,7 @@ public void addTag(UUID selectedDocumentId, String text) { var entry = archive.getArchiveEntries().get(selectedDocumentId); var newTag = new Tag(text); entry.getTags().add(newTag); + entry.updateLastModified(); publisher.publishEvent(new DocumentTagAddedEvent(newTag, selectedDocumentId)); publisher.publishEvent(new AllTagsUpdatedEvent(getAllUniqueTags())); saveArchiveAndPublishUpdate();