from __future__ import annotations from PyQt6.QtWidgets import ( QWidget, QVBoxLayout, QTabWidget, QListWidget, QListWidgetItem, QLabel, QStyledItemDelegate, QApplication, ) from PyQt6.QtCore import Qt, pyqtSignal, QSize, QRect from PyQt6.QtGui import QColor, QPainter, QFontMetrics from core.models import Article _LINE2_ROLE = Qt.ItemDataRole.UserRole + 1 class ArticleItemDelegate(QStyledItemDelegate): def paint(self, painter: QPainter, option, index): painter.save() self.initStyleOption(option, index) style = option.widget.style() if option.widget else QApplication.style() style.drawPrimitive(style.PrimitiveElement.PE_PanelItemViewItem, option, painter, option.widget) rect: QRect = option.rect fm = QFontMetrics(option.font) line_h = fm.height() pad = 4 line1 = index.data(Qt.ItemDataRole.DisplayRole) or "" line2 = index.data(_LINE2_ROLE) or "" fg = index.data(Qt.ItemDataRole.ForegroundRole) painter.setPen(fg.color() if fg else option.palette.text().color()) r1 = QRect(rect.left() + pad, rect.top() + pad, rect.width() - pad * 2, line_h) painter.drawText(r1, Qt.TextFlag.TextSingleLine, line1) if line2: painter.setPen(QColor("#888")) r2 = QRect(rect.left() + pad, rect.top() + pad + line_h + 2, rect.width() - pad * 2, line_h) painter.drawText(r2, Qt.TextFlag.TextSingleLine, line2) painter.restore() def sizeHint(self, option, index): fm = QFontMetrics(option.font) line_h = fm.height() pad = 4 line2 = index.data(_LINE2_ROLE) or "" height = (line_h * 2 + 2 + pad * 2) if line2 else (line_h + pad * 2) return QSize(0, height) class ArticleItem(QListWidgetItem): def __init__(self, article: Article): super().__init__() self.article = article if article.has_translation: badge = "🇬🇧 ✓" if article.lang == "it" else "🇮🇹 ✓" else: badge = "🇬🇧 ✗" if article.lang == "it" else "🇮🇹 ✗" line1 = f"{article.slug} [{badge}]" if article.draft: line1 = f"[DRAFT] {line1}" parts = [] if article.meta_type: parts.append(article.meta_type) if article.meta_date: parts.append(article.meta_date) if article.meta_tags: parts.append(f"#{article.meta_tags.replace(', ', ' #')}") if article.meta_categories: parts.append(f"[{article.meta_categories}]") line2 = " ".join(parts) if parts else "" self.setText(line1) self.setData(_LINE2_ROLE, line2) if article.draft: self.setForeground(QColor("#f59e0b")) elif not article.has_translation: self.setForeground(QColor("#ff6b6b")) class ArticlesView(QWidget): article_selected = pyqtSignal(object) # Article translate_requested = pyqtSignal(object) # Article def __init__(self, parent=None): super().__init__(parent) self._articles: list[Article] = [] self._build_ui() def _build_ui(self): layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) self._tabs = QTabWidget() self._tabs.setStyleSheet("QTabBar::tab { padding: 6px 16px; }") self._list_it = QListWidget() self._list_it.setItemDelegate(ArticleItemDelegate(self._list_it)) self._list_en = QListWidget() self._list_en.setItemDelegate(ArticleItemDelegate(self._list_en)) self._tabs.addTab(self._list_it, "🇮🇹 Italiano") self._tabs.addTab(self._list_en, "🇬🇧 English") layout.addWidget(self._tabs) self._list_it.itemClicked.connect(lambda item: self.article_selected.emit(item.article)) self._list_en.itemClicked.connect(lambda item: self.article_selected.emit(item.article)) def set_articles(self, articles: list[Article]): self._articles = articles self._list_it.clear() self._list_en.clear() for a in articles: item = ArticleItem(a) if a.lang == "it": self._list_it.addItem(item) else: self._list_en.addItem(item) class MissingTranslationView(QWidget): article_selected = pyqtSignal(object) # Article translate_requested = pyqtSignal(object) # Article def __init__(self, parent=None): super().__init__(parent) self._build_ui() def _build_ui(self): layout = QVBoxLayout(self) header = QLabel("⚠️ Articoli senza traduzione") header.setStyleSheet("color: #ff6b6b; font-weight: bold; font-size: 13px; padding: 10px;") layout.addWidget(header) self._list = QListWidget() self._list.setItemDelegate(ArticleItemDelegate(self._list)) layout.addWidget(self._list) self._list.itemClicked.connect(lambda item: self.article_selected.emit(item.article)) def set_articles(self, articles: list[Article]): self._list.clear() missing = [a for a in articles if not a.has_translation] for a in missing: lang_other = "🇬🇧" if a.lang == "it" else "🇮🇹" item = ArticleItem(a) item.setText(f"{a.slug} [manca {lang_other}] ({a.lang.upper()})") item.setData(_LINE2_ROLE, "") self._list.addItem(item)