tui: honour user's default visibility preference

Mastodon allows the user to configure a default visibility which should
apply to all clients.  This setting is returned by the
/api/v1/preferences method.

Fetch the user preferences when the TUI starts, and use it to set the
default visibility when composing a new toot.  The preference can be
overridden by a new command-line option, toot tui --default-visibility=.
If neither the preference nor the option are set, fall back to
get_default_visibility().
This commit is contained in:
Lexi Winter 2023-12-31 17:13:42 +00:00
parent 4e55fba15e
commit 5dd53b1b9c
4 changed files with 39 additions and 6 deletions

View File

@ -618,6 +618,10 @@ def get_instance(base_url: str) -> Response:
return http.anon_get(url)
def get_preferences(app, user) -> Response:
return http.get(app, user, '/api/v1/preferences')
def get_lists(app, user):
return http.get(app, user, "/api/v1/lists").json()

View File

@ -1,7 +1,7 @@
import click
from typing import Optional
from toot.cli import TUI_COLORS, Context, cli, pass_context
from toot.cli import TUI_COLORS, VISIBILITY_CHOICES, Context, cli, pass_context
from toot.cli.validators import validate_tui_colors
from toot.tui.app import TUI, TuiOptions
@ -24,12 +24,18 @@ COLOR_OPTIONS = ", ".join(TUI_COLORS.keys())
help=f"""Number of colors to use, one of {COLOR_OPTIONS}, defaults to 16 if
using --color, and 1 if using --no-color."""
)
@click.option(
"-v", "--default-visibility",
type=click.Choice(VISIBILITY_CHOICES),
help="Default visibility when posting new toots; overrides the server-side preference"
)
@pass_context
def tui(
ctx: Context,
colors: Optional[int],
media_viewer: Optional[str],
relative_datetimes: bool,
default_visibility: Optional[str]
):
"""Launches the toot terminal user interface"""
if colors is None:
@ -39,6 +45,7 @@ def tui(
colors=colors,
media_viewer=media_viewer,
relative_datetimes=relative_datetimes,
default_visibility=default_visibility
)
tui = TUI.create(ctx.app, ctx.user, options)
tui.run()

View File

@ -31,6 +31,7 @@ class TuiOptions(NamedTuple):
colors: int
media_viewer: Optional[str]
relative_datetimes: bool
default_visibility: Optional[bool]
class Header(urwid.WidgetWrap):
@ -137,11 +138,13 @@ class TUI(urwid.Frame):
self.can_translate = False
self.account = None
self.followed_accounts = []
self.preferences = {}
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_preferences())
self.loop.set_alarm_in(0, lambda *args: self.async_load_timeline(
is_initial=True, timeline_name="home"))
self.loop.set_alarm_in(0, lambda *args: self.async_load_followed_accounts())
@ -326,6 +329,19 @@ class TUI(urwid.Frame):
return self.run_in_thread(_load_instance, done_callback=_done)
def async_load_preferences(self):
"""
Attempt to update user preferences from instance.
https://docs.joinmastodon.org/methods/preferences/
"""
def _load_preferences():
return api.get_preferences(self.app, self.user).json()
def _done(preferences):
self.preferences = preferences
return self.run_in_thread(_load_preferences, done_callback=_done)
def async_load_followed_accounts(self):
def _load_accounts():
try:
@ -400,7 +416,15 @@ class TUI(urwid.Frame):
def _post(timeline, *args):
self.post_status(*args)
composer = StatusComposer(self.max_toot_chars, self.user.username, in_reply_to)
# If the user specified --default-visibility, use that; otherwise,
# try to use the server-side default visibility. If that fails, fall
# back to get_default_visibility().
visibility = (self.options.default_visibility or
self.preferences.get('posting:default:visibility',
get_default_visibility()))
composer = StatusComposer(self.max_toot_chars, self.user.username,
visibility, in_reply_to)
urwid.connect_signal(composer, "close", _close)
urwid.connect_signal(composer, "post", _post)
self.open_overlay(composer, title="Compose status")

View File

@ -1,8 +1,6 @@
import urwid
import logging
from toot.cli import get_default_visibility
from .constants import VISIBILITY_OPTIONS
from .widgets import Button, EditBox
@ -15,7 +13,7 @@ class StatusComposer(urwid.Frame):
"""
signals = ["close", "post"]
def __init__(self, max_chars, username, in_reply_to=None):
def __init__(self, max_chars, username, visibility, in_reply_to=None):
self.in_reply_to = in_reply_to
self.max_chars = max_chars
self.username = username
@ -34,7 +32,7 @@ class StatusComposer(urwid.Frame):
on_press=self.remove_content_warning)
self.visibility = (
in_reply_to.visibility if in_reply_to else get_default_visibility()
in_reply_to.visibility if in_reply_to else visibility
)
self.visibility_button = Button("Visibility: {}".format(self.visibility),
on_press=self.choose_visibility)