154 lines
No EOL
6.2 KiB
Python
154 lines
No EOL
6.2 KiB
Python
# tabs/review_tab.py
|
|
import random
|
|
from PyQt6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
|
QLineEdit, QPushButton, QTableWidget, QTableWidgetItem,
|
|
QHeaderView, QFormLayout, QMessageBox
|
|
)
|
|
from PyQt6.QtCore import Qt, pyqtSlot
|
|
import database
|
|
|
|
class ReviewTab(QWidget):
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
|
|
# Master cache of records loaded from the database
|
|
self.all_cached_records = []
|
|
|
|
# Primary Layout
|
|
main_layout = QVBoxLayout(self)
|
|
main_layout.setContentsMargins(30, 20, 30, 20)
|
|
main_layout.setSpacing(15)
|
|
|
|
# --- SECTION 1: TOP REGION (Source Context & Tags) ---
|
|
top_container = QWidget()
|
|
top_layout = QFormLayout(top_container)
|
|
top_layout.setLabelAlignment(Qt.AlignmentFlag.AlignRight)
|
|
top_layout.setSpacing(10)
|
|
|
|
self.txt_review_context = QLineEdit()
|
|
self.txt_review_context.setPlaceholderText("Filter deck by context (e.g., Camino 2027)...")
|
|
self.txt_review_context.setStyleSheet("padding: 6px; font-size: 14px;")
|
|
self.txt_review_context.textChanged.connect(self.handle_live_filter)
|
|
|
|
self.txt_review_tags = QLineEdit()
|
|
self.txt_review_tags.setPlaceholderText("Filter deck by tags (e.g., verb, greeting)...")
|
|
self.txt_review_tags.setStyleSheet("padding: 6px; font-size: 14px;")
|
|
self.txt_review_tags.textChanged.connect(self.handle_live_filter)
|
|
|
|
top_layout.addRow(QLabel("<b>Source Context:</b>"), self.txt_review_context)
|
|
top_layout.addRow(QLabel("<b>Tags:</b>"), self.txt_review_tags)
|
|
|
|
main_layout.addWidget(top_container)
|
|
|
|
# --- SECTION 2: MIDDLE REGION (Translations Table View) ---
|
|
self.table = QTableWidget()
|
|
self.table.setColumnCount(2)
|
|
self.table.setHorizontalHeaderLabels(["English Phrase", "Spanish Translation"])
|
|
self.table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)
|
|
self.table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers)
|
|
|
|
# Format table header behaviors to stretch beautifully
|
|
header = self.table.horizontalHeader()
|
|
header.setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch)
|
|
header.setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
|
|
|
|
main_layout.addWidget(self.table)
|
|
|
|
# --- SECTION 3: BOTTOM REGION (Action Control Panel) ---
|
|
bottom_layout = QHBoxLayout()
|
|
bottom_layout.setSpacing(15)
|
|
|
|
self.btn_generate_deck = QPushButton("🗂️ Generate Deck")
|
|
self.btn_generate_deck.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
self.btn_generate_deck.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #27AE60;
|
|
color: white;
|
|
font-weight: bold;
|
|
font-size: 14px;
|
|
padding: 10px 22px;
|
|
border-radius: 5px;
|
|
}
|
|
QPushButton:hover { background-color: #219653; }
|
|
""")
|
|
self.btn_generate_deck.clicked.connect(self.generate_deck_action)
|
|
|
|
self.btn_generate_video = QPushButton("🎬 Generate Video")
|
|
self.btn_generate_video.setCursor(Qt.CursorShape.PointingHandCursor)
|
|
self.btn_generate_video.setStyleSheet("""
|
|
QPushButton {
|
|
background-color: #2980B9;
|
|
color: white;
|
|
font-weight: bold;
|
|
font-size: 14px;
|
|
padding: 10px 22px;
|
|
border-radius: 5px;
|
|
}
|
|
QPushButton:hover { background-color: #1F618D; }
|
|
""")
|
|
self.btn_generate_video.clicked.connect(self.generate_video_action)
|
|
|
|
bottom_layout.addWidget(self.btn_generate_deck)
|
|
bottom_layout.addWidget(self.btn_generate_video)
|
|
bottom_layout.addStretch()
|
|
|
|
main_layout.addLayout(bottom_layout)
|
|
|
|
# Populate initial table layout on startup
|
|
self.reload_review_pool()
|
|
|
|
@pyqtSlot()
|
|
def reload_review_pool(self):
|
|
"""Fetches consolidated text entries from the database and initializes cache."""
|
|
try:
|
|
self.all_cached_records = database.get_all_translations_explicit()
|
|
self.handle_live_filter()
|
|
except Exception as e:
|
|
print(f"Error initializing flashcard display: {e}")
|
|
|
|
@pyqtSlot()
|
|
def handle_live_filter(self):
|
|
"""Filters the display table row contents matching current Context and Tags criteria."""
|
|
self.table.blockSignals(True)
|
|
self.table.setRowCount(0)
|
|
|
|
filter_ctx = self.txt_review_context.text().lower().strip()
|
|
filter_tag = self.txt_review_tags.text().lower().strip()
|
|
|
|
visible_row_index = 0
|
|
for row in self.all_cached_records:
|
|
val_ctx = (row["source_context"] or "").lower()
|
|
val_tag = (row["tags"] or "").lower()
|
|
|
|
# Show row if it satisfies both filter boxes
|
|
if (filter_ctx in val_ctx) and (filter_tag in val_tag):
|
|
self.table.insertRow(visible_row_index)
|
|
|
|
item_en = QTableWidgetItem(row["en_text"])
|
|
item_es = QTableWidgetItem(row["es_text"])
|
|
|
|
self.table.setItem(visible_row_index, 0, item_en)
|
|
self.table.setItem(visible_row_index, 1, item_es)
|
|
|
|
visible_row_index += 1
|
|
|
|
self.table.blockSignals(False)
|
|
|
|
@pyqtSlot()
|
|
def generate_deck_action(self):
|
|
"""Placeholder function execution trigger for processing deck compiler passes."""
|
|
QMessageBox.information(
|
|
self,
|
|
"Deck Compiler Active",
|
|
f"Compiling a custom Anki training deck container using the {self.table.rowCount()} visible filtered rows."
|
|
)
|
|
|
|
@pyqtSlot()
|
|
def generate_video_action(self):
|
|
"""Placeholder function execution trigger for media compiler production automation."""
|
|
QMessageBox.information(
|
|
self,
|
|
"Media Generator Active",
|
|
f"Initiating background video asset production using the {self.table.rowCount()} visible phrases."
|
|
) |