Skip to content

Set timestamp menu item#58

Merged
meesoft merged 5 commits intomainfrom
features/SetTimeStamp
Dec 5, 2025
Merged

Set timestamp menu item#58
meesoft merged 5 commits intomainfrom
features/SetTimeStamp

Conversation

@meesoft
Copy link
Owner

@meesoft meesoft commented Nov 30, 2025

Summary by CodeRabbit

  • New Features

    • Added a "Set timestamp" action to the Metadata/EXIF context menu to prompt for and apply timestamps to selected photos (batch support).
  • Bug Fixes

    • Improved null-safety when focusing list items to avoid errors.
    • Made UI update timing more reliable after tone-mapping changes.
  • Chores

    • Simplified file-selection behavior so files are re-focused more predictably after operations.

✏️ Tip: You can customize this high-level summary in your review settings.

@meesoft meesoft marked this pull request as ready for review December 5, 2025 21:22
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 5, 2025

Walkthrough

Change signatures to use full file paths for selection, add a UI command and ExifTool API to set EXIF timestamps, tighten ToneMapping setter logic, make ListBox focus handling null-safe, and rename/adjust ExifTool timestamp method names.

Changes

Cohort / File(s) Summary
SelectFile signature
PhotoLocator/IMainViewModel.cs, PhotoLocator/MainViewModel.cs
Renamed SelectFileAsync(string fileName)SelectFileAsync(string fullPath) and updated internal usages to compare/select by FullPath.
Set timestamp feature
PhotoLocator/MainViewModel.cs, PhotoLocator/Metadata/ExifTool.cs, PhotoLocator/MainWindow.xaml
Added SetTimestampCommand in MainViewModel; added ExifTool.SetTimestampAsync(...) and renamed AdjustTimeStampAsyncAdjustTimestampAsync; added "Set timestamp" context menu binding in UI.
ViewModel logic & UI safety
PhotoLocator/LocalContrastViewModel.cs, PhotoLocator/MainWindow.xaml.cs
In ToneMapping setter, set MaxStretch = 100 when new value > 1 and ensure StartUpdateTimer runs only after successful change; refactored FocusListBoxItem to use safe cast / null-conditional calls.
Tests updated
PhotoLocatorTest/Metadata/ExifToolTest.cs
Updated test to call renamed ExifTool.AdjustTimestampAsync(...).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as MainWindow
    participant VM as MainViewModel
    participant Dialog as TimestampPrompt
    participant Exif as ExifTool
    participant FS as FileSystem

    User->>UI: Right-click -> "Set timestamp"
    UI->>VM: Execute SetTimestampCommand
    VM->>Dialog: Show timestamp input (initial suggestion)
    Dialog-->>VM: Return timestamp string
    VM->>VM: Start parallel tasks for each selected item
    VM->>Exif: SetTimestampAsync(item.FullPath, item.FullPath, timestamp, exifToolPath, ct)
    Exif->>FS: Invoke exiftool process to write EXIF timestamps
    FS-->>Exif: Process exit / success
    Exif-->>VM: Task(s) complete
    VM->>VM: Select first affected item's FullPath
    VM->>UI: Update selection / refresh
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Review MainViewModel: new SetTimestampCommand (parallel execution, error/cancellation handling), changed RunProcessWithProgressBarAsync selection flow, and updated SelectFileAsync usages.
  • Inspect ExifTool.SetTimestampAsync and renamed AdjustTimestampAsync for correct ProcessStartInfo construction, quoting/escaping, and cancellation propagation.
  • Validate LocalContrastViewModel ToneMapping setter behavior and StartUpdateTimer conditions.
  • Confirm MainWindow focus handling null-safety and XAML binding to the new command.
  • Update/verify unit test changes in PhotoLocatorTest/Metadata/ExifToolTest.cs.

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Set timestamp menu item' directly and accurately reflects the main changes in the pull request: adding a new SetTimestampCommand and corresponding menu item UI binding.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch features/SetTimeStamp

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8da4d8b and 9a5dd7c.

📒 Files selected for processing (3)
  • PhotoLocator/MainViewModel.cs (3 hunks)
  • PhotoLocator/Metadata/ExifTool.cs (2 hunks)
  • PhotoLocatorTest/Metadata/ExifToolTest.cs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
PhotoLocator/Metadata/ExifTool.cs (2)
PhotoLocator/PictureItemViewModel.cs (3)
  • Task (233-249)
  • Task (345-359)
  • Task (372-405)
PhotoLocator/Helpers/VideoProcessing.cs (4)
  • Task (34-53)
  • Task (57-99)
  • Task (103-166)
  • Task (168-178)
PhotoLocatorTest/Metadata/ExifToolTest.cs (1)
PhotoLocator/Metadata/ExifTool.cs (1)
  • ExifTool (14-206)
PhotoLocator/MainViewModel.cs (2)
PhotoLocator/IMainViewModel.cs (3)
  • Task (17-17)
  • Task (19-19)
  • Task (21-21)
PhotoLocator/Metadata/ExifTool.cs (1)
  • ExifTool (14-206)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (csharp)
  • GitHub Check: build
🔇 Additional comments (6)
PhotoLocatorTest/Metadata/ExifToolTest.cs (1)

18-18: LGTM!

The test method call is correctly updated to use the renamed AdjustTimestampAsync method, maintaining consistency with the API change in ExifTool.cs.

PhotoLocator/Metadata/ExifTool.cs (2)

18-26: LGTM!

The method rename to AdjustTimestampAsync improves naming consistency. Implementation logic remains correct with proper offset validation and ExifTool command construction.


28-32: LGTM!

The new SetTimestampAsync method correctly follows the established pattern, delegating to RunExifToolAsync. ExifTool will validate the timestamp format and return appropriate errors if invalid.

PhotoLocator/MainViewModel.cs (3)

271-284: LGTM!

The parameter rename from fileName to fullPath improves clarity, and the comparison now correctly matches against item.FullPath instead of item.Name, which aligns with how callers pass full path values.


486-493: LGTM!

The updated logic correctly ensures the selected item is focused after operation completion. SelectIfNotNull safely handles null values, maintaining consistent focus behavior.


947-968: LGTM!

The command correctly uses the renamed AdjustTimestampAsync method. The SelectFileAsync call at the end ensures proper item selection after the operation completes, improving the user experience.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
PhotoLocator/LocalContrastViewModel.cs (1)

171-175: Consider documenting the MaxStretch side effect.

When ToneMapping exceeds 1, this setter automatically sets MaxStretch to 100. This coupling between properties may not be intuitive to users. Consider adding a comment explaining the rationale for this behavior.

Note: Setting MaxStretch will trigger its own StartUpdateTimer call (Line 129), resulting in two timer starts when ToneMapping > 1. While this appears safe given the implementation, it's worth being aware of.

</review_comment_end>

PhotoLocator/MainWindow.xaml (1)

181-181: LGTM! New menu item added correctly.

The new "Set timestamp" menu item is properly placed in the Metadata / EXIF section and bound to SetTimestampCommand.

For visual consistency, consider adding an icon similar to the "Adjust timestamps" item above it.

</review_comment_end>

PhotoLocator/Metadata/ExifTool.cs (1)

28-32: Consider adding timestamp format validation.

Unlike AdjustTimeStampAsync (Line 20-21), which validates the offset format, this method doesn't validate the timestamp parameter. Consider adding validation to ensure the timestamp matches the expected ExifTool format (likely "yyyy:MM:dd HH:mm:ss") before constructing the command.

Example validation:

 public static async Task SetTimeStampAsync(string sourceFileName, string targetFileName, string timestamp, string exifToolPath, CancellationToken ct)
 {
+    if (string.IsNullOrWhiteSpace(timestamp))
+        throw new UserMessageException("Timestamp cannot be empty");
     var startInfo = new ProcessStartInfo(exifToolPath, $"\"-AllDates={timestamp}\" \"{sourceFileName}\" ");
     await RunExifToolAsync(sourceFileName, targetFileName, startInfo, ct);
 }

</review_comment_end>

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7a496a6 and 9dbda98.

📒 Files selected for processing (6)
  • PhotoLocator/IMainViewModel.cs (1 hunks)
  • PhotoLocator/LocalContrastViewModel.cs (1 hunks)
  • PhotoLocator/MainViewModel.cs (3 hunks)
  • PhotoLocator/MainWindow.xaml (1 hunks)
  • PhotoLocator/MainWindow.xaml.cs (1 hunks)
  • PhotoLocator/Metadata/ExifTool.cs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
PhotoLocator/Metadata/ExifTool.cs (1)
PhotoLocator/PictureItemViewModel.cs (3)
  • Task (233-249)
  • Task (345-359)
  • Task (372-405)
🔇 Additional comments (5)
PhotoLocator/MainWindow.xaml.cs (1)

142-144: LGTM! Improved null-safety.

The refactor to use a safe cast and null-conditional operators prevents potential NullReferenceException if the container is not a ListBoxItem or is null.

</review_comment_end>

PhotoLocator/IMainViewModel.cs (1)

17-17: LGTM! Parameter rename improves clarity.

Renaming fileName to fullPath better reflects that the parameter expects a complete file path rather than just a filename. The implementation in MainViewModel is correctly updated to match.

</review_comment_end>

PhotoLocator/MainViewModel.cs (3)

271-275: LGTM! Parameter rename improves clarity.

The rename from fileName to fullPath aligns with the interface change and makes the code more self-documenting.

</review_comment_end>


488-489: LGTM! Simplified focus handling.

The change from else-if to else simplifies the logic and ensures an item is always focused after the operation completes.

</review_comment_end>


959-966: LGTM! Improved file selection after timestamp adjustment.

Replacing the delay with SelectFileAsync is better because it actively waits for the file to appear (with retry logic) rather than using a passive delay.

</review_comment_end>

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9dbda98 and 8da4d8b.

📒 Files selected for processing (1)
  • PhotoLocator/MainViewModel.cs (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
PhotoLocator/MainViewModel.cs (5)
PhotoLocator/IMainViewModel.cs (3)
  • Task (17-17)
  • Task (19-19)
  • Task (21-21)
PhotoLocator/PictureItemViewModel.cs (4)
  • Task (233-249)
  • Task (345-359)
  • Task (372-405)
  • GetProcessedFileName (361-370)
PhotoLocator/Metadata/ExifTool.cs (1)
  • ExifTool (14-206)
PhotoLocator/Helpers/RelayCommand.cs (2)
  • RelayCommand (6-32)
  • RelayCommand (11-15)
PhotoLocator/BitmapOperations/BitmapPlaneInt16.cs (1)
  • ToString (58-61)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (csharp)
🔇 Additional comments (3)
PhotoLocator/MainViewModel.cs (3)

271-284: FullPath-based SelectFileAsync implementation looks correct

Using item.FullPath with a case-insensitive comparison and a bounded wait loop cleanly aligns this helper with the new full-path API and the EXIF commands that re-select processed files. No issues from an async/selection perspective.


483-493: RunProcessWithProgressBarAsync finally-branch simplification is safe

Changing the else if (focusItem is null) to a plain else keeps the behavior the same (the else only runs when focusItem is null anyway) while making the code slightly clearer. The selection fallback to SelectedItem remains intact.


947-968: Adjusted-timestamp EXIF operation wiring looks consistent

The updated AdjustTimestampsCommand correctly:

  • Prompts for a signed offset with basic validation,
  • Calls ExifTool.AdjustTimeStampAsync(item.FullPath, item.GetProcessedFileName(), offset, ...) in parallel with the configured degree of parallelism,
  • And re-selects the first affected item via SelectFileAsync(selectedItems[0].FullPath) to wait for any file-system updates.

This matches the existing ExifTool usage patterns and should behave as intended.

@meesoft meesoft merged commit 62df788 into main Dec 5, 2025
5 checks passed
@meesoft meesoft deleted the features/SetTimeStamp branch December 5, 2025 22:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant