Render status details

This commit is contained in:
Ivan Habunek 2019-08-24 12:53:55 +02:00
parent ea1ef6f207
commit c99999161d
No known key found for this signature in database
GPG Key ID: CDBD63C43A30BB95
4 changed files with 90 additions and 39 deletions

View File

@ -3,7 +3,7 @@ import urwid
from concurrent.futures import ThreadPoolExecutor
from toot.api import home_timeline_generator
from toot import api
from .constants import PALETTE
from .entities import Status
@ -48,12 +48,14 @@ class Footer(urwid.Pile):
def set_status(self, text):
self.status.set_text(text)
def clear_status(self, text):
self.status.set_text(urwid.Text())
def set_message(self, text):
self.message.set_text(text)
def set_error(self, text):
# TODO: change to red
self.message.set_text(text)
def clear_message(self):
self.message.set_text(urwid.Text())
class TUI(urwid.Frame):
@ -80,7 +82,8 @@ class TUI(urwid.Frame):
self.loop = None # set in `create`
self.executor = ThreadPoolExecutor(max_workers=1)
self.timeline_generator = home_timeline_generator(app, user, 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)
@ -104,10 +107,23 @@ class TUI(urwid.Frame):
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)
return [Status(s, self.app.instance) for s in data]
def toots_loaded(self, future):
self.body = Timeline(self, future.result())
urwid.connect_signal(self.body, "status_focused",
lambda _, args: self.status_focused(*args))
self.body.status_focused() # Draw first status
def status_focused(self, status, index, count):
self.footer.set_status([
("footer_status_bold", "[home] "), status.id,
" - status ", str(index + 1), " of ", str(count),
])
def unhandled_input(self, key):
if key in ('q', 'Q'):

View File

@ -6,8 +6,12 @@ PALETTE = [
# Footer
('footer_status', 'white', 'dark blue'),
('footer_status_bold', 'white, bold', 'dark blue'),
('footer_message', 'dark green', ''),
# Functional
('link', ',italics', ''),
# by color name
('blue', 'light blue', ''),
('blue_bold', 'light blue, bold', ''),

View File

@ -17,9 +17,13 @@ class Status:
self.instance = instance
self.id = self.data["id"]
self.display_name = self.data["account"]["display_name"]
self.account = self.get_account()
self.created_at = parse_datetime(data["created_at"])
self.favourited = data.get("favourited", False)
self.reblogged = data.get("reblogged", False)
def get_account(self):
acct = self.data['account']['acct']
return acct if "@" in acct else "{}@{}".format(acct, self.instance)

View File

@ -1,6 +1,8 @@
import logging
import urwid
from toot.utils import format_content
from .widgets import SelectableText, SelectableColumns
logger = logging.getLogger("toot")
@ -11,9 +13,12 @@ class Timeline(urwid.Columns):
Displays a list of statuses to the left, and status details on the right.
TODO: Switch to top/bottom for narrow views.
TODO: Cache rendered statuses?
"""
signals = ["status_focused"]
signals = [
"status_focused",
"status_activated",
]
def __init__(self, tui, statuses):
self.tui = tui
@ -21,10 +26,7 @@ class Timeline(urwid.Columns):
self.instance = tui.app.instance
self.status_list = self.build_status_list(statuses)
self.status_details = self.build_status_details(statuses[0], self.instance)
# TODO:
# self.status_cache = {}
self.status_details = self.build_status_details(statuses[0])
super().__init__([
("weight", 50, self.status_list),
@ -32,31 +34,13 @@ class Timeline(urwid.Columns):
], dividechars=1)
def build_status_list(self, statuses):
items = [self.list_item(status) for status in statuses]
items = [self.build_list_item(status) for status in statuses]
walker = urwid.SimpleFocusListWalker(items)
urwid.connect_signal(walker, "modified", self.status_focused)
return urwid.ListBox(walker)
def build_status_details(self, status, instance):
details = StatusDetails(status, instance)
return urwid.Filler(details, valign="top")
def get_focused_status(self):
return self.statuses[self.status_list.body.focus]
def status_activated(self, *args):
"""Called when a status is clicked, or Enter is pressed."""
# logger.info("status_activated " + str(args))
def status_focused(self):
"""Called when the list focus switches to a new status"""
status = self.get_focused_status()
details = StatusDetails(status, self.instance)
self.status_details.set_body(details)
self._emit("status_focused", [status])
def list_item(self, status):
item = StatusListItem(status, self.instance)
def build_list_item(self, status):
item = StatusListItem(status)
urwid.connect_signal(item, "click", self.status_activated)
return urwid.AttrMap(item, None, focus_map={
"blue": "green_selected",
@ -65,20 +49,62 @@ class Timeline(urwid.Columns):
None: "green_selected",
})
def build_status_details(self, status):
details = StatusDetails(status)
return urwid.Filler(details, valign="top")
def get_focused_status(self):
return self.statuses[self.status_list.body.focus]
def status_activated(self, *args):
"""Called when a status is clicked, or Enter is pressed."""
self._emit("status_activated", [status])
def status_focused(self):
"""Called when the list focus switches to a new status"""
status = self.get_focused_status()
details = StatusDetails(status)
self.status_details.set_body(details)
index = self.status_list.body.focus
count = len(self.statuses)
self._emit("status_focused", [status, index, count])
class StatusDetails(urwid.Pile):
def __init__(self, status, instance):
return super().__init__([
urwid.Text(status.id)
])
def __init__(self, status):
widget_list = list(self.content_generator(status))
return super().__init__(widget_list)
def content_generator(self, status):
if status.display_name:
yield urwid.Text(("green", status.display_name))
yield urwid.Text(("yellow", status.account))
yield urwid.Divider()
for line in format_content(status.data["content"]):
yield urwid.Text(line)
if status.data["card"]:
yield urwid.Divider()
yield self.build_card(status.data["card"])
def card_generator(self, card):
yield urwid.Text(("green", card["title"].strip()))
if card["author_name"]:
yield urwid.Text(["by ", ("yellow", card["author_name"].strip())])
yield urwid.Text(("link", card["url"]))
def build_card(self, card):
contents = list(self.card_generator(card))
return urwid.LineBox(urwid.Pile(contents))
class StatusListItem(SelectableColumns):
def __init__(self, status, instance):
def __init__(self, status):
created_at = status.created_at.strftime("%Y-%m-%d %H:%M")
favourited = ("yellow", "") if status.data["favourited"] else " "
reblogged = ("yellow", "") if status.data["reblogged"] else " "
favourited = ("yellow", "") if status.favourited else " "
reblogged = ("yellow", "") if status.reblogged else " "
return super().__init__([
("pack", SelectableText(("blue", created_at), wrap="clip")),
@ -86,5 +112,6 @@ class StatusListItem(SelectableColumns):
urwid.Text(("green", status.account), wrap="clip"),
("pack", urwid.Text(" ")),
("pack", urwid.Text(favourited)),
("pack", urwid.Text(" ")),
("pack", urwid.Text(reblogged)),
])