refactor: pin the look-alike code paths that must not be merged

Several pairs of near-identical code paths differ in one load-bearing
line. Each site now carries a comment naming the invariant that forces it
apart, backed by a characterization test so a future deduplication fails
loudly instead of silently changing behaviour.

Pinned: focusable wrapper vs. chip D-pad activation policy, profile
connection cleanup's raw-id vs. ServerId-typed server projections, live TV
tab loaders, video player display matching and playback service wiring,
track selection container ordering, tracker HTTP client status ladder, and
the MediaServerHttpClient shutdown/cancellation contract versus
ManagedHttpClient's closing guard.

New tests:
  test/focus/dpad_activation_policy_test.dart
  test/services/track_selection_container_ordinal_test.dart
  test/services/trackers/tracker_status_ladder_test.dart
  test/utils/media_server_http_client_shutdown_test.dart
This commit is contained in:
edde746
2026-07-26 06:09:47 +02:00
parent 4307c49cd2
commit 04d8070fd4
24 changed files with 419 additions and 2 deletions
+11
View File
@@ -1509,6 +1509,11 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
_chromeController.dispose();
_toastController.dispose();
// The release sequence below mirrors _tearDownFailedPlayerAttempt but is
// deliberately separate: dispose() cannot await, and it destroys the
// notifiers, focus nodes and player that the rollback path keeps alive
// for a retry on a still-mounted screen.
//
// Stop progress tracking and send final state. Normal back navigation
// awaits this before popping; dispose keeps a fallback for externally
// removed routes where dispose() cannot await.
@@ -1531,6 +1536,9 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
SleepTimerService().markNeedsRestart();
}
// Teardown scope: every subscription the screen ever owns, including the
// initState-owned sleep-timer and Apple TV ones that the rollback path
// must leave alive.
_playingSubscription?.cancel();
_completedSubscription?.cancel();
_errorSubscription?.cancel();
@@ -1577,6 +1585,9 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
FullscreenStateManager().removeListener(_onFullscreenChanged);
_fullscreenListenerAttached = false;
}
// Not _restoreWindowsDisplayMode(): that helper waits 200ms after clearing
// the HDR hint before restoring, which dispose() cannot do. Fire the hint
// clear at the still-live player and restore immediately.
if (!isReplacingWithVideo &&
Platform.isWindows &&
_displayModeService != null &&