"""Macros page — list macros, show steps, delete. Recording is voice-only.""" import flet as ft from gui import services as svc def build(page: ft.Page) -> ft.Control: list_view = ft.Column(spacing=8, expand=True, scroll=ft.ScrollMode.AUTO) def render(): list_view.controls.clear() macros = svc.macros_all() rec_on, rec_name = svc.macros_recording() if rec_on: list_view.controls.append(_recording_banner(rec_name)) if not macros: list_view.controls.append( ft.Text( "Макросов пока нет. Запиши голосом: «Запиши макрос работа», " "потом скажи команды, потом «Сохрани макрос».", color="#8aa0a8", ) ) for m in sorted(macros, key=lambda x: x["name"]): list_view.controls.append(_macro_card(m, on_delete=lambda n=m["name"]: do_delete(n))) page.update() def do_delete(name: str) -> None: if svc.macros_delete(name): page.open(ft.SnackBar(content=ft.Text(f"Удалил «{name}»", color="white"), bgcolor="#33d3a4")) render() render() return ft.Column( [ ft.Row([ ft.Text("Макросы", size=24, weight=ft.FontWeight.W_700), ft.FilledButton(text="Обновить", icon=ft.Icons.REFRESH, on_click=lambda e: render()), ], alignment=ft.MainAxisAlignment.SPACE_BETWEEN), list_view, ], expand=True, spacing=10, ) def _recording_banner(name: str | None) -> ft.Control: return ft.Container( content=ft.Row([ ft.Icon(ft.Icons.FIBER_MANUAL_RECORD, color="#ff5757"), ft.Text( f"Идёт запись макроса «{name or '—'}». " "Произнесите команды, затем «Сохрани макрос».", ), ]), bgcolor="#3a2020", border_radius=8, padding=10, ) def _macro_card(m: dict, on_delete) -> ft.Control: steps = m.get("steps", []) preview = steps[:5] extra = len(steps) - len(preview) return ft.Container( content=ft.Column([ ft.Row([ ft.Text(m["name"], weight=ft.FontWeight.W_600, size=14), ft.Container( content=ft.Text(f"{m['steps_count']} шагов", size=10), bgcolor="#1e3a44", padding=ft.padding.symmetric(horizontal=8, vertical=2), border_radius=10, ), ], alignment=ft.MainAxisAlignment.SPACE_BETWEEN), ft.Column([ ft.Text(f"• {s}", size=11, color="#a8b8c0") for s in preview ] + ([ft.Text(f"+ ещё {extra}…", size=11, color="#5a6a72", italic=True)] if extra > 0 else []), spacing=2), ft.Row([ ft.OutlinedButton(text="Удалить", icon=ft.Icons.DELETE, on_click=lambda e: on_delete()), ]), ], spacing=8), bgcolor="#15252b", border_radius=8, padding=12, )