不成熟的改进

This commit is contained in:
2025-07-19 23:20:36 +08:00
parent 768b5bc5bc
commit 7e28958462
8 changed files with 391 additions and 30 deletions

236
main.py
View File

@@ -0,0 +1,236 @@
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
import particles as parti
import pathlib
ver = '0.2.1'
class MemScreen(Screen):
BINDINGS = [
("d", "toggle_dark", "改变色调"),
("q", "pop_screen", "返回主菜单"),
("v", "play_voice", "朗读"),
("0", "press('q0')", None),
("1", "press('q1')", None),
("2", "press('q2')", None),
("3", "press('q3')", None),
("4", "press('q4')", None),
("5", "press('q5')", None),
("[", "press('q5')", None),
("]", "press('q4')", None),
(";", "press('q3')", None),
("'", "press('q2')", None),
(".", "press('q1')", None),
("/", "press('q0')", None),
]
btn = dict()
def __init__(
self,
atoms_file: str = 'test_atoms.json',
tasked_num: int = 8, # 记忆最小单元数目
):
super().__init__(name=None, id=None, classes=None)
self.memobj = MemObject(atoms_file=atoms_file, tasked_num=tasked_num)
self.memobj.next_round()
self.memobj.update_runtime(1)
def compose(self) -> ComposeResult:
yield Header(show_clock=True)
with Container(id="main_container"):
yield Label("", id="round_label")
yield Label("记住了吗?", id="question")
yield Static(self.memobj.runtime['current_atom'].content, id="sentence")
yield Static("", id="feedback") # 用于显示反馈
yield Label(self._get_progress_text(), id="progress")
with Container(id="button_container"):
self.btn['5'] = Button("完美回想", variant="success", id="q5", classes="choice")
self.btn['4'] = Button("犹豫后正确", variant="success", id="q4", classes="choice")
self.btn['3'] = Button("困难地正确", variant="warning", id="q3", classes="choice")
self.btn['2'] = Button("错误但熟悉", variant="warning", id="q2", classes="choice")
self.btn['1'] = Button("错误且不熟", variant="error", id="q1", classes="choice")
self.btn['0'] = Button("完全空白", variant="error", id="q0", classes="choice")
yield Horizontal(self.btn['5'], self.btn['4'])
yield Horizontal(self.btn['3'], self.btn['2'])
yield Horizontal(self.btn['1'], self.btn['0'])
yield Footer()
def _get_progress_text(self):
return f"{self.memobj.runtime['left'] + 1}/{self.memobj.runtime['total']}"
def _get_round_text(self):
t = {
'A': "复习模式",
'B': "建立新记忆",
'C': "总复习"
}
return "当前模式: " + t[self.memobj.runtime['stage']]
def on_mount(self):
# 首次挂载时调用
self._update_ui()
def _update_ui(self):
self.query_one("#round_label", Label).update(self._get_round_text())
self.query_one("#sentence", Static).update(self.memobj.runtime['current_atom'].content)
self.query_one("#progress", Label).update(self._get_progress_text())
self.query_one("#feedback", Static).update("") # 清除任何之前的反馈消息
def _show_finished_screen(self, message):
self.query_one("#question", Label).update(message)
self.query_one("#sentence", Static).update("已经完成记忆任务")
self.query_one("#round_label").display = False
self.query_one("#progress").display = False
for i in range(6):
self.query_one(f"#q{i}", Button).display = False
def on_button_pressed(self, event):
feedback_label = self.query_one("#feedback", Static)
if type(event) == str:
btnid = event
else:
btnid = event.button.id
btnid = str(btnid)
quality = int(btnid.replace('q', ''))
assessment = self.memobj.report(self.memobj.runtime['current_atom'], quality)
if assessment == 1:
# 需要复习
feedback_label.update(f"评分为 {quality}, 已经加入至复习, 请重复记忆")
else:
ret = self.memobj.update_runtime(1)
if ret == 1:
self.memobj.switch_to_extra_review()
self.memobj.update_runtime(1)
elif ret == 2:
self.memobj.next_round()
self.memobj.update_runtime(1)
elif ret == 3:
self.memobj.save()
self._show_finished_screen("今日目标已完成")
return
#feedback_label.update("") # 清除反馈消息
self._update_ui()
def action_press(self, btnid):
self.on_button_pressed(btnid)
def action_play_voice(self):
def play():
cache = Path(f"./cache/voice/{self.memobj.runtime['current_atom'].content}.wav")
if not cache.exists():
communicate = tts.Communicate(self.memobj.runtime['current_atom'].content, "zh-CN-YunjianNeural")
communicate.save_sync(f"./cache/voice/{self.memobj.runtime['current_atom'].content}.wav")
playsound(str(cache))
threading.Thread(target=play).start()
def action_toggle_dark(self):
self.app.action_toggle_dark()
def action_pop_screen(self):
"""返回到上一个屏幕"""
self.app.pop_screen()
class PreparationScreen(Screen):
BINDINGS = [
("q", "go_back", "返回"),
("escape", "quit_app", "退出")
]
def __init__(self, nucleon_file: parti.AtomicFile, electron_file: parti.AtomicFile) -> None:
super().__init__(name=None, id=None, classes=None)
self.nucleon_file = nucleon_file
self.electron_file = electron_file
def compose(self) -> ComposeResult:
yield Header(show_clock=True)
with Container(id="learning_screen_container"):
yield Label(f"记忆项目: [b]{self.nucleon_file.name}[/b]\n")
yield Label(f"核子文件对象: ./nucleon/[b]{self.nucleon_file.name}[/b].toml")
yield Label(f"电子文件对象: ./electron/[b]{self.electron_file.name}[/b].toml")
yield Label(f"核子数量:{self.nucleon_file.get_len()}")
yield Button("开始记忆", id="start_memorizing_button", variant="primary", classes="start-button")
yield Static(f"\n全文如下:\n")
yield Static(self.nucleon_file.get_full_content(), classes="full")
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:
pass
#if event.button.id == "start_memorizing_button":
# #init_file(Path(self.atom_file).name)
# newscr = proc.MemScreen(Path(self.atom_file).name)
# self.app.push_screen(
# newscr
# )
#if event.button.id == "edit_metadata_button":
# init_file(Path(self.atom_file).name)
# os.system("reset;nano ./data/" + str(Path(self.atom_file).name.replace(".txt", "_atoms.json")))
class FileSelectorScreen(Screen):
global ver
def compose(self) -> ComposeResult:
yield Header(show_clock=True)
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:
file_list_widget = self.query_one("#file-list", ListView)
nucleon_path = pathlib.Path("./nucleon")
nucleon_files = sorted([f.name for f in nucleon_path.iterdir() if f.suffix == ".toml"])
if nucleon_files:
for filename in nucleon_files:
file_list_widget.append(ListItem(Label(filename)))
else:
file_list_widget.append(ListItem(Static("在 ./nucleon/ 中未找到任何核子文件. 请放置文件后重启应用.")))
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 "未找到任何 .toml 文件" in str(selected_label.renderable):
self.notify("请先在 `./atoms/` 目录中放置 .toml 文件。", severity="warning")
return
selected_filename = str(selected_label.renderable)
nucleon_file = parti.AtomicFile(pathlib.Path("./nucleon") / selected_filename, "nucleon")
electron_file_path = pathlib.Path("./electron") / selected_filename
if electron_file_path.exists():
pass
else:
electron_file_path.touch()
electron_file = parti.AtomicFile(pathlib.Path("./electron") / selected_filename, "electron")
# self.notify(f"已选择: {selected_filename}", timeout=2)
self.app.push_screen(PreparationScreen(nucleon_file, electron_file))
def action_quit_app(self) -> None:
self.app.exit()
class AppLauncher(App):
CSS_PATH = "styles.tcss"
TITLE = '潜进 - 辅助记忆程序'
BINDINGS = [("escape", "quit", "退出"), ("d", "toggle_dark", "改变色调")]
SCREENS = {
"file_selection_screen": FileSelectorScreen,
}
def on_mount(self) -> None:
self.action_toggle_dark()
self.push_screen("file_selection_screen")
if __name__ == "__main__":
css_path = pathlib.Path("styles_dashboard.tcss")
app = AppLauncher()
app.run()