feat: 开发 unifront 前端会话模块
This commit is contained in:
@@ -25,6 +25,7 @@ from .screens.navigator import NavigatorScreen
|
||||
from .screens.precache import PrecachingScreen
|
||||
from .screens.setting import SettingScreen
|
||||
from .screens.synctool import SyncScreen
|
||||
from . import shim
|
||||
|
||||
_end = perf_counter()
|
||||
print(f"已完成! (耗时: {round(1000 * (_end - _start))}ms)")
|
||||
@@ -56,6 +57,9 @@ class HeurAMSApp(App):
|
||||
"setting": SettingScreen,
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def on_mount(self) -> None:
|
||||
self.push_screen("dashboard")
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
.repo-list-item {
|
||||
layout: grid;
|
||||
grid-size: 2;
|
||||
grid-size: 1;
|
||||
height: 3;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ from textual.containers import ScrollableContainer
|
||||
from textual.screen import Screen
|
||||
from textual.widgets import Button, Footer, Header, Label, Markdown, Static
|
||||
|
||||
from textual import events, on
|
||||
|
||||
import heurams.services.version as version
|
||||
from heurams.context import *
|
||||
import platform
|
||||
@@ -19,8 +21,19 @@ class AboutScreen(Screen):
|
||||
("q", "go_back", "返回"),
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@on(events.ScreenResume)
|
||||
def post_active(self, event):
|
||||
from heurams.interface import shim
|
||||
|
||||
shim.set_term_title(f"{self.app.TITLE} - {self.SUB_TITLE}")
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Header(show_clock=True)
|
||||
|
||||
if config_var.get()['interface']['global']['show_header']:
|
||||
yield Header(show_clock=config_var.get()['interface']['global']['clock_on_header'])
|
||||
with ScrollableContainer(id="about_container"):
|
||||
yield Label("[b]关于与版本信息[/b]")
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ from textual.containers import ScrollableContainer, Container, Horizontal, Verti
|
||||
from textual.screen import Screen
|
||||
from textual.widgets import Button, Footer, Header, Label, ListItem, ListView, Static
|
||||
from textual.layouts import horizontal
|
||||
from textual import events, on
|
||||
from textual.reactive import reactive
|
||||
|
||||
import heurams.kernel.particles as pt
|
||||
import heurams.services.timer as timer
|
||||
@@ -37,6 +39,8 @@ class DashboardScreen(Screen):
|
||||
|
||||
CSS_PATH = rootdir / "interface" / "css" / "screens" / "dashboard.tcss"
|
||||
|
||||
repolink = reactive({})
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str | None = None,
|
||||
@@ -44,12 +48,12 @@ class DashboardScreen(Screen):
|
||||
classes: str | None = None,
|
||||
) -> None:
|
||||
super().__init__(name, id, classes)
|
||||
self.repolink = {}
|
||||
self._load_data()
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
"""组合界面组件"""
|
||||
self._load_data()
|
||||
yield Header(show_clock=True)
|
||||
if config_var.get()['interface']['global']['show_header']:
|
||||
yield Header(show_clock=config_var.get()['interface']['global']['clock_on_header'])
|
||||
with ScrollableContainer():
|
||||
yield Horizontal( # 顶部的状态
|
||||
Vertical(
|
||||
@@ -58,7 +62,7 @@ class DashboardScreen(Screen):
|
||||
f"应用时区修正: UTC+{str(config_var.get()['services']['timer']['timezone_offset'] / 3600).rstrip('.0')}"
|
||||
),
|
||||
Label(
|
||||
f"默认算法设置: {config_var.get()['interface']['global']['algorithm']}"
|
||||
f"默认算法设置: {config_var.get()['interface']['global']['algorithm']}",
|
||||
),
|
||||
classes="left",
|
||||
),
|
||||
@@ -81,6 +85,13 @@ class DashboardScreen(Screen):
|
||||
yield Label(f"版本 {version.ver} {version.stage.capitalize()}") # 版本信息
|
||||
yield Footer()
|
||||
|
||||
@on(events.ScreenResume)
|
||||
def post_active(self, event):
|
||||
from heurams.interface import shim
|
||||
shim.set_term_title(f"{self.app.TITLE} - {self.SUB_TITLE}")
|
||||
# https://github.com/Textualize/textual/discussions/4268
|
||||
# self.refresh(recompose=True) 此函数有问题且官方不管 而且性能低
|
||||
|
||||
def _load_data(self):
|
||||
repo_dirs = Repo.probe_valid_repos_in_dir(
|
||||
Path(config_var.get()["global"]["paths"]["repo"])
|
||||
@@ -154,7 +165,7 @@ class DashboardScreen(Screen):
|
||||
for r in self.repos:
|
||||
self.repolink[str(id(r))] = r # 用于规避 ctype id 对象还原
|
||||
list_item = ListItem(
|
||||
Label(r.prompt),
|
||||
*[Label(line) for line in r.prompt.splitlines()],
|
||||
Button(
|
||||
f"开始学习",
|
||||
flat=True,
|
||||
|
||||
@@ -4,6 +4,8 @@ import base64
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
from textual import events, on
|
||||
|
||||
from textual.app import ComposeResult
|
||||
from textual.containers import ScrollableContainer
|
||||
from textual.screen import Screen
|
||||
@@ -18,6 +20,7 @@ from textual.widgets import (
|
||||
Static,
|
||||
)
|
||||
|
||||
from textual import events, on
|
||||
from heurams.context import config_var
|
||||
from heurams.kernel.repolib import Repo
|
||||
from heurams.services.favorite_service import FavoriteItem, favorite_manager
|
||||
@@ -53,7 +56,9 @@ class FavoriteManagerScreen(Screen):
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
"""组合界面组件"""
|
||||
yield Header(show_clock=True)
|
||||
|
||||
if config_var.get()['interface']['global']['show_header']:
|
||||
yield Header(show_clock=config_var.get()['interface']['global']['clock_on_header'])
|
||||
with ScrollableContainer(id="favorites-container"):
|
||||
if not self.favorites:
|
||||
yield Label("暂无收藏", classes="empty-label")
|
||||
@@ -63,6 +68,12 @@ class FavoriteManagerScreen(Screen):
|
||||
yield ListView(id="favorites-list")
|
||||
yield Footer()
|
||||
|
||||
@on(events.ScreenResume)
|
||||
def post_active(self, event):
|
||||
from heurams.interface import shim
|
||||
|
||||
shim.set_term_title(f"{self.app.TITLE} - {self.SUB_TITLE}")
|
||||
|
||||
def on_mount(self) -> None:
|
||||
"""挂载后填充列表"""
|
||||
if self.favorites:
|
||||
|
||||
@@ -10,6 +10,8 @@ from textual.reactive import reactive
|
||||
from textual.screen import Screen
|
||||
from textual.widgets import Button, Footer, Header, Label, Static
|
||||
|
||||
from textual import events, on
|
||||
|
||||
import heurams.kernel.particles as pt
|
||||
import heurams.kernel.puzzles as pz
|
||||
from heurams.context import config_var, rootdir
|
||||
@@ -17,10 +19,13 @@ from heurams.kernel.reactor import *
|
||||
from heurams.services.favorite_service import favorite_manager
|
||||
from heurams.services.logger import get_logger
|
||||
|
||||
import pickle
|
||||
|
||||
from .. import shim
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
class MemScreen(Screen):
|
||||
BINDINGS = [
|
||||
("q", "go_back", "返回"),
|
||||
@@ -33,7 +38,8 @@ class MemScreen(Screen):
|
||||
("z", "block_prompt"),
|
||||
]
|
||||
|
||||
CSS_PATH = rootdir / 'interface' / 'css' / 'screens' / 'memoqueue.tcss'
|
||||
SUB_TITLE = "学习中"
|
||||
CSS_PATH = rootdir / "interface" / "css" / "screens" / "memoqueue.tcss"
|
||||
|
||||
if config_var.get()["interface"]["global"]["quick_pass"]:
|
||||
BINDINGS.append(("k", "quick_pass", "正确应答"))
|
||||
@@ -55,8 +61,15 @@ class MemScreen(Screen):
|
||||
self.update_state()
|
||||
self.expander: Expander
|
||||
|
||||
@on(events.ScreenResume)
|
||||
def post_active(self, event):
|
||||
from heurams.interface import shim
|
||||
|
||||
shim.set_term_title(f"{self.app.TITLE} - {self.SUB_TITLE}")
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Header(show_clock=True)
|
||||
if config_var.get()['interface']['global']['show_header']:
|
||||
yield Header(show_clock=config_var.get()['interface']['global']['clock_on_header'])
|
||||
with ScrollableContainer():
|
||||
yield Label(self._get_progress_text(), id="head_stat")
|
||||
yield ScrollableContainer(id="puzzle_container")
|
||||
@@ -83,7 +96,7 @@ class MemScreen(Screen):
|
||||
return Static(f"无法生成谜题 {e}")
|
||||
|
||||
def _get_progress_text(self):
|
||||
s = f"阶段: {self.procession.phase.name}\n"
|
||||
s = f"阶段: {self.procession.route.name}\n"
|
||||
# 收藏状态
|
||||
if self.repo is not None:
|
||||
fav_status = "已收藏" if self._is_current_atom_favorited() else "未收藏"
|
||||
@@ -98,7 +111,7 @@ class MemScreen(Screen):
|
||||
|
||||
def mount_puzzle(self):
|
||||
"""挂载当前谜题组件"""
|
||||
if self.procession.phase == RouterState.FINISHED:
|
||||
if self.procession.route == RouterState.FINISHED:
|
||||
self.mount_finished_widget()
|
||||
return
|
||||
container = self.query_one("#puzzle_container")
|
||||
@@ -144,7 +157,7 @@ class MemScreen(Screen):
|
||||
if new_rating == -1: # 安全值
|
||||
return
|
||||
self.update_state()
|
||||
if self.procession.phase == RouterState.FINISHED:
|
||||
if self.procession.route == RouterState.FINISHED:
|
||||
rating = -1
|
||||
return
|
||||
self.expander.report(new_rating)
|
||||
@@ -231,4 +244,4 @@ class MemScreen(Screen):
|
||||
self.update_display()
|
||||
|
||||
def action_block_prompt(self):
|
||||
self.app.notify("功能在记忆界面中不可用, 完成或返回后再试", severity="error")
|
||||
self.app.notify("功能在记忆界面中不可用, 完成或返回后再试", severity="error")
|
||||
|
||||
@@ -5,6 +5,8 @@ from textual.containers import Grid, ScrollableContainer
|
||||
from textual.screen import ModalScreen
|
||||
from textual.widgets import Button, Footer, Header, Label, ListItem, ListView, Static
|
||||
|
||||
from textual import events, on
|
||||
|
||||
from heurams.context import *
|
||||
from heurams.services.logger import get_logger
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ from textual.screen import Screen
|
||||
from textual.widgets import Button, Footer, Header, Label, ProgressBar, Static
|
||||
from textual.worker import get_current_worker
|
||||
|
||||
from textual import events, on
|
||||
|
||||
import heurams.kernel.particles as pt
|
||||
import heurams.services.hasher as hasher
|
||||
from heurams.context import *
|
||||
@@ -80,6 +82,12 @@ class PrecachingScreen(Screen):
|
||||
continue
|
||||
return total
|
||||
|
||||
@on(events.ScreenResume)
|
||||
def post_active(self, event):
|
||||
from heurams.interface import shim
|
||||
|
||||
shim.set_term_title(f"{self.app.TITLE} - {self.SUB_TITLE}")
|
||||
|
||||
def _update_cache_stats(self) -> None:
|
||||
"""更新缓存统计信息"""
|
||||
total_size = 0
|
||||
@@ -103,7 +111,9 @@ class PrecachingScreen(Screen):
|
||||
self.cache_stats["cache_rate"] = cache_rate
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Header(show_clock=True)
|
||||
|
||||
if config_var.get()['interface']['global']['show_header']:
|
||||
yield Header(show_clock=config_var.get()['interface']['global']['clock_on_header'])
|
||||
with ScrollableContainer(id="precache_container"):
|
||||
yield Label("[b]音频预缓存[/b]", classes="title-label")
|
||||
with Container():
|
||||
|
||||
@@ -17,6 +17,8 @@ from textual.widgets import (
|
||||
)
|
||||
from textual.lazy import Reveal, Lazy
|
||||
|
||||
from textual import events, on
|
||||
|
||||
import heurams.kernel.particles as pt
|
||||
import heurams.services.hasher as hasher
|
||||
from heurams.context import *
|
||||
@@ -34,7 +36,7 @@ class PreparationScreen(Screen):
|
||||
|
||||
BINDINGS = [
|
||||
("q", "go_back", "返回"),
|
||||
("p", "precache", "预缓存音频"),
|
||||
("p", "precache", "缓存"),
|
||||
("d", "toggle_dark", ""),
|
||||
("0,1,2,3", "app.push_screen('about')", ""),
|
||||
]
|
||||
@@ -46,8 +48,16 @@ class PreparationScreen(Screen):
|
||||
self.repo = repo
|
||||
self.load_data()
|
||||
|
||||
@on(events.ScreenResume)
|
||||
def post_active(self, event):
|
||||
from heurams.interface import shim
|
||||
|
||||
shim.set_term_title(f"{self.app.TITLE} - {self.SUB_TITLE}")
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Header(show_clock=True)
|
||||
|
||||
if config_var.get()['interface']['global']['show_header']:
|
||||
yield Header(show_clock=config_var.get()['interface']['global']['clock_on_header'])
|
||||
with ScrollableContainer(id="main_container"):
|
||||
yield Markdown(
|
||||
f"**准备就绪**: `{self.repo.manifest['title']}`\n", id="title"
|
||||
@@ -72,7 +82,7 @@ class PreparationScreen(Screen):
|
||||
classes="btn",
|
||||
),
|
||||
Button(
|
||||
"预缓存音频",
|
||||
"管理缓存",
|
||||
id="precache_button",
|
||||
variant="success",
|
||||
classes="btn",
|
||||
|
||||
@@ -23,6 +23,8 @@ from textual.widgets import (
|
||||
)
|
||||
from textual.layouts import horizontal
|
||||
|
||||
from textual import events, on
|
||||
|
||||
import heurams.kernel.particles as pt
|
||||
import heurams.services.timer as timer
|
||||
import heurams.services.version as version
|
||||
@@ -54,9 +56,16 @@ class SettingScreen(Screen):
|
||||
) -> None:
|
||||
super().__init__(name, id, classes)
|
||||
|
||||
@on(events.ScreenResume)
|
||||
def post_active(self, event):
|
||||
from heurams.interface import shim
|
||||
|
||||
shim.set_term_title(f"{self.app.TITLE} - {self.SUB_TITLE}")
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
"""组合界面组件"""
|
||||
yield Header(show_clock=True)
|
||||
if config_var.get()['interface']['global']['show_header']:
|
||||
yield Header(show_clock=config_var.get()['interface']['global']['clock_on_header'])
|
||||
with ScrollableContainer():
|
||||
yield Label("[b]设置页面[/b]")
|
||||
for i in config_var.get():
|
||||
@@ -65,7 +74,7 @@ class SettingScreen(Screen):
|
||||
a = self._get_subcfg(f"{i}")
|
||||
if a:
|
||||
yield Collapsible(
|
||||
*a, title=i + f'\n{config_var.get().get(f"_{i}_desc", "")}'
|
||||
*a, title=i + f'\n[d]{config_var.get().get(f"_{i}_desc", "")}[/d]'
|
||||
)
|
||||
yield Label(
|
||||
"退出页面时, 所作的更改会立即保存, 但仍建议重启软件以确保新的配置得到应用",
|
||||
@@ -85,7 +94,7 @@ class SettingScreen(Screen):
|
||||
if a:
|
||||
lst.append(
|
||||
Collapsible(
|
||||
*a, title=i + f'\n{parent.get(f"_{i}_desc", "")}'
|
||||
*a, title=i + f'\n[d]{parent.get(f"_{i}_desc", "")}[/d]'
|
||||
)
|
||||
)
|
||||
return lst
|
||||
@@ -101,17 +110,17 @@ class SettingScreen(Screen):
|
||||
if a:
|
||||
lst.append(
|
||||
Collapsible(
|
||||
*a, title=i + f'\n{parent.get(f"_{i}_desc", "")}'
|
||||
*a, title=i + f'\n[d]{parent.get(f"_{i}_desc", "")}[/d]'
|
||||
)
|
||||
)
|
||||
elif f"_{i}_candidate" in parent: # 选择框模式
|
||||
if isinstance(parent[f"_{i}_candidate"], dict):
|
||||
lst.append(
|
||||
Horizontal(
|
||||
Label(i + f'\n{parent.get(f"_{i}_desc", "")}'),
|
||||
Label(i + f'\n[d]{parent.get(f"_{i}_desc", "")}[/d]'),
|
||||
Select(
|
||||
(
|
||||
(f"{j} ({k})", j)
|
||||
(f"{j}\n[d]{k}[/d]", j)
|
||||
for j, k in parent[f"_{i}_candidate"].items()
|
||||
),
|
||||
prompt=f'{parent.get(f"{i}", "")}',
|
||||
@@ -122,7 +131,7 @@ class SettingScreen(Screen):
|
||||
elif isinstance(parent[f"_{i}_candidate"], list):
|
||||
lst.append(
|
||||
Horizontal(
|
||||
Label(i + f'\n{parent.get(f"_{i}_desc", "")}'),
|
||||
Label(i + f'\n[d]{parent.get(f"_{i}_desc", "")}[/d]'),
|
||||
Select(
|
||||
((j, j) for j in parent[f"_{i}_candidate"]),
|
||||
prompt=f'{parent.get(f"{i}", "")}',
|
||||
@@ -134,7 +143,7 @@ class SettingScreen(Screen):
|
||||
if isinstance(parent[i], float):
|
||||
lst.append(
|
||||
Horizontal(
|
||||
Label(i + f'\n{parent.get(f"_{i}_desc", "")}'),
|
||||
Label(i + f'\n[d]{parent.get(f"_{i}_desc", "")}[/d]'),
|
||||
Input(
|
||||
value=str(parent[i]),
|
||||
placeholder="要求一个浮点数",
|
||||
@@ -146,7 +155,7 @@ class SettingScreen(Screen):
|
||||
elif isinstance(parent[i], str):
|
||||
lst.append(
|
||||
Horizontal(
|
||||
Label(i + f'\n{parent.get(f"_{i}_desc", "")}'),
|
||||
Label(i + f'\n[d]{parent.get(f"_{i}_desc", "")}[/d]'),
|
||||
Input(
|
||||
value=parent[i],
|
||||
placeholder="要求一个字符串",
|
||||
@@ -158,7 +167,7 @@ class SettingScreen(Screen):
|
||||
elif isinstance(parent[i], bool):
|
||||
lst.append(
|
||||
Horizontal(
|
||||
Label(i + f'\n{parent.get(f"_{i}_desc", "")}'),
|
||||
Label(i + f'\n[d]{parent.get(f"_{i}_desc", "")}[/d]'),
|
||||
Switch(
|
||||
value=parent[i], id=domize(f"{parent_epath}.{i}")
|
||||
),
|
||||
@@ -167,7 +176,7 @@ class SettingScreen(Screen):
|
||||
elif isinstance(parent[i], int):
|
||||
lst.append(
|
||||
Horizontal(
|
||||
Label(i + f'\n{parent.get(f"_{i}_desc", "")}'),
|
||||
Label(i + f'\n[d]{parent.get(f"_{i}_desc", "")}[/d]'),
|
||||
Input(
|
||||
value=str(parent[i]),
|
||||
placeholder="要求一个整数",
|
||||
|
||||
@@ -9,6 +9,8 @@ from textual.screen import Screen
|
||||
from textual.widgets import Button, Footer, Header, Label, ProgressBar, Static
|
||||
from textual.worker import get_current_worker
|
||||
|
||||
from textual import events, on
|
||||
|
||||
import heurams.kernel.particles as pt
|
||||
import heurams.services.hasher as hasher
|
||||
from heurams.context import *
|
||||
@@ -26,8 +28,16 @@ class SyncScreen(Screen):
|
||||
self.log_messages = []
|
||||
self.max_log_lines = 50
|
||||
|
||||
@on(events.ScreenResume)
|
||||
def post_active(self, event):
|
||||
from heurams.interface import shim
|
||||
|
||||
shim.set_term_title(f"{self.app.TITLE} - {self.SUB_TITLE}")
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
yield Header(show_clock=True)
|
||||
|
||||
if config_var.get()['interface']['global']['show_header']:
|
||||
yield Header(show_clock=config_var.get()['interface']['global']['clock_on_header'])
|
||||
with ScrollableContainer(id="sync_container"):
|
||||
# 标题和连接状态
|
||||
yield Static("同步工具", classes="title")
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import heurams.interface.widgets as pzw
|
||||
import heurams.kernel.puzzles as pz
|
||||
import platform, os, sys
|
||||
from heurams.context import config_var
|
||||
|
||||
puzzle2widget = {
|
||||
pz.RecognitionPuzzle: pzw.Recognition,
|
||||
@@ -9,3 +11,13 @@ puzzle2widget = {
|
||||
pz.MCQPuzzle: pzw.MCQPuzzle,
|
||||
pz.BasePuzzle: pzw.BasePuzzleWidget,
|
||||
}
|
||||
|
||||
|
||||
def set_term_title(title):
|
||||
if not config_var.get()['interface']['global']['change_window_title']:
|
||||
return
|
||||
system = platform.system()
|
||||
if system == "Windows":
|
||||
os.system(f"title {title}")
|
||||
else: # Linux, Mac, etc.
|
||||
os.write(2, f"\033]2;{title}\007".encode("utf-8"))
|
||||
|
||||
Reference in New Issue
Block a user