Feat/long operation feedback#538
Open
azfoo wants to merge 5 commits into
Open
Conversation
Adds a QToolBar in the bottom-left toolbar area that shows a progress
bar and label during long-running operations.
Infrastructure (tilia/requests/post.py):
- LongOperation enum: STARTED(label), PROGRESS(value, max), DONE
- long_operation(label) decorator: posts STARTED on entry, DONE in
finally; supports indeterminate and determinate operations; nestable
- Post.LONG_OPERATION added to Post enum
Toolbar (tilia/ui/long_operation.py):
- Stack-based nesting: STARTED pushes, DONE pops; toolbar stays visible
until the stack empties and the outer label is restored on inner DONE
- Wait cursor via QApplication.setOverrideCursor, set on first push and
restored on final pop
- _DialogCursorFilter: app-level event filter that lifts the wait cursor
while any QDialog is visible and re-sets it when all dialogs close
- _InputBlockFilter: swallows mouse press/release/double-click while the
wait cursor is active
Current callers:
- App._do_open: @long_operation("Loading file...")
- App._do_load_media: @long_operation("Loading media...")
- BeatTimeline.fill_with_beats: @long_operation("Creating beats...")
with per-beat PROGRESS posts for a determinate bar
When a new replier takes over a Get request, the old replier's entry in _servers_to_requests was not cleaned up. A later stop_serving_all(old) would then pop the NEW replier's callback, leaving the request with no handler and causing NoReplyToRequest on every subsequent get().
Creating the new player first ensures the old one is only torn down after a successful handover — if the constructor raises, app.player stays valid. This is safe because serve() now keeps _servers_to_requests consistent when ownership changes (see previous commit). Making destroy() safe to call after QWebEngineView is already live required moving media teardown into QtPlayer._engine_exit(): direct player.stop() + player.setSource(QUrl()) calls replace the wait_for_signal → QEventLoop.exec() path that SIGSEGVs on Python 3.10 when the web-engine subprocess is already running.
test_sentry_not_logging relied on test ordering because ignore_logger() was only called as a side-effect of other fixtures. Wire use_test_logger explicitly so the assertion is order-independent. test_media_path_is_youtube_url was constructing YouTubePlayer without a main window. Add qtui so Get.PLAYER_CLASS and Get.MAIN_WINDOW are both served by the real UI layer, and drop the now-unnecessary Serve(Get.PLAYER_CLASS, ...) override.
97f4c2b to
860d314
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Non-blocking progress feedback for long-running operations
LongOperationToolbar(bottom-left) shows a progress bar and label during slow operations. Stack-based nesting keeps the toolbar visible across multiple concurrent operations and restores the outer label when an inner one finishes.WaitCursorset for the full duration;_DialogCursorFilterlifts it while anyQDialogis visible and restores it on close._InputBlockFilterswallows mouse clicks while the cursor is active.@long_operation(label)decorator postsSTARTED/DONEaround a function. The bar is indeterminate by default; postingPROGRESS(value, maximum)inside promotes it to determinate.DONEis always posted even if the function raises.App._do_open,App._do_load_media, andBeatTimeline.fill_with_beats(with per-beatPROGRESSposts).CursorMixInwas callingrestoreOverrideCursor()unconditionally on hover-leave, popping theWaitCursoroff the application stack. Replaced withQGraphicsItem.setCursor(), which does not interact with the override cursor stack.closes #545
ps. is there anything else that would benefit from this?