[polari] Add support for pasting image to public image service



commit e5c418909d8e5fe49f0ba5ab60def7f2d71f4ae1
Author: Kunaal Jain <kunaalus gmail com>
Date:   Thu Feb 11 09:46:32 2016 +0530

    Add support for pasting image to public image service
    
    Support pasting images in polari by uploading them
    to public image service (currently Imgur).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=760346

 src/application.js  |    3 +++
 src/entryArea.js    |   24 +++++++++++++++++++++++-
 src/pasteManager.js |   44 ++++++++++++++++++++++++++++++++++++++++++++
 src/utils.js        |   38 +++++++++++++++++++++++++++++++++++++-
 4 files changed, 107 insertions(+), 2 deletions(-)
---
diff --git a/src/application.js b/src/application.js
index b0ca0cf..a1e50d6 100644
--- a/src/application.js
+++ b/src/application.js
@@ -385,6 +385,9 @@ const Application = new Lang.Class({
                 let text = data.toString();
                 this.pasteManager.pasteText(text);
                 break;
+            case PasteManager.DndTargetType.IMAGE:
+                this.pasteManager.pasteImage(data);
+                break;
             default:
                 log('Unhandled paste content of type %d'.format(type));
         }
diff --git a/src/entryArea.js b/src/entryArea.js
index dff3187..320750f 100644
--- a/src/entryArea.js
+++ b/src/entryArea.js
@@ -1,4 +1,5 @@
 const Gdk = imports.gi.Gdk;
+const GdkPixbuf = imports.gi.GdkPixbuf;
 const GLib = imports.gi.GLib;
 const GObject = imports.gi.GObject;
 const Gtk = imports.gi.Gtk;
@@ -19,7 +20,8 @@ const ChatEntry = new Lang.Class({
     Name: 'ChatEntry',
     Extends: Gtk.Entry,
     Signals: { 'text-pasted': { param_types: [GObject.TYPE_STRING,
-                                              GObject.TYPE_INT] } },
+                                              GObject.TYPE_INT] },
+               'image-pasted': { param_types: [GdkPixbuf.Pixbuf.$gtype] } },
 
     _init: function(params) {
         this.parent(params);
@@ -50,6 +52,13 @@ const ChatEntry = new Lang.Class({
                 this.emit('paste-clipboard');
                 this._useDefaultHandler = false;
             }));
+
+        clipboard.request_image(Lang.bind(this,
+            function(clipboard, pixbuf) {
+                if (pixbuf == null)
+                    return;
+                this.emit('image-pasted', pixbuf);
+            }));
     },
 });
 
@@ -105,6 +114,7 @@ const EntryArea = new Lang.Class({
         this._nickPopover.set_default_widget(this._changeButton);
 
         this._chatEntry.connect('text-pasted', Lang.bind(this, this._onTextPasted));
+        this._chatEntry.connect('image-pasted', Lang.bind(this, this._onImagePasted));
         this._chatEntry.connect('changed', Lang.bind(this, this._onEntryChanged));
 
         this._chatEntry.connect('activate', Lang.bind(this,
@@ -215,6 +225,18 @@ const EntryArea = new Lang.Class({
         this._pasteButton.grab_focus();
     },
 
+    _onImagePasted: function(entry, data) {
+        this._multiLineLabel.label = _("Upload image to public paste service?");
+
+        let [success, buffer] = data.save_to_bufferv('png',[],[]);
+        if (!success)
+            return;
+
+        this._pasteButton.action_target = new GLib.Variant('(ayi)', [buffer, 
PasteManager.DndTargetType.IMAGE]);
+        this.visible_child_name = 'multiline';
+        this._pasteButton.grab_focus();
+    },
+
     _onButtonClicked: function() {
             this._chatEntry.text = '';
             this.visible_child_name = 'default';
diff --git a/src/pasteManager.js b/src/pasteManager.js
index cccd048..2b02080 100644
--- a/src/pasteManager.js
+++ b/src/pasteManager.js
@@ -81,6 +81,14 @@ const PasteManager = new Lang.Class({
         this._pasteText(text, n);
     },
 
+    pasteImage: function(data) {
+        let app = Gio.Application.get_default();
+        let n = new UploadNotification("image");
+        app.notificationQueue.addNotification(n);
+
+        this._pasteImage(data, n);
+    },
+
     _pasteText: function(text, notification) {
         let room = this._roomManager.getActiveRoom();
         if (!room) {
@@ -120,6 +128,42 @@ const PasteManager = new Lang.Class({
             }));
     },
 
+    _pasteImage: function(data, notification) {
+        let room = this._roomManager.getActiveRoom();
+        if (!room) {
+            notification.close();
+            return;
+        }
+
+        let title;
+        let nick = room.channel.connection.self_contact.alias;
+        if (room.type == Tp.HandleType.ROOM)
+            /* translators: %s is a nick, #%s a channel */
+            title = _("%s in #%s").format(nick, room.display_name);
+        else
+            title = _("Paste from %s").format(nick);
+
+        Utils.imgurPaste(data, title, Lang.bind(this,
+            function(url) {
+                if (!url) {
+                    notification.close();
+                    return;
+                }
+
+                let type = Tp.ChannelTextMessageType.NORMAL;
+                let message = Tp.ClientMessage.new_text(type, url);
+                room.channel.send_message_async(message, 0, Lang.bind(this,
+                    function(c, res) {
+                        try {
+                             c.send_message_finish(res);
+                        } catch(e) {
+                             logError(e, 'Failed to send message')
+                        }
+                        notification.close();
+                    }));
+            }));
+    },
+
     _onDragDrop: function(widget, context, x, y, time) {
         if (!Polari.drag_dest_supports_target(widget, context, null))
             return Gdk.EVENT_PROPAGATE;
diff --git a/src/utils.js b/src/utils.js
index e9643b8..6d8dea7 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -36,7 +36,9 @@ const SECRET_SCHEMA = new Secret.Schema(
     { 'account-id': Secret.SchemaAttributeType.STRING }
 );
 
-const GPASTE_BASEURL = 'https://paste.gnome.org/'
+const GPASTE_BASEURL = 'https://paste.gnome.org/';
+
+const IMGUR_CLIENT_ID = '4109e59177ec95e';
 
 // http://daringfireball.net/2010/07/improved_regex_for_matching_urls
 const _balancedParens = '\\((?:[^\\s()<>]+|(?:\\(?:[^\\s()<>]+\\)))*\\)';
@@ -204,3 +206,37 @@ function gpaste(text, title, callback) {
                 callback(null);
         });
 }
+
+function imgurPaste(data, title, callback) {
+    let base64EncodedBuffer = GLib.base64_encode(data);
+
+    let params = {
+        title: title,
+        image: base64EncodedBuffer
+    };
+
+    let session = new Soup.Session();
+    let createUrl = 'https://api.imgur.com/3/image';
+    let message = Soup.form_request_new_from_hash('POST', createUrl, params);
+
+    let requestHeaders = message.request_headers;
+    requestHeaders.append('Authorization', 'Client-ID ' + IMGUR_CLIENT_ID);
+    session.queue_message(message,
+        function(session, message) {
+            if (message.status_code != Soup.KnownStatusCode.OK) {
+                callback(null);
+                return;
+            }
+
+            let info = {};
+            try {
+                info = JSON.parse(message.response_body.data);
+            } catch(e) {
+                log(e.message);
+            }
+            if (info.success)
+                callback(info.data.link);
+            else
+                callback(null);
+        });
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]