From 8ccbf68fd2ed2eb7c849952df93ae6cebed227d9 Mon Sep 17 00:00:00 2001 From: karolinaszczur Date: Tue, 15 Oct 2013 11:56:40 -0700 Subject: [PATCH 1/4] [ux] fix bookmark appearance --- public/css/app/roster.styl | 5 +++++ public/css/otalk.css | 3 +++ public/x-manifest.cache | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/public/css/app/roster.styl b/public/css/app/roster.styl index f1007cf..cac0d40 100644 --- a/public/css/app/roster.styl +++ b/public/css/app/roster.styl @@ -191,6 +191,11 @@ font-size: 10px color: darken($textSecondary, 50%) +#bookmarks + + .name + padding: 10px 15px 10px 40px + @keyframes pulsate 0% opacity: 1.0 diff --git a/public/css/otalk.css b/public/css/otalk.css index 9a03b24..b5919e9 100644 --- a/public/css/otalk.css +++ b/public/css/otalk.css @@ -568,6 +568,9 @@ h3 { font-size: 10px; color: #5c5c5c; } +#bookmarks .name { + padding: 10px 15px 10px 40px; +} @-moz-keyframes pulsate { 0% { opacity: 1; diff --git a/public/x-manifest.cache b/public/x-manifest.cache index 9f8d00b..a840d1c 100644 --- a/public/x-manifest.cache +++ b/public/x-manifest.cache @@ -1,5 +1,5 @@ CACHE MANIFEST -# 0.0.1 1381784954237 +# 0.0.1 1381863218449 CACHE: /app.js From d796b8816043e82cca15dbef602b4778c4233c0e Mon Sep 17 00:00:00 2001 From: karolinaszczur Date: Tue, 15 Oct 2013 12:14:16 -0700 Subject: [PATCH 2/4] [ux] small visual tweaks: sizes, placement and cancel button --- clientapp/templates/main.html | 2 +- public/css/app/aux.styl | 4 ++++ public/css/app/forms.styl | 5 ++++- public/css/app/settings.styl | 4 ++++ public/css/otalk.css | 11 +++++++++++ public/x-manifest.cache | 2 +- 6 files changed, 25 insertions(+), 3 deletions(-) diff --git a/clientapp/templates/main.html b/clientapp/templates/main.html index e9b3ae5..d4c08ff 100644 --- a/clientapp/templates/main.html +++ b/clientapp/templates/main.html @@ -11,7 +11,7 @@

Connecting...

- Cancel + Cancel
diff --git a/public/css/app/aux.styl b/public/css/app/aux.styl index 3e742f1..e7aa9d9 100644 --- a/public/css/app/aux.styl +++ b/public/css/app/aux.styl @@ -24,6 +24,10 @@ h2 padding: 0 + .button + float: none + margin-top: 20px + .head, .content padding: 0 20px diff --git a/public/css/app/forms.styl b/public/css/app/forms.styl index 8c111bc..57c411a 100644 --- a/public/css/app/forms.styl +++ b/public/css/app/forms.styl @@ -59,4 +59,7 @@ button, a.button cursor: pointer &:hover - background: darken($activeBlue, 30%) \ No newline at end of file + background: darken($activeBlue, 30%) + +.enableAlerts + margin-right: 5px \ No newline at end of file diff --git a/public/css/app/settings.styl b/public/css/app/settings.styl index c5b402b..37da7e2 100644 --- a/public/css/app/settings.styl +++ b/public/css/app/settings.styl @@ -12,6 +12,7 @@ padding: 5px background: $grayBackground roundall(3px) + font-size: $fontSmall .uploadRegion padding: 15px @@ -26,3 +27,6 @@ input width: 100% + + img + margin: 10px 0 diff --git a/public/css/otalk.css b/public/css/otalk.css index b5919e9..91085f0 100644 --- a/public/css/otalk.css +++ b/public/css/otalk.css @@ -859,6 +859,7 @@ h3 { -o-border-radius: 3px; -border-radius: 3px; border-radius: 3px; + font-size: 12px; } .uploadRegion { padding: 15px; @@ -879,6 +880,9 @@ h3 { .uploadRegion input { width: 100%; } +.uploadRegion img { + margin: 10px 0; +} .aux { background: #f7f7f7; } @@ -910,6 +914,10 @@ h3 { .box.connect h2 { padding: 0; } +.box.connect .button { + float: none; + margin-top: 20px; +} .box .head, .box .content { padding: 0 20px; @@ -1020,3 +1028,6 @@ button:hover, a.button:hover { background: #007aa7; } +.enableAlerts { + margin-right: 5px; +} diff --git a/public/x-manifest.cache b/public/x-manifest.cache index a840d1c..925d3c3 100644 --- a/public/x-manifest.cache +++ b/public/x-manifest.cache @@ -1,5 +1,5 @@ CACHE MANIFEST -# 0.0.1 1381863218449 +# 0.0.1 1381864437928 CACHE: /app.js From 274febbc7c77af6904a68929f7d86d7e4e773b5f Mon Sep 17 00:00:00 2001 From: karolinaszczur Date: Tue, 15 Oct 2013 12:52:59 -0700 Subject: [PATCH 3/4] [ux] fix call button appearance --- public/css/app/chat.styl | 12 +++++++++++- public/css/otalk.css | 13 ++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/public/css/app/chat.styl b/public/css/app/chat.styl index d98bc05..839ba84 100644 --- a/public/css/app/chat.styl +++ b/public/css/app/chat.styl @@ -45,17 +45,21 @@ left: 11px vertical-align: top + .name, .call + float: left + .name margin: 15px padding: 0px margin-left: 45px font-size: 14px line-height: 14px + max-width: 50% .tzo:not(:empty) position: absolute right: 15px - top: 25px + top: 28px height: 20px margin-top: -10px padding: 0 5px @@ -67,6 +71,12 @@ color: lighten($baseText, 30%) background: $grayOutline + .call + margin-top: 10px + height: 25px + line-height: 25px + min-width: 60px + .messages margin: 0px padding: 0px diff --git a/public/css/otalk.css b/public/css/otalk.css index 5506da4..12b42d4 100644 --- a/public/css/otalk.css +++ b/public/css/otalk.css @@ -689,17 +689,22 @@ h3 { left: 11px; vertical-align: top; } +.conversation header .name, +.conversation header .call { + float: left; +} .conversation header .name { margin: 15px; padding: 0px; margin-left: 45px; font-size: 14px; line-height: 14px; + max-width: 50%; } .conversation header .tzo:not(:empty) { position: absolute; right: 15px; - top: 25px; + top: 28px; height: 20px; margin-top: -10px; padding: 0 5px; @@ -716,6 +721,12 @@ h3 { color: #898989; background: #e4e4e4; } +.conversation header .call { + margin-top: 10px; + height: 25px; + line-height: 25px; + min-width: 60px; +} .messages { margin: 0px; padding: 0px; From d611b9fddaa1d55a2c2050d0779deb8dd07fdb6d Mon Sep 17 00:00:00 2001 From: Lance Stout Date: Tue, 15 Oct 2013 14:48:39 -0700 Subject: [PATCH 4/4] Save user profile (avatar id/status/etc) --- clientapp/app.js | 10 ++-- clientapp/helpers/xmppEventHandlers.js | 5 +- clientapp/models/me.js | 57 ++++++++++++++++------ clientapp/storage/index.js | 8 ++-- clientapp/storage/profile.js | 66 ++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 25 deletions(-) create mode 100644 clientapp/storage/profile.js diff --git a/clientapp/app.js b/clientapp/app.js index e7396a1..a8f2673 100644 --- a/clientapp/app.js +++ b/clientapp/app.js @@ -32,6 +32,7 @@ module.exports = { _.extend(this, Backbone.Events); + var profile = {}; async.series([ function (cb) { app.notifications = new Notify(); @@ -40,16 +41,17 @@ module.exports = { app.storage.open(cb); }, function (cb) { - app.storage.rosterver.get(config.jid, function (err, ver) { - if (ver) { - config.rosterVer = ver; + app.storage.profiles.get(config.jid, function (err, res) { + if (res) { + profile = res; + config.rosterVer = res.rosterVer; } cb(); }); }, function (cb) { app.state = new AppState(); - app.me = window.me = new MeModel(); + app.me = window.me = new MeModel(profile); window.onbeforeunload = function () { if (app.api.sessionStarted) { diff --git a/clientapp/helpers/xmppEventHandlers.js b/clientapp/helpers/xmppEventHandlers.js index 7b9d77e..4c0c13e 100644 --- a/clientapp/helpers/xmppEventHandlers.js +++ b/clientapp/helpers/xmppEventHandlers.js @@ -107,7 +107,7 @@ module.exports = function (client, app) { client.getRoster(function (err, resp) { resp = resp.toJSON(); - app.storage.rosterver.set(me.jid.bare, resp.roster.ver); + me.rosterVer = resp.roster.ver; _.each(resp.roster.items, function (item) { me.setContact(item, true); @@ -116,6 +116,7 @@ module.exports = function (client, app) { var caps = client.updateCaps(); app.storage.disco.add(caps.ver, caps.discoInfo, function () { client.sendPresence({ + status: me.status, caps: client.disco.caps }); client.enableCarbons(); @@ -129,7 +130,7 @@ module.exports = function (client, app) { iq = iq.toJSON(); var items = iq.roster.items; - app.storage.rosterver.set(me.jid.bare, iq.roster.ver); + me.rosterVer = iq.roster.ver; _.each(items, function (item) { var contact = me.getContact(item.jid); diff --git a/clientapp/models/me.js b/clientapp/models/me.js index 633804f..70e18b9 100644 --- a/clientapp/models/me.js +++ b/clientapp/models/me.js @@ -11,20 +11,30 @@ var fetchAvatar = require('../helpers/fetchAvatar'); module.exports = HumanModel.define({ - initialize: function () { - this.bind('change:jid', this.loadContacts, this); + initialize: function (opts) { + if (opts.avatarID) { + this.setAvatar(opts.avatarID); + } + + this.bind('change:jid', this.load, this); this.bind('change:hasFocus', function () { this.setActiveContact(this._activeContact); }, this); + this.bind('change:avatarID', this.save, this); + this.bind('change:status', this.save, this); + this.bind('change:rosterVer', this.save, this); this.contacts.bind('change:unreadCount', this.updateUnreadCount, this); app.state.bind('change:active', this.updateIdlePresence, this); }, - session: { + props: { jid: ['object', true], status: ['string', true, ''], - avatar: ['string', true, ''], avatarID: ['string', true, ''], + rosterVer: ['string', true, ''] + }, + session: { + avatar: ['string', true, ''], connected: ['bool', true, false], shouldAskForAlertsPermission: ['bool', true, false], hasFocus: ['bool', true, false], @@ -83,22 +93,30 @@ module.exports = HumanModel.define({ this.contacts.remove(jid.bare); app.storage.roster.remove(jid.bare); }, - loadContacts: function () { + load: function () { if (!this.jid.bare) return; var self = this; - app.storage.roster.getAll(this.jid.bare, function (err, contacts) { - if (err) return; - contacts.forEach(function (contact) { - contact = new Contact(contact); - contact.owner = self.jid.bare; - contact.inRoster = true; - contact.save(); - self.contacts.add(contact); + app.storage.profiles.get(this.jid.bare, function (err, profile) { + if (!err) { + self.status = profile.status; + self.avatarID = profile.avatarID; + } + self.save(); + app.storage.roster.getAll(self.jid.bare, function (err, contacts) { + if (err) return; + + contacts.forEach(function (contact) { + contact = new Contact(contact); + contact.owner = self.jid.bare; + contact.inRoster = true; + contact.save(); + self.contacts.add(contact); + }); + + self.contacts.trigger('loaded'); }); - - self.contacts.trigger('loaded'); }); }, isMe: function (jid) { @@ -124,5 +142,14 @@ module.exports = HumanModel.define({ count = ''; } app.state.badge = '' + count; + }, + save: function () { + var data = { + jid: this.jid.bare, + avatarID: this.avatarID, + status: this.status, + rosterVer: this.rosterVer + }; + app.storage.profiles.set(data); } }); diff --git a/clientapp/storage/index.js b/clientapp/storage/index.js index de83d3d..2a7383c 100644 --- a/clientapp/storage/index.js +++ b/clientapp/storage/index.js @@ -5,7 +5,7 @@ var AvatarStorage = require('./avatars'); var RosterStorage = require('./roster'); var DiscoStorage = require('./disco'); var ArchiveStorage = require('./archive'); -var RosterVerStorage = require('./rosterver'); +var ProfileStorage = require('./profile'); function Storage() { @@ -16,13 +16,13 @@ function Storage() { this.roster = new RosterStorage(this); this.disco = new DiscoStorage(this); this.archive = new ArchiveStorage(this); - this.rosterver = new RosterVerStorage(this); + this.profiles = new ProfileStorage(this); } Storage.prototype = { constructor: { value: Storage }, - version: 2, + version: 3, open: function (cb) { cb = cb || function () {}; @@ -38,7 +38,7 @@ Storage.prototype = { self.roster.setup(db); self.disco.setup(db); self.archive.setup(db); - self.rosterver.setup(db); + self.profiles.setup(db); }; request.onerror = cb; } diff --git a/clientapp/storage/profile.js b/clientapp/storage/profile.js new file mode 100644 index 0000000..d66c3ff --- /dev/null +++ b/clientapp/storage/profile.js @@ -0,0 +1,66 @@ +/*global, IDBKeyRange*/ +"use strict"; + +// SCHEMA +// jid: string +// name: string +// avatarID: string +// status: string +// rosterVer: string + + +function ProfileStorage(storage) { + this.storage = storage; +} + +ProfileStorage.prototype = { + constructor: { + value: ProfileStorage + }, + setup: function (db) { + if (db.objectStoreNames.contains('profiles')) { + db.deleteObjectStore('profiles'); + } + var store = db.createObjectStore('profiles', { + keyPath: 'jid' + }); + }, + transaction: function (mode) { + var trans = this.storage.db.transaction('profiles', mode); + return trans.objectStore('profiles'); + }, + set: function (profile, cb) { + cb = cb || function () {}; + var request = this.transaction('readwrite').put(profile); + request.onsuccess = function () { + cb(false, profile); + }; + request.onerror = cb; + }, + get: function (id, cb) { + cb = cb || function () {}; + if (!id) { + return cb('not-found'); + } + var request = this.transaction('readonly').get(id); + request.onsuccess = function (e) { + var res = request.result; + if (res === undefined) { + return cb('not-found'); + } + cb(false, request.result); + }; + request.onerror = cb; + }, + remove: function (id, cb) { + cb = cb || function () {}; + var request = this.transaction('readwrite')['delete'](id); + request.onsuccess = function (e) { + cb(false, request.result); + }; + request.onerror = cb; + } +}; + + +module.exports = ProfileStorage;