267 lines
13 KiB
Python
267 lines
13 KiB
Python
# announcement_dialog.py
|
|
from PySide6.QtWidgets import (
|
|
QDialog, QVBoxLayout, QLabel, QPushButton, QScrollArea, QWidget,
|
|
QTextEdit, QHBoxLayout, QCheckBox, QMessageBox
|
|
)
|
|
from PySide6.QtCore import Qt, QTimer, QSettings
|
|
from PySide6.QtGui import QFont
|
|
from datetime import datetime, timezone
|
|
|
|
class AnnouncementDialog(QDialog):
|
|
def __init__(self, supabase_manager, user_info, parent=None):
|
|
super().__init__(parent)
|
|
self.supabase_manager = supabase_manager
|
|
self.user_info = user_info # dict, 예: {"email": "...", "name": "...", ...}
|
|
self.settings = QSettings("WhenRideMycar", "AutoPercenty3")
|
|
self.setWindowTitle("로그인 성공 - 공지사항 및 사용자 정보")
|
|
self.setMinimumSize(600, 500)
|
|
self.auto_close_timer = None # 자동 닫힘 타이머
|
|
self.remaining_seconds = 3 # 3초 카운트다운
|
|
self.init_ui()
|
|
self.load_announcements()
|
|
self.check_auto_close_condition()
|
|
self.handle_membership_validity()
|
|
|
|
def init_ui(self):
|
|
main_layout = QVBoxLayout(self)
|
|
main_layout.setContentsMargins(20, 20, 20, 20)
|
|
main_layout.setSpacing(15)
|
|
|
|
# 사용자 정보 패널
|
|
self.info_label = QLabel(self.format_user_info())
|
|
self.info_label.setStyleSheet("font-size: 16px; font-weight: bold; color: #333;")
|
|
main_layout.addWidget(self.info_label)
|
|
|
|
# 이벤트 안내 레이블 (나중에 get_membership_message의 결과를 표시)
|
|
self.event_label = QLabel("")
|
|
self.event_label.setStyleSheet("font-size: 14px; color: #d32f2f;")
|
|
main_layout.addWidget(self.event_label)
|
|
|
|
# 공지사항 헤더
|
|
header_label = QLabel("새 공지사항")
|
|
header_label.setStyleSheet("font-size: 16px; font-weight: bold;")
|
|
main_layout.addWidget(header_label)
|
|
|
|
|
|
# 스크롤 영역에 공지사항 목록
|
|
self.scroll_area = QScrollArea()
|
|
self.scroll_area.setWidgetResizable(True)
|
|
container = QWidget()
|
|
self.ann_layout = QVBoxLayout(container)
|
|
self.ann_layout.setSpacing(10)
|
|
container.setLayout(self.ann_layout)
|
|
self.scroll_area.setWidget(container)
|
|
main_layout.addWidget(self.scroll_area)
|
|
|
|
# "다음부터 공지사항 보지 않기" 체크박스
|
|
self.hide_checkbox = QCheckBox("다음부터 공지사항 보지 않기")
|
|
self.hide_checkbox.setToolTip("체크 시, 새로운 공지사항이 없으면 3초 후 자동으로 닫힙니다.")
|
|
main_layout.addWidget(self.hide_checkbox)
|
|
|
|
# 카운트다운 레이블 (초 단위)
|
|
self.countdown_label = QLabel("")
|
|
self.countdown_label.setAlignment(Qt.AlignRight)
|
|
self.countdown_label.setStyleSheet("font-size: 12px; color: #666;")
|
|
main_layout.addWidget(self.countdown_label)
|
|
|
|
# 닫기 버튼
|
|
self.close_btn = QPushButton("닫기")
|
|
self.close_btn.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #1877f2;
|
|
color: white;
|
|
border-radius: 4px;
|
|
padding: 8px;
|
|
font-size: 14px;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #166fe5;
|
|
}
|
|
""")
|
|
self.close_btn.clicked.connect(self.accept)
|
|
main_layout.addWidget(self.close_btn)
|
|
|
|
self.setLayout(main_layout)
|
|
|
|
def format_user_info(self):
|
|
# 환영 메시지: nickname이 있으면 사용, 없으면 이메일 사용
|
|
welcome = self.user_info.get("nickname") or self.user_info.get("email", "사용자")
|
|
email = self.user_info.get("email")
|
|
membership = self.user_info.get("membership_level", "free")
|
|
|
|
# 남은 사용 기간 계산 (payment_period_end와 현재 시간 비교)
|
|
payment_period_end_str = self.user_info.get("payment_period_end")
|
|
remaining_period_str = "N/A"
|
|
if payment_period_end_str:
|
|
try:
|
|
# payment_period_end_str에 타임존 정보가 없다면 UTC로 지정
|
|
payment_period_end = datetime.fromisoformat(payment_period_end_str)
|
|
if payment_period_end.tzinfo is None:
|
|
payment_period_end = payment_period_end.replace(tzinfo=timezone.utc)
|
|
now = datetime.now(timezone.utc)
|
|
if payment_period_end > now:
|
|
delta = payment_period_end - now
|
|
days = delta.days
|
|
hours, remainder = divmod(delta.seconds, 3600)
|
|
minutes, seconds = divmod(remainder, 60)
|
|
remaining_period_str = f"{days}일 {hours:02d}:{minutes:02d}:{seconds:02d}"
|
|
else:
|
|
remaining_period_str = "만료됨"
|
|
except Exception as e:
|
|
remaining_period_str = "N/A"
|
|
print(f"에러 : {e}")
|
|
|
|
# 마지막 로그인 시간 포맷 (YYYY-MM-DD HH:MM:SS)
|
|
last_login_str = self.user_info.get("last_login", "N/A")
|
|
formatted_last_login = last_login_str
|
|
try:
|
|
dt = datetime.fromisoformat(last_login_str)
|
|
formatted_last_login = dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
except Exception:
|
|
pass
|
|
|
|
# banned_keyword_count: SupabaseManager에서 해당 사용자의 금지어 개수를 조회
|
|
user_id = self.user_info.get("id")
|
|
banned_keyword_count = self.supabase_manager.get_banned_keyword_count(user_id)
|
|
|
|
info_text = (
|
|
f"환영합니다, {welcome}님!\n"
|
|
f"회원이메일: {email} | 회원 등급: {membership} | 남은 사용 기간: {remaining_period_str}\n"
|
|
f"관리 중 금지키워드: {banned_keyword_count}개 | 마지막 로그인: {formatted_last_login}"
|
|
)
|
|
return info_text
|
|
|
|
def load_announcements(self):
|
|
"""공지사항 목록을 Supabase에서 로드하고, 읽은 항목은 QSettings에 기록된 대로 처리합니다."""
|
|
# 먼저, 기존 위젯 제거
|
|
for i in reversed(range(self.ann_layout.count())):
|
|
widget = self.ann_layout.itemAt(i).widget()
|
|
if widget:
|
|
widget.setParent(None)
|
|
try:
|
|
announcements = self.supabase_manager.get_announcements()
|
|
if not announcements:
|
|
self.ann_layout.addWidget(QLabel("새 공지사항이 없습니다."))
|
|
return
|
|
# QSettings에서 이미 읽은 공지사항 ID 목록을 불러옴
|
|
read_ids = self.settings.value("read_announcements", [])
|
|
if not isinstance(read_ids, list):
|
|
read_ids = []
|
|
# 정렬: position 기준 오름차순
|
|
announcements = sorted(announcements, key=lambda x: x["position"])
|
|
for ann in announcements:
|
|
# 만약 공지사항이 중요하지 않고, 이미 읽은 상태라면 표시하지 않음.
|
|
if (ann.get("id") in read_ids) and (not ann.get("important", False)):
|
|
continue
|
|
# 버튼 텍스트: 중요 공지라면 "[중요공지]" 접두어 추가
|
|
prefix = "[중요공지] " if ann.get("important", False) else ""
|
|
btn = QPushButton(f"{prefix}{ann['position']}. {ann['title']}")
|
|
btn.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #1877f2;
|
|
color: white;
|
|
border-radius: 5px;
|
|
padding: 8px;
|
|
text-align: left;
|
|
font-size: 14px;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #166fe5;
|
|
}
|
|
""")
|
|
# 버튼 클릭 시 상세 공지사항 팝업 표시
|
|
btn.clicked.connect(lambda checked, a=ann: self.show_announcement_detail(a))
|
|
self.ann_layout.addWidget(btn)
|
|
except Exception as e:
|
|
QMessageBox.warning(self, "오류", f"공지사항 로드 중 오류 발생: {e}")
|
|
|
|
def show_announcement_detail(self, announcement):
|
|
"""공지사항 버튼 클릭 시 상세 내용을 팝업으로 보여주고, 읽은 것으로 처리합니다."""
|
|
try:
|
|
dialog = QDialog(self)
|
|
dialog.setWindowTitle(f"{announcement['position']}. {announcement['title']}")
|
|
dialog.setMinimumSize(400, 300)
|
|
layout = QVBoxLayout(dialog)
|
|
text_edit = QTextEdit()
|
|
text_edit.setReadOnly(True)
|
|
text_edit.setHtml(announcement["content"])
|
|
layout.addWidget(text_edit)
|
|
close_btn = QPushButton("닫기")
|
|
close_btn.clicked.connect(dialog.accept)
|
|
layout.addWidget(close_btn)
|
|
dialog.setLayout(layout)
|
|
dialog.exec()
|
|
|
|
# 읽음 처리 (중요 공지가 아니면)
|
|
if not announcement.get("important", False):
|
|
read_ids = self.settings.value("read_announcements", [])
|
|
if not isinstance(read_ids, list):
|
|
read_ids = []
|
|
if announcement.get("id") not in read_ids:
|
|
read_ids.append(announcement.get("id"))
|
|
self.settings.setValue("read_announcements", read_ids)
|
|
self.settings.sync()
|
|
self.load_announcements()
|
|
except Exception as e:
|
|
QMessageBox.warning(self, "오류", f"공지사항 표시 중 오류 발생: {e}")
|
|
|
|
def handle_membership_validity(self):
|
|
"""
|
|
SupabaseManager의 check_membership_validity()를 호출하여 사용 기간이 유효한지 확인합니다.
|
|
- 유효하다면 get_membership_message()로 이벤트 메시지를 표시합니다.
|
|
- 만약 기간이 만료되었다면, 재결제 안내 메시지와 함께 다이얼로그를 종료(프로그램 사용 제한)합니다.
|
|
"""
|
|
valid = self.supabase_manager.check_membership_validity(self.user_info)
|
|
|
|
print(f"membership_validity : {valid}")
|
|
if valid:
|
|
membership_msg = self.supabase_manager.get_membership_message(self.user_info)
|
|
self.event_label.setText(membership_msg)
|
|
# 만약 "다음부터 공지사항 보지 않기" 체크되어 있고, 공지사항 목록이 비어있다면 자동 종료 조건을 시작
|
|
self.check_auto_close_condition()
|
|
else:
|
|
QMessageBox.warning(self, "사용 기간 만료", "사용 기간이 만료되었습니다. 재결제 후 이용해 주세요.")
|
|
# 재결제 페이지 호출(예: RePaymentDialog) 또는 프로그램 종료
|
|
# self.open_repayment_page()
|
|
self.reject()
|
|
|
|
def open_repayment_page(self):
|
|
"""
|
|
재결제 안내 및 재결제 페이지를 표시합니다.
|
|
실제 구현에서는 재결제 다이얼로그나 웹 페이지를 호출할 수 있습니다.
|
|
"""
|
|
QMessageBox.information(self, "재결제 안내", "사용 기간이 만료되었습니다. 재결제 페이지로 이동합니다.")
|
|
# 예: self.parent().open_repayment_dialog() 또는 웹 브라우저를 통해 특정 URL 오픈
|
|
|
|
|
|
def check_auto_close_condition(self):
|
|
"""
|
|
"다음부터 공지사항 보지 않기" 체크박스가 선택되어 있고,
|
|
현재 표시할 공지사항(읽지 않은, 중요 공지를 제외한)이 없다면 3초 후 자동으로 닫히도록 카운트다운 시작.
|
|
"""
|
|
# 조건: 체크박스가 체크되어 있고, announcements가 빈 경우
|
|
announcements = self.supabase_manager.get_announcements()
|
|
read_ids = self.settings.value("read_announcements", [])
|
|
if not isinstance(read_ids, list):
|
|
read_ids = []
|
|
# 필터: 중요 공지를 제외하고, 읽지 않은 항목만 계산
|
|
new_announcements = [ann for ann in announcements
|
|
if (ann.get("id") not in read_ids) and (not ann.get("important", False))]
|
|
if self.hide_checkbox.isChecked() and not new_announcements:
|
|
# 3초 카운트다운 시작
|
|
self.remaining_seconds = 3
|
|
self.countdown_label.setText(f"자동 종료까지: {self.remaining_seconds}초")
|
|
self.auto_close_timer = QTimer(self)
|
|
self.auto_close_timer.timeout.connect(self.update_countdown)
|
|
self.auto_close_timer.start(1000)
|
|
|
|
def update_countdown(self):
|
|
self.remaining_seconds -= 1
|
|
if self.remaining_seconds > 0:
|
|
self.countdown_label.setText(f"자동 종료까지: {self.remaining_seconds}초")
|
|
else:
|
|
self.auto_close_timer.stop()
|
|
self.accept() # 다이얼로그 자동 종료
|
|
|
|
|