Skip to content

Feature/lbx 793#2390

Open
Hachi-R wants to merge 7 commits into
mainfrom
feature/lbx-793
Open

Feature/lbx 793#2390
Hachi-R wants to merge 7 commits into
mainfrom
feature/lbx-793

Conversation

@Hachi-R

@Hachi-R Hachi-R commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

Hachi-R added 2 commits June 22, 2026 04:43
Introduced a new helper component for rendering file entry icons based on file extensions. This includes support for image, audio, video, archive, disc, script, save, patch, and code file types, enhancing the user interface for file management.
Added a new FileExplorerModal component to facilitate directory selection within the application. This modal allows users to navigate their file system, view directory contents, and select directories for download paths. Integrated necessary hooks and state management for loading directories and handling user interactions. Updated relevant styles and added new helper functions for file handling.
@greptile-apps

greptile-apps Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a custom FileExplorerModal component for Hydra's big-picture (gamepad) UI, replacing the native showOpenDialog with a keyboard/gamepad-navigable file browser. New IPC handlers (readDirectory, getPathInfo, listDrives) are added to the main process, with the Windows drive-list detection rewritten to probe drive letters via fs.access instead of the deprecated wmic command.

  • FileExplorerModal — new component with path-input navigation, drive listing, filter support, and breadcrumb-style back navigation via gamepad B button.
  • file-system.ts — three new IPC handlers; listDrives uses fs.access for Windows (more reliable than wmic); readDirectory calls stat() per file for size but does not resolve symlinks, leaving symlinked directories unnavigable.
  • file-entry-icon.tsx — comprehensive extension-to-icon mapping helper; DirectoryEntry interface is defined here, in file-system.ts, and inlined in declaration.d.ts creating three separate definitions of the same shape.

Confidence Score: 4/5

Safe to merge once the symlink resolution in readDirectory is addressed; all other changes are additive and well-structured.

The readDirectory handler classifies Dirent entries using isDirectory()/isFile() which return false for symlinks. On macOS and Linux, symlinked directories silently become unnavigable in selectDirectory mode — the user can see them but clicking navigates nowhere useful. This is a real usability defect on non-Windows platforms. Everything else (drive listing, filter logic, gamepad navigation hooks, cancellation) looks correct.

src/main/events/misc/file-system.ts — the symlink classification block inside readDirectory's Promise.all mapper

Important Files Changed

Filename Overview
src/main/events/misc/file-system.ts New IPC handlers for readDirectory, getPathInfo, and listDrives — symlinks not resolved, so symlinked directories appear as neither file nor directory and cannot be navigated
src/big-picture/src/components/common/file-explorer-modal/use-file-explorer.ts Custom hook for the file explorer modal with proper cancellation, error handling, and drive listing; async handlePathEnter called without void (already flagged)
src/big-picture/src/helpers/file-entry-icon.tsx Large icon-mapping helper with its own DirectoryEntry interface — duplicate of the one in file-system.ts; also has a duplicate mka entry in audioExtensions (already flagged)
src/big-picture/src/components/common/file-explorer-modal/styles.scss Styles for the file explorer; hardcoded magic px values (44px, 46px, 10px) not extracted to named constants per project convention
src/big-picture/src/pages/settings/download-directories-section.tsx Replaces native showOpenDialog with the new FileExplorerModal for the big-picture UI download directory picker
src/preload/index.ts Exposes readDirectory, getPathInfo, and listDrives through the context bridge

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant UI as FileExplorerModal
    participant Hook as useFileExplorer
    participant Preload as contextBridge
    participant Main as file-system.ts (main)

    UI->>Hook: "visible=true, initialPath"
    Hook->>Preload: listDrives()
    Preload->>Main: ipcRenderer.invoke("listDrives")
    Main-->>Preload: string[] (drive letters / "/")
    Preload-->>Hook: drives[]
    Hook->>Hook: setDrives / showDriveList

    UI->>Hook: user selects drive / types path
    Hook->>Preload: readDirectory(path)
    Preload->>Main: ipcRenderer.invoke("readDirectory", path)
    Main-->>Preload: DirectoryEntry[]
    Preload-->>Hook: entries[]
    Hook->>Hook: filteredEntries (matchesFilters)

    UI->>Hook: user types path + Enter
    Hook->>Preload: getPathInfo(path)
    Preload->>Main: ipcRenderer.invoke("getPathInfo", path)
    Main-->>Preload: "PathInfo {exists, isDirectory}"
    Preload-->>Hook: pathInfo
    Hook->>Hook: setCurrentPath or reset input

    UI->>Hook: user clicks Select this directory
    Hook->>UI: onSelect(currentPath)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant UI as FileExplorerModal
    participant Hook as useFileExplorer
    participant Preload as contextBridge
    participant Main as file-system.ts (main)

    UI->>Hook: "visible=true, initialPath"
    Hook->>Preload: listDrives()
    Preload->>Main: ipcRenderer.invoke("listDrives")
    Main-->>Preload: string[] (drive letters / "/")
    Preload-->>Hook: drives[]
    Hook->>Hook: setDrives / showDriveList

    UI->>Hook: user selects drive / types path
    Hook->>Preload: readDirectory(path)
    Preload->>Main: ipcRenderer.invoke("readDirectory", path)
    Main-->>Preload: DirectoryEntry[]
    Preload-->>Hook: entries[]
    Hook->>Hook: filteredEntries (matchesFilters)

    UI->>Hook: user types path + Enter
    Hook->>Preload: getPathInfo(path)
    Preload->>Main: ipcRenderer.invoke("getPathInfo", path)
    Main-->>Preload: "PathInfo {exists, isDirectory}"
    Preload-->>Hook: pathInfo
    Hook->>Hook: setCurrentPath or reset input

    UI->>Hook: user clicks Select this directory
    Hook->>UI: onSelect(currentPath)
Loading

Reviews (2): Last reviewed commit: "refactor: restructure FileExplorerModal ..." | Re-trigger Greptile

Comment thread src/main/events/misc/list-drives.ts Outdated
Comment thread src/big-picture/src/components/common/file-explorer-modal/index.tsx Outdated
Comment thread src/big-picture/src/components/common/file-explorer-modal/index.tsx Outdated
@Hachi-R

Hachi-R commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator Author

@greptile

Hachi-R added 4 commits June 22, 2026 06:52
Refactored the FileExplorerModal to use dynamic titles for empty states and improved error handling in the useFileExplorer hook. Introduced a new error message mapping for better user feedback and ensured proper path management when navigating directories. Updated the preload API to streamline file system interactions.
Modified the type definitions in declaration.d.ts to use rest parameters for the listener functions in the on and off methods. This change enhances type safety and aligns with TypeScript best practices.
Updated the useFileExplorer hook to resolve the initial path dynamically, improving path management and user experience. Refactored the GameCompatibilitySettingsTab and GameCustomizationSettingsTab components to integrate the FileExplorerModal for selecting wine prefixes and assets, respectively. Adjusted state handling and callback functions for better clarity and functionality across the game settings modal components.
… and state management

Updated the GameCompatibilitySettingsTab to include a dynamic initial path for the wine prefix selection. Refactored the GameLaunchSettingsTab to implement platform-specific executable filters, improving the user experience when selecting game executables. Adjusted the GameCustomizationSettingsTab to use explicit image file extensions, ensuring clarity and consistency in asset selection.
@sonarqubecloud

Copy link
Copy Markdown

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