From 81d6e6afa3294a13670dc8a2419ee56c0ff8534f Mon Sep 17 00:00:00 2001 From: RyuJongJin <266630912+RyuJongJin@users.noreply.github.com> Date: Mon, 5 Oct 2026 02:49:32 +0900 Subject: [PATCH] =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8:=20=EB=8B=A4=EB=A5=B8=20=EB=B2=84=EC=A0=84?= =?UTF-8?q?=EC=9D=B4=20=EB=82=A8=EA=B8=B4=20=ED=99=95=EC=9D=B8=20=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=EC=9D=B4=EB=A9=B4=20=EB=8B=A4=EC=8B=9C=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=20=C2=B7=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EC=9E=91?= =?UTF-8?q?=EC=97=85=20=EA=B8=B0=EB=A1=9D=EC=97=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 같은 PC 에서 설정 파일을 같이 쓰는 새 버전 (개발 빌드 등) 이 "확인함" 을 남기면 옛 버전 (Windows 배포 폴더) 이 20시간 동안 확인을 건너뛰어 10월 1일 판에 머물렀다. 확인한 버전 (lastUpdateCheckVersion) 을 함께 저장해 지금 버전과 다르면 바로 확인한다. Co-Authored-By: Claude Opus 5.5 --- assets/l10n/en.json | 1 + assets/l10n/ja.json | 1 + assets/l10n/zh-Hans.json | 1 + lib/app/settings.dart | 5 +++++ lib/core/app_update.dart | 6 ++++-- lib/ui/update_dialog.dart | 21 +++++++++++++++++---- test/update_test.dart | 5 +++++ 7 files changed, 34 insertions(+), 6 deletions(-) diff --git a/assets/l10n/en.json b/assets/l10n/en.json index 160382b..f533c63 100644 --- a/assets/l10n/en.json +++ b/assets/l10n/en.json @@ -426,6 +426,7 @@ "삭제 (출력에서 제외)": "Delete (exclude from output)", "삭제: {0}": "Deleted: {0}", "새 버전 v{0}": "New version v{0}", + "새 버전 확인: 지금 v{0} · 최신 v{1}": "Update check: current v{0} · latest v{1}", "새 버전을 확인할 수 없습니다: {0}": "Cannot check for a new version: {0}", "새 즐겨찾기 추가": "Add new bookmark", "새 창에서": "In a new window", diff --git a/assets/l10n/ja.json b/assets/l10n/ja.json index 4db221d..7e09860 100644 --- a/assets/l10n/ja.json +++ b/assets/l10n/ja.json @@ -426,6 +426,7 @@ "삭제 (출력에서 제외)": "削除(出力から除外)", "삭제: {0}": "削除: {0}", "새 버전 v{0}": "新しいバージョン v{0}", + "새 버전 확인: 지금 v{0} · 최신 v{1}": "新しいバージョンの確認: 現在 v{0} · 最新 v{1}", "새 버전을 확인할 수 없습니다: {0}": "新しいバージョンを確認できません: {0}", "새 즐겨찾기 추가": "新しいブックマークを追加", "새 창에서": "新しいウィンドウで", diff --git a/assets/l10n/zh-Hans.json b/assets/l10n/zh-Hans.json index 9c31b07..92d4640 100644 --- a/assets/l10n/zh-Hans.json +++ b/assets/l10n/zh-Hans.json @@ -426,6 +426,7 @@ "삭제 (출력에서 제외)": "删除(从输出中排除)", "삭제: {0}": "已删除: {0}", "새 버전 v{0}": "新版本 v{0}", + "새 버전 확인: 지금 v{0} · 최신 v{1}": "检查新版本: 当前 v{0} · 最新 v{1}", "새 버전을 확인할 수 없습니다: {0}": "无法检查新版本: {0}", "새 즐겨찾기 추가": "添加新书签", "새 창에서": "在新窗口中", diff --git a/lib/app/settings.dart b/lib/app/settings.dart index 75a3bdc..820c6fb 100644 --- a/lib/app/settings.dart +++ b/lib/app/settings.dart @@ -140,6 +140,9 @@ class AppSettings { bool autoCheckUpdates = true; String lastUpdateCheck = ''; + /// [lastUpdateCheck] 를 한 버전 (같은 설정 파일을 쓰는 다른 버전이 확인했으면 다시 확인) + String lastUpdateCheckVersion = ''; + /// "이 버전 건너뛰기" 한 버전 String skippedVersion = ''; @@ -198,6 +201,7 @@ class AppSettings { 'webJavaScript': webJavaScript, 'autoCheckUpdates': autoCheckUpdates, 'lastUpdateCheck': lastUpdateCheck, + 'lastUpdateCheckVersion': lastUpdateCheckVersion, 'skippedVersion': skippedVersion, 'playlistMode': playlistMode.name, 'externalPlayers': externalPlayers, @@ -271,6 +275,7 @@ class AppSettings { ..webJavaScript = j['webJavaScript'] as bool? ?? true ..autoCheckUpdates = j['autoCheckUpdates'] as bool? ?? true ..lastUpdateCheck = j['lastUpdateCheck'] as String? ?? '' + ..lastUpdateCheckVersion = j['lastUpdateCheckVersion'] as String? ?? '' ..skippedVersion = j['skippedVersion'] as String? ?? '' ..playlistMode = pick(PlaylistMode.values, j['playlistMode'], PlaylistMode.series) ..externalPlayers = ((j['externalPlayers'] as Map?) ?? const {}).cast() diff --git a/lib/core/app_update.dart b/lib/core/app_update.dart index 07b3bac..a6ab0db 100644 --- a/lib/core/app_update.dart +++ b/lib/core/app_update.dart @@ -103,8 +103,10 @@ ReleaseInfo? parseLatestRelease(Map j, {String assetPattern = w ); } -/// 자동 확인은 하루에 한 번 -bool updateCheckDue(String lastCheckIso, DateTime now) { +/// 자동 확인은 하루에 한 번. 단 마지막 확인을 다른 버전이 했으면 ([checkedBy] ≠ [current]) 바로 확인한다: +/// 같은 PC 에서 새 버전 (개발 빌드 등) 이 확인한 기록 때문에 옛 버전이 확인을 건너뛰지 않도록 (설정 파일을 같이 쓴다). +bool updateCheckDue(String lastCheckIso, DateTime now, {String checkedBy = '', String current = ''}) { + if (current.isNotEmpty && checkedBy != current) return true; final last = DateTime.tryParse(lastCheckIso); return last == null || now.difference(last) >= const Duration(hours: 20); } diff --git a/lib/ui/update_dialog.dart b/lib/ui/update_dialog.dart index 376f673..e185664 100644 --- a/lib/ui/update_dialog.dart +++ b/lib/ui/update_dialog.dart @@ -12,22 +12,35 @@ Future checkForUpdate(BuildContext context, AppController c, {bool manual final up = c.services.updater; if (up == null) return; final s = c.settings; - if (!manual && (!s.autoCheckUpdates || !updateCheckDue(s.lastUpdateCheck, DateTime.now()))) return; + final String current; + try { + current = await up.currentVersion(); + } catch (_) { + return; + } + if (!manual && + (!s.autoCheckUpdates || + !updateCheckDue(s.lastUpdateCheck, DateTime.now(), checkedBy: s.lastUpdateCheckVersion, current: current))) { + return; + } void snack(String t) { if (context.mounted) ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(t))); } - final String current; final ReleaseInfo? r; try { - current = await up.currentVersion(); r = await up.latest(); } catch (e) { + c.note(trf('새 버전을 확인할 수 없습니다: {0}', [e])); if (manual) snack(trf('새 버전을 확인할 수 없습니다: {0}', [e])); return; } - await c.updateSettings((x) => x.lastUpdateCheck = DateTime.now().toIso8601String()); + await c.updateSettings((x) => x + ..lastUpdateCheck = DateTime.now().toIso8601String() + ..lastUpdateCheckVersion = current); + // 작업 기록에 남긴다 (업데이트가 안 될 때 원인을 찾을 수 있게) + c.note(trf('새 버전 확인: 지금 v{0} · 최신 v{1}', [current, r?.version ?? '-'])); if (r == null || !r.isNewerThan(current)) { if (manual) snack(trf('최신 버전입니다 (v{0})', [current])); return; diff --git a/test/update_test.dart b/test/update_test.dart index 8202bc5..a40893d 100644 --- a/test/update_test.dart +++ b/test/update_test.dart @@ -85,6 +85,11 @@ void main() { expect(updateCheckDue('', now), isTrue); expect(updateCheckDue(DateTime(2026, 10, 1, 9).toIso8601String(), now), isFalse); expect(updateCheckDue(DateTime(2026, 9, 30, 9).toIso8601String(), now), isTrue); + // 방금 확인했어도 다른 버전이 한 확인이면 다시 (같은 설정 파일을 쓰는 새 버전 개발 빌드 등) + final recent = DateTime(2026, 10, 1, 9).toIso8601String(); + expect(updateCheckDue(recent, now, checkedBy: '2026.10.04_012', current: '2026.10.01_003'), isTrue); + expect(updateCheckDue(recent, now, checkedBy: '', current: '2026.10.01_003'), isTrue); // 예전 판이 남긴 기록 + expect(updateCheckDue(recent, now, checkedBy: '2026.10.01_003', current: '2026.10.01_003'), isFalse); }); });