From 99060d221b40b1f68d9aa9712ba5927900b188c8 Mon Sep 17 00:00:00 2001 From: Dan Schwarz Date: Mon, 2 Jan 2023 22:55:16 -0500 Subject: [PATCH] Basic support for followed accounts in TUI In the status detail window, followed accounts are shown in yellow, while unfollowed accounts are shown in grey. --- toot/commands.py | 20 ++++++++++---------- toot/tui/app.py | 22 ++++++++++++++++++++-- toot/tui/timeline.py | 15 +++++++++++++-- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/toot/commands.py b/toot/commands.py index f86e2f3..e105a8d 100644 --- a/toot/commands.py +++ b/toot/commands.py @@ -359,7 +359,7 @@ def _do_upload(app, user, file, description, thumbnail): return api.upload_media(app, user, file, description=description, thumbnail=thumbnail) -def _find_account(app, user, account_name): +def find_account(app, user, account_name): if not account_name: raise ConsoleError("Empty account name given") @@ -383,25 +383,25 @@ def _find_account(app, user, account_name): def follow(app, user, args): - account = _find_account(app, user, args.account) + account = find_account(app, user, args.account) api.follow(app, user, account['id']) print_out("✓ You are now following {}".format(args.account)) def unfollow(app, user, args): - account = _find_account(app, user, args.account) + account = find_account(app, user, args.account) api.unfollow(app, user, account['id']) print_out("✓ You are no longer following {}".format(args.account)) def following(app, user, args): - account = _find_account(app, user, args.account) + account = find_account(app, user, args.account) response = api.following(app, user, account['id']) print_acct_list(response) def followers(app, user, args): - account = _find_account(app, user, args.account) + account = find_account(app, user, args.account) response = api.followers(app, user, account['id']) print_acct_list(response) @@ -424,25 +424,25 @@ def tags_followed(app, user, args): def mute(app, user, args): - account = _find_account(app, user, args.account) + account = find_account(app, user, args.account) api.mute(app, user, account['id']) print_out("✓ You have muted {}".format(args.account)) def unmute(app, user, args): - account = _find_account(app, user, args.account) + account = find_account(app, user, args.account) api.unmute(app, user, account['id']) print_out("✓ {} is no longer muted".format(args.account)) def block(app, user, args): - account = _find_account(app, user, args.account) + account = find_account(app, user, args.account) api.block(app, user, account['id']) print_out("✓ You are now blocking {}".format(args.account)) def unblock(app, user, args): - account = _find_account(app, user, args.account) + account = find_account(app, user, args.account) api.unblock(app, user, account['id']) print_out("✓ {} is no longer blocked".format(args.account)) @@ -453,7 +453,7 @@ def whoami(app, user, args): def whois(app, user, args): - account = _find_account(app, user, args.account) + account = find_account(app, user, args.account) print_account(account) diff --git a/toot/tui/app.py b/toot/tui/app.py index 330035b..937b7da 100644 --- a/toot/tui/app.py +++ b/toot/tui/app.py @@ -6,6 +6,7 @@ from concurrent.futures import ThreadPoolExecutor from toot import api, config, __version__ from toot.console import get_default_visibility from toot.exceptions import ApiError +from toot.commands import find_account from .compose import StatusComposer from .constants import PALETTE @@ -112,11 +113,13 @@ class TUI(urwid.Frame): self.exception = None self.can_translate = False self.screen = urwid.raw_display.Screen() + self.account = None super().__init__(self.body, header=self.header, footer=self.footer) def run(self): self.loop.set_alarm_in(0, lambda *args: self.async_load_instance()) + self.loop.set_alarm_in(0, lambda *args: self.async_load_followed_accounts()) self.loop.set_alarm_in(0, lambda *args: self.async_load_followed_tags()) self.loop.set_alarm_in(0, lambda *args: self.async_load_timeline( is_initial=True, timeline_name="home")) @@ -257,7 +260,7 @@ class TUI(urwid.Frame): self.loop.set_alarm_in(5, lambda *args: self.footer.clear_message()) config.save_config(self.config) - timeline = Timeline(name, statuses, self.can_translate, self.followed_tags) + timeline = Timeline(name, statuses, self.can_translate, self.followed_tags, self.followed_accounts) self.connect_default_timeline_signals(timeline) urwid.connect_signal(timeline, "next", _next) @@ -287,7 +290,7 @@ class TUI(urwid.Frame): focus = len(ancestors) timeline = Timeline("thread", statuses, self.can_translate, - self.followed_tags, focus, is_thread=True) + self.followed_tags, self.followed_accounts, focus, is_thread=True) self.connect_default_timeline_signals(timeline) urwid.connect_signal(timeline, "close", _close) @@ -356,6 +359,21 @@ class TUI(urwid.Frame): return self.run_in_thread(_load_instance, done_callback=_done) + def async_load_followed_accounts(self): + def _load_accounts(): + try: + acct = f'@{self.user.username}@{self.user.instance}' + self.account = find_account(self.app, self.user, acct) + return api.following(self.app, self.user, self.account["id"]) + except ApiError: + # not supported by all Mastodon servers so fail silently if necessary + return [] + + def _done_accounts(accounts): + self.followed_accounts = {a["acct"] for a in accounts} + + self.run_in_thread(_load_accounts, done_callback=_done_accounts) + def async_load_followed_tags(self): def _load_tag_list(): try: diff --git a/toot/tui/timeline.py b/toot/tui/timeline.py index 24968e5..42299e1 100644 --- a/toot/tui/timeline.py +++ b/toot/tui/timeline.py @@ -44,13 +44,22 @@ class Timeline(urwid.Columns): "copy-status", # Copy status to clipboard ] - def __init__(self, name, statuses, can_translate, followed_tags=[], focus=0, is_thread=False): + def __init__(self, + name, + statuses, + can_translate, + followed_tags=[], + followed_accounts=[], + focus=0, + is_thread=False): + self.name = name self.is_thread = is_thread self.statuses = statuses self.can_translate = can_translate self.status_list = self.build_status_list(statuses, focus=focus) self.followed_tags = followed_tags + self.followed_accounts = followed_accounts try: focused_status = statuses[focus] @@ -320,6 +329,7 @@ class StatusDetails(urwid.Pile): def __init__(self, timeline: Timeline, status: Optional[Status]): self.status = status self.followed_tags = timeline.followed_tags + self.followed_accounts = timeline.followed_accounts reblogged_by = status.author if status and status.reblog else None widget_list = list(self.content_generator(status.original, reblogged_by) @@ -335,7 +345,8 @@ class StatusDetails(urwid.Pile): if status.author.display_name: yield ("pack", urwid.Text(("green", status.author.display_name))) - yield ("pack", urwid.Text(("yellow", status.author.account))) + account_color = "yellow" if status.author.account in self.followed_accounts else "gray" + yield ("pack", urwid.Text((account_color, status.author.account))) yield ("pack", urwid.Divider()) if status.data["spoiler_text"]: