diff libervia/desktop_kivy/plugins/plugin_wid_blog.py @ 493:b3cedbee561d

refactoring: rename `cagou` to `libervia.desktop_kivy` + update imports and names following backend changes
author Goffi <goffi@goffi.org>
date Fri, 02 Jun 2023 18:26:16 +0200
parents cagou/plugins/plugin_wid_blog.py@203755bbe0fe
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libervia/desktop_kivy/plugins/plugin_wid_blog.py	Fri Jun 02 18:26:16 2023 +0200
@@ -0,0 +1,192 @@
+#!/usr/bin/env python3
+
+#desktop/mobile frontend for Libervia XMPP client
+# Copyright (C) 2016-2022 Jérôme Poisson (goffi@goffi.org)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+from functools import partial
+import json
+from typing import Any, Dict, Optional
+
+from kivy import properties
+from kivy.metrics import sp
+from kivy.uix.behaviors import ButtonBehavior
+from kivy.uix.boxlayout import BoxLayout
+from libervia.backend.core import log as logging
+from libervia.backend.core.i18n import _
+from libervia.backend.tools.common import data_format
+from libervia.frontends.bridge.bridge_frontend import BridgeException
+from libervia.frontends.quick_frontend import quick_widgets
+from libervia.frontends.tools import jid
+
+from libervia.desktop_kivy import G
+from libervia.desktop_kivy.core.menu import SideMenu
+
+from ..core import cagou_widget
+from ..core.common import SymbolButton
+from ..core.constants import Const as C
+from ..core.image import Image
+
+log = logging.getLogger(__name__)
+
+PLUGIN_INFO = {
+    "name": _("blog"),
+    "main": "Blog",
+    "description": _("(micro)blog"),
+    "icon_symbol": "pencil",
+}
+
+
+class SearchButton(SymbolButton):
+    blog = properties.ObjectProperty()
+
+    def on_release(self, *args):
+        self.blog.header_input.dispatch('on_text_validate')
+
+
+class NewPostButton(SymbolButton):
+    blog = properties.ObjectProperty()
+
+    def on_release(self, *args):
+        self.blog.show_new_post_menu()
+
+
+class NewPosttMenu(SideMenu):
+    blog = properties.ObjectProperty()
+    size_hint_close = (1, 0)
+    size_hint_open = (1, 0.9)
+
+    def _publish_cb(self, item_id: str) -> None:
+        G.host.add_note(
+            _("blog post published"),
+            _("your blog post has been published with ID {item_id}").format(
+                item_id=item_id
+            )
+        )
+        self.blog.load_blog()
+
+    def _publish_eb(self, exc: BridgeException) -> None:
+        G.host.add_note(
+            _("Problem while publish blog post"),
+            _("Can't publish blog post at {node!r} from {service}: {problem}").format(
+                node=self.blog.node or G.host.ns_map.get("microblog"),
+                service=(
+                    self.blog.service if self.blog.service
+                    else G.host.profiles[self.blog.profile].whoami,
+                ),
+                problem=exc
+            ),
+            C.XMLUI_DATA_LVL_ERROR
+        )
+
+    def publish(
+            self,
+            title: str,
+            content: str,
+            e2ee: bool = False
+    ) -> None:
+        self.hide()
+        mb_data: Dict[str, Any] = {"content_rich": content}
+        if e2ee:
+            mb_data["encrypted"] = True
+        title = title.strip()
+        if title:
+            mb_data["title_rich"] = title
+        G.host.bridge.mb_send(
+            self.blog.service,
+            self.blog.node,
+            data_format.serialise(mb_data),
+            self.blog.profile,
+            callback=self._publish_cb,
+            errback=self._publish_eb,
+        )
+
+
+class BlogPostAvatar(ButtonBehavior, Image):
+    pass
+
+
+class BlogPostWidget(BoxLayout):
+    blog_data = properties.DictProperty()
+    font_size = properties.NumericProperty(sp(12))
+    title_font_size = properties.NumericProperty(sp(14))
+
+
+class Blog(quick_widgets.QuickWidget, cagou_widget.LiberviaDesktopKivyWidget):
+    posts_widget = properties.ObjectProperty()
+    service = properties.StringProperty()
+    node = properties.StringProperty()
+    use_header_input = True
+
+    def __init__(self, host, target, profiles):
+        quick_widgets.QuickWidget.__init__(self, G.host, target, profiles)
+        cagou_widget.LiberviaDesktopKivyWidget.__init__(self)
+        search_btn = SearchButton(blog=self)
+        self.header_input_add_extra(search_btn)
+        new_post_btn = NewPostButton(blog=self)
+        self.header_input_add_extra(new_post_btn)
+        self.load_blog()
+
+    def on_kv_post(self, __):
+        self.bind(
+            service=lambda __, value: self.load_blog(),
+            node=lambda __, value: self.load_blog(),
+        )
+
+    def on_header_wid_input(self):
+        text = self.header_input.text.strip()
+        # for now we only use text as node
+        self.node = text
+
+    def show_new_post_menu(self):
+        """Show the "add a contact" menu"""
+        NewPosttMenu(blog=self).show()
+
+    def _mb_get_cb(self, blog_data_s: str) -> None:
+        blog_data = json.loads(blog_data_s)
+        for item in blog_data["items"]:
+            self.posts_widget.add_widget(BlogPostWidget(blog_data=item))
+
+    def _mb_get_eb(
+        self,
+        exc: BridgeException,
+    ) -> None:
+        G.host.add_note(
+            _("Problem while getting blog data"),
+            _("Can't get blog for {node!r} at {service}: {problem}").format(
+                node=self.node or G.host.ns_map.get("microblog"),
+                service=self.service if self.service else G.host.profiles[self.profile].whoami,
+                problem=exc
+            ),
+            C.XMLUI_DATA_LVL_ERROR
+        )
+
+    def load_blog(
+        self,
+    ) -> None:
+        """Retrieve a blog and display it"""
+        extra = {}
+        self.posts_widget.clear_widgets()
+        G.host.bridge.mb_get(
+            self.service,
+            self.node,
+            20,
+            [],
+            data_format.serialise(extra),
+            self.profile,
+            callback=self._mb_get_cb,
+            errback=self._mb_get_eb,
+        )