Some checks failed
CI / test (push) Has been cancelled
핵심 기능: - 단축근무·표준·반일 등 다양한 근무 패턴 (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>
162 lines
4.7 KiB
Python
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}")
|