Skip to content

Conversation

chungcc454-design
Copy link

@chungcc454-design chungcc454-design commented Oct 5, 2025

Summary by Sourcery

Enable drag-and-drop file input in the UI by migrating to tkdnd.TkinterDnD.Tk, grouping widgets in a main frame, updating to dark mode, and adding drop handlers with preview support

New Features:

  • Add drag-and-drop file support for source and target selection using tkdnd.TkinterDnD.Tk integration
  • Introduce handle_drop_source and handle_drop_target handlers to process dropped files and render previews

Enhancements:

  • Switch UI root from CTk to tkdnd.TkinterDnD.Tk and encapsulate widgets in a main frame
  • Set appearance mode to dark and apply custom background colors

Copy link
Contributor

sourcery-ai bot commented Oct 5, 2025

Reviewer's Guide

Refactor create_root to use a tkdnd.TkinterDnD root with dark mode and a main_frame layout, reparent all widgets under this container, integrate drag-and-drop support with new handlers, and remove unused NSFW filter code.

Class diagram for updated UI root and drag-and-drop handlers

classDiagram
    class TkinterDnD_Tk {
        +minsize()
        +title()
        +configure(bg)
        +protocol()
    }
    class CTkFrame {
        +pack()
    }
    class CTkLabel {
        +place()
        +drop_target_register()
        +dnd_bind()
        +configure(image)
    }
    class CTkButton {
        +place()
        +drop_target_register()
        +dnd_bind()
    }
    class handle_drop_source {
        +__call__(event)
    }
    class handle_drop_target {
        +__call__(event)
    }
    TkinterDnD_Tk <|-- CTkFrame
    CTkFrame <|-- CTkLabel
    CTkFrame <|-- CTkButton
    CTkLabel <.. handle_drop_source : dnd_bind
    CTkButton <.. handle_drop_source : dnd_bind
    CTkLabel <.. handle_drop_target : dnd_bind
    CTkButton <.. handle_drop_target : dnd_bind
Loading

File-Level Changes

Change Details Files
Root initialization and appearance adjustment
  • Changed create_root return type to tkdnd.TkinterDnD.Tk
  • Switched appearance mode to dark and configured background color
  • Added main_frame container and packed it into root
modules/ui.py
Reparented UI widgets under main_frame container
  • Updated all CTkLabel, CTkButton, CTkSwitch, and CTkOptionMenu creations to use main_frame as parent
modules/ui.py
Integrated drag-and-drop support for source and target selection
  • Registered drop targets and bound <> events on labels and select buttons
  • Implemented handle_drop_source and handle_drop_target to parse file paths, validate types, render previews, and update status
modules/ui.py
Removed unused NSFW filter code
  • Deleted commented-out nsfw_switch block and cleaned up extra blank lines
modules/ui.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • create_root has become very long and mixes UI layout with event binding—consider splitting it into smaller helper functions for better readability and maintainability.
  • There’s a lot of repeated drop_target_register and dnd_bind code—extracting a helper to register DnD handlers would reduce duplication.
  • The create_root return annotation still mentions ctk.CTk but the function now returns tkdnd.TkinterDnD.Tk; please update the type hint to match.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- create_root has become very long and mixes UI layout with event binding—consider splitting it into smaller helper functions for better readability and maintainability.
- There’s a lot of repeated drop_target_register and dnd_bind code—extracting a helper to register DnD handlers would reduce duplication.
- The create_root return annotation still mentions ctk.CTk but the function now returns tkdnd.TkinterDnD.Tk; please update the type hint to match.

## Individual Comments

### Comment 1
<location> `modules/ui.py:1220-1234` </location>
<code_context>
+
+
+# New drop handler functions
+def handle_drop_source(event):
+    """Handle files dropped on source button or label"""
+    file_path = event.data
+    # On Windows, file paths may be enclosed in {}
+    if file_path.startswith("{") and file_path.endswith("}"):
+        file_path = file_path[1:-1]
+
+    if is_image(file_path):
+        modules.globals.source_path = file_path
+        global RECENT_DIRECTORY_SOURCE
+        RECENT_DIRECTORY_SOURCE = os.path.dirname(modules.globals.source_path)
+        image = render_image_preview(modules.globals.source_path, (200, 200))
+        source_label.configure(image=image)
+    else:
+        update_status("Please drop an image file for the source.")
+
+
</code_context>

<issue_to_address>
**suggestion (bug_risk):** handle_drop_source does not sanitize or validate file paths beyond extension.

Please add error handling for invalid, inaccessible, or corrupted files to ensure robust file access and image loading.

```suggestion
def handle_drop_source(event):
    """Handle files dropped on source button or label"""
    file_path = event.data
    # On Windows, file paths may be enclosed in {}
    if file_path.startswith("{") and file_path.endswith("}"):
        file_path = file_path[1:-1]

    if not is_image(file_path):
        update_status("Please drop an image file for the source.")
        return

    # Check if file exists and is accessible
    if not os.path.isfile(file_path):
        update_status("File does not exist or is not accessible.")
        return

    try:
        # Try opening the file to check for accessibility/corruption
        with open(file_path, "rb") as f:
            data = f.read(10)  # Try reading a small chunk

        modules.globals.source_path = file_path
        global RECENT_DIRECTORY_SOURCE
        RECENT_DIRECTORY_SOURCE = os.path.dirname(modules.globals.source_path)
        try:
            image = render_image_preview(modules.globals.source_path, (200, 200))
            if image is None:
                update_status("Failed to load image preview. The file may be corrupted or unsupported.")
                return
            source_label.configure(image=image)
        except Exception as e:
            update_status(f"Error loading image preview: {str(e)}")
    except Exception as e:
        update_status(f"Error accessing file: {str(e)}")
```
</issue_to_address>

### Comment 2
<location> `modules/ui.py:1252-1254` </location>
<code_context>
+            image = render_image_preview(modules.globals.target_path, (200, 200))
+            target_label.configure(image=image)
+        elif is_video(file_path):
+            video_frame = render_video_preview(file_path, (200, 200))
+            target_label.configure(image=video_frame)
+    else:
</code_context>

<issue_to_address>
**suggestion:** No error handling for video preview rendering failures.

Add error handling to render_video_preview to catch exceptions and inform the user if preview generation fails.

```suggestion
        elif is_video(file_path):
            try:
                video_frame = render_video_preview(file_path, (200, 200))
                target_label.configure(image=video_frame)
            except Exception as e:
                import tkinter.messagebox as messagebox
                messagebox.showerror("Preview Error", f"Failed to generate video preview:\n{e}")
                target_label.configure(text="Video preview unavailable", image="")
```
</issue_to_address>

### Comment 3
<location> `modules/ui.py:1244` </location>
<code_context>
def handle_drop_target(event):
    """Handle files dropped on target button or label"""
    file_path = event.data
    # On Windows, file paths may be enclosed in {}
    if file_path.startswith("{") and file_path.endswith("}"):
        file_path = file_path[1:-1]

    if is_image(file_path) or is_video(file_path):
        modules.globals.target_path = file_path
        global RECENT_DIRECTORY_TARGET
        RECENT_DIRECTORY_TARGET = os.path.dirname(modules.globals.target_path)

        if is_image(file_path):
            image = render_image_preview(modules.globals.target_path, (200, 200))
            target_label.configure(image=image)
        elif is_video(file_path):
            video_frame = render_video_preview(file_path, (200, 200))
            target_label.configure(image=video_frame)
    else:
        update_status("Please drop an image or video file for the target.")

</code_context>

<issue_to_address>
**issue (code-quality):** We've found these issues:

- Split conditional into multiple branches ([`split-or-ifs`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/split-or-ifs/))
- Extract duplicate code into function ([`extract-duplicate-method`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/extract-duplicate-method/))
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

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.

2 participants