Skip to content

Conversation

@baiyuanneko
Copy link
Contributor

@baiyuanneko baiyuanneko commented Oct 25, 2025

In my environment (Arch Linux), when I attempt 2.0.0alpha9 I noticed several bugs including:

  • Opening Mix Studio (Mix editing modal) will cause the app to crash immediately (error message 'Invalid collection type');
  • Track list at the right of mix studio modal is incomplete, not displaying all the tracks satisfying the mix query condition; Also does the situation in track list page of Mix.

In this PR, I've done the following:

  1. Added some debug level logs to help confirm the situation
  2. Modified the pagination logic of Mix Studio modal and Mix track list page, to support lazy loading and correct pagination processing.
  3. Modified the call method of SearchCollectionSummaryRequest to deliver the correct collection type, and process them correctly.
  4. I've tested on my machine that after the fix, the Mix Studio modal can display all the tracks satisfying the Mix query condition; The mix studio modal no longer causes the app to crash; The track list of a Mix can display correctly; The track list of a playlist can display correctly; Other functions remain working well.

Summary by Sourcery

Fix several collection display and editing issues by correcting collection type handling, implementing proper pagination for mix and track views, and adding extensive logging to aid debugging.

Bug Fixes:

  • Prevent Mix Studio from crashing by correcting the collection type passed to SearchCollectionSummaryRequest
  • Restore complete track listings in the Mix Studio modal and mix/playlist track pages by fixing pagination logic and supporting lazy loading
  • Ensure SearchCollectionSummaryRequest handles unsupported collection types gracefully instead of panicking

Enhancements:

  • Introduce detailed debug and error logs in FS path resolution, API query building, and local GUI requests
  • Refactor mix studio dialog and query tracks list with scroll-based pagination, debounce handling, and controlled state updates

@sourcery-ai
Copy link

sourcery-ai bot commented Oct 25, 2025

Reviewer's Guide

This PR resolves crashes and incomplete track listings in the Mix Studio modal and track list pages by overhauling pagination and lazy loading, corrects collection type dispatch for summary requests, and adds extensive logging and error handling across the client and server stacks for easier debugging.

Sequence diagram for lazy loading and pagination in Mix Studio modal

sequenceDiagram
    actor User
    participant "MixStudioDialog"
    participant "MixEditorController"
    participant "queryMixTracks()"
    participant "TrackListGrid"
    User->>MixStudioDialog: Open Mix Studio modal
    MixStudioDialog->>MixEditorController: loadMix(mixId)
    MixEditorController->>MixStudioDialog: setData(queryData)
    MixStudioDialog->>queryMixTracks(): Query tracks (cursor=0, pageSize)
    queryMixTracks()-->>MixStudioDialog: Return first page of tracks
    MixStudioDialog->>TrackListGrid: Display tracks
    User->>TrackListGrid: Scrolls down
    TrackListGrid->>MixStudioDialog: onScroll event
    MixStudioDialog->>queryMixTracks(): Query tracks (next cursor, pageSize)
    queryMixTracks()-->>MixStudioDialog: Return next page of tracks
    MixStudioDialog->>TrackListGrid: Append tracks
Loading

Class diagram for updated MixStudioDialogImplementationState and related pagination logic

classDiagram
    class MixStudioDialogImplementationState {
        -MixEditorController _controller
        -StartScreenLayoutManager _layoutManager
        -ScrollController _scrollController
        -bool isLoading
        -String _query
        -int _cursor
        -bool _isLoadingMore
        -bool _hasMore
        -List<InternalMediaFile> _allTracks
        -Timer? _debounceTimer
        -bool _isInitialLoad
        +void initState()
        +void dispose()
        +Future<void> loadMix(int mixId)
        +void _debouncedResetAndLoad()
        +void _onScroll()
        +Future<void> _resetAndLoadTracks()
        +Future<void> _loadMoreTracks()
    }
    class MixEditorController {
        +void setData(queryData)
        +void addListener(listener)
        +queryData getData()
    }
    class InternalMediaFile {
        +int id
        +other attributes
    }
    MixStudioDialogImplementationState "1" o-- "1" MixEditorController
    MixStudioDialogImplementationState "1" o-- "1" StartScreenLayoutManager
    MixStudioDialogImplementationState "1" o-- "1" ScrollController
    MixStudioDialogImplementationState "*" o-- "*" InternalMediaFile
Loading

Class diagram for SearchCollectionSummaryRequest changes

classDiagram
    class SearchCollectionSummaryRequest {
        +CollectionType collectionType
        +int n
        +Future<Response> sendSignalToRust()
    }
    class SearchCollectionSummaryResponse {
        +Stream rustSignalStream
        +Response message
    }
    SearchCollectionSummaryRequest --> SearchCollectionSummaryResponse
Loading

Class diagram for updated VirtualFS error handling and logging

classDiagram
    class VirtualFS {
        +Result path_to_query(Path)
        +Result resolve_path_with_ids(Path)
        +Result validate_path(Path)
        +void cache_entries(Path, entries, CollectionType)
        +Map cache
    }
    class Path {
        +int components().count()
        +Path parent()
        +String file_name()
    }
    VirtualFS o-- Path
Loading

File-Level Changes

Change Details Files
Implemented lazy loading and debounce-based pagination in the Mix Studio modal
  • Replaced SearchTask with ScrollController and pagination state variables
  • Added debounced reload logic on controller data changes
  • Introduced _resetAndLoadTracks and _loadMoreTracks methods for initial and subsequent data loads
  • Updated GridView to bind to the paginated _allTracks list and scroll controller
lib/utils/dialogs/mix/mix_studio_dialog.dart
Added initial page preloading and dynamic pagination to the query tracks list
  • Introduced _loadPageForInitialization to fetch the first page before marking as initialized
  • Adjusted _loadPage to update total item count and detect end-of-data
  • Managed loading indices and _reachedEnd flag to prevent duplicate or unnecessary loads
lib/screens/query_tracks/query_tracks_list.dart
Enhanced logging and error handling for collection type resolution and query construction
  • Added debug and error logs around path-to-collection logic and query builders in virtual FS
  • Logged collection_type and query flow in build_query and path_to_collection_type in the API client
  • Improved error reporting in SearchCollectionSummaryRequest handler for unsupported types
  • Extended GUI backend to log full error chains and backtraces on request failures
  • Inserted info logs in database mix media query to report pagination parameters and result counts
native/hub/src/server/client/fs.rs
native/hub/src/server/client/api.rs
native/hub/src/handlers/collection.rs
native/hub/src/backends/local/gui_request.rs
database/src/actions/mixes.rs
Corrected SearchCollectionSummaryRequest usage to include collectionType
  • Updated search_collection_summary.dart to pass the collectionType parameter in the request
lib/utils/api/search_collection_summary.dart

Possibly linked issues

  • #Accessing "Mix 8" After Canceling Analysis Causes Missing Metadata Error: The PR resolves the missing metadata error by correctly passing the collection type for mixes, preventing data fetching failures, which caused the reported issue.

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

@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 and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `lib/screens/query_tracks/query_tracks_list.dart:50-56` </location>
<code_context>
+    // Pre-load first page before marking as initialized
+    await _loadPageForInitialization(0);
</code_context>

<issue_to_address>
**suggestion (performance):** Blocking initialization on data load may impact perceived performance.

Initializing the UI before loading data and displaying a loading indicator can enhance responsiveness, especially on slow networks.

```suggestion
  Future<void> _initializeData() async {
    // Mark as initialized before loading data
    setState(() {
      _isInitialized = true;
    });
    // Start loading first page, but don't block initialization
    _loadPageForInitialization(0);
  }
```
</issue_to_address>

### Comment 2
<location> `native/hub/src/server/client/fs.rs:189-193` </location>
<code_context>
                             let collection_type = path_to_collection_type(&parent_path)
-                                .ok_or_else(|| anyhow!("Invalid collection type"))?;
+                                .ok_or_else(|| {
+                                    log::error!("resolve_path_with_ids: Failed to determine collection type for parent_path: {:?}", parent_path);
+                                    anyhow!("Invalid collection type for path: {:?}", parent_path)
+                                })?;
</code_context>

<issue_to_address>
**🚨 suggestion (security):** Logging errors with potentially large or sensitive paths may have privacy or performance implications.

Sanitize or truncate paths before logging to avoid exposing sensitive data and generating excessively large logs.

```suggestion
                            fn sanitize_path_for_log(path: &std::path::Path) -> String {
                                // Truncate to 100 chars and remove sensitive components
                                let path_str = path.to_string_lossy();
                                let sanitized = if path_str.len() > 100 {
                                    format!("{}...[truncated]", &path_str[..100])
                                } else {
                                    path_str.to_string()
                                };
                                sanitized.replace("\\", "/") // Normalize separators
                            }

                            let collection_type = path_to_collection_type(&parent_path)
                                .ok_or_else(|| {
                                    let sanitized_path = sanitize_path_for_log(&parent_path);
                                    log::error!(
                                        "resolve_path_with_ids: Failed to determine collection type for parent_path: {}",
                                        sanitized_path
                                    );
                                    anyhow!("Invalid collection type for path: {}", sanitized_path)
                                })?;
```
</issue_to_address>

### Comment 3
<location> `database/src/actions/mixes.rs:727` </location>
<code_context>
     cursor: usize,
     page_size: usize,
 ) -> Result<Vec<media_files::Model>> {
+    log::info!("query_mix_media_files: cursor={}, page_size={}, queries={:?}", cursor, page_size, queries);
+
     let mut all: bool = false;
</code_context>

<issue_to_address>
**suggestion:** Info-level logging for every query may be excessive in production.

Consider lowering the log level or adding log sampling to prevent excessive logging if this function is called often.

Suggested implementation:

```rust
    log::debug!("query_mix_media_files: cursor={}, page_size={}, queries={:?}", cursor, page_size, queries);

```

```rust
    log::debug!("query_mix_media_files: returning {} media files", media_files.len());

```

If you want to implement log sampling (e.g., only log every Nth call), you would need to introduce a counter or use a sampling library. If you want this, let me know and I can provide a code example.
</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.

Comment on lines 50 to +56
Future<void> _initializeData() async {
// Pre-load first page before marking as initialized
await _loadPageForInitialization(0);
setState(() {
_isInitialized = true;
});
// Pre-load first page
_loadPage(0);
}
Copy link

Choose a reason for hiding this comment

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

suggestion (performance): Blocking initialization on data load may impact perceived performance.

Initializing the UI before loading data and displaying a loading indicator can enhance responsiveness, especially on slow networks.

Suggested change
Future<void> _initializeData() async {
// Pre-load first page before marking as initialized
await _loadPageForInitialization(0);
setState(() {
_isInitialized = true;
});
// Pre-load first page
_loadPage(0);
}
Future<void> _initializeData() async {
// Mark as initialized before loading data
setState(() {
_isInitialized = true;
});
// Start loading first page, but don't block initialization
_loadPageForInitialization(0);
}

cursor: usize,
page_size: usize,
) -> Result<Vec<media_files::Model>> {
log::info!("query_mix_media_files: cursor={}, page_size={}, queries={:?}", cursor, page_size, queries);
Copy link

Choose a reason for hiding this comment

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

suggestion: Info-level logging for every query may be excessive in production.

Consider lowering the log level or adding log sampling to prevent excessive logging if this function is called often.

Suggested implementation:

    log::debug!("query_mix_media_files: cursor={}, page_size={}, queries={:?}", cursor, page_size, queries);
    log::debug!("query_mix_media_files: returning {} media files", media_files.len());

If you want to implement log sampling (e.g., only log every Nth call), you would need to introduce a counter or use a sampling library. If you want this, let me know and I can provide a code example.

@dosubot dosubot bot added the C - bug Something isn't working label Oct 25, 2025
@Losses
Copy link
Owner

Losses commented Oct 27, 2025

Hey! Thank you for the fix!

I think I can merge it after some tweaks. I agree with Sourcey AI's suggestion about logs. Too much log will affect the normal debugging process. If you are sure that the bug has been fixed, please reduce the log level and avoid accumulating a large amount of logs in the Terminal.

@baiyuanneko
Copy link
Contributor Author

Ok, I will delete the logs later

@baiyuanneko
Copy link
Contributor Author

Now I've deleted many of the unused log function calls, and have tested that the program works still well now.

@Losses
Copy link
Owner

Losses commented Oct 29, 2025

lgtm, thx!

@Losses Losses merged commit 65a2d38 into Losses:master Oct 29, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C - bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants