diff --git a/UI/MailerUI/UIxMailListActions.m b/UI/MailerUI/UIxMailListActions.m index 677d642d4..0f1c11abe 100644 --- a/UI/MailerUI/UIxMailListActions.m +++ b/UI/MailerUI/UIxMailListActions.m @@ -1,6 +1,5 @@ /* - Copyright (C) 2004-2005 SKYRIX Software AG - Copyright (C) 2006-2013 Inverse inc. + Copyright (C) 2006-2014 Inverse inc. This file is part of SOGo @@ -32,8 +31,10 @@ #import #import #import +#import /* for locale string constants */ #import +#import #import #import #import @@ -59,6 +60,7 @@ #import #import #import +#import #import #import @@ -128,11 +130,20 @@ } else if ([now dayOfCommonEra] - [messageDate dayOfCommonEra] == 1) { + // Yesterday return [self labelForKey: @"Yesterday"]; } + else if ([now dayOfCommonEra] - [messageDate dayOfCommonEra] < 7) + { + // Same week + WOResourceManager *resMgr = [[WOApplication application] resourceManager]; + NSString *language = [[[context activeUser] userDefaults] language]; + NSDictionary *locale = [resMgr localeForLanguageNamed: language]; + return [[locale objectForKey: NSWeekDayNameArray] objectAtIndex: [messageDate dayOfWeek]]; + } else { - return [dateFormatter formattedDate: messageDate]; + return [dateFormatter shortFormattedDate: messageDate]; } } @@ -690,7 +701,7 @@ msgsList = [[msgs objectForKey: @"fetch"] objectEnumerator]; [self setMessage: [msgsList nextObject]]; - msg = [NSMutableArray arrayWithObjects: @"To", @"hasAttachment", @"isFlagged", @"Subject", @"From", @"isRead", @"Priority", @"Date", @"Size", @"Flags", @"uid", nil]; + msg = [NSMutableArray arrayWithObjects: @"To", @"hasAttachment", @"isFlagged", @"Subject", @"From", @"isRead", @"Priority", @"RelativeDate", @"Size", @"Flags", @"uid", nil]; [headers addObject: msg]; while (message) { @@ -748,7 +759,7 @@ // Priority [msg addObject: [self messagePriority]]; - // Date + // Relative Date msgDate = [self messageDate]; if (msgDate == nil) msgDate = @""; diff --git a/UI/MailerUI/UIxMailView.m b/UI/MailerUI/UIxMailView.m index 631253c85..819501986 100644 --- a/UI/MailerUI/UIxMailView.m +++ b/UI/MailerUI/UIxMailView.m @@ -1,6 +1,5 @@ /* - Copyright (C) 2004-2005 SKYRIX Software AG - Copyright (C) 2005-2013 Inverse inc. + Copyright (C) 2005-2014 Inverse inc. This file is part of SOGo. @@ -15,7 +14,7 @@ License for more details. You should have received a copy of the GNU Lesser General Public - License along with OGo; see the file COPYING. If not, write to the + License along with SOGo; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -194,17 +193,23 @@ static NSString *mailETag = nil; - (NSArray *) formattedAddresses: (NSArray *) theAddresses { NSMutableArray *addresses; - NSFormatter *formatter; - NGImap4EnvelopeAddress *address; + NSMutableDictionary *metaAddress; + NSString *name, *address; + NGImap4EnvelopeAddress *envelopeAddress; int count, i; - formatter = [[self context] mailEnvelopeFullAddressFormatter]; count = [theAddresses count]; addresses = [NSMutableArray arrayWithCapacity: count]; for (i = 0; i < count; i++) { - address = [theAddresses objectAtIndex: i]; - [addresses addObject: [formatter stringForObjectValue: address]]; + envelopeAddress = [theAddresses objectAtIndex: i]; + address = [envelopeAddress baseEMail]; + name = [envelopeAddress personalName]; + metaAddress = [NSMutableDictionary dictionaryWithObject: address forKey: @"address"]; + if (name) + [metaAddress setObject: name forKey: @"name"]; + + [addresses addObject: metaAddress]; } return addresses; diff --git a/UI/Templates/MailerUI/UIxMailMainFrame.wox b/UI/Templates/MailerUI/UIxMailMainFrame.wox index 7e038dc8b..40cbd7c05 100644 --- a/UI/Templates/MailerUI/UIxMailMainFrame.wox +++ b/UI/Templates/MailerUI/UIxMailMainFrame.wox @@ -254,7 +254,7 @@
{{currentMessage.from}} - +
{{currentMessage.subject}}
-

+

+
+
+ +
- {{message.subject}} {{flag}}
-
-
- -
-
- {{addr}} -
-
diff --git a/UI/Templates/Themes/mobile/MailerUI/UIxMailMainFrame.wox b/UI/Templates/Themes/mobile/MailerUI/UIxMailMainFrame.wox new file mode 100644 index 000000000..144a2eb92 --- /dev/null +++ b/UI/Templates/Themes/mobile/MailerUI/UIxMailMainFrame.wox @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + diff --git a/UI/WebServerResources/js/Mailer/message-model.js b/UI/WebServerResources/js/Mailer/message-model.js index fb55ef572..67495e052 100644 --- a/UI/WebServerResources/js/Mailer/message-model.js +++ b/UI/WebServerResources/js/Mailer/message-model.js @@ -101,6 +101,15 @@ Message.$timeout(function() { angular.extend(_this, data); _this.id = _this.$absolutePath(); + // Build long representation of email addresses + _.each(['from', 'to', 'cc', 'bcc', 'replyTo'], function(type) { + _.each(_this[type + 'Addresses'], function(data, i) { + if (data.name != data.address) + data.full = data.name + ' <' + data.address + '>'; + else + data.full = '<' + data.address + '>'; + }); + }); deferred.resolve(_this.content); }); }, function(data) { diff --git a/UI/WebServerResources/js/MailerUI.js b/UI/WebServerResources/js/MailerUI.js index db552ac6b..c1f46860a 100644 --- a/UI/WebServerResources/js/MailerUI.js +++ b/UI/WebServerResources/js/MailerUI.js @@ -144,7 +144,6 @@ $scope.setCurrentFolder = function(account, folder) { $rootScope.currentFolder = folder; - console.debug('setCurrentFolder ' + folder.type + ' ' + account.id + ' ' + encodeUriFilter(folder.path)) $state.go('mail.account.mailbox', { accountId: account.id, mailboxId: encodeUriFilter(folder.path) }); }; @@ -156,7 +155,6 @@ }]) .controller('MailboxCtrl', ['$scope', '$rootScope', '$stateParams', 'stateAccount', 'stateMailbox', '$timeout', '$modal', 'sgFocus', 'sgDialog', 'sgAccount', 'sgMailbox', function($scope, $rootScope, $stateParams, stateAccount, stateMailbox, $timeout, $modal, focus, Dialog, Account, Mailbox) { - console.debug('MailboxCtrl ' + stateMailbox.path); $scope.account = stateAccount; $scope.mailbox = stateMailbox; $rootScope.currentFolder = stateMailbox; diff --git a/UI/WebServerResources/js/mobile/MailerUI.js b/UI/WebServerResources/js/mobile/MailerUI.js new file mode 100644 index 000000000..345e59765 --- /dev/null +++ b/UI/WebServerResources/js/mobile/MailerUI.js @@ -0,0 +1,157 @@ +/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* JavaScript for SOGo.Mailer (mobile) */ + +(function() { + 'use strict'; + + angular.module('SOGo.Common', []); + + angular.module('SOGo.MailerUI', ['ionic', 'SOGo.Common', 'SOGo.UICommon', 'SOGo.UIMobile']) + + .constant('sgSettings', { + baseURL: ApplicationBaseURL + }) + + .run(function($ionicPlatform) { + $ionicPlatform.ready(function() { + // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard + // for form inputs) + if (window.cordova && window.cordova.plugins.Keyboard) { + cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); + } + if (window.StatusBar) { + // org.apache.cordova.statusbar required + StatusBar.styleDefault(); + } + }); + }) + + .config(function($stateProvider, $urlRouterProvider) { + $stateProvider + .state('app', { + url: '/app', + abstract: true, + templateUrl: 'menu.html', + controller: 'AppCtrl' + }) + .state('app.mail', { + url: '/mail', + views: { + menuContent: { + templateUrl: 'mailboxes.html', + controller: 'MailboxesCtrl', + } + }, + resolve: { + stateAccounts: ['$q', 'sgAccount', function($q, Account) { + var accounts = Account.$findAll(mailAccounts); + var promises = []; + // Resolve mailboxes of each account + angular.forEach(accounts, function(account, i) { + var mailboxes = account.$getMailboxes(); + promises.push(mailboxes.then(function(objects) { + accounts[i].mailboxes = objects; + return account; + })); + }); + return $q.all(promises); + }] + } + }) + .state('app.mail.account', { + url: '/:accountId', + abstract: true, + resolve: { + stateAccount: ['$stateParams', 'stateAccounts', function($stateParams, stateAccounts) { + return _.find(stateAccounts, function(account) { + return account.id == $stateParams.accountId; + }); + }] + } + }) + .state('app.mail.account.mailbox', { + url: '/:mailboxId', + views: { + 'menuContent@app': { + templateUrl: 'mailbox.html', + controller: 'MailboxCtrl' + } + }, + resolve: { + stateMailbox: ['$stateParams', 'stateAccount', 'decodeUriFilter', function($stateParams, stateAccount, decodeUriFilter) { + var mailboxId = decodeUriFilter($stateParams.mailboxId); + // Recursive find function + var _find = function(mailboxes) { + var mailbox = _.find(mailboxes, function(o) { + return o.path == mailboxId; + }); + if (!mailbox) { + angular.forEach(mailboxes, function(o) { + if (!mailbox && o.children && o.children.length > 0) { + mailbox = _find(o.children); + } + }); + } + return mailbox; + }; + return _find(stateAccount.mailboxes); + }], + stateMessages: ['stateMailbox', function(stateMailbox) { + return stateMailbox.$update(); + }] + } + }) + .state('app.mail.account.mailbox.message', { + url: "/:messageId", + views: { + 'menuContent@app': { + templateUrl: "message.html", + controller: 'MessageCtrl' + } + }, + resolve: { + stateMessage: ['$stateParams', 'stateMailbox', 'stateMessages', function($stateParams, stateMailbox, stateMessages) { + var message = _.find(stateMessages, function(messageObject) { + return messageObject.uid == $stateParams.messageId; + }); + return message; + }] + } + }); + + + // if none of the above states are matched, use this as the fallback + $urlRouterProvider.otherwise('/app/mail'); + }) + + .controller('AppCtrl', ['$scope', '$http', function($scope, $http) { + $scope.UserLogin = UserLogin; + $scope.UserFolderURL = UserFolderURL; + $scope.ApplicationBaseURL = ApplicationBaseURL; + }]) + + .controller('MailboxesCtrl', ['$scope', '$http', '$state', 'sgAccount', 'sgMailbox', 'encodeUriFilter', 'stateAccounts', function($scope, $http, $state, Account, Mailbox, encodeUriFilter, stateAccounts) { + $scope.accounts = stateAccounts + + angular.forEach($scope.accounts, function(account, i) { + var mailboxes = account.$getMailboxes(); + mailboxes.then(function(objects) { + $scope.accounts[i].mailboxes = objects; + }); + }); + + $scope.setCurrentFolder = function(account, folder) { + $state.go('app.mail.account.mailbox', { accountId: account.id, mailboxId: encodeUriFilter(folder.path) }); + }; + }]) + + .controller('MailboxCtrl', ['$scope', 'stateAccount', 'stateMailbox', function($scope, stateAccount, stateMailbox) { + $scope.account = stateAccount; + $scope.mailbox = stateMailbox; + }]) + + .controller('MessageCtrl', ['$scope', '$stateParams', 'stateMessage', function($scope, $stateParams, stateMessage) { + $scope.message = stateMessage; + }]); + +})(); diff --git a/UI/WebServerResources/scss/MailerUI.scss b/UI/WebServerResources/scss/MailerUI.scss index 3f1fdd714..d0127c1eb 100644 --- a/UI/WebServerResources/scss/MailerUI.scss +++ b/UI/WebServerResources/scss/MailerUI.scss @@ -240,6 +240,7 @@ $column-gutter: 0; h1, h2, h3, h4, h5, h6 { margin-left: rem-calc(12); margin-top: 0; + padding-top: rem-calc(12); } h1 { margin-bottom: 0; @@ -247,7 +248,7 @@ $column-gutter: 0; .header { background-color: $secondary-color; padding-bottom: 0.2em; - h1, h6 { + h1, h4, h6 { color: #fff; } .label { diff --git a/UI/WebServerResources/scss/mobile.scss b/UI/WebServerResources/scss/mobile.scss index cd07d83a3..7c5714b56 100644 --- a/UI/WebServerResources/scss/mobile.scss +++ b/UI/WebServerResources/scss/mobile.scss @@ -57,11 +57,38 @@ ion-content { } } +ion-list { + &.small { + a { + padding-top: $padding-small-vertical !important; + padding-bottom: $padding-small-vertical !important; + } + h2, p { + font-size: $font-size-base; + } + p { + margin: 0 !important; + } + } +} + ion-item { small { display: block; color: $positive !important; } + .right { + float: right; + } + &[collection-repeat] { + width: 100%; + } +} + +$i: 1; +@while $i < 12 { + .item-complex.item-icon-left.childLevel#{$i} { padding-left: 10px * $i; } + $i: $i + 1; } /* Additional styles */