v2.11.2: 통계 차트 frozen 실제 수정(numpy _multiarray_tests) + 도전과제 라이트 가독성

- fix: frozen main.exe에서 numpy.core._multiarray_tests 누락으로 matplotlib import 실패 → 차트 폴백. spec에 hiddenimport 추가 + numpy.testing 제외 제거 (디버그 로그로 원인 확인)
- fix: 도전과제 라이트 테마 헤더 숫자/배지/진행 텍스트/바 대비 개선

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
KINDNICK 2026-06-04 19:21:49 +09:00
parent e7e85dcf7b
commit f5751460e3
4 changed files with 35 additions and 17 deletions

View File

@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [2.11.2] — 2026-06-04
### Fixed
- **통계 차트가 빌드(main.exe)에서 안 뜨던 진짜 원인** — frozen 빌드에서 numpy C-확장
`numpy.core._multiarray_tests`가 누락(`numpy.testing` 제외의 영향)되어 matplotlib import가
`ModuleNotFoundError`로 실패 → "matplotlib 필요" 폴백. `main.spec`에 해당 모듈 hiddenimport
추가 + `numpy.testing` 제외 제거. (디버그 로그로 원인 확인: chart_widget이 실패 사유를 기록)
- **도전과제 라이트 테마 가독성** — 헤더 강조 숫자/등급 배지/진행 숫자/진행 바를 라이트에서
대비 높은 색으로 조정 (다크는 기존 비비드 색 유지).
## [2.11.1] — 2026-06-04
### Fixed

View File

@ -4,4 +4,4 @@
릴리스 값을 올린 git tag push.
CHANGELOG.md의 최상단 항목과 일치시킬 .
"""
__version__ = '2.11.1'
__version__ = '2.11.2'

View File

@ -36,11 +36,13 @@ a = Analysis(
'matplotlib.backends.backend_qt5agg',
'PyQt5.QtSvg',
'PyQt5.sip', # matplotlib qt_compat가 sip 사용
'numpy.core._multiarray_tests', # numpy import 체인이 참조 (frozen 차트 깨짐 방지)
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=['pandas', 'numpy.testing', 'PyQt5.QtWebEngineWidgets'],
# numpy.testing 제외 금지 — numpy.core._multiarray_tests 참조가 끊겨 matplotlib import 실패함
excludes=['pandas', 'PyQt5.QtWebEngineWidgets'],
noarchive=False,
optimize=0,
)

View File

@ -165,7 +165,13 @@ class AchievementsView(QDialog):
num_row = QHBoxLayout()
num_row.setSpacing(24)
big = QLabel(f"<span style='font-size: 32pt; font-weight: bold; color: #ffd24a;'>{stats['earned']}</span>"
# 헤더 강조 숫자색 — 다크는 비비드, 라이트는 동일 색조 진하게(가독성)
if _is_dark():
c_earned, c_secret, c_pct = '#ffd24a', '#ff90b8', '#4adef0'
else:
c_earned, c_secret, c_pct = '#C8950A', '#C2185B', '#0E7490'
big = QLabel(f"<span style='font-size: 32pt; font-weight: bold; color: {c_earned};'>{stats['earned']}</span>"
f"<span style='font-size: 18pt; color: {tc('text_dim')};'> / {stats['total']}</span>")
big.setTextFormat(Qt.RichText)
num_row.addWidget(big)
@ -178,7 +184,7 @@ class AchievementsView(QDialog):
secret_lbl = QLabel(
f"<div style='line-height: 1.3;'>"
f"<span style='font-size: 9pt; color: {tc('text_dim')};'>🌑 시크릿</span><br>"
f"<span style='font-size: 18pt; font-weight: bold; color: #ff90b8;'>"
f"<span style='font-size: 18pt; font-weight: bold; color: {c_secret};'>"
f"{stats['secret_earned']}</span>"
f"<span style='font-size: 12pt; color: {tc('text_dim')};'> / {stats['secret_total']}</span>"
f"</div>"
@ -191,7 +197,7 @@ class AchievementsView(QDialog):
pct_lbl = QLabel(
f"<div style='text-align: right; line-height: 1.3;'>"
f"<span style='font-size: 9pt; color: {tc('text_dim')};'>달성률</span><br>"
f"<span style='font-size: 24pt; font-weight: bold; color: #4adef0;'>"
f"<span style='font-size: 24pt; font-weight: bold; color: {c_pct};'>"
f"{pct:.1f}%</span></div>"
)
pct_lbl.setTextFormat(Qt.RichText)
@ -207,17 +213,17 @@ class AchievementsView(QDialog):
bar.setTextVisible(False)
bar.setMinimumHeight(8)
bar.setMaximumHeight(8)
bar.setStyleSheet("""
QProgressBar {
background: #1a1a26;
bar.setStyleSheet(f"""
QProgressBar {{
background: {tc('panel2')};
border: none;
border-radius: 4px;
}
QProgressBar::chunk {
}}
QProgressBar::chunk {{
background: qlineargradient(x1:0, y1:0, x2:1, y2:0,
stop:0 #4adef0, stop:0.5 #6b9eff, stop:1 #ff90b8);
border-radius: 4px;
}
}}
""")
layout.addWidget(bar)
@ -343,8 +349,8 @@ class AchievementsView(QDialog):
cat_label = QLabel(f" {theme['label']} {theme['name']} · {cat_text} ")
cat_label.setStyleSheet(
f"font-size: 8.5pt; "
f"color: {theme['border_strong']}; "
f"background: rgba(255,255,255,0.05); "
f"color: {theme['border_strong'] if _is_dark() else tc('text_dim')}; "
f"background: {'rgba(255,255,255,0.05)' if _is_dark() else tc('panel2')}; "
f"border: 1px solid {theme['border']}; "
f"border-radius: 8px; "
f"padding: 1px 4px;"
@ -377,9 +383,9 @@ class AchievementsView(QDialog):
if is_earned:
earned = QLabel(f"{item['earned_date']} 달성 ")
earned.setStyleSheet(
f"color: {theme['border_strong']}; "
f"color: {theme['border_strong'] if _is_dark() else tc('text')}; "
f"font-weight: bold; font-size: 9.5pt; "
f"background: rgba(255,255,255,0.08); "
f"background: {'rgba(255,255,255,0.08)' if _is_dark() else tc('panel2')}; "
f"border: 1px solid {theme['border']}; "
f"border-radius: 6px; padding: 4px 8px;"
)
@ -405,7 +411,7 @@ class AchievementsView(QDialog):
pb.setMaximumHeight(10)
pb.setStyleSheet(f"""
QProgressBar {{
background: rgba(0,0,0,0.4);
background: {'rgba(0,0,0,0.4)' if _is_dark() else tc('panel2')};
border: none;
border-radius: 5px;
}}
@ -419,7 +425,7 @@ class AchievementsView(QDialog):
num = QLabel(f"{progress} / {target}")
num.setStyleSheet(
f"color: {theme['border_strong']}; font-size: 9pt; "
f"color: {theme['border_strong'] if _is_dark() else tc('text_dim')}; font-size: 9pt; "
f"font-weight: bold; background: transparent; border: none;"
)
num.setMinimumWidth(60)