fix video refresh race condition causing black screen with play button
Replace JS-side `window._injected` guard with a Dart-controlled `_needsInit` flag so `initVideo()` reliably runs after every refresh. The previous approach loaded `about:blank` then `videoUrl` back-to-back, but `loadRequest` resolves on navigation start (not page load), so the JS context often survived and `onPageFinished` skipped re-initialization. Also adds an explicit `play()` call to handle cases where the Twitch player loads in a paused state. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
929d525c13
commit
9cec89a67c
1 changed files with 16 additions and 20 deletions
|
|
@ -38,6 +38,12 @@ abstract class VideoStoreBase with Store {
|
||||||
|
|
||||||
var _firstTimeSettingQuality = true;
|
var _firstTimeSettingQuality = true;
|
||||||
|
|
||||||
|
/// Whether [initVideo] should run on the next [onPageFinished].
|
||||||
|
///
|
||||||
|
/// Dart-controlled instead of JS-side (`window._injected`) to avoid race
|
||||||
|
/// conditions when `loadRequest` fires before the previous page fully loads.
|
||||||
|
var _needsInit = true;
|
||||||
|
|
||||||
/// The video web view params used for enabling auto play.
|
/// The video web view params used for enabling auto play.
|
||||||
late final PlatformWebViewControllerCreationParams _videoWebViewParams;
|
late final PlatformWebViewControllerCreationParams _videoWebViewParams;
|
||||||
|
|
||||||
|
|
@ -126,18 +132,8 @@ abstract class VideoStoreBase with Store {
|
||||||
NavigationDelegate(
|
NavigationDelegate(
|
||||||
onPageFinished: (url) async {
|
onPageFinished: (url) async {
|
||||||
if (url != videoUrl) return;
|
if (url != videoUrl) return;
|
||||||
// Safe evaluation of JavaScript boolean result
|
if (!_needsInit) return;
|
||||||
final result = await videoWebViewController
|
_needsInit = false;
|
||||||
.runJavaScriptReturningResult(
|
|
||||||
'window._injected ? true : false',
|
|
||||||
);
|
|
||||||
final injected = result is bool
|
|
||||||
? result
|
|
||||||
: (result.toString().toLowerCase() == 'true');
|
|
||||||
if (injected) return;
|
|
||||||
await videoWebViewController.runJavaScript(
|
|
||||||
'window._injected = true;',
|
|
||||||
);
|
|
||||||
await initVideo();
|
await initVideo();
|
||||||
_acceptContentWarning();
|
_acceptContentWarning();
|
||||||
},
|
},
|
||||||
|
|
@ -810,6 +806,9 @@ abstract class VideoStoreBase with Store {
|
||||||
videoElement.textTracks[0].mode = "hidden";
|
videoElement.textTracks[0].mode = "hidden";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Explicitly attempt autoplay in case the player loaded paused
|
||||||
|
try { await videoElement.play(); } catch (e) {}
|
||||||
});
|
});
|
||||||
''');
|
''');
|
||||||
if (settingsStore.showOverlay) {
|
if (settingsStore.showOverlay) {
|
||||||
|
|
@ -991,27 +990,24 @@ abstract class VideoStoreBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Refreshes the stream webview and updates the stream info.
|
/// Refreshes the stream webview and updates the stream info.
|
||||||
///
|
|
||||||
/// Performs a hard refresh by loading about:blank first to completely clear
|
|
||||||
/// the webview state, then immediately reloads the video URL. This is more
|
|
||||||
/// reliable than a soft reload when the webview is sluggish.
|
|
||||||
@action
|
@action
|
||||||
Future<void> handleRefresh() async {
|
Future<void> handleRefresh() async {
|
||||||
HapticFeedback.lightImpact();
|
HapticFeedback.lightImpact();
|
||||||
_paused = true;
|
_paused = true;
|
||||||
_firstTimeSettingQuality = true;
|
_firstTimeSettingQuality = true;
|
||||||
_isInPipMode = false;
|
_isInPipMode = false;
|
||||||
|
_latency = null;
|
||||||
|
_availableStreamQualities = [];
|
||||||
|
|
||||||
|
// Signal that initVideo() should run on the next onPageFinished
|
||||||
|
_needsInit = true;
|
||||||
|
|
||||||
// Stop latency tracker immediately to free up JS main thread for refresh
|
|
||||||
try {
|
try {
|
||||||
videoWebViewController.runJavaScript('window._latencyTracker?.stop()');
|
videoWebViewController.runJavaScript('window._latencyTracker?.stop()');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Ignore - may not exist yet
|
// Ignore - may not exist yet
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hard refresh: clear everything by loading blank page first
|
|
||||||
await videoWebViewController.loadRequest(Uri.parse('about:blank'));
|
|
||||||
// Then immediately load the video URL for a fresh start
|
|
||||||
await videoWebViewController.loadRequest(Uri.parse(videoUrl));
|
await videoWebViewController.loadRequest(Uri.parse(videoUrl));
|
||||||
|
|
||||||
updateStreamInfo();
|
updateStreamInfo();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue