feat(gui): add clip list and subtitle preview edit UI

This commit is contained in:
hmo
2026-05-04 00:31:32 +08:00
parent 5f3396378f
commit b9dc5b163b
+149 -8
View File
@@ -24,9 +24,11 @@ if ffmpeg_path:
from PySide6.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLineEdit, QPushButton, QTextEdit, QLabel, QFileDialog,
QMessageBox, QGroupBox, QFormLayout, QProgressBar
QMessageBox, QGroupBox, QFormLayout, QProgressBar, QListWidget,
QListWidgetItem, QInputDialog, QMenu
)
from PySide6.QtCore import Qt, Signal, QObject
from PySide6.QtGui import QColor
# 底层函数(与 CLI 共用)
from core import parse_ppt_to_config, Pipeline
@@ -193,14 +195,153 @@ class GUI(QMainWindow):
layout.addLayout(btn_layout)
def _setup_edit_ui(self):
"""
编辑界面(Task 9 实现)
目前显示 TODO 提示
"""
QMessageBox.information(
self, "提示",
"编辑模式将在 Task 9 中实现\n目前可以手动编辑 generated_config.yaml 后重新运行"
"""编辑界面:左侧 clip 列表 + 右侧字幕预览"""
central = QWidget()
self.setCentralWidget(central)
main_layout = QVBoxLayout(central) # Changed to QVBoxLayout for bottom bar
# Top: Split left and right
top_layout = QHBoxLayout()
# === 左侧:clip 列表 ===
left_widget = QWidget()
left_layout = QVBoxLayout(left_widget)
left_header = QLabel("知识点")
left_header.setStyleSheet("font-weight: bold; font-size: 14px;")
left_layout.addWidget(left_header)
# clip 列表
self.clip_list = QListWidget()
self.clip_list.itemDoubleClicked.connect(self._on_clip_double_clicked)
self.clip_list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.clip_list.customContextMenuRequested.connect(self._on_clip_context_menu)
left_layout.addWidget(self.clip_list)
# 底部按钮
left_btn_layout = QHBoxLayout()
self.add_clip_btn = QPushButton("+ 新增知识点")
self.add_clip_btn.clicked.connect(self._on_add_clip)
self.add_clip_btn.setMaximumWidth(120)
left_btn_layout.addWidget(self.add_clip_btn)
left_btn_layout.addStretch()
left_layout.addLayout(left_btn_layout)
top_layout.addWidget(left_widget, 1)
# === 右侧:字幕预览 ===
right_widget = QWidget()
right_layout = QVBoxLayout(right_widget)
right_header = QLabel("字幕预览(可直接编辑)")
right_header.setStyleSheet("font-weight: bold; font-size: 14px;")
right_layout.addWidget(right_header)
self.subtitle_edit = QTextEdit()
self.subtitle_edit.setReadOnly(False) # 用户可编辑
right_layout.addWidget(self.subtitle_edit)
right_btn_layout = QHBoxLayout()
self.load_subtitle_btn = QPushButton("加载字幕")
self.load_subtitle_btn.clicked.connect(self._load_subtitle_file)
right_btn_layout.addWidget(self.load_subtitle_btn)
right_layout.addLayout(right_btn_layout)
top_layout.addWidget(right_widget, 2)
main_layout.addLayout(top_layout, 1) # Stretch factor 1 for top area
# === 底部状态栏 ===
bottom_layout = QHBoxLayout()
self.status_label = QLabel("就绪")
bottom_layout.addWidget(self.status_label)
bottom_layout.addStretch()
self.apply_btn = QPushButton("应用")
self.apply_btn.setStyleSheet("font-weight: bold; background-color: #4CAF50; color: white;")
self.apply_btn.clicked.connect(self._on_apply) # Task 10 实现
bottom_layout.addWidget(self.apply_btn)
self.back_btn = QPushButton("返回")
self.back_btn.clicked.connect(self._show_project_info)
bottom_layout.addWidget(self.back_btn)
main_layout.addLayout(bottom_layout)
# 填充 clip 列表
self._refresh_clip_list()
# 加载字幕
self._load_subtitle_file()
def _refresh_clip_list(self):
"""刷新 clip 列表"""
self.clip_list.clear()
for i, clip in enumerate(self.pipeline.clips):
title = clip.get('title', '未知')
matched = clip.get('matched', True)
item_text = f"Clip {i+1}: {title}"
if not matched:
item_text += " ⚠️ 未匹配"
item = QListWidgetItem(item_text)
if not matched:
item.setBackground(QColor(255, 200, 200)) # 红色背景
item.setData(Qt.ItemDataRole.UserRole, i) # 存索引
self.clip_list.addItem(item)
def _on_clip_double_clicked(self, item):
"""双击 clip 进入编辑模式"""
clip_index = item.data(Qt.ItemDataRole.UserRole)
# 简单的实现:弹出 QInputDialog 让用户输入新标题
clip = self.pipeline.clips[clip_index]
new_title, ok = QInputDialog.getText(
self, "修改标题", f"Clip {clip_index+1} 标题:",
text=clip.get('title', '')
)
if ok and new_title.strip():
self.pipeline.reextract_clip(clip_index, new_title.strip())
self._refresh_clip_list()
self.status_label.setText(f"已修改 Clip {clip_index+1} 标题为: {new_title}")
def _on_clip_context_menu(self, pos):
"""右键菜单:删除"""
item = self.clip_list.itemAt(pos)
if not item:
return
clip_index = item.data(Qt.ItemDataRole.UserRole)
menu = QMenu()
delete_action = menu.addAction("删除此 Clip")
action = menu.exec_(self.clip_list.mapToGlobal(pos))
if action == delete_action:
self.pipeline.delete_clip(clip_index)
self._refresh_clip_list()
self.status_label.setText(f"已删除 Clip {clip_index+1}")
def _on_add_clip(self):
"""新增知识点"""
new_title, ok = QInputDialog.getText(self, "新增知识点", "请输入知识点标题:")
if ok and new_title.strip():
idx, matched = self.pipeline.add_clip_by_title(new_title.strip())
self._refresh_clip_list()
if matched:
self.status_label.setText(f"已新增: {new_title} (Clip {idx+1})")
else:
self.status_label.setText(f"已新增: {new_title},但未匹配到转录内容")
def _load_subtitle_file(self):
"""加载 v1_content.srt 到字幕编辑框"""
srt_path = os.path.join(self.pipeline.subs_dir, 'v1_content.srt')
if os.path.exists(srt_path):
with open(srt_path, 'r', encoding='utf-8') as f:
self.subtitle_edit.setPlainText(f.read())
else:
self.subtitle_edit.setPlainText("# 字幕文件不存在")
def _on_apply(self):
"""Task 10 预留:应用修改"""
pass
def _setup_new_project_ui(self):
"""新建项目的文件选择界面"""