changeset 336:b0c9017a1db7

core: added forgotten share_widget module
author Goffi <goffi@goffi.org>
date Sat, 28 Dec 2019 16:09:54 +0100
parents 597cc207c8e7
children 544c437f5094
files cagou/core/share_widget.py
diffstat 1 files changed, 185 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cagou/core/share_widget.py	Sat Dec 28 16:09:54 2019 +0100
@@ -0,0 +1,185 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Cagou: desktop/mobile frontend for Salut à Toi XMPP client
+# Copyright (C) 2016-2019 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 pathlib import Path
+from sat.core import log as logging
+from sat.core.i18n import _
+from sat.tools.common import data_format
+from sat_frontends.tools import jid
+from kivy.uix.boxlayout import BoxLayout
+from kivy.uix.behaviors import ButtonBehavior
+from kivy.properties import StringProperty, DictProperty, ObjectProperty
+from kivy.core.window import Window
+from kivy.metrics import dp
+from .common import ContactItem
+from .constants import Const as C
+from cagou import G
+
+
+log = logging.getLogger(__name__)
+
+
+PLUGIN_INFO = {
+    "name": _("share"),
+    "main": "Share",
+    "description": _("share a file"),
+    "icon_symbol": "share",
+}
+
+class ShareContactItem(ButtonBehavior, ContactItem):
+
+    def filterDataCb(self, data):
+        G.host.doAction('chat', jid.JID(self.jid), [self.profile])
+        chat_wid = G.host.selected_widget
+
+        if self.share_wid.type == 'text':
+            text = self.share_wid.data['text']
+            chat_wid.message_input.text += text
+        else:
+            path = self.share_wid.data['path']
+            chat_wid.transferFile(path, cleaning_cb=data.get('cleaning_cb'))
+        self.share_wid.close()
+
+    def filterDataEb(self, failure_):
+        G.host.addNote(
+            _("file filter error"),
+            _("Can't apply filter to file: {msg}").format(msg=failure_),
+            level=C.XMLUI_DATA_LVL_ERROR)
+
+    def on_press(self):
+        self.share_wid = G.host.getAncestorWidget(self, ShareWidget)
+        self.share_wid.getFilteredData(self.filterDataCb, self.filterDataEb)
+
+
+class TextPreview(BoxLayout):
+    """Widget previewing shared text"""
+    text = StringProperty()
+
+
+class ImagePreview(BoxLayout):
+    """Widget previewing shared image"""
+    path = StringProperty()
+    reduce_layout = ObjectProperty()
+    reduce_checkbox = ObjectProperty()
+
+    def _checkImageCb(self, report_raw):
+        self.report = data_format.deserialise(report_raw)
+        if self.report['too_large']:
+            self.reduce_layout.opacity = 1
+            self.reduce_layout.height = self.reduce_layout.minimum_height + dp(10)
+            self.reduce_layout.padding = [0, dp(5)]
+
+    def _checkImageEb(self, failure_):
+        log.error(f"Can't check image: {failure_}")
+
+    def on_path(self, wid, path):
+        G.host.bridge.imageCheck(
+            path, callback=self._checkImageCb, errback=self._checkImageEb)
+
+    def resizeImage(self, data, callback, errback):
+
+        def imageResizeCb(new_path):
+            new_path = Path(new_path)
+            log.debug(f"image {data['path']} resized at {new_path}")
+            data['path'] = new_path
+            data['cleaning_cb'] = lambda: new_path.unlink()
+            callback(data)
+
+        path = data['path']
+        width, height = self.report['recommended_size']
+        G.host.bridge.imageResize(
+            path, width, height,
+            callback=imageResizeCb,
+            errback=errback
+        )
+
+    def getFilter(self):
+        if self.report['too_large'] and self.reduce_checkbox.active:
+            return self.resizeImage
+        else:
+            return lambda data, callback, errback: callback(data)
+
+
+class GenericPreview(BoxLayout):
+    """Widget previewing shared image"""
+    path = StringProperty()
+
+
+class ShareWidget(BoxLayout):
+    media_type = StringProperty()
+    data = DictProperty()
+    preview_box = ObjectProperty()
+    layout = ObjectProperty()
+
+    def __init__(self, **kwargs):
+        super().__init__(**kwargs)
+        G.host.addListener("contactsFilled", self.onContactsFilled)
+        Window.bind(on_keyboard=self.key_input)
+
+    def on_kv_post(self, wid):
+        self.type, self.subtype = self.media_type.split('/')
+        if self.type == 'text':
+            self.preview_box.add_widget(TextPreview(text=self.data['text']))
+        elif self.type == 'image':
+            self.preview_box.add_widget(ImagePreview(path=self.data['path']))
+        else:
+            self.preview_box.add_widget(GenericPreview(path=self.data['path']))
+        self.addRosterContacts()
+
+    def close(self):
+        G.host.closeUI()
+
+    def on_parent(self, wid, parent):
+        if parent is None:
+            log.debug("removing contactsFilled listener")
+            G.host.removeListener("contactsFilled", self.onContactsFilled)
+
+
+    def addRosterContacts(self):
+        log.debug("starting addRosterContacts")
+        self.layout.clear_widgets()
+        for profile in G.host.profiles:
+            contact_list = G.host.contact_lists[profile]
+            for entity_jid in sorted(contact_list.roster):
+                item = ShareContactItem(
+                    jid=entity_jid,
+                    data=contact_list.getItem(entity_jid),
+                    profile=profile,
+                )
+                self.layout.add_widget(item)
+
+    def onContactsFilled(self, profile):
+        log.debug("onContactsFilled event received")
+        self.addRosterContacts()
+
+    def getFilteredData(self, callback, errback):
+        """Apply filter if suitable, and call callback with with modified data"""
+        try:
+            getFilter = self.preview_box.children[0].getFilter
+        except AttributeError:
+            callback(self.data)
+        else:
+            filter_ = getFilter()
+            filter_(self.data, callback=callback, errback=errback)
+
+    def key_input(self, window, key, scancode, codepoint, modifier):
+        if key == 27:
+            self.close()
+            return True