diff --git a/lib/main.dart b/lib/main.dart index d9d1907..395a232 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -507,6 +507,7 @@ class JjCapCutApp extends StatelessWidget { theme: buildTheme(), navigatorKey: navigatorKey, scaffoldMessengerKey: messengerKey, + navigatorObservers: [browserRouteObserver], // 모든 화면에: 환경 설정 · 종료 버튼이 쓸 것 + 끌어다 놓은 동영상을 목록에 추가 builder: (context, child) => AppScope( controller: controller, diff --git a/lib/ui/browser_page.dart b/lib/ui/browser_page.dart index 222dfe6..69e6141 100644 --- a/lib/ui/browser_page.dart +++ b/lib/ui/browser_page.dart @@ -30,8 +30,17 @@ abstract class WebNav { /// YouTube · Google 로그인 쿠키를 yt-dlp 용 cookies.txt 로 내보내기 Future exportCookies(); + + /// 페이지의 동영상 · 소리 멈추기 (다른 화면으로 갈 때) + Future pauseMedia(); } +/// 페이지의 모든 동영상 · 소리를 멈추는 스크립트 +const pauseMediaScript = "document.querySelectorAll('video,audio').forEach(function(m){try{m.pause()}catch(e){}})"; + +/// 화면 이동 알림 (브라우저 위에 다른 화면이 올라오면 동영상을 멈춘다). MaterialApp.navigatorObservers 에 넣는다. +final browserRouteObserver = RouteObserver>(); + /// 웹뷰 → 화면으로 알리는 통로 class BrowserHost { final void Function(String url) onUrl; @@ -97,7 +106,7 @@ class BrowserPage extends StatefulWidget { } } -class _BrowserPageState extends State { +class _BrowserPageState extends State with RouteAware { late String _url = widget.initialUrl ?? widget.c.settings.homeUrl; String _title = ''; double _progress = 1; @@ -138,8 +147,22 @@ class _BrowserPageState extends State { BrowserPage._open++; } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final route = ModalRoute.of(context); + if (route != null) browserRouteObserver.subscribe(this, route); + } + + /// 다운로드 목록 · 플레이어 · 설정 등이 위에 올라왔다: 보던 동영상을 멈춘다 (가려진 채 소리만 나지 않게) + @override + void didPushNext() { + _nav?.pauseMedia(); + } + @override void dispose() { + browserRouteObserver.unsubscribe(this); BrowserPage._open--; _address.dispose(); _addressFocus.dispose(); @@ -492,6 +515,13 @@ class _InAppNav implements WebNav { final String dataDir; _InAppNav(this.c, this.env, this.dataDir); + @override + Future pauseMedia() async { + try { + await c.evaluateJavascript(source: pauseMediaScript); + } catch (_) {} + } + static const _cookieSites = [ 'https://www.youtube.com/', 'https://m.youtube.com/', @@ -642,6 +672,13 @@ class _CefNav implements WebNav { final String dataDir; _CefNav(this.c, this.dataDir); + @override + Future pauseMedia() async { + try { + await c.evaluateJavascript(pauseMediaScript); + } catch (_) {} + } + /// YouTube · Google 쿠키를 yt-dlp 용 cookies.txt 로 (Edge 와 같은 파일 - 지금 쓰는 엔진의 로그인이 쓰인다). /// Chrome 엔진은 쿠키의 이름 · 값만 알려 주므로 만료 · 보안 표시는 기본값으로 적는다. @override diff --git a/test/browser_test.dart b/test/browser_test.dart index c21d00f..683c2d9 100644 --- a/test/browser_test.dart +++ b/test/browser_test.dart @@ -40,6 +40,9 @@ class _Backend implements DownloadBackend { } class _Nav implements WebNav { + int paused = 0; + @override + Future pauseMedia() async => paused++; final loads = []; @override Future load(String url) async => loads.add(url);