Module userland.scripts.messages.details_modal
Message details screen
Classes
class DetailsModal (*args,
reply_to: Message | None = None,
**kwargs)-
Expand source code
class DetailsModal(ModalScreen): """Message details screen""" CSS = """ DetailsModal { align: center middle; background: rgba(0, 0, 0, 0.5); } Label { margin-top: 1; width: 5 } Input { width: 53; } SelectionList { height: 10; } Button { margin-top: 1; width: 50%; } #save { margin-right: 1; margin-top: 1; } #wrapper { background: $primary-background; height: 20; padding: 1; width: 60; } """ reply_to: Message | None response: str def __init__(self, *args, reply_to: Message | None = None, **kwargs): super().__init__(*args, **kwargs) self.reply_to = reply_to def compose(self): yield Vertical( Horizontal( Label("Title", shrink=True), Input( ( f"Re: {self.reply_to.title.lstrip('Re: ')}" if self.reply_to else "" ), id="title", max_length=MAX_TITLE_LENGTH, validators=[ validation.Length( 1, failure_description="Title is required" ) ], validate_on=("changed", "submitted"), ), ), SelectionList(id="tags"), Horizontal( Button("Save", variant="success", name="save", id="save"), Button("Cancel", variant="error", name="cancel"), ), id="wrapper", ) async def on_mount(self) -> None: tags: SelectionList = self.get_widget_by_id("tags") # type: ignore async with db_session() as db: if not self.reply_to: my_tags = [] else: my_tags = ( await db.exec( select(MessageTags.tag_name).where( MessageTags.message_id == self.reply_to.id ) ) ).all() all_tags: Sequence[str] = ( # type: ignore await db.exec( select(MessageTag.name).where( and_( col(MessageTag.name).is_not(None), col(MessageTag.name).not_in(my_tags), ) ) ) ).all() tags.add_options([Selection(t, t, True) for t in my_tags]) tags.add_options([Selection(t, t, False) for t in all_tags]) async def submit(self) -> None: app: XthuluApp = self.app # type: ignore title: Input = self.get_widget_by_id("title") # type: ignore title_validator = title.validate(title.value) if title_validator and not title_validator.is_valid: return content = self.app._background_screens[-1].query_one(TextArea) tags: SelectionList = self.get_widget_by_id("tags") # type: ignore if len(tags.selected) == 0: return # create message async with db_session() as db: message = Message( author_id=app.context.user.id, title=title.value, content=content.text, parent_id=self.reply_to.id if self.reply_to else None, ) db.add(message) await db.commit() await db.refresh(message) assert message.id # link tags to message for t in tags.selected: async with db_session() as db: db.add(MessageTags(message_id=message.id, tag_name=t)) await db.commit() self.app.pop_screen() # pop this modal self.app.pop_screen() # pop the editor async def on_input_submitted(self, event: Input.Submitted) -> None: await self.submit() async def on_button_pressed(self, event: Button.Pressed) -> None: if event.button.name == "cancel": self.app.pop_screen() # pop this modal return await self.submit() async def key_escape(self, _): self.app.pop_screen() # pop this modalMessage details screen
Initialize the screen.
Args
name- The name of the screen.
id- The ID of the screen in the DOM.
classes- The CSS classes for the screen.
Ancestors
- textual.screen.ModalScreen
- textual.screen.Screen
- typing.Generic
- textual.widget.Widget
- textual.dom.DOMNode
- textual.message_pump.MessagePump
Class variables
var CSSvar can_focusvar can_focus_childrenvar reply_to : Message | Nonevar response : str
Methods
def compose(self)-
Expand source code
def compose(self): yield Vertical( Horizontal( Label("Title", shrink=True), Input( ( f"Re: {self.reply_to.title.lstrip('Re: ')}" if self.reply_to else "" ), id="title", max_length=MAX_TITLE_LENGTH, validators=[ validation.Length( 1, failure_description="Title is required" ) ], validate_on=("changed", "submitted"), ), ), SelectionList(id="tags"), Horizontal( Button("Save", variant="success", name="save", id="save"), Button("Cancel", variant="error", name="cancel"), ), id="wrapper", )Called by Textual to create child widgets.
This method is called when a widget is mounted or by setting
recompose=Truewhen calling [refresh()][textual.widget.Widget.refresh].Note that you don't typically need to explicitly call this method.
Example
def compose(self) -> ComposeResult: yield Header() yield Label("Press the button below:") yield Button() yield Footer() async def key_escape(self, _)-
Expand source code
async def key_escape(self, _): self.app.pop_screen() # pop this modal -
Expand source code
async def on_button_pressed(self, event: Button.Pressed) -> None: if event.button.name == "cancel": self.app.pop_screen() # pop this modal return await self.submit() async def on_input_submitted(self, event: textual.widgets._input.Input.Submitted) ‑> None-
Expand source code
async def on_input_submitted(self, event: Input.Submitted) -> None: await self.submit() async def on_mount(self) ‑> None-
Expand source code
async def on_mount(self) -> None: tags: SelectionList = self.get_widget_by_id("tags") # type: ignore async with db_session() as db: if not self.reply_to: my_tags = [] else: my_tags = ( await db.exec( select(MessageTags.tag_name).where( MessageTags.message_id == self.reply_to.id ) ) ).all() all_tags: Sequence[str] = ( # type: ignore await db.exec( select(MessageTag.name).where( and_( col(MessageTag.name).is_not(None), col(MessageTag.name).not_in(my_tags), ) ) ) ).all() tags.add_options([Selection(t, t, True) for t in my_tags]) tags.add_options([Selection(t, t, False) for t in all_tags]) async def submit(self) ‑> None-
Expand source code
async def submit(self) -> None: app: XthuluApp = self.app # type: ignore title: Input = self.get_widget_by_id("title") # type: ignore title_validator = title.validate(title.value) if title_validator and not title_validator.is_valid: return content = self.app._background_screens[-1].query_one(TextArea) tags: SelectionList = self.get_widget_by_id("tags") # type: ignore if len(tags.selected) == 0: return # create message async with db_session() as db: message = Message( author_id=app.context.user.id, title=title.value, content=content.text, parent_id=self.reply_to.id if self.reply_to else None, ) db.add(message) await db.commit() await db.refresh(message) assert message.id # link tags to message for t in tags.selected: async with db_session() as db: db.add(MessageTags(message_id=message.id, tag_name=t)) await db.commit() self.app.pop_screen() # pop this modal self.app.pop_screen() # pop the editor