~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
1

[PATCH tooi v2] ComposeScreen: support Hometown's unfederated posts (#13)

Lexi Winter <lexi@le-Fay.ORG>
Details
Message ID
<20240109172016.89067-1-lexi@le-Fay.ORG>
DKIM signature
missing
Download raw message
Patch: +69 -23
This is a Hometown-specific feature which allows posts to be marked as
unfederated.

Add a local_only option to api.statuses.post() to set the local_only
flag in the status.  By default this is None, so it won't be sent to
Mastodon servers.

Detect support for unfederated posts in ComposeScreen by checking if the
posting:default:federation preference is present.  If it is, display a
new post option for selecting the federation status.

If reply to a post with the local_only flag, default to the federation
status of the post being replied to rather than the user preference.
---
Fix a type error in SelectFederationModal.

 tooi/api/statuses.py    |  2 +
 tooi/screens/compose.py | 90 ++++++++++++++++++++++++++++++-----------
 2 files changed, 69 insertions(+), 23 deletions(-)

diff --git a/tooi/api/statuses.py b/tooi/api/statuses.py
index ce940a7..2c2abf6 100644
--- a/tooi/api/statuses.py
+++ b/tooi/api/statuses.py
@@ -23,6 +23,7 @@ async def post(
    sensitive: bool = False,
    spoiler_text: str | None = None,
    in_reply_to: Optional[str] = None,
    local_only: bool | None = None,
) -> Response:
    # Idempotency key assures the same status is not posted multiple times
    # if the request is retried.
@@ -34,6 +35,7 @@ async def post(
        "sensitive": sensitive,
        "spoiler_text": spoiler_text,
        "in_reply_to_id": in_reply_to,
        "local_only": local_only,
    })

    return await request("POST", "/api/v1/statuses", headers=headers, json=payload)
diff --git a/tooi/screens/compose.py b/tooi/screens/compose.py
index 27e9413..473c9e4 100644
--- a/tooi/screens/compose.py
+++ b/tooi/screens/compose.py
@@ -43,8 +43,17 @@ class ComposeScreen(ModalScreen[None]):
        self.in_reply_to = in_reply_to
        self.content_warning = None

        # posting:default:federation is used by Hometown's local-only
        # (unfederated) posts feature.  We treat this as a 3-way switch; if
        # it's not present, the instance doesn't support local-only posts at
        # all, otherwise it indicates if the post should be federated by
        # default.
        self.federated = instance_info.user_preferences.get('posting:default:federation')

        if in_reply_to:
            self.visibility = in_reply_to.original.visibility
            if in_reply_to.local_only is not None:
                self.federated = not in_reply_to.local_only
        else:
            self.visibility = instance_info.user_preferences.get(
                    'posting:default:visibility', Visibility.Public)
@@ -61,19 +70,25 @@ class ComposeScreen(ModalScreen[None]):
        if initial_text:
            self.text_area.cursor_location = (0, len(initial_text))

        self.menu = Menu()

        self.visibility_menu_item = MenuItem("visibility", f"Visibility: {self.visibility}")
        self.menu.append(self.visibility_menu_item)

        if self.federated is not None:
            label = federated_label(self.federated)
            self.federation_menu_item = MenuItem("federation", f"Federation: {label}")
            self.menu.append(self.federation_menu_item)

        self.post_menu_item = MenuItem("post", "Post status")
        self.menu.append(self.post_menu_item)

        self.cancel_menu_item = MenuItem("cancel", "Cancel")
        self.menu.append(self.cancel_menu_item)

        self.toggle_cw_menu_item = MenuItem("add_cw", "Add content warning")
        self.status = Static(id="compose_status")

        self.menu = Menu(
            self.toggle_cw_menu_item,
            self.visibility_menu_item,
            self.post_menu_item,
            self.cancel_menu_item,
        )

        self.character_count = ComposeCharacterCount(self.instance_info, self.text_area.text)

        yield Header("Compose toot")
@@ -103,12 +118,15 @@ class ComposeScreen(ModalScreen[None]):
        self.set_status("Posting...", "text-muted")

        try:
            await statuses.post(
                self.text_area.text,
                visibility=self.visibility,
                spoiler_text=self.content_warning.text if self.content_warning else None,
                in_reply_to=self.in_reply_to.original.id if self.in_reply_to else None
            )
            args = {
                'visibility': self.visibility,
                'spoiler_text': self.content_warning.text if self.content_warning else None,
                'in_reply_to': self.in_reply_to.original.id if self.in_reply_to else None
            }
            if self.federated is not None:
                args['local_only'] = not self.federated

            await statuses.post(self.text_area.text, **args)
            self.set_status("Status posted", "text-success")
            await asyncio.sleep(0.5)
            self.dismiss()
@@ -129,6 +147,8 @@ class ComposeScreen(ModalScreen[None]):
        match message.item.code:
            case "visibility":
                self.app.push_screen(SelectVisibilityModal(), self.set_visibility)
            case "federation":
                self.app.push_screen(SelectFederationModal(), self.set_federation)
            case "post":
                asyncio.create_task(self.post_status())
            case "add_cw":
@@ -161,6 +181,11 @@ class ComposeScreen(ModalScreen[None]):
        self.visibility = visibility
        self.visibility_menu_item.update(f"Visibility: {visibility.name}")

    def set_federation(self, federated: bool):
        self.federated = federated
        label = federated_label(federated)
        self.federation_menu_item.update(label)

    def set_status(self, message: str, classes: str = ""):
        self.status.set_classes(classes)
        self.status.update(message)
@@ -223,6 +248,18 @@ class ComposeTextArea(TextArea):
            super().__init__()


def visibility_label(visibilty: Visibility):
    match visibilty:
        case Visibility.Public:
            return "Public - Visible to everyone, shown in public timelines."
        case Visibility.Unlisted:
            return "Unlisted - Visible to public, but not included in public timelines."
        case Visibility.Private:
            return "Private - Visible to followers only, and to any mentioned users."
        case Visibility.Direct:
            return "Direct - Visible only to mentioned users."


class SelectVisibilityModal(ModalScreen[Visibility]):
    def compose_modal(self):
        yield Static("Select visibility", classes="modal_title")
@@ -237,16 +274,23 @@ class SelectVisibilityModal(ModalScreen[Visibility]):
        self.dismiss(cast(Visibility, message.item.code))


def visibility_label(visibilty: Visibility):
    match visibilty:
        case Visibility.Public:
            return "Public - Visible to everyone, shown in public timelines."
        case Visibility.Unlisted:
            return "Unlisted - Visible to public, but not included in public timelines."
        case Visibility.Private:
            return "Private - Visible to followers only, and to any mentioned users."
        case Visibility.Direct:
            return "Direct - Visible only to mentioned users."
def federated_label(federated: bool) -> str:
    if federated:
        return "Federated"
    else:
        return "Local only (unfederated)"


class SelectFederationModal(ModalScreen[Visibility]):
    def compose_modal(self):
        yield Static("Select federation", classes="modal_title")
        yield Menu(
            MenuItem(True, federated_label(True)),
            MenuItem(False, federated_label(False)),
        )

    def on_menu_item_selected(self, message: Menu.ItemSelected):
        self.dismiss(message.item.code)


class ComposeCharacterCount(Static):
-- 
2.43.0
Details
Message ID
<5c52233e-b422-4bb4-944b-0e93e1a7b63c@app.fastmail.com>
In-Reply-To
<20240109172016.89067-1-lexi@le-Fay.ORG> (view parent)
DKIM signature
missing
Download raw message
Thanks, applied.

-- Ivan
Reply to thread Export thread (mbox)