Plugin loader (mirrors Rust #29): - plugins_store.py walks %APPDATA%\com.priler.jarvis\plugins\<name>\ for commands.yaml fragments and merges them into VA_CMD_LIST at startup. Same schema as the project root commands.yaml. Per-pack `disabled` flag file skips a pack without deletion. Built-in ids win conflicts so a malicious pack can't silently override open_browser. 9 unit tests (parity with the Rust tests). - main.py: plugin merge runs after the root yaml load; logs the number of extra commands picked up. Flet GUI (#27 — first parity with the Rust Tauri GUI): - New gui/ package: __main__.py launches via `python -m gui` (or gui.bat). app.py routes between 7 pages (Главная / Команды / Макросы / Расписание / Память / Плагины / Настройки) via NavigationRail; dark theme matching the Tauri look. - gui/services.py centralises every store-module call the pages share — single place to swap implementations later. - One file per page in gui/pages/, all expose `build(page)` and use the same card layout idiom. Pages mirror the Tauri ones feature- for-feature: home (status + counters + launcher), commands (filterable list of all VA_CMD_LIST entries), macros (list + delete + recording banner), scheduler (list + remove), memory (add/forget/search), plugins (toggle/open folder), settings (profile + LLM hot-swap). - requirements.txt: flet>=0.85 (optional; assistant runs without). - 3 smoke tests verify imports + build callables; skip cleanly when Flet isn't installed. README: documents both the GUI and the plugin layout in user-facing terms. Tests: 42 → 54 (+9 plugins +3 GUI smoke).
81 lines
2.6 KiB
Python
81 lines
2.6 KiB
Python
"""Flet GUI router and shell.
|
||
|
||
Provides:
|
||
- Top navigation bar with the 6 pages (Главная / Команды / Макросы / Расписание / Память / Плагины / Настройки)
|
||
- Page swap on click, no full reload
|
||
- Dark theme matching the Tauri GUI vibe
|
||
|
||
Each page lives in `gui/pages/<name>.py` and exposes `build(page) -> Control`.
|
||
"""
|
||
|
||
import flet as ft
|
||
|
||
from gui.pages import home, commands, macros, scheduler, memory, plugins, settings
|
||
|
||
|
||
PAGES = [
|
||
("Главная", home.build),
|
||
("Команды", commands.build),
|
||
("Макросы", macros.build),
|
||
("Расписание", scheduler.build),
|
||
("Память", memory.build),
|
||
("Плагины", plugins.build),
|
||
("Настройки", settings.build),
|
||
]
|
||
|
||
|
||
def _make_app(page: ft.Page):
|
||
page.title = "J.A.R.V.I.S. — Python GUI"
|
||
page.theme_mode = ft.ThemeMode.DARK
|
||
page.window.width = 940
|
||
page.window.height = 720
|
||
page.padding = 0
|
||
page.bgcolor = "#0a1419"
|
||
|
||
content_holder = ft.Container(expand=True, padding=20)
|
||
|
||
def go(idx: int):
|
||
nav.selected_index = idx
|
||
title, builder = PAGES[idx]
|
||
try:
|
||
content_holder.content = builder(page)
|
||
except (RuntimeError, ValueError, OSError) as exc:
|
||
content_holder.content = ft.Text(
|
||
f"Не удалось открыть «{title}»:\n{exc}",
|
||
color="red",
|
||
)
|
||
page.update()
|
||
|
||
nav = ft.NavigationRail(
|
||
selected_index=0,
|
||
label_type=ft.NavigationRailLabelType.ALL,
|
||
min_width=80,
|
||
min_extended_width=180,
|
||
bgcolor="#0d1b21",
|
||
destinations=[
|
||
ft.NavigationRailDestination(icon=ft.Icons.HOME, label="Главная"),
|
||
ft.NavigationRailDestination(icon=ft.Icons.LIST_ALT, label="Команды"),
|
||
ft.NavigationRailDestination(icon=ft.Icons.PLAY_CIRCLE_OUTLINE, label="Макросы"),
|
||
ft.NavigationRailDestination(icon=ft.Icons.SCHEDULE, label="Расписание"),
|
||
ft.NavigationRailDestination(icon=ft.Icons.MEMORY, label="Память"),
|
||
ft.NavigationRailDestination(icon=ft.Icons.EXTENSION, label="Плагины"),
|
||
ft.NavigationRailDestination(icon=ft.Icons.SETTINGS, label="Настройки"),
|
||
],
|
||
on_change=lambda e: go(int(e.control.selected_index)),
|
||
)
|
||
|
||
layout = ft.Row(
|
||
controls=[
|
||
nav,
|
||
ft.VerticalDivider(width=1, color="#1f3540"),
|
||
content_holder,
|
||
],
|
||
expand=True,
|
||
)
|
||
|
||
page.add(layout)
|
||
go(0)
|
||
|
||
|
||
def run():
|
||
ft.app(target=_make_app)
|