import os from pathlib import Path import memoria from textual.app import App, ComposeResult from textual.widgets import Header, Footer, ListView, ListItem, Label, Static, Button from textual.containers import Container from textual.screen import Screen ver = 0.01 # --- MemApp 学习屏幕 --- class MemAppLearningScreen(Screen): BINDINGS = [ ("q", "go_back", "返回"), ("escape", "quit_app", "退出") ] def __init__(self, file_to_learn: str, history_file: str, name: str | None = None, id: str | None = None, classes: str | None = None) -> None: super().__init__(name=name, id=id, classes=classes) self.file_to_learn = file_to_learn self.history_file = history_file def compose(self) -> ComposeResult: yield Header() with Container(id="learning_screen_container"): yield Label(f"正在学习文件: [b]{Path(self.file_to_learn).name}[/b]", classes="learning-info") yield Label(f"历史文件: [b]{Path(self.history_file).name}[/b]", classes="learning-info") yield Label("\n[i]点击 '开始记忆' 进入学习模式.[/i]", classes="placeholder-message") yield Static("\n按 [b]Q[/b] 返回;按 [b]ESC[/b] 退出.", classes="instructions") yield Button("开始记忆", id="start_memorizing_button", variant="primary", classes="start-button") yield Static(f"\n以下是全文:\n", classes="read-info") with open(self.file_to_learn, 'r', encoding='UTF-8') as f: for i in f.readlines(): yield Static(' ' + i, classes="read-info") yield Footer() def action_go_back(self): self.app.pop_screen() def action_quit_app(self): self.app.exit() def on_button_pressed(self, event: Button.Pressed) -> None: if event.button.id == "start_memorizing_button": self.app.push_screen( memoria.MemScreen( file_to_learn=self.file_to_learn, history_file=self.history_file ) ) # --- 文件选择屏幕 --- class FileSelectionScreen(Screen): global ver def compose(self) -> ComposeResult: yield Header() yield Container( Label(f'欢迎使用 "青鸟" 辅助记忆软件, 版本 {ver}', classes="title-label"), Label("选择要学习的文件:", classes="title-label"), ListView(id="file-list", classes="file-list-view") ) yield Footer() def on_mount(self) -> None: Path("./history").mkdir(parents=True, exist_ok=True) Path("./library").mkdir(parents=True, exist_ok=True) file_list_widget = self.query_one("#file-list", ListView) library_path = Path("./library") txt_files = sorted([f.name for f in library_path.iterdir() if f.suffix == ".txt"]) if txt_files: for filename in txt_files: file_list_widget.append(ListItem(Label(filename))) else: file_list_widget.append(ListItem(Static("在 ./library/ 中未找到任何 .txt 文件。请放置文件后重启应用。"))) file_list_widget.disabled = True def on_list_view_selected(self, event: ListView.Selected) -> None: if not isinstance(event.item, ListItem): self.notify("无法选择此项。", severity="error") return selected_label = event.item.query_one(Label) if "未找到任何 .txt 文件" in str(selected_label.renderable): self.notify("请先在 `./library/` 目录中放置 .txt 文件。", severity="warning") return selected_filename = str(selected_label.renderable) file_to_learn_path = Path("./library") / selected_filename history_file_name = f"{Path(selected_filename).stem}_history.json" history_file_path = Path("./history") / history_file_name self.notify(f"已选择: {selected_filename}", timeout=2) self.app.push_screen(MemAppLearningScreen( file_to_learn=str(file_to_learn_path), history_file=str(history_file_path) )) def action_quit_app(self) -> None: self.app.exit() # --- 主 Textual 应用类 --- class MemAppLauncher(App): CSS_PATH = "styles.css" TITLE = '青鸟 辅助记忆程序' BINDINGS = [("escape", "quit", "退出"), ("d", "toggle_dark", "改变色调")] SCREENS = { "file_selection_screen": FileSelectionScreen, } def on_mount(self) -> None: self.action_toggle_dark() self.push_screen("file_selection_screen") if __name__ == "__main__": css_path = Path("styles_dashboard.css") app = MemAppLauncher() app.run()