diff --git a/main.spec b/main.spec index 9f0716a..09a7f1a 100644 --- a/main.spec +++ b/main.spec @@ -5,7 +5,7 @@ a = Analysis( ['main.py'], pathex=[], binaries=[], - datas=[], + datas=[()], hiddenimports=[], hookspath=[], hooksconfig={}, @@ -21,7 +21,7 @@ exe = EXE( a.scripts, [], exclude_binaries=True, - name='main', + name='Spanish Voice Trainer', debug=False, bootloader_ignore_signals=False, strip=False, diff --git a/tabs/review_tab.py b/tabs/review_tab.py index 32e3570..208ff9f 100644 --- a/tabs/review_tab.py +++ b/tabs/review_tab.py @@ -1,5 +1,4 @@ # tabs/review_tab.py -import random import os import re import subprocess @@ -60,14 +59,15 @@ class ReviewTab(QWidget): # Left Half: Live Translation Grid View Table self.table = QTableWidget() - self.table.setColumnCount(2) - self.table.setHorizontalHeaderLabels(["English Phrase", "Spanish Translation"]) + self.table.setColumnCount(3) + self.table.setHorizontalHeaderLabels(["Sort", "English Phrase", "Spanish Translation"]) self.table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows) self.table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers) header = self.table.horizontalHeader() - header.setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch) + header.setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents) header.setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch) + header.setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch) split_layout.addWidget(self.table, stretch=1) @@ -192,7 +192,7 @@ class ReviewTab(QWidget): @pyqtSlot() def handle_live_filter(self): - """Filters grid contents and generates a randomized matching queue for the card engine.""" + """Filters grid contents and sorts by sort_order for the card engine.""" self.table.blockSignals(True) self.table.setRowCount(0) @@ -200,7 +200,6 @@ class ReviewTab(QWidget): filter_tag = self.txt_review_tags.text().lower().strip() self.filtered_review_pool = [] - visible_row_index = 0 for row in self.all_cached_records: val_ctx = (row["source_context"] or "").lower() @@ -209,15 +208,21 @@ class ReviewTab(QWidget): if (filter_ctx in val_ctx) and (filter_tag in val_tag): self.filtered_review_pool.append(row) - self.table.insertRow(visible_row_index) - self.table.setItem(visible_row_index, 0, QTableWidgetItem(row["en_text"])) - self.table.setItem(visible_row_index, 1, QTableWidgetItem(row["es_text"])) - visible_row_index += 1 + # Sort sequentially by sort_order (fallback to translation_id if unset) + self.filtered_review_pool.sort( + key=lambda r: (r.get("sort_order") if r.get("sort_order") is not None else 999999, r.get("translation_id", 0)) + ) + + visible_row_index = 0 + for row in self.filtered_review_pool: + self.table.insertRow(visible_row_index) + self.table.setItem(visible_row_index, 0, QTableWidgetItem(str(row.get("sort_order", 0)))) + self.table.setItem(visible_row_index, 1, QTableWidgetItem(row["en_text"])) + self.table.setItem(visible_row_index, 2, QTableWidgetItem(row["es_text"])) + visible_row_index += 1 self.table.blockSignals(False) - # Reshuffle the active localized queue stack and reset card state tracking pointer - random.shuffle(self.filtered_review_pool) self.current_index = 0 if self.filtered_review_pool else -1 self.is_flipped = False self.display_current_card() @@ -251,7 +256,7 @@ class ReviewTab(QWidget): @pyqtSlot() def handle_card_interaction(self): - """State machine cycling through card flipped values or increments indices sequential steps.""" + """State machine cycling through card flipped values and automatically playing audio on both side transitions.""" if not self.filtered_review_pool: return @@ -259,15 +264,18 @@ class ReviewTab(QWidget): # Transition State: Front -> Back self.is_flipped = True self.display_current_card() + # Automatically play Spanish neural audio on flip + self.play_card_audio() else: - # Transition State: Advance to next index item row + # Transition State: Advance to next sequential item self.current_index += 1 if self.current_index >= len(self.filtered_review_pool): self.current_index = 0 - random.shuffle(self.filtered_review_pool) # Rescramble on completion pass loops self.is_flipped = False self.display_current_card() + # Automatically play English neural audio on advancing to next card + self.play_card_audio() def _async_edge_speech_worker(self, text, voice, rate_modifier): """Background thread worker to render neural speech with terminal debug logging."""