diff --git a/toot/tui/app.py b/toot/tui/app.py index 763ba2a..1796787 100644 --- a/toot/tui/app.py +++ b/toot/tui/app.py @@ -49,13 +49,13 @@ class Footer(urwid.Pile): self.status.set_text(text) def clear_status(self, text): - self.status.set_text(urwid.Text()) + self.status.set_text("") def set_message(self, text): self.message.set_text(text) def clear_message(self): - self.message.set_text(urwid.Text()) + self.message.set_text("") class TUI(urwid.Frame): @@ -82,8 +82,8 @@ class TUI(urwid.Frame): self.loop = None # set in `create` self.executor = ThreadPoolExecutor(max_workers=1) - # self.timeline_generator = api.home_timeline_generator(app, user, limit=40) - self.timeline_generator = api.public_timeline_generator(app.instance, local=False, limit=40) + self.timeline_generator = api.home_timeline_generator(app, user, limit=40) + # self.timeline_generator = api.public_timeline_generator(app.instance, local=False, limit=40) self.body = urwid.Filler(urwid.Text("Loading toots...", align="center")) self.header = Header(app, user) @@ -93,32 +93,50 @@ class TUI(urwid.Frame): super().__init__(self.body, header=self.header, footer=self.footer) def run(self): - self.loop.set_alarm_in(0, self.schedule_loading_toots) + self.loop.set_alarm_in(0, self.schedule_load_statuses) self.loop.run() self.executor.shutdown(wait=False) def run_in_thread(self, fn, args=[], kwargs={}, done_callback=None): - future = self.executor.submit(self.load_toots) + future = self.executor.submit(fn) if done_callback: future.add_done_callback(done_callback) - def schedule_loading_toots(self, *args): - self.run_in_thread(self.load_toots, done_callback=self.toots_loaded) + def schedule_load_statuses(self, *args): + self.run_in_thread(self.load_statuses, done_callback=self.statuses_loaded_initial) - def load_toots(self): - data = next(self.timeline_generator) - with open("tmp/statuses2.json", "w") as f: - import json - json.dump(data, f, indent=4) + def load_statuses(self): + self.footer.set_message("Loading statuses...") + try: + data = next(self.timeline_generator) + except StopIteration: + return [] + finally: + self.footer.clear_message() + + # with open("tmp/statuses2.json", "w") as f: + # import json + # json.dump(data, f, indent=4) return [Status(s, self.app.instance) for s in data] - def toots_loaded(self, future): + def schedule_load_next(self): + self.run_in_thread(self.load_statuses, done_callback=self.statuses_loaded_next) + + def statuses_loaded_initial(self, future): + # TODO: handle errors in future self.body = Timeline(self, future.result()) + urwid.connect_signal(self.body, "status_focused", lambda _, args: self.status_focused(*args)) + urwid.connect_signal(self.body, "next", + lambda *args: self.schedule_load_next()) self.body.status_focused() # Draw first status + def statuses_loaded_next(self, future): + # TODO: handle errors in future + self.body.add_statuses(future.result()) + def status_focused(self, status, index, count): self.footer.set_status([ ("footer_status_bold", "[home] "), status.id, diff --git a/toot/tui/timeline.py b/toot/tui/timeline.py index c4d9553..4e34a23 100644 --- a/toot/tui/timeline.py +++ b/toot/tui/timeline.py @@ -1,5 +1,6 @@ import logging import urwid +import webbrowser from toot.utils import format_content @@ -18,6 +19,7 @@ class Timeline(urwid.Columns): signals = [ "status_focused", "status_activated", + "next", ] def __init__(self, tui, statuses): @@ -70,6 +72,28 @@ class Timeline(urwid.Columns): count = len(self.statuses) self._emit("status_focused", [status, index, count]) + def keypress(self, size, key): + # If down is pressed on last status in list emit a signal to load more. + # TODO: Consider pre-loading statuses earlier + command = self._command_map[key] + if command in [urwid.CURSOR_DOWN, urwid.CURSOR_PAGE_DOWN]: + index = self.status_list.body.focus + 1 + count = len(self.statuses) + if index >= count: + self._emit("next") + + if key in ("v", "V"): + status = self.get_focused_status() + webbrowser.open(status.data["url"]) + return + + return super().keypress(size, key) + + def add_statuses(self, statuses): + self.statuses += statuses + new_items = [self.build_list_item(status) for status in statuses] + self.status_list.body.extend(new_items) + class StatusDetails(urwid.Pile): def __init__(self, status):