From 1bc036a12d6877f78f1f5033603d803ac01a13d2 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sun, 31 Aug 2014 00:40:42 +0100 Subject: [PATCH] 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 | 302 ++++++++++-------- webclient/app.js | 10 +- webclient/components/matrix/matrix-service.js | 14 +- webclient/home/home-controller.js | 4 +- webclient/home/home.html | 42 ++- webclient/index.html | 18 +- webclient/login/login-controller.js | 59 +--- webclient/login/login.html | 92 +++--- 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 | 38 +-- 15 files changed, 363 insertions(+), 317 deletions(-) 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; +} + +#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; + 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 { - max-width: 1280px; - width: 100%; - text-align: right; - top: -40px; - position: absolute; + 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 @@
-
- -
-
- - - - - -
-
- -
-
-
-
{{ profile.displayName }}
-
{{ config.user_id }}
-
-
-
+ +
+ [matrix]
-

Recents

+

Welcome to homeserver {{ config.homeserver }}

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

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