changeset 78:46d962910801

chat: file upload first draft: - added a icon to upload files - only do a basic upload with list file browser for now - use the new progressFinished and progressError listeners
author Goffi <goffi@goffi.org>
date Thu, 22 Dec 2016 19:03:06 +0100
parents bc170ccca744
children 72ab6670668f
files src/cagou/core/cagou_main.py src/cagou/plugins/plugin_wid_chat.kv src/cagou/plugins/plugin_wid_chat.py
diffstat 3 files changed, 116 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/cagou/core/cagou_main.py	Thu Dec 22 18:24:24 2016 +0100
+++ b/src/cagou/core/cagou_main.py	Thu Dec 22 19:03:06 2016 +0100
@@ -170,6 +170,9 @@
         # backend XMLUI (popups, forms, etc)
         xmlui_screen = Screen(name='xmlui')
         self._manager.add_widget(xmlui_screen)
+        # extra (file chooser, audio record, etc)
+        extra_screen = Screen(name='extra')
+        self._manager.add_widget(extra_screen)
         self.add_widget(self._manager)
 
     def changeWidget(self, widget, screen_name="main"):
@@ -553,9 +556,15 @@
         self.app.root.addNotifUI(ui)
 
     def showUI(self, ui):
+        """show a XMLUI"""
         self.app.root.changeWidget(ui, "xmlui")
         self.app.root.show("xmlui")
 
+    def showExtraUI(self, widget):
+        """show any extra widget"""
+        self.app.root.changeWidget(widget, "extra")
+        self.app.root.show("extra")
+
     def closeUI(self):
         self.app.root.show()
 
--- a/src/cagou/plugins/plugin_wid_chat.kv	Thu Dec 22 18:24:24 2016 +0100
+++ b/src/cagou/plugins/plugin_wid_chat.kv	Thu Dec 22 19:03:06 2016 +0100
@@ -14,6 +14,8 @@
 # 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/>.
 
+#:import expanduser os.path.expanduser
+#:import platform kivy.utils.platform
 
 <SimpleXHTMLWidgetEscapedText>:
     size_hint: None, None
@@ -81,7 +83,34 @@
             padding: root.mess_padding
             bold: True if root.mess_data.type == "info" else False
 
-<MessageInputWidget>:
+<MessageInputBox>:
     size_hint: 1, None
     height: dp(40)
-    hint_text: "Enter your message here"
+    message_input: message_input
+    MessageInputWidget:
+        id: message_input
+        size_hint: 1, 1
+        hint_text: "Enter your message here"
+        on_text_validate: root.parent.onSend(args[0])
+    IconButton
+        # upload button
+        source: app.expand("{media}/icons/tango/actions/32/list-add.png")
+        allow_stretch: True
+        size_hint: None, 1
+        width: max(self.texture_size[0], dp(40))
+        on_release: root.parent.onUploadButton()
+
+<FileUploader>:
+    FileChooserListView:
+        id: filechooser
+        rootpath: "/" if platform == 'android' else expanduser('~')
+    Button:
+        text: "upload"
+        size_hint: 1, None
+        height: dp(50)
+        on_release: root.parent_chat.onUploadOK(filechooser)
+    Button:
+        text: "cancel"
+        size_hint: 1, None
+        height: dp(50)
+        on_release: root.parent_chat.onUploadCancel(filechooser)
--- a/src/cagou/plugins/plugin_wid_chat.py	Thu Dec 22 18:24:24 2016 +0100
+++ b/src/cagou/plugins/plugin_wid_chat.py	Thu Dec 22 19:03:06 2016 +0100
@@ -22,6 +22,7 @@
 log = logging.getLogger(__name__)
 from sat.core.i18n import _
 from cagou.core.constants import Const as C
+from kivy.uix.boxlayout import BoxLayout
 from kivy.uix.gridlayout import GridLayout
 from kivy.uix.stacklayout import StackLayout
 from kivy.uix.scrollview import ScrollView
@@ -529,6 +530,10 @@
             self.avatar.source = update_dict['avatar']
 
 
+class MessageInputBox(BoxLayout):
+    pass
+
+
 class MessageInputWidget(TextInput):
 
     def _key_down(self, key, repeat=False):
@@ -543,7 +548,15 @@
     pass
 
 
+class FileUploader(BoxLayout):
+
+    def __init__(self, parent_chat, **kwargs):
+        self.parent_chat = parent_chat
+        super(FileUploader, self).__init__(orientation='vertical', **kwargs)
+
+
 class Chat(quick_chat.QuickChat, cagou_widget.CagouWidget):
+    message_input = properties.ObjectProperty()
 
     def __init__(self, host, target, type_=C.CHAT_ONE2ONE, nick=None, occupants=None, subject=None, profiles=None):
         quick_chat.QuickChat.__init__(self, host, target, type_, nick, occupants, subject, profiles=profiles)
@@ -553,9 +566,10 @@
         self.messages_widget = MessagesWidget()
         scroll_view.add_widget(self.messages_widget)
         self.add_widget(scroll_view)
-        message_input = MessageInputWidget()
-        message_input.bind(on_text_validate=self.onSend)
-        self.add_widget(message_input)
+        self.add_widget(MessageInputBox())
+        self.host.addListener('progressError', self.onProgressError, profiles)
+        self.host.addListener('progressFinished', self.onProgressFinished, profiles)
+        self._waiting_pids = {}  # waiting progress ids
         self.postInit()
 
     @classmethod
@@ -592,6 +606,58 @@
             )
         input_widget.text = ''
 
+    def onProgressFinished(self, progress_id, metadata, profile):
+        try:
+            callback = self._waiting_pids.pop(progress_id)
+        except KeyError:
+            return
+        callback(metadata, profile)
+
+    def onProgressError(self, progress_id, err_msg, profile):
+        try:
+            del self._waiting_pids[progress_id]
+        except KeyError:
+            return
+        # TODO: display message to user
+        log.warning(u"Can't upload file: {}".format(err_msg))
+
+    def onUploadButton(self):
+        G.host.showExtraUI(FileUploader(self))
+
+    def fileUploadDone(self, metadata, profile):
+        log.debug("file uploaded: {}".format(metadata))
+        G.host.messageSend(
+            self.target,
+            {'': metadata['url']},
+            mess_type = C.MESS_TYPE_GROUPCHAT if self.type == C.CHAT_GROUP else C.MESS_TYPE_CHAT,
+            profile_key=profile
+            )
+
+    def fileUploadCb(self, progress_data):
+        try:
+            progress_id = progress_data['progress']
+        except KeyError:
+            xmlui = progress_data['xmlui']
+            G.host.showUI(xmlui)
+        else:
+            self._waiting_pids[progress_id] = self.fileUploadDone
+
+    def onUploadOK(self, file_chooser):
+        if file_chooser.selection:
+            file_path = file_chooser.selection[0]
+            G.host.bridge.fileUpload(
+                file_path,
+                "",
+                "",
+                {"ignore_tls_errors": C.BOOL_TRUE},  # FIXME: should not be the default
+                self.profile,
+                callback = self.fileUploadCb
+                )
+        G.host.closeUI()
+
+    def onUploadCancel(self, file_chooser):
+        G.host.closeUI()
+
     def _mucJoinCb(self, joined_data):
         joined, room_jid_s, occupants, user_nick, subject, profile = joined_data
         self.host.mucRoomJoinedHandler(*joined_data[1:])
@@ -633,12 +699,17 @@
 
         G.host.bridge.discoInfos(jid_.domain, self.profile, callback=discoCb, errback=discoEb)
 
+    def _onDelete(self):
+        self.host.removeListener('progressFinished', self.onProgressFinished)
+        self.host.removeListener('progressError', self.onProgressError)
+        return super(Chat, self).onDelete()
+
     def onDelete(self, force=False):
         if force==True:
-            return super(Chat, self).onDelete()
+            return self._onDelete()
         if len(list(G.host.widgets.getWidgets(self.__class__, self.target, profiles=self.profiles))) > 1:
             # we don't keep duplicate widgets
-            return super(Chat, self).onDelete()
+            return self._onDelete()
         return False