업데이트 확인: 다른 버전이 남긴 확인 기록이면 다시 확인 · 결과를 작업 기록에

같은 PC 에서 설정 파일을 같이 쓰는 새 버전 (개발 빌드 등) 이 "확인함" 을 남기면
옛 버전 (Windows 배포 폴더) 이 20시간 동안 확인을 건너뛰어 10월 1일 판에 머물렀다.
확인한 버전 (lastUpdateCheckVersion) 을 함께 저장해 지금 버전과 다르면 바로 확인한다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main
RyuJongJin 2026-10-05 02:49:32 +09:00
parent 7ddc32d5af
commit 81d6e6afa3
7 changed files with 34 additions and 6 deletions

View File

@ -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",

View File

@ -426,6 +426,7 @@
"삭제 (출력에서 제외)": "削除(出力から除外)",
"삭제: {0}": "削除: {0}",
"새 버전 v{0}": "新しいバージョン v{0}",
"새 버전 확인: 지금 v{0} · 최신 v{1}": "新しいバージョンの確認: 現在 v{0} · 最新 v{1}",
"새 버전을 확인할 수 없습니다: {0}": "新しいバージョンを確認できません: {0}",
"새 즐겨찾기 추가": "新しいブックマークを追加",
"새 창에서": "新しいウィンドウで",

View File

@ -426,6 +426,7 @@
"삭제 (출력에서 제외)": "删除(从输出中排除)",
"삭제: {0}": "已删除: {0}",
"새 버전 v{0}": "新版本 v{0}",
"새 버전 확인: 지금 v{0} · 최신 v{1}": "检查新版本: 当前 v{0} · 最新 v{1}",
"새 버전을 확인할 수 없습니다: {0}": "无法检查新版本: {0}",
"새 즐겨찾기 추가": "添加新书签",
"새 창에서": "在新窗口中",

View File

@ -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<String, String>()

View File

@ -103,8 +103,10 @@ ReleaseInfo? parseLatestRelease(Map<String, dynamic> 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);
}

View File

@ -12,22 +12,35 @@ Future<void> 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;

View File

@ -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);
});
});