~ihabunek/toot-discuss

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
2 2

[PATCH tooi] Add personal timeline to GotoScreen

Lexi Winter <lexi@le-Fay.ORG>
Details
Message ID
<20240109155211.17959-1-lexi@le-Fay.ORG>
DKIM signature
missing
Download raw message
Patch: +69 -9
Add a new AccountTimeline which can fetch statuses from any account.

Add new API methods get_account_by_id and get_account_by_name.

Extend GotoScreen and TooiApp with a new message type, GotoPersonalTimeline,
which shows AccountTimeline for the logged-in account.
---
 tooi/api/accounts.py | 18 ++++++++++++++++++
 tooi/api/timeline.py | 44 +++++++++++++++++++++++++++++++++++++-------
 tooi/app.py          |  7 ++++++-
 tooi/messages.py     |  4 ++++
 tooi/screens/goto.py |  5 ++++-
 5 files changed, 69 insertions(+), 9 deletions(-)

diff --git a/tooi/api/accounts.py b/tooi/api/accounts.py
index c2dee4c..8dae0c8 100644
--- a/tooi/api/accounts.py
+++ b/tooi/api/accounts.py
@@ -4,6 +4,24 @@ https://docs.joinmastodon.org/methods/accounts/
"""
from httpx import Response
from tooi.api import request
from tooi.entities import Account, from_dict


async def get_account_by_id(account_id: str) -> Account:
    """Look up an account by database id and return its info."""
    path = "/api/v1/accounts/{account_id}"

    response = await request("GET", path)
    return from_dict(Account, response.json())


async def get_account_by_name(account_name: str) -> Account:
    """Look up an account by name and return its info."""
    path = "/api/v1/accounts/lookup"
    params = {"acct": account_name}

    response = await request("GET", path, params=params)
    return from_dict(Account, response.json())


async def verify_credentials() -> Response:
diff --git a/tooi/api/timeline.py b/tooi/api/timeline.py
index 5db03f3..5ecbfca 100644
--- a/tooi/api/timeline.py
+++ b/tooi/api/timeline.py
@@ -12,6 +12,7 @@ from httpx import Headers
from httpx._types import QueryParamTypes

from tooi.api import request, statuses
from tooi.api.accounts import get_account_by_name
from tooi.data.events import Event, StatusEvent, MentionEvent, NewFollowerEvent, ReblogEvent
from tooi.data.events import FavouriteEvent
from tooi.data.instance import InstanceInfo
@@ -82,6 +83,42 @@ class LocalTimeline(Timeline):
        return public_timeline_generator(self.instance, local=True, limit=limit)


class AccountTimeline(Timeline):
    """
    AccountTimeline loads events from the given account's timeline.
    This timeline only ever returns events of type StatusEvent.
    This requires the account id; to fetch based on a username use AccountTimeline.from_name.
    """
    def __init__(self,
                 instance: InstanceInfo,
                 title: str,
                 account_id: str,
                 replies=True,
                 reblogs=True):
        super().__init__(title, instance)
        self.account_id = account_id
        self.replies = replies
        self.reblogs = reblogs

    @staticmethod
    async def from_name(
            instance: InstanceInfo,
            account_name: str,
            replies: bool = True,
            reblogs: bool = True):
        account = await get_account_by_name(account_name)
        return AccountTimeline(instance, account_name, account.id, replies, reblogs)

    def create_generator(self, limit: int = 40):
        path = f"/api/v1/accounts/{self.account_id}/statuses"
        params = {
            "limit": limit,
            "exclude_replies": not self.replies,
            "exclude_reblogs": not self.reblogs
        }
        return _status_generator(self.instance, path, params)


class FederatedTimeline(Timeline):
    """
    FederatedTimeline loads events from the user's federated timeline.
@@ -204,13 +241,6 @@ def bookmark_timeline_generator(instance: InstanceInfo, limit: int = 40):
#    return _conversation_timeline_generator(path, params)


# def account_timeline_generator(account_name: str, replies=False, reblogs=False, limit: int = 40):
#     account = await find_account(account_name)
#     path = f"/api/v1/accounts/{account["id"]}/statuses"
#     params = {"limit": limit, "exclude_replies": not replies, "exclude_reblogs": not reblogs}
#     return _timeline_generator(path, params)


# def list_timeline_generator(list_id: str, limit: int = 20):
#    path = f"/api/v1/timelines/list/{list_id}"
#    return _timeline_generator(path, {"limit": limit})
diff --git a/tooi/app.py b/tooi/app.py
index 8a8995d..ac77586 100644
--- a/tooi/app.py
+++ b/tooi/app.py
@@ -5,13 +5,14 @@ from textual.app import App
from textual.screen import ModalScreen
from urllib.parse import urlparse

from tooi.api.timeline import Timeline, HomeTimeline, LocalTimeline, TagTimeline
from tooi.api.timeline import Timeline, HomeTimeline, LocalTimeline, TagTimeline, AccountTimeline
from tooi.api.timeline import FederatedTimeline, ContextTimeline, NotificationTimeline
from tooi.context import get_context
from tooi.data.instance import get_instance_info
from tooi.messages import GotoHashtagTimeline, GotoHomeTimeline, GotoLocalTimeline
from tooi.messages import ShowAccount, ShowSource, ShowStatusMenu, ShowThread, ShowNotifications
from tooi.messages import ShowHashtagPicker, StatusReply, GotoFederatedTimeline
from tooi.messages import GotoPersonalTimeline
from tooi.screens.account import AccountScreen
from tooi.screens.compose import ComposeScreen
from tooi.screens.goto import GotoScreen, GotoHashtagScreen
@@ -104,6 +105,10 @@ class TooiApp(App[None]):
        # TODO: add footer message while loading statuses
        await self._open_timeline(HomeTimeline(self.instance))

    async def on_goto_personal_timeline(self, message: GotoPersonalTimeline):
        timeline = await AccountTimeline.from_name(self.instance, self.context.auth.acct)
        await self._open_timeline(timeline)

    async def on_goto_local_timeline(self, message: GotoLocalTimeline):
        await self._open_timeline(LocalTimeline(self.instance))

diff --git a/tooi/messages.py b/tooi/messages.py
index 4dc4690..2b15fc9 100644
--- a/tooi/messages.py
+++ b/tooi/messages.py
@@ -37,6 +37,10 @@ class GotoHomeTimeline(Message):
    pass


class GotoPersonalTimeline(Message):
    pass


class GotoLocalTimeline(Message):
    pass

diff --git a/tooi/screens/goto.py b/tooi/screens/goto.py
index 869ab1a..91de775 100644
--- a/tooi/screens/goto.py
+++ b/tooi/screens/goto.py
@@ -4,7 +4,7 @@ from textual.message import Message
from textual.widgets import Input, ListItem, Static

from tooi.messages import GotoHomeTimeline, GotoLocalTimeline, ShowNotifications
from tooi.messages import GotoFederatedTimeline, ShowHashtagPicker
from tooi.messages import GotoFederatedTimeline, ShowHashtagPicker, GotoPersonalTimeline
from tooi.screens.modal import ModalScreen
from tooi.widgets.list_view import ListView

@@ -19,6 +19,7 @@ class GotoScreen(ModalScreen[Message | None]):
    def compose_modal(self) -> ComposeResult:
        self.list_view = ListView(
            ListItem(Static("< Home timeline >"), id="goto_home"),
            ListItem(Static("< Personal timeline >"), id="goto_personal"),
            ListItem(Static("< Local timeline >"), id="goto_local"),
            ListItem(Static("< Federated timeline >"), id="goto_federated"),
            ListItem(Static("< Notifications >"), id="goto_notifications"),
@@ -39,6 +40,8 @@ class GotoScreen(ModalScreen[Message | None]):
        match message.item.id:
            case "goto_home":
                self.dismiss(GotoHomeTimeline())
            case "goto_personal":
                self.dismiss(GotoPersonalTimeline())
            case "goto_local":
                self.dismiss(GotoLocalTimeline())
            case "goto_federated":
-- 
2.43.0
Details
Message ID
<3406db6b-3714-4866-82b9-369c8395b9d4@app.fastmail.com>
In-Reply-To
<20240109155211.17959-1-lexi@le-Fay.ORG> (view parent)
DKIM signature
missing
Download raw message
On Tue, 9 Jan 2024, at 16:52, Lexi Winter wrote:
> diff --git a/tooi/app.py b/tooi/app.py
> index 8a8995d..ac77586 100644
> --- a/tooi/app.py
> +++ b/tooi/app.py
> @@ -5,13 +5,14 @@ from textual.app import App
>  from textual.screen import ModalScreen
>  from urllib.parse import urlparse
> 
> -from tooi.api.timeline import Timeline, HomeTimeline, LocalTimeline, 
> TagTimeline
> +from tooi.api.timeline import Timeline, HomeTimeline, LocalTimeline, 
> TagTimeline, AccountTimeline
>  from tooi.api.timeline import FederatedTimeline, ContextTimeline, 
> NotificationTimeline
>  from tooi.context import get_context
>  from tooi.data.instance import get_instance_info
>  from tooi.messages import GotoHashtagTimeline, GotoHomeTimeline, 
> GotoLocalTimeline
>  from tooi.messages import ShowAccount, ShowSource, ShowStatusMenu, 
> ShowThread, ShowNotifications
>  from tooi.messages import ShowHashtagPicker, StatusReply, 
> GotoFederatedTimeline
> +from tooi.messages import GotoPersonalTimeline
>  from tooi.screens.account import AccountScreen
>  from tooi.screens.compose import ComposeScreen
>  from tooi.screens.goto import GotoScreen, GotoHashtagScreen
> @@ -104,6 +105,10 @@ class TooiApp(App[None]):
>          # TODO: add footer message while loading statuses
>          await self._open_timeline(HomeTimeline(self.instance))
> 
> +    async def on_goto_personal_timeline(self, message: 
> GotoPersonalTimeline):
> +        timeline = await AccountTimeline.from_name(self.instance, 
> self.context.auth.acct)

Not a blocker, but it would be useful to store the personal account id
somewhere so we don't need to fetch it here. Perhaps fetch from
`/api/v1/accounts/verify_credentials` on boot and cache it.

> +        await self._open_timeline(timeline)
> +
>      async def on_goto_local_timeline(self, message: GotoLocalTimeline):
>          await self._open_timeline(LocalTimeline(self.instance))
> 

Thanks! Applied.

-- Ivan
Details
Message ID
<ZZ2rvarxHXeh1Ofp@ilythia.eden.le-fay.org>
In-Reply-To
<3406db6b-3714-4866-82b9-369c8395b9d4@app.fastmail.com> (view parent)
DKIM signature
missing
Download raw message
Ivan Habunek:
> > +    async def on_goto_personal_timeline(self, message: 
> > GotoPersonalTimeline):
> > +        timeline = await AccountTimeline.from_name(self.instance, 
> > self.context.auth.acct)
 
> Not a blocker, but it would be useful to store the personal account id
> somewhere so we don't need to fetch it here. Perhaps fetch from
> `/api/v1/accounts/verify_credentials` on boot and cache it.
 
i wondered about that, i was actually surprised we don't already do
that.  i created ticket #47 so i don't forgot (or maybe someone else
will do it).
Reply to thread Export thread (mbox)