Merge pull request #11 from whiteout-io/dev/choose-account

[WO-207] implement accout selection
This commit is contained in:
Felix Hammerl 2014-01-28 06:18:47 -08:00
commit 66ef501a16
14 changed files with 340 additions and 43 deletions

BIN
src/img/google_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
src/img/outlook_logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
src/img/tonline_logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
src/img/yahoo_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

View File

@ -203,12 +203,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({
@ -217,14 +211,7 @@ define(function(require) {
return;
}
self.fetchOAuthToken(function(err, oauth) {
if (err) {
callback(err);
return;
}
callback(null, oauth.emailAddress);
});
callback(null, cachedEmailAddress);
});
};

View File

@ -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

View File

@ -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;
});

View File

@ -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') {

View File

@ -22,6 +22,7 @@
// Views
@import "views/shared";
@import "views/add-account";
@import "views/account";
@import "views/dialog";
@import "views/navigation";

View File

@ -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;
}
}
}
}
}

92
src/tpl/add-account.html Normal file
View File

@ -0,0 +1,92 @@
<div class="view-add-account">
<h1>Select email account</h1>
<ul>
<li class="google enabled" popover="#google-info" ng-click="connectToGoogle()">
<div><img src="img/google_logo.png" alt="Google Mail"></div>
</li>
<li class="whiteout disabled" popover="#whiteout-info">
<div><img src="img/whiteout_logo.svg" alt="Whiteout Mailbox"></div>
</li>
<li class="outlook disabled" popover="#outlook-info">
<div><img src="img/outlook_logo.jpg" alt="Outlook.com"></div>
</li>
<li class="yahoo disabled" popover="#yahoo-info">
<div><img src="img/yahoo_logo.png" alt="Yahoo! Mail"></div>
</li>
<li class="tonline disabled" popover="#tonline-info">
<div><img src="img/tonline_logo.jpg" alt="T-Online"></div>
</li>
<li class="other disabled" popover="#custom-info">
<h3>Custom server...</h3>
</li>
</ul>
</div>
<!-- lightbox -->
<div class="lightbox-overlay" ng-class="{'show': state.dialog.open}">
<div class="lightbox lightbox-effect view-dialog" ng-include="'tpl/dialog.html'"></div>
</div>
<!-- popovers -->
<div id="google-info" class="popover right" ng-controller="PopoverCtrl">
<div class="arrow"></div>
<div class="popover-title"><b>Google Account</b></div>
<div class="popover-content">
<p>Connect Whiteout Mail to your Gmail or Google Apps account.</p>
<p>Encrypted and cleartext messages are stored on Google's servers.</p>
<p>No data is sent to our servers.</p>
</div>
</div><!--/.popover-->
<div id="whiteout-info" class="popover right" ng-controller="PopoverCtrl">
<div class="arrow"></div>
<div class="popover-title"><b>Whiteout Mailbox (coming soon)</b></div>
<div class="popover-content">
<p>Connect Whiteout Mail to your secure Whiteout Mailbox.</p>
<p>All incoming messages are encrypted at rest and can only be read on your device.</p>
<p>Whiteout Mailbox is an email service hosted in Germany.</p>
</div>
</div><!--/.popover-->
<div id="outlook-info" class="popover right" ng-controller="PopoverCtrl">
<div class="arrow"></div>
<div class="popover-title"><b>Outlook.com Account (coming soon)</b></div>
<div class="popover-content">
<p>Connect Whiteout Mail to your Outlook.com account.</p>
<p>Encrypted and cleartext messages are stored on Microsoft's servers.</p>
<p>No data is sent to our servers.</p>
</div>
</div><!--/.popover-->
<div id="yahoo-info" class="popover right" ng-controller="PopoverCtrl">
<div class="arrow"></div>
<div class="popover-title"><b>Yahoo Mail (coming soon)</b></div>
<div class="popover-content">
<p>Connect Whiteout Mail to your Yahoo Mail account.</p>
<p>Encrypted and cleartext messages are stored on Yahoo's servers.</p>
<p>No data is sent to our servers.</p>
</div>
</div><!--/.popover-->
<div id="tonline-info" class="popover right" ng-controller="PopoverCtrl">
<div class="arrow"></div>
<div class="popover-title"><b>T-Online Account (coming soon)</b></div>
<div class="popover-content">
<p>Connect Whiteout Mail to your T-Online account.</p>
<p>Encrypted and cleartext messages are stored on T-Online's servers.</p>
<p>No data is sent to our servers.</p>
</div>
</div><!--/.popover-->
<div id="custom-info" class="popover right" ng-controller="PopoverCtrl">
<div class="arrow"></div>
<div class="popover-title"><b>Custom server (coming soon)</b></div>
<div class="popover-content">
<p>Connect Whiteout Mail to your own email server.</p>
<p>Encrypted and cleartext messages are stored on your server.</p>
<p>No data is sent to our servers.</p>
</div>
</div><!--/.popover-->

View File

@ -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();
});
});
});
});

View File

@ -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() {

View File

@ -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',