From 1bc036a12d6877f78f1f5033603d803ac01a13d2 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 31 Aug 2014 00:40:42 +0100 Subject: nasty big monolithic commit of a whole bunch of UI/UX improvements: - add a simple CSS template across the app for navigation & cosmetics - split login into login & register, and totally reskin it - restructure room CSS to play nicely with it - implement basis 1:1 chat from user pages - disable autofocus on iOS to improve UX --- webclient/app-controller.js | 12 ++ webclient/app-directive.js | 7 +- webclient/app.css | 296 ++++++++++++++------------ webclient/app.js | 10 +- webclient/components/matrix/matrix-service.js | 14 +- webclient/home/home-controller.js | 4 +- webclient/home/home.html | 40 ++-- webclient/index.html | 18 +- webclient/login/login-controller.js | 59 +---- webclient/login/login.html | 88 ++++---- webclient/room/room-controller.js | 7 +- webclient/room/room.html | 30 +-- webclient/settings/settings.html | 17 +- webclient/user/user-controller.js | 28 +++ webclient/user/user.html | 36 ++-- 15 files changed, 356 insertions(+), 310 deletions(-) (limited to 'webclient') diff --git a/webclient/app-controller.js b/webclient/app-controller.js index 775113bc87..77a7ad03a5 100644 --- a/webclient/app-controller.js +++ b/webclient/app-controller.js @@ -37,6 +37,8 @@ angular.module('MatrixWebClientController', ['matrixService', 'mPresence', 'even mPresence.start(); } + $scope.user_id = matrixService.config().user_id; + /** * Open a given page. * @param {String} url url of the page @@ -45,6 +47,16 @@ angular.module('MatrixWebClientController', ['matrixService', 'mPresence', 'even $location.url(url); }; + // Open the given user profile page + $scope.goToUserPage = function(user_id) { + if (user_id === $scope.user_id) { + $location.url("/settings"); + } + else { + $location.url("/user/" + user_id); + } + }; + // Logs the user out $scope.logout = function() { diff --git a/webclient/app-directive.js b/webclient/app-directive.js index 01f60fdadf..eee0d3842f 100644 --- a/webclient/app-directive.js +++ b/webclient/app-directive.js @@ -32,7 +32,12 @@ angular.module('matrixWebClient') .directive('ngFocus', ['$timeout', function($timeout) { return { link: function(scope, element, attr) { - $timeout(function() { element[0].focus(); }, 0); + // XXX: slightly evil hack to disable autofocus on iOS, as in general + // it causes more problems than it fixes, by bouncing the page + // around + if (!/(iPad|iPhone|iPod)/g.test(navigator.userAgent)) { + $timeout(function() { element[0].focus(); }, 0); + } } }; }]); \ No newline at end of file diff --git a/webclient/app.css b/webclient/app.css index a5d0199bab..142e764ef1 100644 --- a/webclient/app.css +++ b/webclient/app.css @@ -1,122 +1,195 @@ -/*** Mobile voodoo ***/ -@media all and (max-device-width: 640px) { - - #messageTableWrapper { - margin-right: 0px ! important; - } - - .leftBlock { - width: 8em ! important; - font-size: 8px ! important; - } - - .rightBlock { - width: 0px ! important; - display: none ! important; - } - - .avatar { - width: 36px ! important; - } - - #header, - #messageTable, - #wrapper, - #roomName, - #controls { - max-width: 640px ! important; - } - - #userIdCell, - #roomRecentsTableWrapper, - #usersTableWrapper, - #extraControls { - display: none; - } - - #buttonsCell { - width: 60px ! important; - padding-left: 20px ! important; - } - - #roomLogo { - display: none; - } - - #roomName { - text-align: left ! important; - top: -35px ! important; - } - - .bubble { - font-size: 12px ! important; - min-height: 20px ! important; - } - - #page { - top: 35px ! important; - bottom: 70px ! important; - } - - #header, - #page { - margin: 5px ! important; - } - - #header { - padding: 5px ! important; - } - - /* stop zoom on select */ - select:focus, - textarea, - input - { - font-size: 16px ! important; - } - +/** Common layout **/ + +html { + height: 100%; } body { + height: 100%; font-family: "Myriad Pro", "Myriad", Helvetica, Arial, sans-serif; font-size: 12pt; margin: 0px; } h1 { - font-family: Helvetica, Arial, sans-serif; + font-size: 20pt; } -/*** Overall page layout ***/ +a:link { color: #666; } +a:visited { color: #666; } +a:hover { color: #000; } +a:active { color: #000; } #page { - position: absolute; - top: 80px; - bottom: 100px; - left: 0px; - right: 0px; - margin: 20px; + min-height: 100%; + margin-bottom: -32px; /* to make room for the footer */ } #wrapper { margin: auto; max-width: 1280px; height: 100%; + padding-top: 40px; + padding-bottom: 40px; + padding-left: 20px; + padding-right: 20px; } -#roomName { +#header +{ + position: absolute; + top: 0px; + width: 100%; + background-color: #333; + height: 32px; +} + +#headerContent { + color: #ccc; max-width: 1280px; + margin: auto; + text-align: right; + height: 32px; + line-height: 32px; +} + +#headerContent a:link, +#headerContent a:visited, +#headerContent a:hover, +#headerContent a:active { + color: #fff; +} + +#footer +{ width: 100%; + border-top: #666 1px solid; + background-color: #aaa; + height: 32px; +} + +#footerContent +{ + font-size: 8pt; + color: #fff; + max-width: 1280px; + margin: auto; + text-align: center; + height: 32px; + line-height: 32px; +} + +#genericHeading +{ + margin-top: 13px; +} + +#feedback { + color: #800; +} + +.mouse-pointer { + cursor: pointer; +} + +.invited { + opacity: 0.2; +} + +/*** Login Pages ***/ + +.loginWrapper { + text-align: center; +} + +#loginForm { + text-align: left; + padding: 1em; + margin-bottom: 40px; + display: inline-block; + + -webkit-border-radius: 10px; + -moz-border-radius: 10px; + border-radius: 10px; + + -webkit-box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.15); + -moz-box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.15); + box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.15); + + background-color: #f8f8f8; + border: 1px #ccc solid; +} + +#loginForm input[type='radio'] { + margin-right: 1em; +} + +#serverConfig { + text-align: center; +} + +#serverConfig, +#serverConfig input, +#serverConfig button +{ + font-size: 10pt ! important; +} + +.smallPrint { + color: #888; + font-size: 9pt ! important; + font-style: italic ! important; +} + +#serverConfig label { + display: inline-block; text-align: right; - top: -40px; + margin-right: 0.5em; + width: 7em; +} + +#loginForm, +#loginForm input, +#loginForm button, +#loginForm select { + font-size: 18px; +} + +/*** Room page ***/ + +#roomPage { position: absolute; + top: 120px; + bottom: 120px; + left: 20px; + right: 20px; +} + +#roomWrapper { + margin: auto; + max-width: 1280px; + height: 100%; +} + +#roomName { + float: right; font-size: 16px; + margin-top: 15px; +} + +#roomHeader { + margin: auto; + padding-left: 20px; + padding-right: 20px; + padding-top: 53px; + max-width: 1280px; } #controlPanel { position: absolute; bottom: 0px; width: 100%; + height: 100px; background-color: #f8f8f8; border-top: #aaa 1px solid; } @@ -147,10 +220,6 @@ h1 { background-color: #faa; } -.mouse-pointer { - cursor: pointer; -} - /*** Participant list ***/ #usersTableWrapper { @@ -409,11 +478,14 @@ h1 { } /*** Recents in the room page ***/ + #roomRecentsTableWrapper { float: left; max-width: 320px; - margin-right: 20px; + padding-right: 10px; + margin-right: 10px; height: 100%; + border-right: 1px solid #ddd; overflow-y: auto; } @@ -434,46 +506,8 @@ h1 { } /*** User profile page ***/ + #user-displayname { font-size: 24px; } -/******************************/ - -#header -{ - padding: 20px; - max-width: 1280px; - margin: auto; -} - -#logo, -#roomLogo { - max-width: 1280px; - margin: auto; -} - -#header-buttons { - float: right; -} - -.text_entry_section { - position: fixed; - bottom: 0; - z-index: 100; - left: 0; - right: 10em; - width: 100%; - background: #e0e0e0; -} - -.member_invited { - color: blue; -} -.member_joined { - -} - -.member_left { - color: gray; -} diff --git a/webclient/app.js b/webclient/app.js index 02695c3ae6..9663ddf967 100644 --- a/webclient/app.js +++ b/webclient/app.js @@ -18,6 +18,7 @@ var matrixWebClient = angular.module('matrixWebClient', [ 'ngRoute', 'MatrixWebClientController', 'LoginController', + 'RegisterController', 'RoomController', 'HomeController', 'RecentsController', @@ -38,6 +39,10 @@ matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider', templateUrl: 'login/login.html', controller: 'LoginController' }). + when('/register', { + templateUrl: 'login/register.html', + controller: 'RegisterController' + }). when('/room/:room_id_or_alias', { templateUrl: 'room/room.html', controller: 'RoomController' @@ -84,7 +89,10 @@ matrixWebClient.config(['$routeProvider', '$provide', '$httpProvider', matrixWebClient.run(['$location', 'matrixService', function($location, matrixService) { // If user auth details are not in cache, go to the login page - if (!matrixService.isUserLoggedIn()) { + if (!matrixService.isUserLoggedIn() && + $location.path() !== "/login" && + $location.path() !== "/register") + { $location.path("login"); } diff --git a/webclient/components/matrix/matrix-service.js b/webclient/components/matrix/matrix-service.js index 8543491dca..746442c280 100644 --- a/webclient/components/matrix/matrix-service.js +++ b/webclient/components/matrix/matrix-service.js @@ -95,14 +95,18 @@ angular.module('matrixService', []) }, // Create a room - create: function(room_id, visibility) { + create: function(room_alias, visibility) { // The REST path spec var path = "/createRoom"; - return doRequest("POST", path, undefined, { - visibility: visibility, - room_alias_name: room_id - }); + var req = { + "visibility": visibility + }; + if (room_alias) { + req.room_alias_name = room_alias; + } + + return doRequest("POST", path, undefined, req); }, // List all rooms joined or been invited to diff --git a/webclient/home/home-controller.js b/webclient/home/home-controller.js index 438ffe1b0e..847918d5dc 100644 --- a/webclient/home/home-controller.js +++ b/webclient/home/home-controller.js @@ -58,14 +58,14 @@ angular.module('HomeController', ['matrixService', 'eventHandlerService', 'Recen ); }; - $scope.createNewRoom = function(room_id, isPrivate) { + $scope.createNewRoom = function(room_alias, isPrivate) { var visibility = "public"; if (isPrivate) { visibility = "private"; } - matrixService.create(room_id, visibility).then( + matrixService.create(room_alias, visibility).then( function(response) { // This room has been created. Refresh the rooms list console.log("Created room " + response.data.room_alias + " with id: "+ diff --git a/webclient/home/home.html b/webclient/home/home.html index 1b1c21d9d2..8d35eb5157 100644 --- a/webclient/home/home.html +++ b/webclient/home/home.html @@ -1,29 +1,24 @@
-
- + +
+ [matrix] +
+ +

Welcome to homeserver {{ config.homeserver }}

+
-
- - - - - -
-
- -
-
-
-
{{ profile.displayName }}
-
{{ config.user_id }}
-
-
-
+
+ +
+
+
{{ profile.displayName }}
+
{{ config.user_id }}
+
-

Recents

+

Recent conversations


@@ -38,9 +33,9 @@
- + private - +
@@ -54,5 +49,4 @@ {{ feedback }}
-
diff --git a/webclient/index.html b/webclient/index.html index fdc50a5212..3c31a8a051 100644 --- a/webclient/index.html +++ b/webclient/index.html @@ -4,6 +4,8 @@ [matrix] + + @@ -19,6 +21,7 @@ + @@ -38,16 +41,23 @@ - +
-
+
+ diff --git a/webclient/login/login-controller.js b/webclient/login/login-controller.js index 51f9a3bdf4..2b91926954 100644 --- a/webclient/login/login-controller.js +++ b/webclient/login/login-controller.js @@ -10,63 +10,26 @@ angular.module('LoginController', ['matrixService']) if ($location.port()) { hs_url += ":" + $location.port(); } + var example_domain = $location.host(); $scope.account = { homeserver: hs_url, + example_domain: example_domain, desired_user_name: "", user_id: "", password: "", - identityServer: "", + identityServer: "http://matrix.org:8090", pwd1: "", - pwd2: "" + pwd2: "", }; - - $scope.register = function() { - - // Set the urls - matrixService.setConfig({ - homeserver: $scope.account.homeserver, - identityServer: $scope.account.identityServer - }); - - if ($scope.account.pwd1 !== $scope.account.pwd2) { - $scope.feedback = "Passwords don't match."; - return; - } - else if ($scope.account.pwd1.length < 6) { - $scope.feedback = "Password must be at least 6 characters."; - return; - } - - matrixService.register($scope.account.desired_user_name, $scope.account.pwd1).then( - function(response) { - $scope.feedback = "Success"; - // Update the current config - var config = matrixService.config(); - angular.extend(config, { - access_token: response.data.access_token, - user_id: response.data.user_id - }); - matrixService.setConfig(config); - - // And permanently save it - matrixService.saveConfig(); - eventStreamService.resume(); - // Go to the user's rooms list page - $location.url("home"); - }, - function(error) { - if (error.data) { - if (error.data.errcode === "M_USER_IN_USE") { - $scope.feedback = "Username already taken."; - } - } - else if (error.status === 0) { - $scope.feedback = "Unable to talk to the server."; - } - }); + + $scope.login_types = [ "email", "mxid" ]; + $scope.login_type_label = { + "email": "Email address", + "mxid": "Matrix ID (e.g. @bob:matrix.org or bob)", }; - + $scope.login_type = 'mxid'; // TODO: remember the user's preferred login_type + $scope.login = function() { matrixService.setConfig({ homeserver: $scope.account.homeserver, diff --git a/webclient/login/login.html b/webclient/login/login.html index 4b2ea60928..8d5a53ebbc 100644 --- a/webclient/login/login.html +++ b/webclient/login/login.html @@ -1,55 +1,49 @@
-

[matrix]

- -
-
- - {{ feedback }} +
-

Register for an account:

-
- -
- -
- + + [matrix] + +
- -
-
- -
-
-

Got an account?

-
- -
{{ login_error_msg }}
-
- -
-
-
- -
- -
+
+ +
+ Log in using:
+ +
+ + +
+ +
+
+ +
+ +

+ +

+
-

Servers

- -
- Home Server: - -
-
-
- Identity Server: - -
-
- -
- + + +
+ + +
Your home server stores all your conversation and account data.
+ + +
Matrix provides identity servers to track which emails etc. belong to which Matrix IDs.
+ Only http://matrix.org:8090 currently exists.
+
+
+ Create account + Forgotten password? +
+
+
diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js index 75adf259cf..c6028f874e 100644 --- a/webclient/room/room-controller.js +++ b/webclient/room/room-controller.js @@ -388,18 +388,13 @@ angular.module('RoomController', ['ngSanitize', 'mFileInput']) matrixService.invite($scope.room_id, user_id).then( function() { console.log("Invited."); - $scope.feedback = "Request for invitation succeeds"; + $scope.feedback = "Invite sent successfully"; }, function(reason) { $scope.feedback = "Failure: " + reason; }); }; - // Open the user profile page - $scope.goToUserPage = function(user_id) { - $location.url("/user/" + user_id); - }; - $scope.leaveRoom = function() { matrixService.leave($scope.room_id).then( diff --git a/webclient/room/room.html b/webclient/room/room.html index aa7879ea8f..cfe6b99ea6 100644 --- a/webclient/room/room.html +++ b/webclient/room/room.html @@ -1,13 +1,15 @@ -
-

[matrix]

+
-
-
- -
- {{ room_alias || room_id }} +
+ [matrix] +
+ {{ room_alias || room_id }} +
+
+
+
@@ -15,16 +17,16 @@
- -
+ {{ member.displayname || member.id.substr(0, member.id.indexOf(':')) }}
{{ member.displayname || member.id.substr(0, member.id.indexOf(':')) }}
{{ member.displayname ? "" : member.id.substr(member.id.indexOf(':')) }}
+ {{ member.mtime_age + (now - member.last_updated) | duration }}
{{ member.mtime_age ? "ago" : "" }}
@@ -40,7 +42,7 @@
{{ (msg.content.hsob_ts || msg.ts) | date:'MMM d HH:mm' }}
- @@ -64,7 +66,7 @@
- @@ -86,12 +88,12 @@ - + -
+
Invite a user: diff --git a/webclient/settings/settings.html b/webclient/settings/settings.html index 75d8e0887c..0ba3fe263a 100644 --- a/webclient/settings/settings.html +++ b/webclient/settings/settings.html @@ -1,16 +1,20 @@
-
- -

Me

+ +
+ [matrix] +
+ +

Settings

- +
- + +
@@ -53,7 +57,7 @@ To enable it, reset the notification setting for this web site into your browser settings.
- +
Sorry, your browser does not support notifications. @@ -73,5 +77,4 @@ {{ feedback }}
-
diff --git a/webclient/user/user-controller.js b/webclient/user/user-controller.js index 620230561c..b5b2d439a2 100644 --- a/webclient/user/user-controller.js +++ b/webclient/user/user-controller.js @@ -25,14 +25,42 @@ angular.module('UserController', ['matrixService']) avatar_url: undefined }; + $scope.user_id = matrixService.config().user_id; + matrixService.getDisplayName($scope.user.id).then( function(response) { $scope.user.displayname = response.data.displayname; } ); + matrixService.getProfilePictureUrl($scope.user.id).then( function(response) { $scope.user.avatar_url = response.data.avatar_url; } ); + + $scope.messageUser = function() { + + // FIXME: create a new room every time, for now + + matrixService.create(null, 'private').then( + function(response) { + // This room has been created. Refresh the rooms list + var room_id = response.data.room_id; + console.log("Created room with id: "+ room_id); + + matrixService.invite(room_id, $scope.user.id).then( + function() { + $scope.feedback = "Invite sent successfully"; + $scope.$parent.goToPage("/room/" + room_id); + }, + function(reason) { + $scope.feedback = "Failure: " + JSON.stringify(reason); + }); + }, + function(error) { + $scope.feedback = "Failure: " + JSON.stringify(error.data); + }); + }; + }]); \ No newline at end of file diff --git a/webclient/user/user.html b/webclient/user/user.html index 4c91c8a48a..3574403c87 100644 --- a/webclient/user/user.html +++ b/webclient/user/user.html @@ -1,31 +1,25 @@
-

[matrix]

-
- + +
+ [matrix] +
+ +

{{ user.displayname || user.id }}

+
- - - - - - -
-
- -
-
-
-
{{ user.displayname }}
-
{{ user.id }}
-
-
- +
+ +
+
+
{{ user.id }}
+
+ +
{{ feedback }} -
-- cgit 1.4.1