Skip to content

Release v0.2 — more improvements#3

Merged
AlanRockefeller merged 2 commits intomainfrom
test
Nov 2, 2025
Merged

Release v0.2 — more improvements#3
AlanRockefeller merged 2 commits intomainfrom
test

Conversation

@AlanRockefeller
Copy link
Copy Markdown
Owner

@AlanRockefeller AlanRockefeller commented Nov 2, 2025

Summary by CodeRabbit

  • New Features

    • Settings dialog: Helicon path (validated), cache size, prefetch radius, theme, default image directory
    • Actions menu: Run/Clear/Show Stacks; S-key toggles selection; stacking tracked with date; footer shows stacked date
  • Changes

    • App version bumped to 0.3; theme toggle refactor; Enter launches Helicon with selected RAWs or all stacks
  • Bug Fixes

    • Various input, dialog theming, QML layout, data integrity, and launch logic fixes

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 2, 2025

Walkthrough

Adds a changelog and bumps version to 0.3; tracks stacking metadata (stacked, stacked_date) in EntryMetadata and persists it after successful Helicon Focus launches; exposes new settings and stacking state to QML, introduces a Settings dialog, theme refactor to isDarkTheme, image anchoring change, and related config/schema updates.

Changes

Cohort / File(s) Summary
Changelog & README
faststack/ChangeLog.md, faststack/README.md, pyproject.toml
Adds ChangeLog documenting v0.2 and v0.3 entries; bumps project version to 0.3 and updates README text (S-key behavior and description).
Data Model
faststack/faststack/models.py
Adds stacked: bool = False and stacked_date: Optional[str] = None to EntryMetadata.
Application Core
faststack/faststack/app.py
Exposes stacking metadata in get_current_metadata; updates launch_helicon flow to record stacked/stacked_date for produced RAWs and save sidecars; adds many config getters/setters and dialog helpers; main now accepts optional image_dir; switches to QApplication.
Config
faststack/faststack/config.py
Replaces numeric core.cache_bytes with core.cache_size_gb string, adds defaults core.theme and core.default_directory, and ensures new keys are present on load.
UI State / Provider
faststack/faststack/ui/provider.py
Exposes isStacked and stackedDate properties (driven by metadata) and adds slots routing settings/getters/setters and dialog helpers to the app controller for QML.
QML — Main & Layout
faststack/faststack/qml/Main.qml, faststack/faststack/qml/Components.qml
Adds isDarkTheme property; derives currentBackgroundColor/currentTextColor from it and refactors toggleTheme(); adds SettingsDialog instance, header/menu/footer layout changes including footer stacked-date label when uiState.isStacked; replaces explicit Image width/height with anchors.fill: parent.
QML — Settings Dialog
faststack/faststack/qml/SettingsDialog.qml
New Settings dialog component exposing heliconPath, cacheSize, prefetchRadius, theme, defaultDirectory with browse/validation and commits via uiState setters on accept.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant QML as Main.qml / SettingsDialog
    participant UIState as provider.py
    participant App as app.py
    participant Model as models.py
    participant Helicon as Helicon Focus

    User->>QML: Select RAWs & press Enter
    QML->>UIState: request launch (launch_helicon)
    UIState->>App: launch_helicon(selected_stacks)
    App->>Helicon: execute Helicon with RAWs
    Helicon-->>App: success + produced RAW paths
    App->>App: compute today's date
    loop per produced RAW
        App->>Model: map RAW -> image stem and set metadata.stacked = True
        App->>Model: set metadata.stacked_date = today
    end
    App->>Model: save sidecar(s)
    App->>UIState: clear selection & refresh
    UIState->>QML: metadataChanged (isStacked/stackedDate)
    QML->>User: footer shows stacked date
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas to focus:
    • app.py launch flow: mapping produced RAWs to image stems, correct date formatting, timing of sidecar.save() vs UI refresh.
    • provider.py: slot wiring and metadata change notifications correctness for QML reactivity.
    • QML changes: theme propagation (isDarkTheme) and new footer/header layouts plus SettingsDialog bindings/validation.
    • config changes: migration of cache size representation and default keys.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The PR title claims to be "Release v0.2 — more improvements," but the actual changeset updates the version to v0.3 across multiple files: pyproject.toml is updated from 0.2 to 0.3, README.md shows the version bump from 0.1 to 0.3, and ChangeLog.md documents versions 0.2 and 0.3. This is a factual inconsistency where the title describes a different release version than what the code changes implement, making the title misleading about the primary purpose of the PR. Update the PR title to accurately reflect that this is releasing v0.3, not v0.2. A more appropriate title would be "Release v0.3 — settings dialog and stacking metadata" or similar, which captures both the version bump and the main feature additions visible in the changeset (new Settings dialog with configuration options, stacking metadata tracking, and UI improvements).
Docstring Coverage ⚠️ Warning Docstring coverage is 9.76% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
faststack/faststack/qml/Components.qml (1)

13-49: Fix pan-and-zoom implementation to work with anchors.fill.

The review comment is correct: the current code cannot work as written. The ChangeLog states this anchor-positioning conflict was "resolved," but the issue persists in the code. Line 13 applies anchors.fill: parent to mainImage, while lines 35–36 attempt manual positioning via mainImage.x and mainImage.y—but anchors override manual position properties in QML, rendering pan non-functional.

Choose one approach:

  • Remove anchors.fill from mainImage and set explicit dimensions, or
  • Replace manual x/y modifications with a Transform (translate property)

Without this fix, pan functionality will not work despite the placeholder MouseArea handler being in place.

🧹 Nitpick comments (2)
faststack/README.md (1)

3-3: LGTM – Version bump looks good.

The version and date update is consistent with the release objectives.

Optionally, some style guides recommend a comma after the year in a date:

-# Version 0.2 - November 1, 2025
+# Version 0.2 - November 1, 2025,
faststack/faststack/app.py (1)

238-254: Consider optimizing the raw-to-stem mapping lookup.

The logic correctly records stacking metadata after a successful Helicon launch. However, the nested loop (lines 241-249) has O(n×m) complexity, where n is the number of raw files and m is the total number of images. For large image sets, this could become slow.

Consider building a reverse lookup dictionary once to improve performance:

                # Record stacking metadata
                today = date.today().isoformat()
+               # Build reverse lookup: raw_path -> stem
+               raw_to_stem = {img.raw_pair: img.path.stem 
+                             for img in self.image_files 
+                             if img.raw_pair}
                for raw_path in unique_raw_files:
-                   # Find the corresponding image file to get the stem
-                   for img_file in self.image_files:
-                       if img_file.raw_pair == raw_path:
-                           stem = img_file.path.stem
-                           meta = self.sidecar.get_metadata(stem)
-                           meta.stacked = True
-                           meta.stacked_date = today
-                           break
+                   if raw_path in raw_to_stem:
+                       stem = raw_to_stem[raw_path]
+                       meta = self.sidecar.get_metadata(stem)
+                       meta.stacked = True
+                       meta.stacked_date = today
                self.sidecar.save()
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fdf4ecb and 54e32eb.

📒 Files selected for processing (7)
  • faststack/ChangeLog.md (1 hunks)
  • faststack/README.md (2 hunks)
  • faststack/faststack/app.py (4 hunks)
  • faststack/faststack/models.py (1 hunks)
  • faststack/faststack/qml/Components.qml (1 hunks)
  • faststack/faststack/qml/Main.qml (2 hunks)
  • faststack/faststack/ui/provider.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
faststack/faststack/ui/provider.py (1)
faststack/faststack/app.py (1)
  • get_current_metadata (142-159)
faststack/faststack/app.py (1)
faststack/faststack/io/sidecar.py (2)
  • get_metadata (85-87)
  • save (54-83)
🪛 LanguageTool
faststack/README.md

[style] ~3-~3: Some style guides suggest that commas should set off the year in a month-day-year date.
Context: ... FastStack # Version 0.2 - November 1, 2025 # By Alan Rockefeller Ultra-fast, cach...

(MISSING_COMMA_AFTER_YEAR)

🔇 Additional comments (9)
faststack/README.md (1)

38-38: LGTM – S key behavior description is clear.

The updated description accurately reflects the new toggle selection functionality.

faststack/faststack/models.py (1)

20-21: Consider future date handling requirements.

The new stacked and stacked_date fields integrate well with the metadata model. Storing the date as a string provides flexibility, though it sacrifices type safety and makes date-based operations (sorting, filtering, comparisons) less straightforward.

If you anticipate needing to query or sort by stacking date, consider using a proper date type or document the expected string format (currently ISO format via date.today().isoformat() in app.py line 240).

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

91-97: LGTM – New UI state properties are well-integrated.

The isStacked and stackedDate properties follow the established pattern for metadata properties, correctly use the metadataChanged signal, and properly delegate to the app controller.

faststack/ChangeLog.md (1)

1-30: LGTM – ChangeLog is comprehensive and well-organized.

The ChangeLog clearly documents the new features, changes, and bug fixes for version 0.2. The structure and content align well with the code changes across the PR.

faststack/faststack/qml/Main.qml (2)

12-19: LGTM – Theme refactor improves maintainability.

The introduction of isDarkTheme as a boolean property and deriving colors from it is cleaner and more robust than directly toggling color values. This makes the theme state explicit and easier to reason about.


64-68: LGTM – Stacked date footer displays correctly.

The new footer label properly uses visible: uiState.isStacked to conditionally display the stacking date, and the color choice (lightgreen) provides good visual feedback.

faststack/faststack/app.py (3)

7-7: LGTM – Date import is necessary.

The import of date from datetime is correctly added to support the stacking date functionality.


157-158: LGTM – Metadata extended with stacking fields.

The addition of stacked and stacked_date to the metadata dictionary properly exposes these fields to the UI layer.


222-222: LGTM – Loop simplification is cleaner.

The simplified iteration over self.stacks using tuple unpacking is more readable and removes an unused loop index.

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 (1)
faststack/faststack/app.py (1)

242-258: Consider optimizing the nested loop.

The stacking metadata recording logic is correct, but the nested loop (lines 245-253) has O(n×m) complexity. For large image sets, you could improve performance by building a reverse map first:

# Build map once
raw_to_image = {img.raw_pair: img for img in self.image_files if img.raw_pair}

# Then lookup in O(1)
for raw_path in unique_raw_files:
    if raw_path in raw_to_image:
        stem = raw_to_image[raw_path].path.stem
        meta = self.sidecar.get_metadata(stem)
        meta.stacked = True
        meta.stacked_date = today
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 54e32eb and 4d53598.

📒 Files selected for processing (8)
  • faststack/ChangeLog.md (1 hunks)
  • faststack/README.md (2 hunks)
  • faststack/faststack/app.py (8 hunks)
  • faststack/faststack/config.py (1 hunks)
  • faststack/faststack/qml/Main.qml (6 hunks)
  • faststack/faststack/qml/SettingsDialog.qml (1 hunks)
  • faststack/faststack/ui/provider.py (2 hunks)
  • faststack/pyproject.toml (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
faststack/faststack/app.py (3)
faststack/faststack/config.py (4)
  • getfloat (65-66)
  • get (59-60)
  • save (49-57)
  • getint (62-63)
faststack/faststack/io/sidecar.py (2)
  • get_metadata (85-87)
  • save (54-83)
faststack/faststack/ui/provider.py (13)
  • get_helicon_path (136-137)
  • set_helicon_path (140-141)
  • open_file_dialog (144-145)
  • check_path_exists (148-149)
  • get_cache_size (152-153)
  • set_cache_size (156-157)
  • get_prefetch_radius (160-161)
  • set_prefetch_radius (164-165)
  • get_theme (168-169)
  • set_theme (172-173)
  • get_default_directory (176-177)
  • set_default_directory (180-181)
  • open_directory_dialog (184-185)
faststack/faststack/ui/provider.py (2)
faststack/faststack/app.py (14)
  • get_current_metadata (146-163)
  • get_helicon_path (277-278)
  • set_helicon_path (280-282)
  • open_file_dialog (284-290)
  • check_path_exists (292-293)
  • get_cache_size (295-296)
  • set_cache_size (298-300)
  • get_prefetch_radius (302-303)
  • set_prefetch_radius (305-307)
  • get_theme (309-310)
  • set_theme (312-315)
  • get_default_directory (317-318)
  • set_default_directory (320-322)
  • open_directory_dialog (324-329)
faststack/faststack/config.py (1)
  • get (59-60)
🪛 LanguageTool
faststack/README.md

[style] ~3-~3: Some style guides suggest that commas should set off the year in a month-day-year date.
Context: ... FastStack # Version 0.3 - November 1, 2025 # By Alan Rockefeller Ultra-fast, cach...

(MISSING_COMMA_AFTER_YEAR)

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

356-356: Do not perform function call typer.Argument in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

🔇 Additional comments (9)
faststack/faststack/ui/provider.py (2)

91-97: LGTM! Stacking metadata exposure is well-structured.

The new isStacked and stackedDate properties correctly expose per-image stacking state to QML, with proper signal bindings and consistent patterns matching the existing metadata properties.


135-185: LGTM! Settings API surface is clean.

The new Slot methods provide a clean pass-through layer to expose app controller capabilities to QML. The blocking nature of file dialogs and config I/O is acceptable for user-initiated settings changes.

faststack/faststack/app.py (7)

7-7: LGTM!

Date import is necessary for the stacking metadata feature.


13-13: LGTM! QApplication switch enables dialog support.

Switching from QGuiApplication to QApplication is correct and necessary to support QFileDialog and other Qt Widgets used in the settings functionality.


45-46: LGTM!

Dynamic cache size configuration is correctly implemented with a sensible default.


82-83: LGTM!

Theme initialization correctly applies the user's theme preference at startup.


226-226: LGTM!

Removing the unused enumeration variable improves code clarity.


284-290: Verify cross-platform requirements for executable selection.

The file dialog filter is hardcoded to "Executables (*.exe)", which limits the application to Windows. If cross-platform support is planned, consider platform-specific filters:

import platform

def open_file_dialog(self):
    dialog = QFileDialog()
    dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
    if platform.system() == "Windows":
        dialog.setNameFilter("Executables (*.exe)")
    # macOS and Linux typically don't use extensions for executables
    if dialog.exec():
        return dialog.selectedFiles()[0]
    return ""

Is Windows-only support intentional for this release?


373-373: LGTM!

Application instantiation correctly uses QApplication to support widgets.

Comment thread faststack/faststack/app.py
Comment thread faststack/faststack/qml/Main.qml
@AlanRockefeller AlanRockefeller merged commit b5a0b9c into main Nov 2, 2025
1 check passed
@coderabbitai coderabbitai Bot mentioned this pull request Jan 2, 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