diff --git a/integration_test/support/shot_services.dart b/integration_test/support/shot_services.dart index 1a53bf2..dddd5ec 100644 --- a/integration_test/support/shot_services.dart +++ b/integration_test/support/shot_services.dart @@ -31,6 +31,7 @@ PlatformServices shotServices() { clock: r.clock, vault: r.vault, privileged: r.privileged, + isMetered: r.isMetered, updater: r.updater, usage: r.usage == null ? null : const FixedUsage(), models: r.models, diff --git a/lib/core/lan_scan.dart b/lib/core/lan_scan.dart index d4c4604..a955bca 100644 --- a/lib/core/lan_scan.dart +++ b/lib/core/lan_scan.dart @@ -41,10 +41,8 @@ Future?> _androidNetKinds() async { } /// X-plore 비교 5-1 ② (관리자 지시 10/21): 지금 쓰는 망이 데이터 요금제인지 (모바일 데이터 · 요금제 Wi-Fi). Android 만 묻고, -/// 그 밖 (PC) 은 false. 물을 수 없으면 true (받지 않는 쪽으로). 시험에서 바꾼다 -Future Function() activeMeteredOf = _androidMetered; - -Future _androidMetered() async { +/// 그 밖 (PC) 은 false. 물을 수 없으면 true (받지 않는 쪽으로). 앱은 PlatformServices.isMetered 로 부른다 (설계 M3 ThumbPolicy - 시험은 그것을 바꿈) +Future deviceMetered() async { if (!Platform.isAndroid) return false; try { return await const MethodChannel('jj_mkvmaker/android').invokeMethod('activeMetered') ?? true; diff --git a/lib/services/platform_services.dart b/lib/services/platform_services.dart index 3fde222..3230dbb 100644 --- a/lib/services/platform_services.dart +++ b/lib/services/platform_services.dart @@ -9,7 +9,7 @@ import '../app/settings.dart'; import '../app/vault_location.dart'; import '../core/shizuku.dart' show PrivilegedFs; import '../core/download_detect.dart'; -import '../core/lan_scan.dart' show LanHost; +import '../core/lan_scan.dart' show LanHost, deviceMetered; import '../platform/common/nllb_translator.dart'; import '../platform/common/opensubtitles_provider.dart'; import '../platform/common/whisper_recognizer.dart'; @@ -88,6 +88,9 @@ class PlatformServices { /// 없으면 PrivilegedFs.current 를 그대로 둔다 (시험이 건 가짜를 덮지 않게) final PrivilegedFs? privileged; + /// 지금 쓰는 망이 데이터 요금제인지 (원격 썸네일 "Wi-Fi 에서만" - 설계 M3 ThumbPolicy). 처음 값 = 실제 (Android 만 묻고 PC 는 false) + final Future Function() isMetered; + /// 이 기기 (Android · Windows · 메모리) - 기기마다 다르게 도는 곳은 이것을 본다 (M1, 처음 값 = 이 기기) final PlatformInfo platform; @@ -114,8 +117,10 @@ class PlatformServices { PlatformInfo? platform, VaultLocation? vault, this.privileged, + Future Function()? isMetered, }) : models = models ?? ModelStore(), vault = vault ?? VaultLocation.under(storage.tempDirectory), + isMetered = isMetered ?? deviceMetered, platform = platform ?? PlatformInfo.host, shell = shell ?? NoopShell(); diff --git a/lib/ui/remote_thumb_view.dart b/lib/ui/remote_thumb_view.dart index 5f35843..dcae562 100644 --- a/lib/ui/remote_thumb_view.dart +++ b/lib/ui/remote_thumb_view.dart @@ -6,7 +6,6 @@ import 'package:path/path.dart' as p; import '../app/app_controller.dart'; import '../core/file_ops.dart' show FileEntry; -import '../core/lan_scan.dart' show activeMeteredOf; import '../core/playlist.dart' show isVideoFile; import '../core/remote_stream.dart'; import '../core/remote_thumbs.dart'; @@ -83,7 +82,7 @@ Future remoteThumbsAllowedNow(AppController c) async { } final now = DateTime.now(); if (_meteredAt == null || now.difference(_meteredAt!) > const Duration(seconds: 10)) { - _metered = await activeMeteredOf(); + _metered = await c.services.isMetered(); _meteredAt = now; } return !_metered; diff --git a/test/remote_thumbs_test.dart b/test/remote_thumbs_test.dart index 6366e18..639d819 100644 --- a/test/remote_thumbs_test.dart +++ b/test/remote_thumbs_test.dart @@ -5,7 +5,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:jj_mkvmaker/app/app_controller.dart'; import 'package:jj_mkvmaker/app/settings.dart'; import 'package:jj_mkvmaker/core/file_ops.dart' show FileEntry; -import 'package:jj_mkvmaker/core/lan_scan.dart' show activeMeteredOf; import 'package:jj_mkvmaker/core/models.dart'; import 'package:jj_mkvmaker/core/remote_stream.dart'; import 'package:jj_mkvmaker/core/remote_thumbs.dart'; @@ -126,24 +125,23 @@ void main() { }); group('받아도 되는 망 (remoteThumbsAllowedNow)', () { - final was = activeMeteredOf; - tearDown(() { - activeMeteredOf = was; - forgetRemoteThumbNet(); - }); - AppController ctl() => AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService())); + // 설계 M3 ThumbPolicy: 망 판단은 PlatformServices.isMetered 로 넘긴다 (예전 전역 함수 activeMeteredOf) + var metered = true; + tearDown(forgetRemoteThumbNet); + AppController ctl() => AppController( + PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService(), isMetered: () async => metered)); test('Wi-Fi 에서만 (처음 값): 데이터 요금제 망이면 아니오 · 아니면 예 · 끔 · 늘', () async { final c = ctl(); - activeMeteredOf = () async => true; + metered = true; forgetRemoteThumbNet(); expect(await remoteThumbsAllowedNow(c), isFalse, reason: '모바일 데이터 (VPN 이어도 그 아래가 모바일 데이터)'); - activeMeteredOf = () async => false; + metered = false; forgetRemoteThumbNet(); expect(await remoteThumbsAllowedNow(c), isTrue, reason: 'Wi-Fi (집 Wi-Fi 위의 Tailscale 포함)'); c.settings.explorer.remoteThumbs = 'off'; expect(await remoteThumbsAllowedNow(c), isFalse); c.settings.explorer.remoteThumbs = 'always'; - activeMeteredOf = () async => true; + metered = true; forgetRemoteThumbNet(); expect(await remoteThumbsAllowedNow(c), isTrue); });