Compare commits
	
		
			2 Commits
		
	
	
		
			3.15.91
			...
			goa-client
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					a69e45b5eb | ||
| 
						 | 
					a355398b0f | 
@@ -1655,3 +1655,49 @@ StTooltip StLabel {
 | 
			
		||||
.magnifier-zoom-region.full-screen {
 | 
			
		||||
    border-width: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* goa message popup */
 | 
			
		||||
 | 
			
		||||
.goa-message-table {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goa-message-base {
 | 
			
		||||
    font-size: 9pt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goa-message-from-header {
 | 
			
		||||
    color: #666666;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goa-message-subject-header {
 | 
			
		||||
    color: #666666;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goa-message-date-header {
 | 
			
		||||
    color: #666666;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goa-message-from {
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    min-width: 125px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goa-message-hbox {
 | 
			
		||||
    spacing: 0.25em;
 | 
			
		||||
    min-width: 300px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goa-message-subject {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goa-message-excerpt {
 | 
			
		||||
    color: rgba(153, 153, 153, 1.0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goa-message-date {
 | 
			
		||||
    min-width: 80px;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/endSessionDialog.js	\
 | 
			
		||||
	ui/environment.js	\
 | 
			
		||||
	ui/extensionSystem.js	\
 | 
			
		||||
	ui/goaClient.js		\
 | 
			
		||||
	ui/iconGrid.js		\
 | 
			
		||||
	ui/lightbox.js		\
 | 
			
		||||
	ui/link.js		\
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										500
									
								
								js/ui/goaClient.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										500
									
								
								js/ui/goaClient.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,500 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
const GLib = imports.gi.GLib;
 | 
			
		||||
const Gio = imports.gi.Gio;
 | 
			
		||||
const Goa = imports.gi.Goa;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
const C_ = Gettext.pgettext;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
const Pango = imports.gi.Pango;
 | 
			
		||||
 | 
			
		||||
const History = imports.misc.history;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function Client() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Client.prototype = {
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this._client = null;
 | 
			
		||||
 | 
			
		||||
        this._accountIdToMailMonitor = {}
 | 
			
		||||
        this._mailSource = null;
 | 
			
		||||
 | 
			
		||||
        // TODO: need to call refreshAllMonitors() when network-connectivity changes
 | 
			
		||||
 | 
			
		||||
        Goa.Client.new(null, /* cancellable */
 | 
			
		||||
                       Lang.bind(this, this._onClientConstructed));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onClientConstructed : function(object, asyncRes) {
 | 
			
		||||
        this._client = object.new_finish(asyncRes);
 | 
			
		||||
        this._updateAccounts();
 | 
			
		||||
        this._client.connect('account-added', Lang.bind(this, this._updateAccounts));
 | 
			
		||||
        this._client.connect('account-removed', Lang.bind(this, this._updateAccounts));
 | 
			
		||||
        this._client.connect('account-changed', Lang.bind(this, this._updateAccounts));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateAccounts : function () {
 | 
			
		||||
 | 
			
		||||
        let objects = this._client.get_accounts();
 | 
			
		||||
        let mailIds = {};
 | 
			
		||||
 | 
			
		||||
        // Add monitors for accounts that now exist
 | 
			
		||||
        for (let n = 0; n < objects.length; n++) {
 | 
			
		||||
            let object = objects[n];
 | 
			
		||||
            let id = object.account.id;
 | 
			
		||||
 | 
			
		||||
            if (object.mail) {
 | 
			
		||||
                mailIds[id] = true;
 | 
			
		||||
                if (!(id in this._accountIdToMailMonitor)) {
 | 
			
		||||
                    let monitor = new MailMonitor(this, object);
 | 
			
		||||
                    this._accountIdToMailMonitor[id] = monitor;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Nuke monitors for accounts that are now non-existant
 | 
			
		||||
        let monitorsToRemove = []
 | 
			
		||||
        for (let existingMonitorId in this._accountIdToMailMonitor) {
 | 
			
		||||
            if (!(existingMonitorId in mailIds)) {
 | 
			
		||||
                monitorsToRemove.push(existingMonitorId);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        for (let n = 0; n < monitorsToRemove.length; n++) {
 | 
			
		||||
            let id = monitorsToRemove[n];
 | 
			
		||||
            let monitor = this._accountIdToMailMonitor[id];
 | 
			
		||||
            delete this._accountIdToMailMonitor[id]
 | 
			
		||||
            monitor.destroy();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _ensureMailSource: function() {
 | 
			
		||||
        if (!this._mailSource) {
 | 
			
		||||
            this._mailSource = new MailSource(this);
 | 
			
		||||
            this._mailSource.connect('destroy', Lang.bind(this,
 | 
			
		||||
                                                          function () {
 | 
			
		||||
                                                              this._mailSource = null;
 | 
			
		||||
                                                          }));
 | 
			
		||||
            Main.messageTray.add(this._mailSource);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addPendingMessage: function(message) {
 | 
			
		||||
        this._ensureMailSource();
 | 
			
		||||
        this._mailSource.addMessage(message);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    refreshAllMonitors: function() {
 | 
			
		||||
        log('Refreshing all mail monitors');
 | 
			
		||||
        for (let id in this._accountIdToMailMonitor) {
 | 
			
		||||
            let monitor = this._accountIdToMailMonitor[id];
 | 
			
		||||
            monitor.refresh();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function Message(uid, from, subject, excerpt, uri, can_be_marked_as_spam, can_be_starred) {
 | 
			
		||||
    this._init(uid, from, subject, excerpt, uri, can_be_marked_as_spam, can_be_starred);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Message.prototype = {
 | 
			
		||||
    _init: function(uid, from, subject, excerpt, uri, can_be_marked_as_spam, can_be_starred) {
 | 
			
		||||
        this.uid = uid;
 | 
			
		||||
        this.from = from;
 | 
			
		||||
        this.subject = subject;
 | 
			
		||||
        this.excerpt = excerpt;
 | 
			
		||||
        this.uri = uri;
 | 
			
		||||
        this.can_be_marked_as_spam = can_be_marked_as_spam;
 | 
			
		||||
        this.can_be_starred = can_be_starred;
 | 
			
		||||
        this.receivedAt = new Date();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function MailMonitor(client, accountObject) {
 | 
			
		||||
    this._init(client, accountObject);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MailMonitor.prototype = {
 | 
			
		||||
    _init : function(client, accountObject) {
 | 
			
		||||
        this._client = client;
 | 
			
		||||
        this._accountObject = accountObject;
 | 
			
		||||
        this._account = this._accountObject.get_account();
 | 
			
		||||
        this._mail = this._accountObject.get_mail();
 | 
			
		||||
 | 
			
		||||
        // Create the remote monitor object
 | 
			
		||||
        this._proxy = null;
 | 
			
		||||
        this._cancellable = new Gio.Cancellable();
 | 
			
		||||
        this._mail.call_create_monitor(this._cancellable, Lang.bind(this, this._onMonitorCreated));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy : function() {
 | 
			
		||||
        this._cancellable.cancel();
 | 
			
		||||
        if (this._proxy) {
 | 
			
		||||
            // We don't really care if this fails or not
 | 
			
		||||
            this._proxy.call_close(null, Lang.bind(this, function() { }));
 | 
			
		||||
            this._proxy.disconnect(this._messageReceivedId);
 | 
			
		||||
            this._proxy = null;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    refresh : function() {
 | 
			
		||||
        if (this._proxy) {
 | 
			
		||||
            // We don't really care if this fails or not
 | 
			
		||||
            log('Refreshing mail monitor for account ' + this._account.name);
 | 
			
		||||
            this._proxy.call_refresh(null, Lang.bind(this, function() { }));
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onMonitorCreated : function(mail, asyncRes) {
 | 
			
		||||
        // TODO: a (gboolean, object_path) tuple is returned here
 | 
			
		||||
        // See https://bugzilla.gnome.org/show_bug.cgi?id=649657
 | 
			
		||||
        let ret = mail.call_create_monitor_finish(asyncRes);
 | 
			
		||||
        let object_path = ret[1];
 | 
			
		||||
        Goa.MailMonitorProxy.new_for_bus(Gio.BusType.SESSION,
 | 
			
		||||
                                       Gio.DBusProxyFlags.NONE,
 | 
			
		||||
                                       'org.gnome.OnlineAccounts',
 | 
			
		||||
                                       object_path,
 | 
			
		||||
                                       null, /* cancellable */
 | 
			
		||||
                                       Lang.bind(this, this._onMonitorProxyConstructed));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onMonitorProxyConstructed : function(monitor, asyncRes) {
 | 
			
		||||
        this._proxy = monitor.new_for_bus_finish(asyncRes);
 | 
			
		||||
 | 
			
		||||
        // Now listen for changes on the mail monitor proxy
 | 
			
		||||
        this._messageReceivedId = this._proxy.connect('message-received',
 | 
			
		||||
                                                      Lang.bind(this, this._onMessageReceived));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onMessageReceived : function(monitor, uid, from, subject, excerpt, uri, can_be_marked_as_spam, can_be_starred) {
 | 
			
		||||
        let message = new Message(uid, from, subject, excerpt, uri, can_be_marked_as_spam, can_be_starred);
 | 
			
		||||
        if (!Main.messageTray.getBusy()) {
 | 
			
		||||
            let source = new Source(this._client, message);
 | 
			
		||||
            let notification = new Notification(source, this._client, this, message);
 | 
			
		||||
            // If the user is not marked as busy, present the notification to the user
 | 
			
		||||
            Main.messageTray.add(source);
 | 
			
		||||
            source.notify(notification);
 | 
			
		||||
        } else {
 | 
			
		||||
            // ... otherwise, if the user is busy, just add it to the MailSource's list
 | 
			
		||||
            // of pending messages
 | 
			
		||||
            this._client.addPendingMessage(message);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    MessageAddStar: function (message) {
 | 
			
		||||
        this._proxy.call_add_star(message.uid,
 | 
			
		||||
                                  null, /* cancellable */
 | 
			
		||||
                                  Lang.bind(this,
 | 
			
		||||
                                            function(object, asyncRes) {
 | 
			
		||||
                                                this._proxy.call_add_star_finish(asyncRes);
 | 
			
		||||
                                            }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    MessageMarkAsSpam: function (message) {
 | 
			
		||||
        this._proxy.call_mark_as_spam(message.uid,
 | 
			
		||||
                                      null, /* cancellable */
 | 
			
		||||
                                      Lang.bind(this,
 | 
			
		||||
                                                function(object, asyncRes) {
 | 
			
		||||
                                                    this._proxy.call_add_star_finish(asyncRes);
 | 
			
		||||
                                                }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function Source(client, message) {
 | 
			
		||||
    this._init(client, message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Source.prototype = {
 | 
			
		||||
    __proto__:  MessageTray.Source.prototype,
 | 
			
		||||
 | 
			
		||||
    _init : function(client, message) {
 | 
			
		||||
        this._client = client;
 | 
			
		||||
        this._message = message;
 | 
			
		||||
 | 
			
		||||
        // Init super class and add ourselves to the message tray
 | 
			
		||||
        MessageTray.Source.prototype._init.call(this, 'Message from ' + _stripEmailAddress(this._message.from));
 | 
			
		||||
        this.setTransient(true);
 | 
			
		||||
        this.isChat = true;
 | 
			
		||||
        this._setSummaryIcon(this.createNotificationIcon());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createNotificationIcon : function() {
 | 
			
		||||
        // TODO: use account icon
 | 
			
		||||
        let icon = new St.Icon({ icon_type: St.IconType.FULLCOLOR,
 | 
			
		||||
                                 icon_size: this.ICON_SIZE,
 | 
			
		||||
                                 icon_name: 'mail-send'});
 | 
			
		||||
        return icon;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function _stripEmailAddress(name_and_addr) {
 | 
			
		||||
    let bracketStartPos = name_and_addr.indexOf(' <');
 | 
			
		||||
    if (bracketStartPos == -1) {
 | 
			
		||||
        return name_and_addr;
 | 
			
		||||
    } else {
 | 
			
		||||
        return name_and_addr.slice(0, bracketStartPos);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Notification(source, client, monitor, message) {
 | 
			
		||||
    this._init(source, client, monitor, message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Notification.prototype = {
 | 
			
		||||
    __proto__: MessageTray.Notification.prototype,
 | 
			
		||||
 | 
			
		||||
    _init : function(source, client, monitor, message) {
 | 
			
		||||
        this._client = client;
 | 
			
		||||
        this._monitor = monitor
 | 
			
		||||
        this._message = message;
 | 
			
		||||
        this._ignore = false;
 | 
			
		||||
        this._alreadyExpanded = false;
 | 
			
		||||
 | 
			
		||||
        this._strippedFrom = _stripEmailAddress(this._message.from);
 | 
			
		||||
 | 
			
		||||
        let title = this._strippedFrom;
 | 
			
		||||
        let banner = this._message.subject + ' \u2014 ' + this._message.excerpt; // — U+2014 EM DASH
 | 
			
		||||
 | 
			
		||||
        // Init super class
 | 
			
		||||
        MessageTray.Notification.prototype._init.call(this, source, title, banner);
 | 
			
		||||
 | 
			
		||||
        // Change the contents once expanded
 | 
			
		||||
        this.connect('expanded', Lang.bind (this, this._onExpanded));
 | 
			
		||||
 | 
			
		||||
        this.update(title, banner);
 | 
			
		||||
        this.setUrgency(MessageTray.Urgency.NORMAL);
 | 
			
		||||
        this.setTransient(true);
 | 
			
		||||
 | 
			
		||||
        this.addButton('ignore', 'Ignore');
 | 
			
		||||
        if (message.can_be_starred)
 | 
			
		||||
            this.addButton('star', 'Star');
 | 
			
		||||
        if (message.can_be_marked_as_spam)
 | 
			
		||||
            this.addButton('spam', 'Junk');
 | 
			
		||||
        if (this._message.uri.length > 0) {
 | 
			
		||||
            this.addButton('open', 'Open');
 | 
			
		||||
        }
 | 
			
		||||
        this.connect('action-invoked', Lang.bind(this,
 | 
			
		||||
                                                 function(notification, id) {
 | 
			
		||||
                                                     if (id == 'ignore') {
 | 
			
		||||
                                                         this._actionIgnore();
 | 
			
		||||
                                                     } else if (id == 'star') {
 | 
			
		||||
                                                         this._actionStar();
 | 
			
		||||
                                                     } else if (id == 'spam') {
 | 
			
		||||
                                                         this._actionSpam();
 | 
			
		||||
                                                     } else if (id == 'open') {
 | 
			
		||||
                                                         this._actionOpen();
 | 
			
		||||
                                                     }
 | 
			
		||||
                                                 }));
 | 
			
		||||
        this.connect('clicked', Lang.bind(this,
 | 
			
		||||
                                          function() {
 | 
			
		||||
                                              if (this._message.uri.length > 0) {
 | 
			
		||||
                                                  this._actionOpen();
 | 
			
		||||
                                              }
 | 
			
		||||
                                          }));
 | 
			
		||||
        // Hmm, should be ::done-displaying instead?
 | 
			
		||||
        this.connect('destroy', Lang.bind(this, this._onDestroyed));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onExpanded : function() {
 | 
			
		||||
        if (this._alreadyExpanded)
 | 
			
		||||
            return;
 | 
			
		||||
        this._alreadyExpanded = true;
 | 
			
		||||
        let escapedExcerpt = GLib.markup_escape_text(this._message.excerpt, -1);
 | 
			
		||||
        let bannerMarkup = '<b>Subject:</b> ' + this._message.subject + '\n';
 | 
			
		||||
        // TODO: if available, insert other headers such as Cc
 | 
			
		||||
        bannerMarkup += '\n' + escapedExcerpt;
 | 
			
		||||
        this.update(this._strippedFrom, bannerMarkup, {bannerMarkup: true});
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDestroyed : function(reason) {
 | 
			
		||||
        // If not ignoring the message, push it onto the Mail source
 | 
			
		||||
        if (!this._ignore) {
 | 
			
		||||
            this._client.addPendingMessage(this._message);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _actionIgnore : function() {
 | 
			
		||||
        this._ignore = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _actionStar : function() {
 | 
			
		||||
        this._ignore = true;
 | 
			
		||||
        this._monitor.MessageAddStar(this._message);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _actionSpam : function() {
 | 
			
		||||
        this._ignore = true;
 | 
			
		||||
        this._monitor.MessageMarkAsSpam(this._message);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _actionOpen : function() {
 | 
			
		||||
        this._ignore = true;
 | 
			
		||||
        Gio.app_info_launch_default_for_uri(this._message.uri,
 | 
			
		||||
                                            global.create_app_launch_context());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
function _sameDay(dateA, dateB) {
 | 
			
		||||
    return (dateA.getDate() == dateB.getDate() &&
 | 
			
		||||
            dateA.getMonth() == dateB.getMonth() &&
 | 
			
		||||
            dateA.getYear() == dateB.getYear());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _sameYear(dateA, dateB) {
 | 
			
		||||
    return (dateA.getYear() == dateB.getYear());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _formatRelativeDate(date) {
 | 
			
		||||
    let ret = ''
 | 
			
		||||
    let now = new Date();
 | 
			
		||||
    if (_sameDay(date, now)) {
 | 
			
		||||
        ret = date.toLocaleFormat("%l:%M %p");
 | 
			
		||||
    } else {
 | 
			
		||||
        if (_sameYear(date, now)) {
 | 
			
		||||
            ret = date.toLocaleFormat("%B %e");
 | 
			
		||||
        } else {
 | 
			
		||||
            ret = date.toLocaleFormat("%B %e, %Y");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _addMessageToTable(table, message) {
 | 
			
		||||
    let formattedExcerpt = message.excerpt.replace(/\r/g, '').replace(/\n/g, ' ');
 | 
			
		||||
    let formattedDate = _formatRelativeDate(message.receivedAt);
 | 
			
		||||
 | 
			
		||||
    let fromLabel = new St.Label({ style_class: 'goa-message-base goa-message-from',
 | 
			
		||||
                                   text: _stripEmailAddress(message.from)});
 | 
			
		||||
    let hbox = new St.BoxLayout({ style_class: 'goa-message-hbox', vertical: false });
 | 
			
		||||
    let subjectLabel = new St.Label({ style_class: 'goa-message-base goa-message-subject',
 | 
			
		||||
                                      text: message.subject });
 | 
			
		||||
    let excerptLabel = new St.Label({ style_class: 'goa-message-base goa-message-excerpt',
 | 
			
		||||
                                      text: formattedExcerpt });
 | 
			
		||||
    let dateLabel = new St.Label({ style_class: 'goa-message-base goa-message-date',
 | 
			
		||||
                                   text: formattedDate });
 | 
			
		||||
 | 
			
		||||
    excerptLabel.clutter_text.line_wrap = false;
 | 
			
		||||
    excerptLabel.clutter_text.ellipsize = Pango.EllipsizeMode.END;
 | 
			
		||||
 | 
			
		||||
    hbox.add(subjectLabel, { x_fill:  true,
 | 
			
		||||
                             y_fill:  false,
 | 
			
		||||
                             x_align: St.Align.END,
 | 
			
		||||
                             y_align: St.Align.START });
 | 
			
		||||
    hbox.add(excerptLabel, { x_fill:  true,
 | 
			
		||||
                             y_fill:  false,
 | 
			
		||||
                             x_align: St.Align.END,
 | 
			
		||||
                             y_align: St.Align.START });
 | 
			
		||||
 | 
			
		||||
    let n = table.get_row_count();
 | 
			
		||||
    table.add(fromLabel, { x_fill: true, x_expand: true, row: n, col: 0 });
 | 
			
		||||
    table.add(hbox, { row: n, col: 1 });
 | 
			
		||||
    table.add(dateLabel, { row: n, col: 2 });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function MailSource(client) {
 | 
			
		||||
    this._init(client);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MailSource.prototype = {
 | 
			
		||||
    __proto__:  MessageTray.Source.prototype,
 | 
			
		||||
 | 
			
		||||
    _init : function(client) {
 | 
			
		||||
        this._client = client;
 | 
			
		||||
        this._pendingMessages = [];
 | 
			
		||||
 | 
			
		||||
        // Init super class and add ourselves to the message tray
 | 
			
		||||
        MessageTray.Source.prototype._init.call(this, 'Mail');
 | 
			
		||||
 | 
			
		||||
        // Create the notification
 | 
			
		||||
        this._notification = new MessageTray.Notification(this)
 | 
			
		||||
        this._notification.setUrgency(MessageTray.Urgency.NORMAL);
 | 
			
		||||
        this._notification.setResident(true);
 | 
			
		||||
        this._updateNotification();
 | 
			
		||||
        this.pushNotification(this._notification);
 | 
			
		||||
        // Refresh all monitors everytime the "Mail" notification is displayed
 | 
			
		||||
        this._notification.connect('expanded', Lang.bind(this,
 | 
			
		||||
                                                         function() {
 | 
			
		||||
                                                             this._client.refreshAllMonitors();
 | 
			
		||||
                                                         }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createNotificationIcon : function() {
 | 
			
		||||
        let numPending = this._pendingMessages.length;
 | 
			
		||||
        let baseIcon = new Gio.ThemedIcon({ name: 'mail-mark-unread'});
 | 
			
		||||
        let numerableIcon = new Gtk.NumerableIcon({ gicon: baseIcon });
 | 
			
		||||
        numerableIcon.set_count(numPending);
 | 
			
		||||
        let icon = new St.Icon({ icon_type: St.IconType.FULLCOLOR,
 | 
			
		||||
                                 icon_size: this.ICON_SIZE });
 | 
			
		||||
        icon.set_gicon(numerableIcon);
 | 
			
		||||
        return icon;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateNotification: function() {
 | 
			
		||||
        if (!this._notification)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        let title = 'Mail';
 | 
			
		||||
        let banner = ''
 | 
			
		||||
        let table = new St.Table({ homogeneous: false,
 | 
			
		||||
                                   style_class: 'goa-message-table',
 | 
			
		||||
                                   reactive: true });
 | 
			
		||||
 | 
			
		||||
        for (let n = 0; n < this._pendingMessages.length; n++)
 | 
			
		||||
            _addMessageToTable (table, this._pendingMessages[n]);
 | 
			
		||||
 | 
			
		||||
        this._notification.update(title, banner, { clear: true,
 | 
			
		||||
                                                   icon: this.createNotificationIcon() });
 | 
			
		||||
        this._notification.addActor(table);
 | 
			
		||||
        this._notification.addButton('close', 'Close');
 | 
			
		||||
        this._notification.addButton('ignore-all', 'Ignore All');
 | 
			
		||||
        this._notification.connect('action-invoked', Lang.bind(this,
 | 
			
		||||
                                                               function(notification, id) {
 | 
			
		||||
                                                                   if (id == 'close') {
 | 
			
		||||
                                                                       // TODO: Can't find another way hide it
 | 
			
		||||
                                                                       notification._onClicked();
 | 
			
		||||
                                                                   } else if (id == 'ignore-all') {
 | 
			
		||||
                                                                       this.clearMessages();
 | 
			
		||||
                                                                   }
 | 
			
		||||
                                                               }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addMessage: function(message) {
 | 
			
		||||
        this._pendingMessages.push(message);
 | 
			
		||||
        // Update notification
 | 
			
		||||
        this._updateNotification();
 | 
			
		||||
        // Update icon with latest pending count
 | 
			
		||||
        this._setSummaryIcon(this.createNotificationIcon());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    clearMessages: function() {
 | 
			
		||||
        let notification = this._notification;
 | 
			
		||||
        this._notification = null;
 | 
			
		||||
        if (notification)
 | 
			
		||||
            notification.destroy();
 | 
			
		||||
        this.destroy();
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -29,6 +29,7 @@ const WindowAttentionHandler = imports.ui.windowAttentionHandler;
 | 
			
		||||
const Scripting = imports.ui.scripting;
 | 
			
		||||
const ShellDBus = imports.ui.shellDBus;
 | 
			
		||||
const TelepathyClient = imports.ui.telepathyClient;
 | 
			
		||||
const GoaClient = imports.ui.goaClient;
 | 
			
		||||
const WindowManager = imports.ui.windowManager;
 | 
			
		||||
const Magnifier = imports.ui.magnifier;
 | 
			
		||||
const XdndHandler = imports.ui.xdndHandler;
 | 
			
		||||
@@ -50,6 +51,7 @@ let messageTray = null;
 | 
			
		||||
let notificationDaemon = null;
 | 
			
		||||
let windowAttentionHandler = null;
 | 
			
		||||
let telepathyClient = null;
 | 
			
		||||
let goaClient = null;
 | 
			
		||||
let ctrlAltTabManager = null;
 | 
			
		||||
let recorder = null;
 | 
			
		||||
let shellDBusService = null;
 | 
			
		||||
@@ -139,6 +141,7 @@ function start() {
 | 
			
		||||
    notificationDaemon = new NotificationDaemon.NotificationDaemon();
 | 
			
		||||
    windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
 | 
			
		||||
    telepathyClient = new TelepathyClient.Client();
 | 
			
		||||
    goaClient = new GoaClient.Client();
 | 
			
		||||
 | 
			
		||||
    overview.init();
 | 
			
		||||
    statusIconDispatcher.start(messageTray.actor);
 | 
			
		||||
 
 | 
			
		||||
@@ -1301,6 +1301,10 @@ MessageTray.prototype = {
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getBusy: function(source) {
 | 
			
		||||
        return this._busy;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    contains: function(source) {
 | 
			
		||||
        return this._getIndexOfSummaryItemForSource(source) >= 0;
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
@@ -1174,17 +1174,17 @@ load_gicon_with_colors (StTextureCache    *cache,
 | 
			
		||||
{
 | 
			
		||||
  AsyncTextureLoadData *request;
 | 
			
		||||
  ClutterActor *texture;
 | 
			
		||||
  char *gicon_string;
 | 
			
		||||
  guint gicon_hash;
 | 
			
		||||
  char *key;
 | 
			
		||||
  GtkIconTheme *theme;
 | 
			
		||||
  GtkIconInfo *info;
 | 
			
		||||
 | 
			
		||||
  gicon_string = g_icon_to_string (icon);
 | 
			
		||||
  gicon_hash = g_icon_hash (icon);
 | 
			
		||||
  if (colors)
 | 
			
		||||
    {
 | 
			
		||||
      /* This raises some doubts about the practice of using string keys */
 | 
			
		||||
      key = g_strdup_printf (CACHE_PREFIX_GICON "icon=%s,size=%d,colors=%2x%2x%2x%2x,%2x%2x%2x%2x,%2x%2x%2x%2x,%2x%2x%2x%2x",
 | 
			
		||||
                             gicon_string, size,
 | 
			
		||||
      key = g_strdup_printf (CACHE_PREFIX_GICON "icon_hash=%u,size=%d,colors=%2x%2x%2x%2x,%2x%2x%2x%2x,%2x%2x%2x%2x,%2x%2x%2x%2x",
 | 
			
		||||
                             gicon_hash, size,
 | 
			
		||||
                             colors->foreground.red, colors->foreground.blue, colors->foreground.green, colors->foreground.alpha,
 | 
			
		||||
                             colors->warning.red, colors->warning.blue, colors->warning.green, colors->warning.alpha,
 | 
			
		||||
                             colors->error.red, colors->error.blue, colors->error.green, colors->error.alpha,
 | 
			
		||||
@@ -1192,10 +1192,9 @@ load_gicon_with_colors (StTextureCache    *cache,
 | 
			
		||||
    }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      key = g_strdup_printf (CACHE_PREFIX_GICON "icon=%s,size=%d",
 | 
			
		||||
                             gicon_string, size);
 | 
			
		||||
      key = g_strdup_printf (CACHE_PREFIX_GICON "icon_hash=%u,size=%d",
 | 
			
		||||
                             gicon_hash, size);
 | 
			
		||||
    }
 | 
			
		||||
  g_free (gicon_string);
 | 
			
		||||
 | 
			
		||||
  if (create_texture_and_ensure_request (cache, key, size, &request, &texture))
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user