Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
5e96fc8138 | |||
e64d1711d0 |
12
README.md
12
README.md
@@ -1,9 +1,15 @@
|
|||||||
# 潜进 (HeurAMS) - 启发式辅助记忆程序
|
# 潜进 (HeurAMS) - 启发式辅助记忆程序
|
||||||
> 形人而我无形,**则我专而敌分**
|
> 形人而我无形,**则我专而敌分**
|
||||||
|
|
||||||
## 概述
|
## 关于此仓库
|
||||||
|
"潜进" 项目包含多个组件:
|
||||||
|
- 此仓库包含了 "潜进" 项目的核心和基于 Textual 的基本用户界面 (T 界面) 的实现
|
||||||
|
- 关于基于 Flutter 的用户界面 (F 界面), 请参阅 "潜进-F" (HeurAMS-F) 仓库
|
||||||
|
- 关于数据同步实现, 请参阅 "潜进-S" (HeurSync) 仓库
|
||||||
|
- 关于云端文档源实现, 请参阅 "潜进-R" (HeurRepo) 仓库
|
||||||
|
|
||||||
"潜进" (HeurAMS) 是为习题册, 古诗词, 及其他问答/记忆/理解型知识设计的辅助记忆软件, 提供动态规划的优化记忆方案
|
## 概述
|
||||||
|
"潜进" (HeurAMS: Heuristic Auxiliary Memorizing Scheduler, 启发式记忆辅助调度器) 是为习题册, 古诗词, 及其他问答/记忆/理解型知识设计的辅助记忆软件, 提供动态规划的优化记忆方案
|
||||||
|
|
||||||
## 技术集成与特性
|
## 技术集成与特性
|
||||||
|
|
||||||
@@ -28,7 +34,7 @@
|
|||||||
- 支持触屏/鼠标/键盘多操作模式
|
- 支持触屏/鼠标/键盘多操作模式
|
||||||
- 简洁直观的复习流程设计
|
- 简洁直观的复习流程设计
|
||||||
|
|
||||||
## 屏幕截图
|
## 屏幕截图 (基本用户界面)
|
||||||
|
|
||||||
> 单击图片以放大
|
> 单击图片以放大
|
||||||
|
|
||||||
|
243
main.py
243
main.py
@@ -1,247 +1,8 @@
|
|||||||
from textual.app import App, ComposeResult
|
from textual.app import App
|
||||||
from textual.widgets import (
|
from screens import FileSelectorScreen
|
||||||
Header,
|
|
||||||
Footer,
|
|
||||||
ListView,
|
|
||||||
ProgressBar,
|
|
||||||
DirectoryTree,
|
|
||||||
ListItem,
|
|
||||||
Label,
|
|
||||||
Static,
|
|
||||||
Button,
|
|
||||||
)
|
|
||||||
from textual.containers import Container, Horizontal, Center
|
|
||||||
from textual.screen import Screen
|
|
||||||
import pathlib
|
|
||||||
import threading
|
|
||||||
import edge_tts as tts
|
|
||||||
from playsound import playsound
|
|
||||||
import particles as pt
|
|
||||||
from reactor import Reactor, Apparatus
|
|
||||||
import auxiliary as aux
|
|
||||||
import compositions as compo
|
|
||||||
import builtins
|
|
||||||
|
|
||||||
ver = "0.3.2"
|
ver = "0.3.2"
|
||||||
|
|
||||||
config = aux.ConfigFile("config.toml")
|
|
||||||
|
|
||||||
|
|
||||||
class MemScreen(Screen):
|
|
||||||
BINDINGS = [
|
|
||||||
("d", "toggle_dark", "改变色调"),
|
|
||||||
("q", "pop_screen", "返回主菜单"),
|
|
||||||
("v", "play_voice", "朗读"),
|
|
||||||
]
|
|
||||||
if config.get("quick_pass"):
|
|
||||||
BINDINGS.append(("k", "quick_pass", "快速通过[调试]"))
|
|
||||||
btn = dict()
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
nucleon_file: pt.NucleonUnion,
|
|
||||||
electron_file: pt.ElectronUnion,
|
|
||||||
tasked_num,
|
|
||||||
):
|
|
||||||
super().__init__(name=None, id=None, classes=None)
|
|
||||||
self.reactor = Reactor(nucleon_file, electron_file, self, tasked_num)
|
|
||||||
self.stage = 1
|
|
||||||
self.stage += self.reactor.set_round_templated(self.stage)
|
|
||||||
self.reactor.forward()
|
|
||||||
self.compo = next(self.reactor.current_appar)
|
|
||||||
|
|
||||||
def compose(self) -> ComposeResult:
|
|
||||||
if type(self.compo).__name__ == "Recognition":
|
|
||||||
self.action_play_voice()
|
|
||||||
yield Header(show_clock=True)
|
|
||||||
with Center():
|
|
||||||
yield Static(
|
|
||||||
f"{len(self.reactor.procession) - self.reactor.index}/{len(self.reactor.procession)}"
|
|
||||||
)
|
|
||||||
yield from self.compo.compose()
|
|
||||||
yield Footer()
|
|
||||||
|
|
||||||
def on_mount(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def on_button_pressed(self, event):
|
|
||||||
ret = self.compo.handler(event, "button")
|
|
||||||
self._forward_judge(ret)
|
|
||||||
|
|
||||||
def _forward_judge(self, ret):
|
|
||||||
if ret == -1:
|
|
||||||
return
|
|
||||||
if ret == 0:
|
|
||||||
try:
|
|
||||||
self.compo = next(self.reactor.current_appar)
|
|
||||||
self.refresh_ui()
|
|
||||||
except StopIteration:
|
|
||||||
nxt = self.reactor.forward(1)
|
|
||||||
try:
|
|
||||||
self.compo = next(self.reactor.current_appar)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
if nxt == -1:
|
|
||||||
if self.reactor.round_set == 0:
|
|
||||||
if self.stage == 4:
|
|
||||||
if config.get("save"):
|
|
||||||
self.reactor.save()
|
|
||||||
self.compo = compo.Finished(
|
|
||||||
self, None, pt.Atom.placeholder()
|
|
||||||
)
|
|
||||||
self.refresh_ui()
|
|
||||||
else:
|
|
||||||
self.reactor.set_round_templated(self.stage)
|
|
||||||
self.reactor.forward(1)
|
|
||||||
self.stage += 1
|
|
||||||
self.compo = next(self.reactor.current_appar)
|
|
||||||
self.refresh_ui()
|
|
||||||
return
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.refresh_ui()
|
|
||||||
return
|
|
||||||
if ret == 1:
|
|
||||||
self.refresh_ui()
|
|
||||||
return
|
|
||||||
|
|
||||||
def refresh_ui(self):
|
|
||||||
self.call_later(self.recompose)
|
|
||||||
print(type(self.compo).__name__)
|
|
||||||
|
|
||||||
def action_play_voice(self):
|
|
||||||
print("VOICE")
|
|
||||||
def play():
|
|
||||||
cache_dir = pathlib.Path(f"./cache/voice/")
|
|
||||||
cache_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
cache = cache_dir / f"{self.reactor.current_atom[1].content.replace('/','')}.wav"
|
|
||||||
if not cache.exists():
|
|
||||||
communicate = tts.Communicate(
|
|
||||||
self.reactor.current_atom[1].content.replace("/", ""),
|
|
||||||
"zh-CN-YunjianNeural",
|
|
||||||
)
|
|
||||||
communicate.save_sync(
|
|
||||||
f"./cache/voice/{self.reactor.current_atom[1].content.replace('/','')}.wav"
|
|
||||||
)
|
|
||||||
playsound(str(cache))
|
|
||||||
|
|
||||||
threading.Thread(target=play).start()
|
|
||||||
|
|
||||||
def action_quick_pass(self):
|
|
||||||
self.reactor.report(self.reactor.current_atom, 5)
|
|
||||||
self._forward_judge(0)
|
|
||||||
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: pt.NucleonUnion, electron_file: pt.ElectronUnion
|
|
||||||
) -> 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"核子数量:{len(self.nucleon_file)}")
|
|
||||||
yield Button(
|
|
||||||
"开始记忆",
|
|
||||||
id="start_memorizing_button",
|
|
||||||
variant="primary",
|
|
||||||
classes="start-button",
|
|
||||||
)
|
|
||||||
yield Static(f"\n全文如下:\n")
|
|
||||||
yield Static(self._get_full_content().replace("/", ""), classes="full")
|
|
||||||
yield Footer()
|
|
||||||
|
|
||||||
def _get_full_content(self):
|
|
||||||
content = ""
|
|
||||||
for i in self.nucleon_file.nucleons:
|
|
||||||
content += i["content"]
|
|
||||||
return content
|
|
||||||
|
|
||||||
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":
|
|
||||||
newscr = MemScreen(
|
|
||||||
self.nucleon_file, self.electron_file, config.get("tasked_number", 6)
|
|
||||||
)
|
|
||||||
self.app.push_screen(newscr)
|
|
||||||
|
|
||||||
|
|
||||||
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):
|
|
||||||
return
|
|
||||||
|
|
||||||
selected_label = event.item.query_one(Label)
|
|
||||||
if "未找到任何 .toml 文件" in str(selected_label.renderable):
|
|
||||||
return
|
|
||||||
|
|
||||||
selected_filename = str(selected_label.renderable)
|
|
||||||
nucleon_file = pt.NucleonUnion(
|
|
||||||
pathlib.Path("./nucleon") / selected_filename
|
|
||||||
)
|
|
||||||
electron_file_path = pathlib.Path("./electron") / selected_filename
|
|
||||||
if electron_file_path.exists():
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
electron_file_path.touch()
|
|
||||||
electron_file = pt.ElectronUnion(
|
|
||||||
pathlib.Path("./electron") / selected_filename
|
|
||||||
)
|
|
||||||
self.app.push_screen(PreparationScreen(nucleon_file, electron_file))
|
|
||||||
|
|
||||||
def action_quit_app(self) -> None:
|
|
||||||
self.app.exit()
|
|
||||||
|
|
||||||
|
|
||||||
class AppLauncher(App):
|
class AppLauncher(App):
|
||||||
CSS_PATH = "styles.css"
|
CSS_PATH = "styles.css"
|
||||||
TITLE = "潜进 - 辅助记忆程序"
|
TITLE = "潜进 - 辅助记忆程序"
|
||||||
|
@@ -20,6 +20,9 @@ class Apparatus():
|
|||||||
for i in self.positron["testdata"].keys():
|
for i in self.positron["testdata"].keys():
|
||||||
if i == "additional_inf":
|
if i == "additional_inf":
|
||||||
continue
|
continue
|
||||||
|
if i == "fill_blank_test": # 加深
|
||||||
|
self.procession.append(comps.registry[i](screen, reactor, atom))
|
||||||
|
self.procession.append(comps.registry[i](screen, reactor, atom))
|
||||||
self.procession.append(comps.registry[i](screen, reactor, atom))
|
self.procession.append(comps.registry[i](screen, reactor, atom))
|
||||||
# self.procession.reverse()
|
# self.procession.reverse()
|
||||||
random.shuffle(self.procession)
|
random.shuffle(self.procession)
|
||||||
@@ -139,6 +142,7 @@ class Reactor():
|
|||||||
e.revisor(5, True)
|
e.revisor(5, True)
|
||||||
continue
|
continue
|
||||||
e.revisor(q)
|
e.revisor(q)
|
||||||
|
|
||||||
def report(self, atom, quality):
|
def report(self, atom, quality):
|
||||||
"向反应器和最低质量记录汇报"
|
"向反应器和最低质量记录汇报"
|
||||||
if atom in self.atoms_new:
|
if atom in self.atoms_new:
|
||||||
|
240
screens.py
Normal file
240
screens.py
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
from textual.app import App, ComposeResult
|
||||||
|
from textual.widgets import (
|
||||||
|
Header,
|
||||||
|
Footer,
|
||||||
|
ListView,
|
||||||
|
ProgressBar,
|
||||||
|
DirectoryTree,
|
||||||
|
ListItem,
|
||||||
|
Label,
|
||||||
|
Static,
|
||||||
|
Button,
|
||||||
|
)
|
||||||
|
from textual.containers import Container, Horizontal, Center
|
||||||
|
from textual.screen import Screen
|
||||||
|
import pathlib
|
||||||
|
import threading
|
||||||
|
import edge_tts as tts
|
||||||
|
from playsound import playsound
|
||||||
|
import particles as pt
|
||||||
|
from reactor import Reactor, Apparatus
|
||||||
|
import auxiliary as aux
|
||||||
|
import compositions as compo
|
||||||
|
import builtins
|
||||||
|
import main
|
||||||
|
|
||||||
|
config = aux.ConfigFile("config.toml")
|
||||||
|
|
||||||
|
class MemScreen(Screen):
|
||||||
|
BINDINGS = [
|
||||||
|
("d", "toggle_dark", "改变色调"),
|
||||||
|
("q", "pop_screen", "返回主菜单"),
|
||||||
|
("v", "play_voice", "朗读"),
|
||||||
|
]
|
||||||
|
if config.get("quick_pass"):
|
||||||
|
BINDINGS.append(("k", "quick_pass", "快速通过[调试]"))
|
||||||
|
btn = dict()
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
nucleon_file: pt.NucleonUnion,
|
||||||
|
electron_file: pt.ElectronUnion,
|
||||||
|
tasked_num,
|
||||||
|
):
|
||||||
|
super().__init__(name=None, id=None, classes=None)
|
||||||
|
self.reactor = Reactor(nucleon_file, electron_file, self, tasked_num)
|
||||||
|
self.stage = 1
|
||||||
|
self.stage += self.reactor.set_round_templated(self.stage)
|
||||||
|
self.reactor.forward()
|
||||||
|
self.compo = next(self.reactor.current_appar)
|
||||||
|
|
||||||
|
def compose(self) -> ComposeResult:
|
||||||
|
if type(self.compo).__name__ == "Recognition":
|
||||||
|
self.action_play_voice()
|
||||||
|
yield Header(show_clock=True)
|
||||||
|
with Center():
|
||||||
|
yield Static(
|
||||||
|
f"{len(self.reactor.procession) - self.reactor.index}/{len(self.reactor.procession)}"
|
||||||
|
)
|
||||||
|
yield from self.compo.compose()
|
||||||
|
yield Footer()
|
||||||
|
|
||||||
|
def on_mount(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_button_pressed(self, event):
|
||||||
|
ret = self.compo.handler(event, "button")
|
||||||
|
self._forward_judge(ret)
|
||||||
|
|
||||||
|
def _forward_judge(self, ret):
|
||||||
|
if ret == -1:
|
||||||
|
return
|
||||||
|
if ret == 0:
|
||||||
|
try:
|
||||||
|
self.compo = next(self.reactor.current_appar)
|
||||||
|
self.refresh_ui()
|
||||||
|
except StopIteration:
|
||||||
|
nxt = self.reactor.forward(1)
|
||||||
|
try:
|
||||||
|
self.compo = next(self.reactor.current_appar)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if nxt == -1:
|
||||||
|
if self.reactor.round_set == 0:
|
||||||
|
if self.stage == 4:
|
||||||
|
if config.get("save"):
|
||||||
|
self.reactor.save()
|
||||||
|
self.compo = compo.Finished(
|
||||||
|
self, None, pt.Atom.placeholder()
|
||||||
|
)
|
||||||
|
self.refresh_ui()
|
||||||
|
else:
|
||||||
|
self.reactor.set_round_templated(self.stage)
|
||||||
|
self.reactor.forward(1)
|
||||||
|
self.stage += 1
|
||||||
|
self.compo = next(self.reactor.current_appar)
|
||||||
|
self.refresh_ui()
|
||||||
|
return
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.refresh_ui()
|
||||||
|
return
|
||||||
|
if ret == 1:
|
||||||
|
self.refresh_ui()
|
||||||
|
return
|
||||||
|
|
||||||
|
def refresh_ui(self):
|
||||||
|
self.call_later(self.recompose)
|
||||||
|
print(type(self.compo).__name__)
|
||||||
|
|
||||||
|
def action_play_voice(self):
|
||||||
|
print("VOICE")
|
||||||
|
def play():
|
||||||
|
cache_dir = pathlib.Path(f"./cache/voice/")
|
||||||
|
cache_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
cache = cache_dir / f"{self.reactor.current_atom[1].content.replace('/','')}.wav"
|
||||||
|
if not cache.exists():
|
||||||
|
communicate = tts.Communicate(
|
||||||
|
self.reactor.current_atom[1].content.replace("/", ""),
|
||||||
|
"zh-CN-YunjianNeural",
|
||||||
|
)
|
||||||
|
communicate.save_sync(
|
||||||
|
f"./cache/voice/{self.reactor.current_atom[1].content.replace('/','')}.wav"
|
||||||
|
)
|
||||||
|
playsound(str(cache))
|
||||||
|
|
||||||
|
threading.Thread(target=play).start()
|
||||||
|
|
||||||
|
def action_quick_pass(self):
|
||||||
|
self.reactor.report(self.reactor.current_atom, 5)
|
||||||
|
self._forward_judge(0)
|
||||||
|
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: pt.NucleonUnion, electron_file: pt.ElectronUnion
|
||||||
|
) -> 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"核子数量:{len(self.nucleon_file)}")
|
||||||
|
yield Button(
|
||||||
|
"开始记忆",
|
||||||
|
id="start_memorizing_button",
|
||||||
|
variant="primary",
|
||||||
|
classes="start-button",
|
||||||
|
)
|
||||||
|
yield Static(f"\n全文如下:\n")
|
||||||
|
yield Static(self._get_full_content().replace("/", ""), classes="full")
|
||||||
|
yield Footer()
|
||||||
|
|
||||||
|
def _get_full_content(self):
|
||||||
|
content = ""
|
||||||
|
for i in self.nucleon_file.nucleons:
|
||||||
|
content += i["content"]
|
||||||
|
return content
|
||||||
|
|
||||||
|
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":
|
||||||
|
newscr = MemScreen(
|
||||||
|
self.nucleon_file, self.electron_file, config.get("tasked_number", 6)
|
||||||
|
)
|
||||||
|
self.app.push_screen(newscr)
|
||||||
|
|
||||||
|
|
||||||
|
class FileSelectorScreen(Screen):
|
||||||
|
|
||||||
|
def compose(self) -> ComposeResult:
|
||||||
|
yield Header(show_clock=True)
|
||||||
|
yield Container(
|
||||||
|
Label(f'欢迎使用 "潜进" 辅助记忆软件, 版本 {main.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):
|
||||||
|
return
|
||||||
|
|
||||||
|
selected_label = event.item.query_one(Label)
|
||||||
|
if "未找到任何 .toml 文件" in str(selected_label.renderable):
|
||||||
|
return
|
||||||
|
|
||||||
|
selected_filename = str(selected_label.renderable)
|
||||||
|
nucleon_file = pt.NucleonUnion(
|
||||||
|
pathlib.Path("./nucleon") / selected_filename
|
||||||
|
)
|
||||||
|
electron_file_path = pathlib.Path("./electron") / selected_filename
|
||||||
|
if electron_file_path.exists():
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
electron_file_path.touch()
|
||||||
|
electron_file = pt.ElectronUnion(
|
||||||
|
pathlib.Path("./electron") / selected_filename
|
||||||
|
)
|
||||||
|
self.app.push_screen(PreparationScreen(nucleon_file, electron_file))
|
||||||
|
|
||||||
|
def action_quit_app(self) -> None:
|
||||||
|
self.app.exit()
|
||||||
|
|
Reference in New Issue
Block a user