Clock_out_Time_Calculator/utils/resource_manager.py
KINDNICK bedbb1e9ec
Some checks failed
CI / test (push) Has been cancelled
Initial release v2.2.0
핵심 기능:
- 단축근무·표준·반일 등 다양한 근무 패턴 (5개 프리셋 + 사용자 정의)
- Windows 이벤트 뷰어 자동 출퇴근 감지
- 30분 단위 연장근무 적립/사용 시스템
- 1.0/0.5/0.25일 연차·반차·반반차
- 자동 점심·저녁·외출·자동 백업·화면 잠금 자동 외출
- 한국 공휴일 자동 등록 (음력 포함, holidays 패키지)
- matplotlib 차트 기반 주간/월간/패턴 통계
- 미니 위젯 + 시스템 트레이 통합
- 한국어/English i18n
- 자가 업데이트 (updater.exe + Gitea Releases)

아키텍처:
- core/ (db, time_calculator, notifier, i18n, version, settings_keys)
- ui/ (main_window + 9 dialogs + 3 controllers)
- utils/ (backup, lock_detector, debug_log, updater_client, time_format)
- tests/ (66 pytest 단위) + 통합/i18n GUI 검증

CI/CD:
- .gitea/workflows/ci.yml: push 시 pytest + 통합 테스트
- .gitea/workflows/release.yml: v* 태그 push 시 두 .exe 자동 빌드 + Releases 첨부

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 12:54:40 +09:00

162 lines
4.7 KiB
Python

"""
리소스 매니저
아이콘, 사운드 등의 리소스 관리
"""
import os
from pathlib import Path
from typing import Optional
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtCore import QSize
class ResourceManager:
"""리소스 관리 클래스"""
def __init__(self):
# 프로젝트 루트 경로
self.root_path = Path(__file__).parent.parent
self.resources_path = self.root_path / "resources"
self.icons_path = self.resources_path / "icons"
self.sounds_path = self.resources_path / "sounds"
# 경로 생성
self.icons_path.mkdir(parents=True, exist_ok=True)
self.sounds_path.mkdir(parents=True, exist_ok=True)
def get_icon_path(self, icon_name: str) -> Optional[Path]:
"""
아이콘 파일 경로 반환
Args:
icon_name: 아이콘 파일명 (확장자 포함)
Returns:
Path: 아이콘 파일 경로
"""
icon_path = self.icons_path / icon_name
if icon_path.exists():
return icon_path
return None
def get_icon(self, icon_name: str, size: int = 64) -> Optional[QIcon]:
"""
QIcon 객체 반환
Args:
icon_name: 아이콘 파일명
size: 아이콘 크기 (픽셀)
Returns:
QIcon: 아이콘 객체, 없으면 None
"""
icon_path = self.get_icon_path(icon_name)
if icon_path:
pixmap = QPixmap(str(icon_path))
scaled_pixmap = pixmap.scaled(
QSize(size, size),
aspectRatioMode=1, # KeepAspectRatio
transformMode=1 # SmoothTransformation
)
return QIcon(scaled_pixmap)
return None
def get_sound_path(self, sound_name: str) -> Optional[Path]:
"""
사운드 파일 경로 반환
Args:
sound_name: 사운드 파일명 (확장자 포함)
Returns:
Path: 사운드 파일 경로
"""
sound_path = self.sounds_path / sound_name
if sound_path.exists():
return sound_path
return None
def play_sound(self, sound_name: str):
"""
사운드 재생
Args:
sound_name: 사운드 파일명
"""
sound_path = self.get_sound_path(sound_name)
if sound_path:
try:
# Windows 기본 사운드 재생
import winsound
winsound.PlaySound(
str(sound_path),
winsound.SND_FILENAME | winsound.SND_ASYNC
)
except Exception as e:
print(f"사운드 재생 실패: {e}")
def has_resources(self) -> bool:
"""리소스가 존재하는지 확인"""
icon_count = len(list(self.icons_path.glob("*.png")))
sound_count = len(list(self.sounds_path.glob("*.wav")))
return icon_count > 0 or sound_count > 0
def list_resources(self):
"""설치된 리소스 목록 출력"""
print("=== 설치된 리소스 ===\n")
print("아이콘:")
icons = list(self.icons_path.glob("*.png")) + list(self.icons_path.glob("*.ico"))
if icons:
for icon in icons:
print(f" - {icon.name}")
else:
print(" (없음)")
print("\n사운드:")
sounds = list(self.sounds_path.glob("*.wav")) + list(self.sounds_path.glob("*.mp3"))
if sounds:
for sound in sounds:
print(f" - {sound.name}")
else:
print(" (없음)")
if not icons and not sounds:
print("\n리소스가 없습니다!")
print("resources/resource_links.md 파일을 참고하여 리소스를 다운로드하세요.")
# 기본 이모지 아이콘 생성 (리소스 없을 때 대체용)
def create_emoji_icon(emoji: str, size: int = 64) -> QIcon:
"""
이모지를 아이콘으로 변환
Args:
emoji: 이모지 문자
size: 아이콘 크기
Returns:
QIcon: 아이콘 객체
"""
from PyQt5.QtGui import QPixmap, QPainter, QFont
from PyQt5.QtCore import Qt
pixmap = QPixmap(size, size)
pixmap.fill(Qt.transparent)
painter = QPainter(pixmap)
font = QFont("Segoe UI Emoji", int(size * 0.7))
painter.setFont(font)
painter.drawText(pixmap.rect(), Qt.AlignCenter, emoji)
painter.end()
return QIcon(pixmap)
# 테스트 코드
if __name__ == "__main__":
manager = ResourceManager()
manager.list_resources()
print("\n=== 경로 정보 ===")
print(f"아이콘 폴더: {manager.icons_path}")
print(f"사운드 폴더: {manager.sounds_path}")