mirror of
https://github.com/ihabunek/toot.git
synced 2024-09-29 04:35:54 -04:00
wip
This commit is contained in:
parent
d42394c111
commit
414a7fc47a
@ -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)
|
||||||
|
@ -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":
|
||||||
|
@ -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())
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user