kopia lustrzana https://github.com/ihabunek/toot
entities
rodzic
d42394c111
commit
414a7fc47a
|
@ -1,4 +1,5 @@
|
|||
import logging
|
||||
from typing import List
|
||||
import urwid
|
||||
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
@ -9,7 +10,7 @@ from toot.exceptions import ApiError
|
|||
|
||||
from .compose import StatusComposer
|
||||
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 StatusDeleteConfirmation, Account
|
||||
from .timeline import Timeline
|
||||
|
@ -182,7 +183,7 @@ class TUI(urwid.Frame):
|
|||
self.show_compose()
|
||||
|
||||
def _delete(timeline, status):
|
||||
if status.is_mine:
|
||||
if status._meta.is_mine:
|
||||
self.show_delete_confirmation(status)
|
||||
|
||||
def _reply(timeline, status):
|
||||
|
@ -258,9 +259,9 @@ class TUI(urwid.Frame):
|
|||
return timeline
|
||||
|
||||
def make_status(self, status_data):
|
||||
return from_dict(Status, status_data)
|
||||
# is_mine = self.user.username == status_data["account"]["acct"]
|
||||
# return Status(status_data, is_mine, self.app.instance)
|
||||
status = from_dict(Status, status_data)
|
||||
status._meta = StatusMeta(status, self.app, self.user)
|
||||
return status
|
||||
|
||||
def show_thread(self, status):
|
||||
def _close(*args):
|
||||
|
@ -307,10 +308,11 @@ class TUI(urwid.Frame):
|
|||
self.refresh_footer(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
|
||||
existing timeline."""
|
||||
self.timeline.append_statuses(statuses)
|
||||
if self.timeline:
|
||||
self.timeline.append_statuses(statuses)
|
||||
|
||||
return self.run_in_thread(_load_statuses,
|
||||
done_callback=_done_initial if is_initial else _done_next)
|
||||
|
@ -517,7 +519,7 @@ class TUI(urwid.Frame):
|
|||
title="Account",
|
||||
)
|
||||
|
||||
def async_toggle_favourite(self, timeline, status):
|
||||
def async_toggle_favourite(self, timeline: Timeline, status: Status):
|
||||
def _favourite():
|
||||
logger.info("Favouriting {}".format(status))
|
||||
api.favourite(self.app, self.user, status.id)
|
||||
|
@ -555,7 +557,7 @@ class TUI(urwid.Frame):
|
|||
timeline.update_status(new_status)
|
||||
|
||||
# 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"
|
||||
if no_reblog_because_private or no_reblog_because_direct:
|
||||
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):
|
||||
if response is not None:
|
||||
status.translation = response["content"]
|
||||
status.translated_from = response["detected_source_language"]
|
||||
status.show_translation = True
|
||||
status._meta.translation = response["content"]
|
||||
status._meta.translated_from = response["detected_source_language"]
|
||||
status._meta.show_translation = True
|
||||
timeline.update_status(status)
|
||||
|
||||
# If already translated, toggle showing translation
|
||||
|
@ -599,7 +601,7 @@ class TUI(urwid.Frame):
|
|||
else:
|
||||
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():
|
||||
logger.info("Bookmarking {}".format(status))
|
||||
api.bookmark(self.app, self.user, status.id)
|
||||
|
|
|
@ -8,6 +8,7 @@ from dataclasses import dataclass, is_dataclass
|
|||
from datetime import date, datetime
|
||||
from typing import Dict, List, Optional, Type, TypeVar, Union
|
||||
from typing import get_type_hints
|
||||
from toot import App, User
|
||||
|
||||
from toot.typing_compat import get_args, get_origin
|
||||
from toot.utils import get_text
|
||||
|
@ -190,16 +191,19 @@ class FilterResult:
|
|||
status_matches: Optional[str]
|
||||
|
||||
|
||||
@dataclass
|
||||
class StatusMeta:
|
||||
"""
|
||||
Additional information kept for a status.
|
||||
"""
|
||||
is_mine: bool
|
||||
show_sensitive: bool = False
|
||||
show_translation: bool = False
|
||||
translated_from: 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
|
||||
class Status:
|
||||
|
@ -238,7 +242,8 @@ class Status:
|
|||
pinned: Optional[bool]
|
||||
filtered: Optional[List[FilterResult]]
|
||||
|
||||
_meta: StatusMeta = dataclasses.field(default_factory=StatusMeta)
|
||||
# Added by TUI for storing some context
|
||||
_meta: Optional[StatusMeta] = None
|
||||
|
||||
@property
|
||||
def original(self) -> "Status":
|
||||
|
|
|
@ -102,10 +102,13 @@ class Timeline(urwid.Columns):
|
|||
if not status:
|
||||
return None
|
||||
|
||||
assert status._meta
|
||||
is_mine = status._meta.is_mine
|
||||
|
||||
options = [
|
||||
"[A]ccount" if not status.is_mine else "",
|
||||
"[A]ccount" if not is_mine else "",
|
||||
"[B]oost",
|
||||
"[D]elete" if status.is_mine else "",
|
||||
"[D]elete" if is_mine else "",
|
||||
"B[o]okmark",
|
||||
"[F]avourite",
|
||||
"[V]iew",
|
||||
|
@ -303,11 +306,15 @@ class StatusDetails(urwid.Pile):
|
|||
self.followed_tags = timeline.followed_tags
|
||||
|
||||
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 ())
|
||||
return super().__init__(widget_list)
|
||||
|
||||
def content_generator(self, status: Status, reblogged_by: Optional[Account]):
|
||||
assert status._meta
|
||||
meta = status._meta
|
||||
status = status.original
|
||||
|
||||
if reblogged_by:
|
||||
text = "♺ {} boosted".format(reblogged_by.display_name or reblogged_by.username)
|
||||
yield ("pack", urwid.Text(("gray", text)))
|
||||
|
@ -323,8 +330,6 @@ class StatusDetails(urwid.Pile):
|
|||
yield ("pack", urwid.Text(status.spoiler_text))
|
||||
yield ("pack", urwid.Divider())
|
||||
|
||||
meta = status._meta
|
||||
|
||||
# Show content warning
|
||||
if status.spoiler_text and not meta.show_sensitive:
|
||||
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):
|
||||
yield ("pack", urwid.Text(highlight_hashtags(line, self.followed_tags)))
|
||||
|
||||
media = status.media_attachments
|
||||
if media:
|
||||
for m in media:
|
||||
yield ("pack", urwid.AttrMap(urwid.Divider("-"), "gray"))
|
||||
yield ("pack", urwid.Text([("bold", "Media attachment"), " (", m["type"], ")"]))
|
||||
if m["description"]:
|
||||
yield ("pack", urwid.Text(m["description"]))
|
||||
yield ("pack", urwid.Text(("link", m["url"])))
|
||||
for m in status.media_attachments:
|
||||
yield ("pack", urwid.AttrMap(urwid.Divider("-"), "gray"))
|
||||
yield ("pack", urwid.Text([("bold", "Media attachment"), f" ({m.type})"]))
|
||||
if m.description:
|
||||
yield ("pack", urwid.Text(m.description))
|
||||
yield ("pack", urwid.Text(("link", m.url)))
|
||||
|
||||
if status.poll:
|
||||
yield ("pack", urwid.Divider())
|
||||
|
|
|
@ -33,7 +33,7 @@ def parse_datetime(value):
|
|||
return dttm.astimezone()
|
||||
|
||||
|
||||
def time_ago(value: datetime) -> datetime:
|
||||
def time_ago(value: datetime) -> str:
|
||||
now = datetime.now().astimezone()
|
||||
delta = now.timestamp() - value.timestamp()
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue