diff --git a/src/img/google_logo.png b/src/img/google_logo.png new file mode 100644 index 0000000..1974f31 Binary files /dev/null and b/src/img/google_logo.png differ diff --git a/src/img/outlook_logo.jpg b/src/img/outlook_logo.jpg new file mode 100644 index 0000000..c2db0be Binary files /dev/null and b/src/img/outlook_logo.jpg differ diff --git a/src/img/tonline_logo.jpg b/src/img/tonline_logo.jpg new file mode 100644 index 0000000..376b2b9 Binary files /dev/null and b/src/img/tonline_logo.jpg differ diff --git a/src/img/yahoo_logo.png b/src/img/yahoo_logo.png new file mode 100644 index 0000000..d558670 Binary files /dev/null and b/src/img/yahoo_logo.png differ diff --git a/src/js/app-controller.js b/src/js/app-controller.js index 316125c..9066029 100644 --- a/src/js/app-controller.js +++ b/src/js/app-controller.js @@ -195,12 +195,6 @@ define(function(require) { return; } - if (cachedEmailAddress) { - // not first time login... address cached - callback(null, cachedEmailAddress); - return; - } - if (!cachedEmailAddress && !self.isOnline()) { // first time login... must be online callback({ @@ -209,14 +203,7 @@ define(function(require) { return; } - self.fetchOAuthToken(function(err, oauth) { - if (err) { - callback(err); - return; - } - - callback(null, oauth.emailAddress); - }); + callback(null, cachedEmailAddress); }); }; diff --git a/src/js/app.js b/src/js/app.js index 6ef0d86..c1974db 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -5,6 +5,7 @@ require([ 'angular', 'js/controller/dialog', 'js/controller/popover', + 'js/controller/add-account', 'js/controller/account', 'js/controller/login', 'js/controller/login-initial', @@ -17,7 +18,7 @@ require([ 'cryptoLib/util', 'angularRoute', 'angularTouch' -], function(angular, DialogCtrl, PopoverCtrl, AccountCtrl, LoginCtrl, LoginInitialCtrl, LoginNewDeviceCtrl, LoginExistingCtrl, MailListCtrl, ReadCtrl, WriteCtrl, NavigationCtrl, util) { +], function(angular, DialogCtrl, PopoverCtrl, AddAccountCtrl, AccountCtrl, LoginCtrl, LoginInitialCtrl, LoginNewDeviceCtrl, LoginExistingCtrl, MailListCtrl, ReadCtrl, WriteCtrl, NavigationCtrl, util) { 'use strict'; // reset window.name @@ -28,6 +29,10 @@ require([ // set router paths app.config(function($routeProvider) { + $routeProvider.when('/add-account', { + templateUrl: 'tpl/add-account.html', + controller: AddAccountCtrl + }); $routeProvider.when('/login', { templateUrl: 'tpl/login.html', controller: LoginCtrl diff --git a/src/js/controller/add-account.js b/src/js/controller/add-account.js new file mode 100644 index 0000000..12b21ab --- /dev/null +++ b/src/js/controller/add-account.js @@ -0,0 +1,31 @@ +define(function(require) { + 'use strict'; + + var appController = require('js/app-controller'), + errorUtil = require('js/util/error'); + + var AddAccountCtrl = function($scope, $location) { + // global state... inherited to all child scopes + $scope.$root.state = {}; + // attach global error handler + errorUtil.attachHandler($scope); + + $scope.connectToGoogle = function() { + appController.fetchOAuthToken(function(err) { + if (err) { + $scope.onError(err); + return; + } + + redirect(); + }); + }; + + function redirect() { + $location.path('/login'); + $scope.$apply(); + } + }; + + return AddAccountCtrl; +}); \ No newline at end of file diff --git a/src/js/controller/login.js b/src/js/controller/login.js index e0658b3..8baeb04 100644 --- a/src/js/controller/login.js +++ b/src/js/controller/login.js @@ -33,6 +33,12 @@ define(function(require) { return; } + // check if account needs to be selected + if (!emailAddress) { + firstLogin(); + return; + } + // initiate controller by creating email dao appController.init({ emailAddress: emailAddress @@ -47,6 +53,11 @@ define(function(require) { }); } + function firstLogin() { + $location.path('/add-account'); + $scope.$apply(); + } + function redirect(availableKeys) { // redirect if needed if (typeof availableKeys === 'undefined') { diff --git a/src/sass/all.scss b/src/sass/all.scss index 94a26ef..5c5f594 100755 --- a/src/sass/all.scss +++ b/src/sass/all.scss @@ -22,6 +22,7 @@ // Views @import "views/shared"; +@import "views/add-account"; @import "views/account"; @import "views/dialog"; @import "views/navigation"; diff --git a/src/sass/views/_add-account.scss b/src/sass/views/_add-account.scss new file mode 100644 index 0000000..b54ced5 --- /dev/null +++ b/src/sass/views/_add-account.scss @@ -0,0 +1,125 @@ +.view-add-account { + height: 100%; + background-color: $color-grey-lightest; + color: $color-grey-dark; + + h1 { + padding: 60px 0 50px 0; + text-align: center; + margin: 0; + font-size: 32px; + line-height: 64px; + } + + ul { + list-style-type: none; + width: 320px; + margin: 0 auto; + padding: 0; + border-width: 1px; + border-style: solid; + border-color: $color-grey-lighter; + + li { + position: relative; + height: 68px; + cursor: pointer; + + &.google { + background-color: white; + + div { + width: 164px; + height: 58px; + margin: 0px auto; + padding: 8px 0; + + img { + width: 164px; + height: 58px; + } + } + } + + &.whiteout { + background-color: $color-grey-lightest; + + div { + width: 210px; + margin: 0 auto; + padding: 15px 0; + + img { + width: 100%; + } + } + } + + &.outlook { + background-color: white; + + div { + width: 256px; + margin: 0 auto; + padding: 13px 0; + + img { + width: 100%; + } + } + } + + &.yahoo { + background-color: $color-grey-lightest; + + div { + width: 181px; + margin: 0 auto; + + img { + width: 100%; + } + } + } + + &.tonline { + background-color: white; + + div { + width: 271px; + margin: 0 auto; + + img { + width: 100%; + } + } + } + + &.other { + h3 { + margin: 0; + line-height: 68px; + font-size: 21px; + text-align: center; + } + } + + &.disabled { + opacity: 0.2; + } + + &.enabled { + &:hover, + &:focus { + opacity: 0.6; + } + + &:active { + opacity: 1; + top: 1px; + left: 1px; + } + } + } + } +} \ No newline at end of file diff --git a/src/tpl/add-account.html b/src/tpl/add-account.html new file mode 100644 index 0000000..da14d5a --- /dev/null +++ b/src/tpl/add-account.html @@ -0,0 +1,92 @@ +
+ +

Select email account

+ + + +
+ + + + + +
+
+
Google Account
+
+

Connect Whiteout Mail to your Gmail or Google Apps account.

+

Encrypted and cleartext messages are stored on Google's servers.

+

No data is sent to our servers.

+
+
+ +
+
+
Whiteout Mailbox (coming soon)
+
+

Connect Whiteout Mail to your secure Whiteout Mailbox.

+

All incoming messages are encrypted at rest and can only be read on your device.

+

Whiteout Mailbox is an email service hosted in Germany.

+
+
+ +
+
+
Outlook.com Account (coming soon)
+
+

Connect Whiteout Mail to your Outlook.com account.

+

Encrypted and cleartext messages are stored on Microsoft's servers.

+

No data is sent to our servers.

+
+
+ +
+
+
Yahoo Mail (coming soon)
+
+

Connect Whiteout Mail to your Yahoo Mail account.

+

Encrypted and cleartext messages are stored on Yahoo's servers.

+

No data is sent to our servers.

+
+
+ +
+
+
T-Online Account (coming soon)
+
+

Connect Whiteout Mail to your T-Online account.

+

Encrypted and cleartext messages are stored on T-Online's servers.

+

No data is sent to our servers.

+
+
+ +
+
+
Custom server (coming soon)
+
+

Connect Whiteout Mail to your own email server.

+

Encrypted and cleartext messages are stored on your server.

+

No data is sent to our servers.

+
+
\ No newline at end of file diff --git a/test/new-unit/add-account-ctrl-test.js b/test/new-unit/add-account-ctrl-test.js new file mode 100644 index 0000000..6e406b3 --- /dev/null +++ b/test/new-unit/add-account-ctrl-test.js @@ -0,0 +1,72 @@ +define(function(require) { + 'use strict'; + + var expect = chai.expect, + angular = require('angular'), + mocks = require('angularMocks'), + AddAccountCtrl = require('js/controller/add-account'), + appController = require('js/app-controller'); + + describe('Add Account Controller unit test', function() { + var scope, location, ctrl, + fetchOAuthTokenStub; + + describe('connectToGoogle', function() { + beforeEach(function() { + // remember original module to restore later, then replace it + fetchOAuthTokenStub = sinon.stub(appController, 'fetchOAuthToken'); + }); + + afterEach(function() { + // restore the app controller module + location && location.path && location.path.restore && location.path.restore(); + fetchOAuthTokenStub.restore(); + }); + + it('should fail on fetchOAuthToken error', function(done) { + angular.module('addaccounttest', []); + mocks.module('addaccounttest'); + mocks.inject(function($controller, $rootScope) { + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(AddAccountCtrl, { + $location: location, + $scope: scope + }); + }); + + scope.onError = function(err) { + expect(err).to.equal(42); + expect(fetchOAuthTokenStub.calledOnce).to.be.true; + done(); + }; + fetchOAuthTokenStub.yields(42); + + scope.connectToGoogle(); + }); + + it('should forward to login', function(done) { + angular.module('addaccounttest', []); + mocks.module('addaccounttest'); + mocks.inject(function($controller, $rootScope, $location) { + location = $location; + sinon.stub(location, 'path', function(path) { + expect(path).to.equal('/login'); + expect(fetchOAuthTokenStub.calledOnce).to.be.true; + done(); + }); + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(AddAccountCtrl, { + $location: location, + $scope: scope + }); + }); + + fetchOAuthTokenStub.yields(); + + scope.connectToGoogle(); + }); + }); + }); +}); \ No newline at end of file diff --git a/test/new-unit/app-controller-test.js b/test/new-unit/app-controller-test.js index 4e882a4..ed46db4 100644 --- a/test/new-unit/app-controller-test.js +++ b/test/new-unit/app-controller-test.js @@ -177,34 +177,6 @@ define(function(require) { done(); }); }); - - it('should fail due to error in fetchOAuthToken', function(done) { - appConfigStoreStub.listItems.yields(null, []); - isOnlineStub.returns(true); - fetchOAuthTokenStub.yields({}); - - controller.getEmailAddress(function(err, emailAddress) { - expect(err).to.exist; - expect(emailAddress).to.not.exist; - expect(fetchOAuthTokenStub.calledOnce).to.be.true; - done(); - }); - }); - - it('should fail work when fetching oauth token', function(done) { - appConfigStoreStub.listItems.yields(null, []); - isOnlineStub.returns(true); - fetchOAuthTokenStub.yields(null, { - emailAddress: 'asfd@example.com' - }); - - controller.getEmailAddress(function(err, emailAddress) { - expect(err).to.not.exist; - expect(emailAddress).to.equal('asfd@example.com'); - expect(fetchOAuthTokenStub.calledOnce).to.be.true; - done(); - }); - }); }); describe('fetchOAuthToken', function() { diff --git a/test/new-unit/main.js b/test/new-unit/main.js index 1d8a653..5e6b99b 100644 --- a/test/new-unit/main.js +++ b/test/new-unit/main.js @@ -39,6 +39,7 @@ function startTests() { 'test/new-unit/keychain-dao-test', 'test/new-unit/devicestorage-dao-test', 'test/new-unit/dialog-ctrl-test', + 'test/new-unit/add-account-ctrl-test', 'test/new-unit/account-ctrl-test', 'test/new-unit/login-existing-ctrl-test', 'test/new-unit/login-initial-ctrl-test',