Skip to content

Feat/long operation feedback#538

Open
azfoo wants to merge 5 commits into
TimeLineAnnotator:devfrom
azfoo:feat/long-operation-feedback
Open

Feat/long operation feedback#538
azfoo wants to merge 5 commits into
TimeLineAnnotator:devfrom
azfoo:feat/long-operation-feedback

Conversation

@azfoo

@azfoo azfoo commented May 17, 2026

Copy link
Copy Markdown
Collaborator

Non-blocking progress feedback for long-running operations

  • New 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.
  • WaitCursor set for the full duration; _DialogCursorFilter lifts it while any QDialog is visible and restores it on close. _InputBlockFilter swallows mouse clicks while the cursor is active.
  • @long_operation(label) decorator posts STARTED/DONE around a function. The bar is indeterminate by default; posting PROGRESS(value, maximum) inside promotes it to determinate. DONE is always posted even if the function raises.
  • Applied to App._do_open, App._do_load_media, and BeatTimeline.fill_with_beats (with per-beat PROGRESS posts).
  • Fixes pre-existing bug: CursorMixIn was calling restoreOverrideCursor() unconditionally on hover-leave, popping the WaitCursor off the application stack. Replaced with QGraphicsItem.setCursor(), which does not interact with the override cursor stack.

closes #545

ps. is there anything else that would benefit from this?

azfoo added 2 commits May 17, 2026 02:14
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
@azfoo azfoo requested a review from FelipeDefensor May 17, 2026 01:17
azfoo added 3 commits May 20, 2026 17:07
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.
@azfoo azfoo force-pushed the feat/long-operation-feedback branch from 97f4c2b to 860d314 Compare May 20, 2026 16:09
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