1
0
mirror of https://github.com/ihabunek/toot.git synced 2024-06-30 06:35:24 +00:00
This commit is contained in:
Ivan Habunek 2023-02-17 09:29:07 +01:00
parent d42394c111
commit 414a7fc47a
No known key found for this signature in database
GPG Key ID: F5F0623FF5EBCB3D
4 changed files with 39 additions and 29 deletions

View File

@ -1,4 +1,5 @@
import logging import logging
from typing import List
import urwid import urwid
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
@ -9,7 +10,7 @@ from toot.exceptions import ApiError
from .compose import StatusComposer from .compose import StatusComposer
from .constants import PALETTE from .constants import PALETTE
from .entities import Status, from_dict from .entities import Status, StatusMeta, from_dict
from .overlays import ExceptionStackTrace, GotoMenu, Help, StatusSource, StatusLinks, StatusZoom from .overlays import ExceptionStackTrace, GotoMenu, Help, StatusSource, StatusLinks, StatusZoom
from .overlays import StatusDeleteConfirmation, Account from .overlays import StatusDeleteConfirmation, Account
from .timeline import Timeline from .timeline import Timeline
@ -182,7 +183,7 @@ class TUI(urwid.Frame):
self.show_compose() self.show_compose()
def _delete(timeline, status): def _delete(timeline, status):
if status.is_mine: if status._meta.is_mine:
self.show_delete_confirmation(status) self.show_delete_confirmation(status)
def _reply(timeline, status): def _reply(timeline, status):
@ -258,9 +259,9 @@ class TUI(urwid.Frame):
return timeline return timeline
def make_status(self, status_data): def make_status(self, status_data):
return from_dict(Status, status_data) status = from_dict(Status, status_data)
# is_mine = self.user.username == status_data["account"]["acct"] status._meta = StatusMeta(status, self.app, self.user)
# return Status(status_data, is_mine, self.app.instance) return status
def show_thread(self, status): def show_thread(self, status):
def _close(*args): def _close(*args):
@ -307,9 +308,10 @@ class TUI(urwid.Frame):
self.refresh_footer(self.timeline) self.refresh_footer(self.timeline)
self.body = self.timeline self.body = self.timeline
def _done_next(statuses): def _done_next(statuses: List[Status]):
"""Process sequential batch of statuses, adds statuses to the """Process sequential batch of statuses, adds statuses to the
existing timeline.""" existing timeline."""
if self.timeline:
self.timeline.append_statuses(statuses) self.timeline.append_statuses(statuses)
return self.run_in_thread(_load_statuses, return self.run_in_thread(_load_statuses,
@ -517,7 +519,7 @@ class TUI(urwid.Frame):
title="Account", title="Account",
) )
def async_toggle_favourite(self, timeline, status): def async_toggle_favourite(self, timeline: Timeline, status: Status):
def _favourite(): def _favourite():
logger.info("Favouriting {}".format(status)) logger.info("Favouriting {}".format(status))
api.favourite(self.app, self.user, status.id) api.favourite(self.app, self.user, status.id)
@ -555,7 +557,7 @@ class TUI(urwid.Frame):
timeline.update_status(new_status) timeline.update_status(new_status)
# Check if status is rebloggable # Check if status is rebloggable
no_reblog_because_private = status.visibility == "private" and not status.is_mine no_reblog_because_private = status.visibility == "private" and not status._meta.is_mine
no_reblog_because_direct = status.visibility == "direct" no_reblog_because_direct = status.visibility == "direct"
if no_reblog_because_private or no_reblog_because_direct: if no_reblog_because_private or no_reblog_because_direct:
self.footer.set_error_message("You may not reblog this {} status".format(status.visibility)) self.footer.set_error_message("You may not reblog this {} status".format(status.visibility))
@ -587,9 +589,9 @@ class TUI(urwid.Frame):
def _done(response): def _done(response):
if response is not None: if response is not None:
status.translation = response["content"] status._meta.translation = response["content"]
status.translated_from = response["detected_source_language"] status._meta.translated_from = response["detected_source_language"]
status.show_translation = True status._meta.show_translation = True
timeline.update_status(status) timeline.update_status(status)
# If already translated, toggle showing translation # If already translated, toggle showing translation
@ -599,7 +601,7 @@ class TUI(urwid.Frame):
else: else:
self.run_in_thread(_translate, done_callback=_done) self.run_in_thread(_translate, done_callback=_done)
def async_toggle_bookmark(self, timeline, status): def async_toggle_bookmark(self, timeline: Timeline, status: Status):
def _bookmark(): def _bookmark():
logger.info("Bookmarking {}".format(status)) logger.info("Bookmarking {}".format(status))
api.bookmark(self.app, self.user, status.id) api.bookmark(self.app, self.user, status.id)

View File

@ -8,6 +8,7 @@ from dataclasses import dataclass, is_dataclass
from datetime import date, datetime from datetime import date, datetime
from typing import Dict, List, Optional, Type, TypeVar, Union from typing import Dict, List, Optional, Type, TypeVar, Union
from typing import get_type_hints from typing import get_type_hints
from toot import App, User
from toot.typing_compat import get_args, get_origin from toot.typing_compat import get_args, get_origin
from toot.utils import get_text from toot.utils import get_text
@ -190,16 +191,19 @@ class FilterResult:
status_matches: Optional[str] status_matches: Optional[str]
@dataclass
class StatusMeta: class StatusMeta:
""" """
Additional information kept for a status. Additional information kept for a status.
""" """
is_mine: bool
show_sensitive: bool = False show_sensitive: bool = False
show_translation: bool = False show_translation: bool = False
translated_from: Optional[str] = None translated_from: Optional[str] = None
translation: Optional[str] = None translation: Optional[str] = None
def __init__(self, status: "Status", app: App, user: User):
self.is_mine = user.username == status.account.acct
@dataclass @dataclass
class Status: class Status:
@ -238,7 +242,8 @@ class Status:
pinned: Optional[bool] pinned: Optional[bool]
filtered: Optional[List[FilterResult]] filtered: Optional[List[FilterResult]]
_meta: StatusMeta = dataclasses.field(default_factory=StatusMeta) # Added by TUI for storing some context
_meta: Optional[StatusMeta] = None
@property @property
def original(self) -> "Status": def original(self) -> "Status":

View File

@ -102,10 +102,13 @@ class Timeline(urwid.Columns):
if not status: if not status:
return None return None
assert status._meta
is_mine = status._meta.is_mine
options = [ options = [
"[A]ccount" if not status.is_mine else "", "[A]ccount" if not is_mine else "",
"[B]oost", "[B]oost",
"[D]elete" if status.is_mine else "", "[D]elete" if is_mine else "",
"B[o]okmark", "B[o]okmark",
"[F]avourite", "[F]avourite",
"[V]iew", "[V]iew",
@ -303,11 +306,15 @@ class StatusDetails(urwid.Pile):
self.followed_tags = timeline.followed_tags self.followed_tags = timeline.followed_tags
reblogged_by = status.account if status and status.reblog else None reblogged_by = status.account if status and status.reblog else None
widget_list = list(self.content_generator(status.original, reblogged_by) widget_list = list(self.content_generator(status, reblogged_by)
if status else ()) if status else ())
return super().__init__(widget_list) return super().__init__(widget_list)
def content_generator(self, status: Status, reblogged_by: Optional[Account]): def content_generator(self, status: Status, reblogged_by: Optional[Account]):
assert status._meta
meta = status._meta
status = status.original
if reblogged_by: if reblogged_by:
text = "{} boosted".format(reblogged_by.display_name or reblogged_by.username) text = "{} boosted".format(reblogged_by.display_name or reblogged_by.username)
yield ("pack", urwid.Text(("gray", text))) yield ("pack", urwid.Text(("gray", text)))
@ -323,8 +330,6 @@ class StatusDetails(urwid.Pile):
yield ("pack", urwid.Text(status.spoiler_text)) yield ("pack", urwid.Text(status.spoiler_text))
yield ("pack", urwid.Divider()) yield ("pack", urwid.Divider())
meta = status._meta
# Show content warning # Show content warning
if status.spoiler_text and not meta.show_sensitive: if status.spoiler_text and not meta.show_sensitive:
yield ("pack", urwid.Text(("content_warning", "Marked as sensitive. Press S to view."))) yield ("pack", urwid.Text(("content_warning", "Marked as sensitive. Press S to view.")))
@ -333,14 +338,12 @@ class StatusDetails(urwid.Pile):
for line in format_content(content): for line in format_content(content):
yield ("pack", urwid.Text(highlight_hashtags(line, self.followed_tags))) yield ("pack", urwid.Text(highlight_hashtags(line, self.followed_tags)))
media = status.media_attachments for m in status.media_attachments:
if media:
for m in media:
yield ("pack", urwid.AttrMap(urwid.Divider("-"), "gray")) yield ("pack", urwid.AttrMap(urwid.Divider("-"), "gray"))
yield ("pack", urwid.Text([("bold", "Media attachment"), " (", m["type"], ")"])) yield ("pack", urwid.Text([("bold", "Media attachment"), f" ({m.type})"]))
if m["description"]: if m.description:
yield ("pack", urwid.Text(m["description"])) yield ("pack", urwid.Text(m.description))
yield ("pack", urwid.Text(("link", m["url"]))) yield ("pack", urwid.Text(("link", m.url)))
if status.poll: if status.poll:
yield ("pack", urwid.Divider()) yield ("pack", urwid.Divider())

View File

@ -33,7 +33,7 @@ def parse_datetime(value):
return dttm.astimezone() return dttm.astimezone()
def time_ago(value: datetime) -> datetime: def time_ago(value: datetime) -> str:
now = datetime.now().astimezone() now = datetime.now().astimezone()
delta = now.timestamp() - value.timestamp() delta = now.timestamp() - value.timestamp()