ModUI: Update for Textual 0.54.0

This commit is contained in:
Mia Herkt 2024-03-30 17:30:33 +01:00
parent 8a912e8744
commit 3330a85c2c
No known key found for this signature in database
3 changed files with 56 additions and 53 deletions

16
mod.css
View file

@ -1,5 +1,6 @@
#ftable { #ftable {
width: 1fr; width: 1fr;
height: 100%;
} }
#infopane { #infopane {
@ -10,7 +11,7 @@
#finfo { #finfo {
background: $boost; background: $boost;
height: 12; height: 14;
width: 1fr; width: 1fr;
box-sizing: content-box; box-sizing: content-box;
} }
@ -27,20 +28,9 @@
width: 1fr; width: 1fr;
} }
#filter_container {
height: auto;
display: none;
}
#filter_label {
content-align: right middle;
height: 1fr;
width: 20%;
margin: 0 1 0 2;
}
#filter_input { #filter_input {
width: 1fr; width: 1fr;
display: none;
} }
Notification { Notification {

49
mod.py
View file

@ -5,7 +5,7 @@ from sys import stdout
import time import time
from textual.app import App, ComposeResult from textual.app import App, ComposeResult
from textual.widgets import DataTable, Header, Footer, TextLog, Static, Input from textual.widgets import DataTable, Header, Footer, RichLog, Static, Input
from textual.containers import Horizontal, Vertical from textual.containers import Horizontal, Vertical
from textual.screen import Screen from textual.screen import Screen
from textual import log from textual import log
@ -20,13 +20,13 @@ fhost_app.app_context().push()
class NullptrMod(Screen): class NullptrMod(Screen):
BINDINGS = [ BINDINGS = [
("q", "quit_app", "Quit"), ("q", "quit_app", "Quit"),
("f1", "filter(1, 'Lookup name:')", "Lookup name"), ("f1", "filter(1, 'Name')", "Lookup name"),
("f2", "filter(2, 'Filter IP address:')", "Filter IP"), ("f2", "filter(2, 'IP address')", "Filter IP"),
("f3", "filter(3, 'Filter MIME Type:')", "Filter MIME"), ("f3", "filter(3, 'MIME Type')", "Filter MIME"),
("f4", "filter(4, 'Filter extension:')", "Filter Ext."), ("f4", "filter(4, 'Extension')", "Filter Ext."),
("f5", "refresh", "Refresh"), ("f5", "refresh", "Refresh"),
("f6", "filter_clear", "Clear filter"), ("f6", "filter_clear", "Clear filter"),
("f7", "filter(5, 'Filter user agent:')", "Filter UA"), ("f7", "filter(5, 'User agent')", "Filter UA"),
("r", "remove_file(False)", "Remove file"), ("r", "remove_file(False)", "Remove file"),
("ctrl+r", "remove_file(True)", "Ban file"), ("ctrl+r", "remove_file(True)", "Ban file"),
("p", "ban_ip(False)", "Ban IP"), ("p", "ban_ip(False)", "Ban IP"),
@ -42,29 +42,28 @@ class NullptrMod(Screen):
ftable.watch_query(None, None) ftable.watch_query(None, None)
def action_filter_clear(self): def action_filter_clear(self):
self.query_one("#filter_container").display = False self.finput.display = False
ftable = self.query_one("#ftable") ftable = self.query_one("#ftable")
ftable.focus() ftable.focus()
ftable.query = ftable.base_query ftable.query = ftable.base_query
def action_filter(self, fcol: int, label: str): def action_filter(self, fcol: int, label: str):
self.query_one("#filter_label").update(label) self.finput.placeholder = label
finput = self.query_one("#filter_input") self.finput.display = True
self.finput.focus()
self.filter_col = fcol self.filter_col = fcol
self.query_one("#filter_container").display = True
finput.focus()
self._refresh_layout() self._refresh_layout()
if self.current_file: if self.current_file:
match fcol: match fcol:
case 1: finput.value = "" case 1: self.finput.value = ""
case 2: finput.value = self.current_file.addr case 2: self.finput.value = self.current_file.addr
case 3: finput.value = self.current_file.mime case 3: self.finput.value = self.current_file.mime
case 4: finput.value = self.current_file.ext case 4: self.finput.value = self.current_file.ext
case 5: finput.value = self.current_file.ua or "" case 5: self.finput.value = self.current_file.ua or ""
def on_input_submitted(self, message: Input.Submitted) -> None: def on_input_submitted(self, message: Input.Submitted) -> None:
self.query_one("#filter_container").display = False self.finput.display = False
ftable = self.query_one("#ftable") ftable = self.query_one("#ftable")
ftable.focus() ftable.focus()
@ -122,13 +121,13 @@ class NullptrMod(Screen):
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
yield Header() yield Header()
yield Horizontal( yield Horizontal(
FileTable(id="ftable", zebra_stripes=True), FileTable(id="ftable", zebra_stripes=True, cursor_type="row"),
Vertical( Vertical(
DataTable(id="finfo", show_header=False), DataTable(id="finfo", show_header=False, cursor_type="none"),
MpvWidget(id="mpv"), MpvWidget(id="mpv"),
TextLog(id="ftextlog"), RichLog(id="ftextlog", auto_scroll=False),
id="infopane")) id="infopane"))
yield Horizontal(Static("Filter:", id="filter_label"), Input(id="filter_input"), id="filter_container") yield Input(id="filter_input")
yield Footer() yield Footer()
def on_mount(self) -> None: def on_mount(self) -> None:
@ -143,6 +142,8 @@ class NullptrMod(Screen):
self.mpvw = self.query_one("#mpv") self.mpvw = self.query_one("#mpv")
self.ftlog = self.query_one("#ftextlog") self.ftlog = self.query_one("#ftextlog")
self.finput = self.query_one("#filter_input")
self.mimehandler = mime.MIMEHandler() self.mimehandler = mime.MIMEHandler()
self.mimehandler.register(mime.MIMECategory.Archive, self.handle_libarchive) self.mimehandler.register(mime.MIMECategory.Archive, self.handle_libarchive)
self.mimehandler.register(mime.MIMECategory.Text, self.handle_text) self.mimehandler.register(mime.MIMECategory.Text, self.handle_text)
@ -261,13 +262,11 @@ class NullptrMod(Screen):
]) ])
self.mpvw.stop_mpv(True) self.mpvw.stop_mpv(True)
self.ftlog.remove() self.ftlog.clear()
self.query_one("#infopane").mount(TextLog(id="ftextlog"))
self.ftlog = self.query_one("#ftextlog")
if f.getpath().is_file(): if f.getpath().is_file():
self.mimehandler.handle(f.mime, f.ext) self.mimehandler.handle(f.mime, f.ext)
self.ftlog.scroll_home(animate=False) self.ftlog.scroll_to(x=0, y=0, animate=False)
class NullptrModApp(App): class NullptrModApp(App):
CSS_PATH = "mod.css" CSS_PATH = "mod.css"

View file

@ -1,6 +1,6 @@
from textual.widgets import DataTable, Static from textual.widgets import DataTable, Static
from textual.reactive import Reactive from textual.reactive import Reactive
from textual.message import Message, MessageTarget from textual.message import Message
from textual import events, log from textual import events, log
from jinja2.filters import do_filesizeformat from jinja2.filters import do_filesizeformat
@ -21,9 +21,9 @@ class FileTable(DataTable):
self.query = self.base_query self.query = self.base_query
class Selected(Message): class Selected(Message):
def __init__(self, sender: MessageTarget, f: File) -> None: def __init__(self, f: File) -> None:
self.file = f self.file = f
super().__init__(sender) super().__init__()
def watch_order_col(self, old, value) -> None: def watch_order_col(self, old, value) -> None:
self.watch_query(None, None) self.watch_query(None, None)
@ -44,25 +44,39 @@ class FileTable(DataTable):
) )
if (self.query): if (self.query):
self.clear()
order = FileTable.colmap[self.order_col] order = FileTable.colmap[self.order_col]
q = self.query q = self.query
if order: q = q.order_by(order.desc() if self.order_desc else order, File.id) if order: q = q.order_by(order.desc() if self.order_desc else order, File.id)
self.add_rows(map(fmt_file, q.limit(self.limit))) qres = list(map(fmt_file, q.limit(self.limit)))
def _scroll_cursor_in_to_view(self, animate: bool = False) -> None: ri = 0
region = self._get_cell_region(self.cursor_row, 0) row = self.cursor_coordinate.row
spacing = self._get_cell_border() if row < self.row_count and row >= 0:
self.scroll_to_region(region, animate=animate, spacing=spacing) ri = int(self.get_row_at(row)[0])
async def watch_cursor_cell(self, old, value) -> None: self.clear()
super().watch_cursor_cell(old, value) self.add_rows(qres)
if value[0] < len(self.data) and value[0] >= 0:
f = File.query.get(int(self.data[value[0]][0])) for i, v in enumerate(qres):
await self.emit(self.Selected(self, f)) if int(v[0]) == ri:
self.move_cursor(row=i)
break
self.on_selected()
def on_selected(self) -> Selected:
row = self.cursor_coordinate.row
if row < self.row_count and row >= 0:
f = File.query.get(int(self.get_row_at(row)[0]))
self.post_message(self.Selected(f))
def watch_cursor_coordinate(self, old, value) -> None:
super().watch_cursor_coordinate(old, value)
if old != value:
self.on_selected()
def on_click(self, event: events.Click) -> None: def on_click(self, event: events.Click) -> None:
super().on_click(event)
meta = self.get_style_at(event.x, event.y).meta meta = self.get_style_at(event.x, event.y).meta
if meta: if meta:
if meta["row"] == -1: if meta["row"] == -1: