mirror of
https://github.com/ihabunek/toot.git
synced 2024-09-29 04:35:54 -04:00
Render status details
This commit is contained in:
parent
ea1ef6f207
commit
c99999161d
@ -3,7 +3,7 @@ import urwid
|
|||||||
|
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
|
||||||
from toot.api import home_timeline_generator
|
from toot import api
|
||||||
|
|
||||||
from .constants import PALETTE
|
from .constants import PALETTE
|
||||||
from .entities import Status
|
from .entities import Status
|
||||||
@ -48,12 +48,14 @@ class Footer(urwid.Pile):
|
|||||||
def set_status(self, text):
|
def set_status(self, text):
|
||||||
self.status.set_text(text)
|
self.status.set_text(text)
|
||||||
|
|
||||||
|
def clear_status(self, text):
|
||||||
|
self.status.set_text(urwid.Text())
|
||||||
|
|
||||||
def set_message(self, text):
|
def set_message(self, text):
|
||||||
self.message.set_text(text)
|
self.message.set_text(text)
|
||||||
|
|
||||||
def set_error(self, text):
|
def clear_message(self):
|
||||||
# TODO: change to red
|
self.message.set_text(urwid.Text())
|
||||||
self.message.set_text(text)
|
|
||||||
|
|
||||||
|
|
||||||
class TUI(urwid.Frame):
|
class TUI(urwid.Frame):
|
||||||
@ -80,7 +82,8 @@ class TUI(urwid.Frame):
|
|||||||
|
|
||||||
self.loop = None # set in `create`
|
self.loop = None # set in `create`
|
||||||
self.executor = ThreadPoolExecutor(max_workers=1)
|
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.body = urwid.Filler(urwid.Text("Loading toots...", align="center"))
|
||||||
self.header = Header(app, user)
|
self.header = Header(app, user)
|
||||||
@ -104,10 +107,23 @@ class TUI(urwid.Frame):
|
|||||||
|
|
||||||
def load_toots(self):
|
def load_toots(self):
|
||||||
data = next(self.timeline_generator)
|
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]
|
return [Status(s, self.app.instance) for s in data]
|
||||||
|
|
||||||
def toots_loaded(self, future):
|
def toots_loaded(self, future):
|
||||||
self.body = Timeline(self, future.result())
|
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):
|
def unhandled_input(self, key):
|
||||||
if key in ('q', 'Q'):
|
if key in ('q', 'Q'):
|
||||||
|
@ -6,8 +6,12 @@ PALETTE = [
|
|||||||
|
|
||||||
# Footer
|
# Footer
|
||||||
('footer_status', 'white', 'dark blue'),
|
('footer_status', 'white', 'dark blue'),
|
||||||
|
('footer_status_bold', 'white, bold', 'dark blue'),
|
||||||
('footer_message', 'dark green', ''),
|
('footer_message', 'dark green', ''),
|
||||||
|
|
||||||
|
# Functional
|
||||||
|
('link', ',italics', ''),
|
||||||
|
|
||||||
# by color name
|
# by color name
|
||||||
('blue', 'light blue', ''),
|
('blue', 'light blue', ''),
|
||||||
('blue_bold', 'light blue, bold', ''),
|
('blue_bold', 'light blue, bold', ''),
|
||||||
|
@ -17,9 +17,13 @@ class Status:
|
|||||||
self.instance = instance
|
self.instance = instance
|
||||||
|
|
||||||
self.id = self.data["id"]
|
self.id = self.data["id"]
|
||||||
|
self.display_name = self.data["account"]["display_name"]
|
||||||
self.account = self.get_account()
|
self.account = self.get_account()
|
||||||
self.created_at = parse_datetime(data["created_at"])
|
self.created_at = parse_datetime(data["created_at"])
|
||||||
|
|
||||||
|
self.favourited = data.get("favourited", False)
|
||||||
|
self.reblogged = data.get("reblogged", False)
|
||||||
|
|
||||||
def get_account(self):
|
def get_account(self):
|
||||||
acct = self.data['account']['acct']
|
acct = self.data['account']['acct']
|
||||||
return acct if "@" in acct else "{}@{}".format(acct, self.instance)
|
return acct if "@" in acct else "{}@{}".format(acct, self.instance)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
import urwid
|
import urwid
|
||||||
|
|
||||||
|
from toot.utils import format_content
|
||||||
|
|
||||||
from .widgets import SelectableText, SelectableColumns
|
from .widgets import SelectableText, SelectableColumns
|
||||||
|
|
||||||
logger = logging.getLogger("toot")
|
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.
|
Displays a list of statuses to the left, and status details on the right.
|
||||||
|
|
||||||
TODO: Switch to top/bottom for narrow views.
|
TODO: Switch to top/bottom for narrow views.
|
||||||
|
TODO: Cache rendered statuses?
|
||||||
"""
|
"""
|
||||||
|
signals = [
|
||||||
signals = ["status_focused"]
|
"status_focused",
|
||||||
|
"status_activated",
|
||||||
|
]
|
||||||
|
|
||||||
def __init__(self, tui, statuses):
|
def __init__(self, tui, statuses):
|
||||||
self.tui = tui
|
self.tui = tui
|
||||||
@ -21,10 +26,7 @@ class Timeline(urwid.Columns):
|
|||||||
self.instance = tui.app.instance
|
self.instance = tui.app.instance
|
||||||
|
|
||||||
self.status_list = self.build_status_list(statuses)
|
self.status_list = self.build_status_list(statuses)
|
||||||
self.status_details = self.build_status_details(statuses[0], self.instance)
|
self.status_details = self.build_status_details(statuses[0])
|
||||||
|
|
||||||
# TODO:
|
|
||||||
# self.status_cache = {}
|
|
||||||
|
|
||||||
super().__init__([
|
super().__init__([
|
||||||
("weight", 50, self.status_list),
|
("weight", 50, self.status_list),
|
||||||
@ -32,31 +34,13 @@ class Timeline(urwid.Columns):
|
|||||||
], dividechars=1)
|
], dividechars=1)
|
||||||
|
|
||||||
def build_status_list(self, statuses):
|
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)
|
walker = urwid.SimpleFocusListWalker(items)
|
||||||
urwid.connect_signal(walker, "modified", self.status_focused)
|
urwid.connect_signal(walker, "modified", self.status_focused)
|
||||||
return urwid.ListBox(walker)
|
return urwid.ListBox(walker)
|
||||||
|
|
||||||
def build_status_details(self, status, instance):
|
def build_list_item(self, status):
|
||||||
details = StatusDetails(status, instance)
|
item = StatusListItem(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."""
|
|
||||||
# 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)
|
|
||||||
urwid.connect_signal(item, "click", self.status_activated)
|
urwid.connect_signal(item, "click", self.status_activated)
|
||||||
return urwid.AttrMap(item, None, focus_map={
|
return urwid.AttrMap(item, None, focus_map={
|
||||||
"blue": "green_selected",
|
"blue": "green_selected",
|
||||||
@ -65,20 +49,62 @@ class Timeline(urwid.Columns):
|
|||||||
None: "green_selected",
|
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):
|
class StatusDetails(urwid.Pile):
|
||||||
def __init__(self, status, instance):
|
def __init__(self, status):
|
||||||
return super().__init__([
|
widget_list = list(self.content_generator(status))
|
||||||
urwid.Text(status.id)
|
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):
|
class StatusListItem(SelectableColumns):
|
||||||
def __init__(self, status, instance):
|
def __init__(self, status):
|
||||||
created_at = status.created_at.strftime("%Y-%m-%d %H:%M")
|
created_at = status.created_at.strftime("%Y-%m-%d %H:%M")
|
||||||
favourited = ("yellow", "★") if status.data["favourited"] else " "
|
favourited = ("yellow", "★") if status.favourited else " "
|
||||||
reblogged = ("yellow", "⤶") if status.data["reblogged"] else " "
|
reblogged = ("yellow", "⤶") if status.reblogged else " "
|
||||||
|
|
||||||
return super().__init__([
|
return super().__init__([
|
||||||
("pack", SelectableText(("blue", created_at), wrap="clip")),
|
("pack", SelectableText(("blue", created_at), wrap="clip")),
|
||||||
@ -86,5 +112,6 @@ class StatusListItem(SelectableColumns):
|
|||||||
urwid.Text(("green", status.account), wrap="clip"),
|
urwid.Text(("green", status.account), wrap="clip"),
|
||||||
("pack", urwid.Text(" ")),
|
("pack", urwid.Text(" ")),
|
||||||
("pack", urwid.Text(favourited)),
|
("pack", urwid.Text(favourited)),
|
||||||
|
("pack", urwid.Text(" ")),
|
||||||
("pack", urwid.Text(reblogged)),
|
("pack", urwid.Text(reblogged)),
|
||||||
])
|
])
|
||||||
|
Loading…
Reference in New Issue
Block a user