# -*- coding: utf-8 -*- """ 메모 위젯 모듈 메모를 표시하고 관리하는 위젯입니다. """ from datetime import date from PySide6.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLabel, QFrame, QTextEdit, QDialog ) from PySide6.QtCore import Qt, Signal, QTimer from PySide6.QtGui import QFont from ui.base.base_widget import BaseWidget, CardWidget from ui.components.custom_button import IconButton from ui.components.custom_input import CustomTextEdit from ui.dialogs.memo_input_dialog import MemoInputDialog from database.crud import CRUDManager from database.models import Memo from core.config import ConfigManager from core.signals import GlobalSignals from core.constants import AUTO_SAVE_INTERVAL from core.logger import get_logger logger = get_logger(__name__) class MemoWidget(CardWidget): """ 메모 위젯 메모를 표시하고 관리합니다. 더블클릭으로 편집 모드로 전환됩니다. Examples: >>> widget = MemoWidget() >>> widget.load_data() """ memo_changed = Signal() def __init__(self, parent=None): super().__init__(parent, padding=12, radius=12) self.crud = CRUDManager() self._current_date = date.today() self._current_memo: Memo = None self._is_editing = False # 자동 저장 타이머 self._save_timer = QTimer() self._save_timer.setSingleShot(True) self._save_timer.timeout.connect(self._auto_save) self._setup_ui() self._connect_signals() logger.info("메모 위젯 초기화 완료") def _setup_ui(self): """UI 설정""" # 헤더 header = QWidget() header_layout = QHBoxLayout(header) header_layout.setContentsMargins(0, 0, 0, 0) title = QLabel("📝 메모") title.setFont(QFont("GmarketSans", 14, QFont.Bold)) theme = self.config.theme text_color = "#f8fafc" if theme == 'dark' else "#1e293b" title.setStyleSheet(f"color: {text_color};") header_layout.addWidget(title) header_layout.addStretch() # 편집 버튼 self.edit_btn = IconButton("✏️", size=28, tooltip="메모 편집") self.edit_btn.clicked.connect(self._on_edit_clicked) header_layout.addWidget(self.edit_btn) self.layout.addWidget(header) # 구분선 separator = QFrame() separator.setFrameShape(QFrame.HLine) separator.setStyleSheet("color: #334155;" if theme == 'dark' else "color: #e2e8f0;") self.layout.addWidget(separator) # 메모 내용 (표시 모드) self.memo_display = QLabel("메모가 없습니다. 더블클릭하여 추가하세요.") self.memo_display.setFont(QFont("GmarketSans", 12)) self.memo_display.setWordWrap(True) self.memo_display.setAlignment(Qt.AlignTop | Qt.AlignLeft) self.memo_display.setMinimumHeight(100) self.memo_display.setCursor(Qt.PointingHandCursor) self.memo_display.mouseDoubleClickEvent = lambda e: self._on_edit_clicked() if theme == 'dark': self.memo_display.setStyleSheet("color: #e2e8f0;") else: self.memo_display.setStyleSheet("color: #374151;") self.layout.addWidget(self.memo_display, 1) # 메모 내용 (편집 모드) self.memo_edit = CustomTextEdit( placeholder="메모를 입력하세요...", min_height=100 ) self.memo_edit.text_changed_signal.connect(self._on_text_changed) self.memo_edit.hide() self.layout.addWidget(self.memo_edit, 1) # 저장/취소 버튼 (편집 모드) self.button_widget = QWidget() button_layout = QHBoxLayout(self.button_widget) button_layout.setContentsMargins(0, 8, 0, 0) button_layout.setSpacing(8) button_layout.addStretch() self.cancel_btn = IconButton("✕", size=28, tooltip="취소") self.cancel_btn.clicked.connect(self._on_cancel_clicked) button_layout.addWidget(self.cancel_btn) self.save_btn = IconButton("✓", size=28, tooltip="저장") self.save_btn.clicked.connect(self._on_save_clicked) button_layout.addWidget(self.save_btn) self.button_widget.hide() self.layout.addWidget(self.button_widget) def _connect_signals(self): """시그널 연결""" self.signals.memo_changed.connect(self._on_memo_signal_changed) def load_data(self): """데이터 로드""" self._current_memo = self.crud.get_latest_memo(self._current_date) if self._current_memo and self._current_memo.content: self.memo_display.setText(self._current_memo.content) else: theme = self.config.theme placeholder_color = "#64748b" if theme == 'dark' else "#94a3b8" self.memo_display.setText("메모가 없습니다. 더블클릭하여 추가하세요.") self.memo_display.setStyleSheet(f"color: {placeholder_color};") def _on_edit_clicked(self): """편집 버튼 클릭""" self._is_editing = True # 표시 모드 숨기기 self.memo_display.hide() self.edit_btn.hide() # 편집 모드 표시 self.memo_edit.show() self.button_widget.show() # 현재 내용 설정 if self._current_memo and self._current_memo.content: self.memo_edit.set_text(self._current_memo.content) else: self.memo_edit.set_text("") self.memo_edit.setFocus() def _on_save_clicked(self): """저장 버튼 클릭""" content = self.memo_edit.get_text() self.crud.upsert_memo( memo_date=self._current_date, content=content ) self._exit_edit_mode() self.load_data() self.memo_changed.emit() def _on_cancel_clicked(self): """취소 버튼 클릭""" self._exit_edit_mode() def _exit_edit_mode(self): """편집 모드 종료""" self._is_editing = False self._save_timer.stop() # 편집 모드 숨기기 self.memo_edit.hide() self.button_widget.hide() # 표시 모드 표시 self.memo_display.show() self.edit_btn.show() def _on_text_changed(self, text: str): """텍스트 변경 시 자동 저장 타이머 시작""" if self._is_editing: self._save_timer.start(AUTO_SAVE_INTERVAL * 1000) def _auto_save(self): """자동 저장""" if self._is_editing: content = self.memo_edit.get_text() self.crud.upsert_memo( memo_date=self._current_date, content=content ) logger.debug("메모 자동 저장") def _on_memo_signal_changed(self, memo_id: int): """메모 변경 시그널""" self.load_data()