Skip to content

Release v0.2 — working Helicon Focus integration and viewer improvements#2

Merged
AlanRockefeller merged 1 commit intomainfrom
test
Nov 2, 2025
Merged

Release v0.2 — working Helicon Focus integration and viewer improvements#2
AlanRockefeller merged 1 commit intomainfrom
test

Conversation

@AlanRockefeller
Copy link
Copy Markdown
Owner

@AlanRockefeller AlanRockefeller commented Nov 1, 2025

Fixes some bugs and adds new menu items.

Summary by CodeRabbit

Release Notes

New Features

  • RAW file selection system—press S to toggle selection, then Enter to stack selected files with Helicon Focus
  • Dark/light theme toggle via View menu
  • Key bindings reference and stack summary dialogs
  • Actions menu for stack management

Bug Fixes

  • Improved Helicon Focus executable path validation
  • Enhanced image prefetching stability and race condition handling

Chores

  • Version bump to 0.2

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 1, 2025

Walkthrough

This PR extends FastStack with RAW file selection capabilities, implements Helicon Focus stack launching functionality, introduces theming support and new UI dialogs, hardens prefetch logic against race conditions, validates Helicon executable paths, and updates project metadata and documentation.

Changes

Cohort / File(s) Summary
Project Configuration
.gitignore, pyproject.toml
Fixed hidden character in comment; updated version from 0.1.0 to 0.2 and changed author from Gemini to Alan Rockefeller.
Core Application Logic
faststack/faststack/app.py
Added RAW file selection state (selected_raws), selection toggling, Helicon Focus launch workflow with deduplication and temporary file cleanup, event filtering improvements, and enhanced logging and UI synchronization.
Data Models
faststack/faststack/models.py
Added optional stack_id field to EntryMetadata for associating entries with stacks.
Image Processing
faststack/faststack/imaging/prefetch.py
Hardened race condition handling by capturing generation at task start, guarding set_image_files against unnecessary cancellations, and re-checking generation before cache updates.
I/O & Validation
faststack/faststack/io/helicon.py, faststack/faststack/io/watcher.py
Added input validation for Helicon executable path with error logging; added Optional type import for type hints.
UI State & Bindings
faststack/faststack/ui/provider.py
Added get_stack_summary property and new launch_helicon and clear_all_stacks slots for QML integration.
User Input & Key Mappings
faststack/faststack/ui/keystrokes.py
Changed S key to toggle selection instead of launching Helicon; added Return key mapping to launch Helicon (alongside Enter).
QML Components
faststack/faststack/qml/Components.qml
Changed Image block anchoring to explicit width/height, updated source condition to check imageCount > 0, and removed metadata overlay Rectangle.
Main QML UI
faststack/faststack/qml/Main.qml
Added theming support with currentBackgroundColor and currentTextColor properties and toggleTheme() function; expanded fullscreen behavior; enhanced footer with dynamic styling and stack info display; added View and Actions menus; introduced showStacksDialog and renamed About to Key Bindings dialog.
Tests & Utilities
faststack/faststack/tests/test_sidecar.py, faststack/test.py, faststack/README.md
Updated import path for EntryMetadata; adjusted default sidecar version expectation; removed TurboJPEG initialization test code; updated README to document S key behavior change.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant UI as QML UI
    participant Keys as Keystrokes
    participant App as AppController
    participant Helicon as Helicon Focus

    rect rgb(220, 240, 220)
    Note over User,Helicon: Selection Workflow
    User->>UI: Press S
    UI->>Keys: Handle Key Event
    Keys->>App: toggle_selection()
    App->>App: Add/Remove current RAW<br/>from selected_raws
    App->>UI: sync_ui_state()
    end

    rect rgb(220, 220, 240)
    Note over User,Helicon: Stack Launch Workflow
    User->>UI: Press Enter or Return<br/>(or click Launch)
    UI->>Keys: Handle Key Event
    Keys->>App: launch_helicon()
    App->>App: Deduplicate selected/stack RAWs
    App->>Helicon: Launch with RAW files
    Helicon->>Helicon: Process stack
    App->>App: Clear selected_raws<br/>Schedule temp cleanup
    App->>UI: sync_ui_state()
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas requiring extra attention:

  • Race condition fixes in prefetch.py: Verify that generation capture and re-checking logic correctly prevents stale cache updates under concurrent access.
  • Event filtering logic in app.py: Ensure eventFilter return value handling correctly consumes/passes through key events based on handler outcomes.
  • Helicon launch workflow in app.py: Validate deduplication logic, temporary file scheduling, and error handling for edge cases (empty selections, missing executable).
  • UIState integration in provider.py: Confirm that new QML-callable slots correctly delegate to app controller and that property exposure doesn't introduce threading issues.
  • QML theming and dialog additions in Main.qml: Review completeness of theme toggle, color binding consistency, and new dialogs' lifecycle management.
  • Import path updates in tests: Verify that all test references to EntryMetadata use the correct faststack.models module.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Release v0.2 — working Helicon Focus integration and viewer improvements" directly relates to the substantial changes in this changeset. The Helicon Focus integration is well-represented through the new launch_helicon method, input validation for the executable, and updated key mappings. The viewer improvements are evident in the significant UI enhancements across Main.qml and Components.qml, including theming support, fullscreen behavior, enhanced footer styling, and new dialogs. The title is specific and meaningful rather than generic, and it accurately captures the primary objectives of the release without claiming to cover every implementation detail, which aligns with the stated expectations.
✨ 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 test

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
Copy Markdown

@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: 2

🧹 Nitpick comments (3)
faststack/faststack/qml/Components.qml (1)

13-14: Consider using anchors.fill: parent for more idiomatic QML.

While the explicit width and height bindings are functionally equivalent, anchors.fill: parent is the standard QML pattern for this use case and is more concise.

Apply this diff if you prefer the standard approach:

-        width: parent.width
-        height: parent.height
+        anchors.fill: parent
faststack/faststack/app.py (1)

236-238: Selection cleared even on launch failure.

The selected_raws set is cleared unconditionally, even if launch_helicon_focus fails. Consider moving the clear operation inside the if success block so users don't lose their selection when launch fails.

Apply this diff:

             success, tmp_path = launch_helicon_focus(unique_raw_files)
             if success and tmp_path:
                 # Schedule delayed deletion of the temporary file
                 QTimer.singleShot(5000, lambda: self._delete_temp_file(tmp_path))
+                # Clear selection after successful launch
+                self.selected_raws.clear()
             
-            # Clear selection after launching
-            self.selected_raws.clear()
             self.sync_ui_state()
faststack/faststack/qml/Main.qml (1)

17-27: Theme toggle works but could be more robust.

The string comparison of currentBackgroundColor with "#212121" works for this simple case but is fragile. Consider using a boolean isDarkTheme property for more reliable theme tracking.

Example alternative approach:

property bool isDarkTheme: true
property color currentBackgroundColor: isDarkTheme ? "#212121" : "white"
property color currentTextColor: isDarkTheme ? "white" : "black"

function toggleTheme() {
    isDarkTheme = !isDarkTheme
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50342e1 and 0d15774.

📒 Files selected for processing (14)
  • .gitignore (2 hunks)
  • faststack/README.md (1 hunks)
  • faststack/faststack/app.py (7 hunks)
  • faststack/faststack/imaging/prefetch.py (3 hunks)
  • faststack/faststack/io/helicon.py (1 hunks)
  • faststack/faststack/io/watcher.py (1 hunks)
  • faststack/faststack/models.py (1 hunks)
  • faststack/faststack/qml/Components.qml (1 hunks)
  • faststack/faststack/qml/Main.qml (4 hunks)
  • faststack/faststack/tests/test_sidecar.py (2 hunks)
  • faststack/faststack/ui/keystrokes.py (1 hunks)
  • faststack/faststack/ui/provider.py (2 hunks)
  • faststack/pyproject.toml (1 hunks)
  • faststack/test.py (0 hunks)
💤 Files with no reviewable changes (1)
  • faststack/test.py
🧰 Additional context used
🧬 Code graph analysis (4)
faststack/faststack/ui/keystrokes.py (2)
faststack/faststack/app.py (2)
  • toggle_selection (192-208)
  • launch_helicon (211-240)
faststack/faststack/ui/provider.py (1)
  • launch_helicon (120-121)
faststack/faststack/ui/provider.py (1)
faststack/faststack/app.py (2)
  • launch_helicon (211-240)
  • clear_all_stacks (250-255)
faststack/faststack/app.py (4)
faststack/faststack/ui/keystrokes.py (1)
  • handle_key_press (38-45)
faststack/faststack/io/sidecar.py (1)
  • load (26-52)
faststack/faststack/ui/provider.py (7)
  • currentIndex (65-66)
  • imageCount (69-70)
  • currentFilename (80-81)
  • isFlagged (84-85)
  • isRejected (88-89)
  • stackInfoText (92-93)
  • launch_helicon (120-121)
faststack/faststack/io/helicon.py (1)
  • launch_helicon_focus (13-57)
faststack/faststack/tests/test_sidecar.py (1)
faststack/faststack/models.py (1)
  • EntryMetadata (15-19)
🪛 LanguageTool
faststack/README.md

[style] ~38-~38: Consider removing “of” to be more concise
Context: ...ge - G: Toggle Grid View - S: Stack all of the selected stacks with Helicon Focus - `[...

(ALL_OF_THE)

🪛 Ruff (0.14.2)
faststack/faststack/app.py

219-219: Loop control variable i not used within loop body

Rename unused i to _i

(B007)

🔇 Additional comments (31)
.gitignore (1)

1-1: Good housekeeping improvements to .gitignore.

Both changes are beneficial: removing the non-ASCII BOM character (line 1) improves file hygiene and prevents potential tool compatibility issues, and adding prompt.md (line 25) prevents accidental commits of generated artifacts.

Also applies to: 25-25

faststack/faststack/io/watcher.py (1)

5-5: LGTM!

The Optional import is correctly used for the self.observer type hint on line 28, accurately reflecting that the attribute can be either an Observer instance or None throughout its lifecycle.

faststack/pyproject.toml (2)

8-8: LGTM! Version bump aligns with the release.

The version increment from "0.1.0" to "0.2" is consistent with the PR title and reflects the working Helicon Focus integration and viewer improvements.


10-10: LGTM! Author metadata updated.

The author change from Gemini to Alan Rockefeller properly reflects the project's ownership.

faststack/faststack/models.py (1)

19-19: LGTM! Well-designed optional field.

The stack_id field properly supports the new stack association feature with an appropriate optional type and default value, maintaining backward compatibility.

faststack/faststack/tests/test_sidecar.py (2)

9-9: LGTM! Import path updated correctly.

The import change reflects the relocation of EntryMetadata from faststack.types to faststack.models, consistent with the model consolidation.


24-24: LGTM! Test expectation updated for new default version.

The version assertion correctly reflects the updated default sidecar version (2), maintaining test accuracy.

faststack/faststack/imaging/prefetch.py (2)

26-28: LGTM! Smart optimization to avoid unnecessary work.

The equality check prevents canceling and restarting prefetch tasks when the image list hasn't actually changed, reducing churn.


65-80: LGTM! Effective race condition mitigation.

The generation capture and dual-check pattern properly guards against race conditions:

  • Line 67 detects if a task is stale before starting work (generation changed between submission and execution)
  • Line 78 detects if generation changed during the decode operation, preventing stale results from being cached

While self.generation is accessed without locks, this best-effort approach is appropriate for prefetch optimization.

faststack/faststack/ui/keystrokes.py (1)

30-32: LGTM! Key bindings align with new workflow.

The changes properly implement the new selection-based workflow:

  • S now toggles selection (line 30), consistent with AppController.toggle_selection
  • Both Enter and Return launch Helicon Focus (lines 31-32), which is standard practice for keyboard compatibility
faststack/faststack/io/helicon.py (1)

23-31: LGTM! Robust input validation added.

The validation improvements properly guard against configuration issues:

  • Lines 23-25: Checks for empty or non-string executable path
  • Lines 27-28: Correctly creates a Path object before calling is_file() (strings don't have this method)
  • Appropriate error logging for debugging
faststack/faststack/ui/provider.py (2)

95-104: LGTM! Clear and informative stack summary.

The get_stack_summary property provides well-formatted stack information for UI display, with appropriate handling of the no-stacks case.


119-125: LGTM! Clean slot implementations.

The new slots (launch_helicon and clear_all_stacks) properly delegate to the controller, maintaining clean separation between UI and business logic.

faststack/faststack/qml/Components.qml (1)

15-15: Good defensive check for image count.

The addition of uiState.imageCount > 0 prevents potential issues when accessing currentImageSource with no images loaded. This aligns well with the Python-side handling of empty image lists.

faststack/faststack/app.py (9)

10-10: LGTM!

Import of concurrent.futures is appropriate for handling prefetch task futures and cancellation.


59-59: LGTM!

The selected_raws attribute properly initializes a set to track user-selected RAW files for batch operations.


63-65: Good fix for proper event handling.

Now correctly respects the return value from handle_key_press and returns True to Qt when the event is handled, preventing further propagation. This follows the proper Qt event filter pattern.


71-74: Good defensive bounds checking.

The clamping logic ensures current_index stays within valid range even if the sidecar's last_index is stale (e.g., files deleted since last run). This prevents index out of bounds errors.


88-90: Good defensive check for empty image list.

Prevents attempting to decode when no images are loaded, returning None safely.


100-112: Proper handling of cancellation, with acknowledged limitation.

The CancelledError handling prevents crashes when prefetch tasks are cancelled. The comment correctly notes that returning None is a simplified fallback. For a more robust solution, consider implementing a direct synchronous decode method as the comment suggests, but the current approach is safe and acceptable.


121-122: Helpful debug logging for UI state synchronization.

These debug logs will aid in troubleshooting UI state issues without cluttering production logs.


143-143: Appropriate debug logging for edge case.

The debug log when image_files is empty helps trace this condition without cluttering normal logs.


192-209: Well-implemented selection toggle with proper guards.

The method correctly checks for empty image lists and RAW pair existence before toggling selection state. The UI sync ensures the interface reflects the change.

faststack/faststack/qml/Main.qml (8)

7-9: LGTM!

Fullscreen configuration with Screen dimensions is appropriate for an image viewer application.


43-54: Good footer layout improvements.

The explicit IDs and anchoring make the layout more maintainable and explicit. The padding calculation is appropriate.


56-70: Good footer label updates with proper theming.

The template literals and conditional color bindings correctly display metadata with appropriate visual feedback. The fallback values ensure graceful display when data is unavailable.


72-85: Stack info display is clear with good contrast.

The orange background with black bold text provides excellent visibility for stack information. The conditional coloring is well-implemented.


108-129: Well-structured menus with proper action bindings.

The new View and Actions menus provide good UI access to features. All action triggers correctly invoke the appropriate methods.


133-133: More descriptive menu text.

Changing from "About" to "Key Bindings" accurately describes the dialog content, improving user experience.


141-173: Key Bindings dialog properly themed and updated.

The dialog correctly adopts the application theme with appropriate background and text colors. The increased height and updated content improve usability.


175-193: The code is correctly implemented; no changes needed.

Verification confirms get_stack_summary is properly decorated with @Property(str, notify=metadataChanged) on line 95 of provider.py, and uiState is correctly exposed to QML via setContextProperty. The usage in Main.qml line 188 (text: uiState.get_stack_summary) is the correct pattern for accessing PyQt properties in QML—no method call parentheses are needed.

Likely an incorrect or invalid review comment.

Comment thread faststack/faststack/app.py
Comment thread faststack/README.md
@AlanRockefeller AlanRockefeller merged commit fdf4ecb into main Nov 2, 2025
1 check passed
@coderabbitai coderabbitai Bot mentioned this pull request Dec 8, 2025
@coderabbitai coderabbitai Bot mentioned this pull request Feb 9, 2026
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