Retro Bulletin Board Systems on atproto. Web app and TUI. lazy mirror of alyraffauf/atbbs atbbs.xyz
forums python tui atproto bbs
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

tui: improve quote handling/compose screen

+36 -11
+3 -1
tui/screens/activity.py
··· 100 100 session = self.app.user_session 101 101 if not session: 102 102 try: 103 - self.query_one("#activity-loading").update("Log in to see your messages.") 103 + self.query_one("#activity-loading").update( 104 + "Log in to see your messages." 105 + ) 104 106 except Exception: 105 107 pass 106 108 return
+30 -9
tui/screens/compose.py
··· 38 38 39 39 40 40 class ComposeThreadScreen(Screen): 41 - BINDINGS = [("escape", "app.pop_screen", "back")] 41 + BINDINGS = [ 42 + ("escape", "app.pop_screen", "back"), 43 + ("ctrl+s", "post", "post"), 44 + ] 42 45 43 46 def __init__(self, bbs, handle: str, board) -> None: 44 47 super().__init__() ··· 60 63 yield Input(placeholder="Thread title", id="thread-title") 61 64 yield TextArea(id="thread-body", language=None) 62 65 yield Input(placeholder="attach file (path, optional)", id="thread-file") 63 - yield Static("ctrl+s to post", classes="subtitle") 64 66 yield Footer() 65 67 66 68 def on_mount(self) -> None: 67 69 self.query_one("#thread-title", Input).focus() 68 70 69 - def key_ctrl_s(self) -> None: 71 + def action_post(self) -> None: 70 72 self.post_thread() 71 73 72 74 @work(exclusive=True) ··· 109 111 110 112 111 113 class ComposeReplyScreen(Screen): 112 - BINDINGS = [("escape", "app.pop_screen", "back")] 114 + BINDINGS = [ 115 + ("escape", "app.pop_screen", "back"), 116 + ("ctrl+s", "post", "post"), 117 + ("ctrl+g", "toggle_quote", "toggle quote"), 118 + ] 113 119 114 120 def __init__(self, bbs, handle: str, thread, quote=None) -> None: 115 121 super().__init__() 116 122 self.bbs = bbs 117 123 self.handle = handle 124 + self._original_quote = quote 118 125 self.quote = quote # Reply object or None 119 126 self.thread = thread 120 127 ··· 134 141 "..." if len(self.quote.body) > 60 else "" 135 142 ) 136 143 yield Static( 137 - f"quoting {self.quote.author.handle}: {body_preview} [clear: ctrl+g]", 144 + f"quoting {self.quote.author.handle}: {body_preview}", 138 145 classes="subtitle", 139 146 id="quote-info", 140 147 ) 141 148 yield TextArea(id="reply-body", language=None) 142 149 yield Input(placeholder="attach file (path, optional)", id="reply-file") 143 - yield Static("ctrl+s to post", classes="subtitle") 144 150 yield Footer() 145 151 146 152 def on_mount(self) -> None: 147 153 self.query_one("#reply-body", TextArea).focus() 148 154 149 - def key_ctrl_g(self) -> None: 155 + def action_toggle_quote(self) -> None: 156 + if not self._original_quote: 157 + return 150 158 if self.quote: 151 159 self.quote = None 152 160 try: 153 161 self.query_one("#quote-info").remove() 154 162 except Exception: 155 163 pass 156 - self.notify("Quote cleared.") 164 + else: 165 + self.quote = self._original_quote 166 + body_preview = self.quote.body[:60] + ( 167 + "..." if len(self.quote.body) > 60 else "" 168 + ) 169 + scroll = self.query_one(Vertical) 170 + scroll.mount( 171 + Static( 172 + f"quoting {self.quote.author.handle}: {body_preview}", 173 + classes="subtitle", 174 + id="quote-info", 175 + ), 176 + before=self.query_one("#reply-body"), 177 + ) 157 178 158 - def key_ctrl_s(self) -> None: 179 + def action_post(self) -> None: 159 180 self.post_reply() 160 181 161 182 @work(exclusive=True)
+3 -1
tui/screens/home.py
··· 35 35 yield Static("") 36 36 yield Static("Dial a BBS", classes="title") 37 37 yield Input(placeholder="handle.example.com", id="handle-input") 38 - yield Static("OR TRY ONE OF THESE", id="discover-label", classes="section-label") 38 + yield Static( 39 + "OR TRY ONE OF THESE", id="discover-label", classes="section-label" 40 + ) 39 41 yield ListView(id="discover-list") 40 42 yield Footer() 41 43