diff --git a/webclient/app-controller.js b/webclient/app-controller.js
index 172770f82f..42c45f7c31 100644
--- a/webclient/app-controller.js
+++ b/webclient/app-controller.js
@@ -21,8 +21,8 @@ limitations under the License.
'use strict';
angular.module('MatrixWebClientController', ['matrixService', 'mPresence', 'eventStreamService'])
-.controller('MatrixWebClientController', ['$scope', '$location', '$rootScope', 'matrixService', 'mPresence', 'eventStreamService',
- function($scope, $location, $rootScope, matrixService, mPresence, eventStreamService) {
+.controller('MatrixWebClientController', ['$scope', '$location', '$rootScope', 'matrixService', 'mPresence', 'eventStreamService', 'matrixPhoneService',
+ function($scope, $location, $rootScope, matrixService, mPresence, eventStreamService, matrixPhoneService) {
// Check current URL to avoid to display the logout button on the login page
$scope.location = $location.path();
@@ -36,8 +36,12 @@ angular.module('MatrixWebClientController', ['matrixService', 'mPresence', 'even
eventStreamService.resume();
mPresence.start();
}
-
- $scope.user_id = matrixService.config().user_id;
+
+ $scope.user_id;
+ var config = matrixService.config();
+ if (config) {
+ $scope.user_id = matrixService.config().user_id;
+ }
/**
* Open a given page.
@@ -84,7 +88,27 @@ angular.module('MatrixWebClientController', ['matrixService', 'mPresence', 'even
$scope.updateHeader = function() {
$scope.user_id = matrixService.config().user_id;
};
+
+ $rootScope.$on(matrixPhoneService.INCOMING_CALL_EVENT, function(ngEvent, call) {
+ console.trace("incoming call");
+ call.onError = $scope.onCallError;
+ call.onHangup = $scope.onCallHangup;
+ $rootScope.currentCall = call;
+ });
+
+ $scope.answerCall = function() {
+ $scope.currentCall.answer();
+ };
+
+ $scope.hangupCall = function() {
+ $scope.currentCall.hangup();
+ $scope.currentCall = undefined;
+ };
-}]);
+ $rootScope.onCallError = function(errStr) {
+ $scope.feedback = errStr;
+ }
-
+ $rootScope.onCallHangup = function() {
+ }
+}]);
diff --git a/webclient/app-filter.js b/webclient/app-filter.js
index b8f4ed25bc..b8d3d2a0d8 100644
--- a/webclient/app-filter.js
+++ b/webclient/app-filter.js
@@ -70,7 +70,7 @@ angular.module('matrixWebClient')
});
filtered.sort(function (a, b) {
- return ((a["mtime_age"] || 10e10) > (b["mtime_age"] || 10e10) ? 1 : -1);
+ return ((a["last_active_ago"] || 10e10) > (b["last_active_ago"] || 10e10) ? 1 : -1);
});
return filtered;
};
@@ -79,4 +79,43 @@ angular.module('matrixWebClient')
return function(text) {
return $sce.trustAsHtml(text);
};
+}])
+
+// Compute the room name according to information we have
+.filter('roomName', ['$rootScope', 'matrixService', function($rootScope, matrixService) {
+ return function(room_id) {
+ var roomName;
+
+ // If there is an alias, use it
+ // TODO: only one alias is managed for now
+ var alias = matrixService.getRoomIdToAliasMapping(room_id);
+ if (alias) {
+ roomName = alias;
+ }
+
+ if (undefined === roomName) {
+ // Else, build the name from its users
+ var room = $rootScope.events.rooms[room_id];
+ if (room) {
+ if (room.members) {
+ // Limit the room renaming to 1:1 room
+ if (2 === Object.keys(room.members).length) {
+ for (var i in room.members) {
+ var member = room.members[i];
+ if (member.user_id !== matrixService.config().user_id) {
+ roomName = member.content.displayname ? member.content.displayname : member.user_id;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (undefined === roomName) {
+ // By default, use the room ID
+ roomName = room_id;
+ }
+
+ return roomName;
+ };
}]);
diff --git a/webclient/app.css b/webclient/app.css
index cd1820e155..8685032d72 100755
--- a/webclient/app.css
+++ b/webclient/app.css
@@ -43,6 +43,10 @@ a:active { color: #000; }
height: 32px;
}
+#callBar {
+ float: left;
+}
+
#headerContent {
color: #ccc;
max-width: 1280px;
diff --git a/webclient/index.html b/webclient/index.html
index 3c31a8a051..f016dbb877 100644
--- a/webclient/index.html
+++ b/webclient/index.html
@@ -44,6 +44,19 @@
<div id="header">
<!-- Do not show buttons on the login page -->
<div id="headerContent" ng-hide="'/login' == location || '/register' == location">
+ <div id="callBar">
+ <div ng-show="currentCall.state == 'ringing'">
+ Incoming call from {{ currentCall.user_id }}
+ <button ng-click="answerCall()">Answer</button>
+ <button ng-click="hangupCall()">Reject</button>
+ </div>
+ <button ng-click="hangupCall()" ng-show="currentCall && currentCall.state != 'ringing' && currentCall.state != 'ended' && currentCall.state != 'fledgling'">Hang up</button>
+ <span ng-show="currentCall.state == 'invite_sent'">Calling...</span>
+ <span ng-show="currentCall.state == 'connecting'">Call Connecting...</span>
+ <span ng-show="currentCall.state == 'connected'">Call Connected</span>
+ <span ng-show="currentCall.state == 'ended'">Call Ended</span>
+ <span style="display: none; ">{{ currentCall.state }}</span>
+ </div>
<a href id="headerUserId" ng-click='goToUserPage(user_id)'>{{ user_id }}</a>
<button ng-click='goToPage("/")'>Home</button>
@@ -56,7 +69,7 @@
<div id="footer" ng-hide="location.indexOf('/room') == 0">
<div id="footerContent">
- © 2014 Matrix.org
+ © 2014 Matrix.org
</div>
</div>
</body>
diff --git a/webclient/recents/recents-controller.js b/webclient/recents/recents-controller.js
index d33d41a922..947bd29de3 100644
--- a/webclient/recents/recents-controller.js
+++ b/webclient/recents/recents-controller.js
@@ -33,8 +33,7 @@ angular.module('RecentsController', ['matrixService', 'eventHandlerService'])
console.log("Invited to room " + event.room_id);
// FIXME push membership to top level key to match /im/sync
event.membership = event.content.membership;
- // FIXME bodge a nicer name than the room ID for this invite.
- event.room_display_name = event.user_id + "'s room";
+
$scope.rooms[event.room_id] = event;
}
});
@@ -43,6 +42,11 @@ angular.module('RecentsController', ['matrixService', 'eventHandlerService'])
$scope.rooms[event.room_id].lastMsg = event;
}
});
+ $scope.$on(eventHandlerService.CALL_EVENT, function(ngEvent, event, isLive) {
+ if (isLive) {
+ $scope.rooms[event.room_id].lastMsg = event;
+ }
+ });
};
@@ -83,7 +87,9 @@ angular.module('RecentsController', ['matrixService', 'eventHandlerService'])
};
$scope.onInit = function() {
- refresh();
+ eventHandlerService.waitForInitialSyncCompletion().then(function() {
+ refresh();
+ });
};
}]);
diff --git a/webclient/recents/recents.html b/webclient/recents/recents.html
index 3f025a98d8..db3b0fb32f 100644
--- a/webclient/recents/recents.html
+++ b/webclient/recents/recents.html
@@ -6,7 +6,7 @@
ng-class="{'recentsRoomSelected': (room.room_id === recentsSelectedRoomID)}">
<tr>
<td class="recentsRoomName">
- {{ room.room_display_name }}
+ {{ room.room_id | roomName }}
</td>
<td class="recentsRoomSummaryTS">
{{ (room.lastMsg.ts) | date:'MMM d HH:mm' }}
@@ -51,7 +51,9 @@
</div>
<div ng-switch-default>
- {{ room.lastMsg }}
+ <div ng-if="room.lastMsg.type.indexOf('m.call.') == 0">
+ Call
+ </div>
</div>
</div>
</td>
diff --git a/webclient/room/room-controller.js b/webclient/room/room-controller.js
index c6028f874e..9861b25617 100644
--- a/webclient/room/room-controller.js
+++ b/webclient/room/room-controller.js
@@ -82,13 +82,6 @@ angular.module('RoomController', ['ngSanitize', 'mFileInput'])
updatePresence(event);
});
- $rootScope.$on(matrixPhoneService.INCOMING_CALL_EVENT, function(ngEvent, call) {
- console.trace("incoming call");
- call.onError = $scope.onCallError;
- call.onHangup = $scope.onCallHangup;
- $scope.currentCall = call;
- });
-
$scope.memberCount = function() {
return Object.keys($scope.members).length;
};
@@ -100,15 +93,6 @@ angular.module('RoomController', ['ngSanitize', 'mFileInput'])
}
};
- $scope.answerCall = function() {
- $scope.currentCall.answer();
- };
-
- $scope.hangupCall = function() {
- $scope.currentCall.hangup();
- $scope.currentCall = undefined;
- };
-
var paginate = function(numItems) {
// console.log("paginate " + numItems);
if ($scope.state.paginating || !$scope.room_id) {
@@ -181,11 +165,11 @@ angular.module('RoomController', ['ngSanitize', 'mFileInput'])
var isNewMember = !(target_user_id in $scope.members);
if (isNewMember) {
// FIXME: why are we copying these fields around inside chunk?
- if ("state" in chunk.content) {
- chunk.presenceState = chunk.content.state; // why is this renamed?
+ if ("presence" in chunk.content) {
+ chunk.presence = chunk.content.presence;
}
- if ("mtime_age" in chunk.content) {
- chunk.mtime_age = chunk.content.mtime_age;
+ if ("last_active_ago" in chunk.content) {
+ chunk.last_active_ago = chunk.content.last_active_ago;
}
if ("displayname" in chunk.content) {
chunk.displayname = chunk.content.displayname;
@@ -201,9 +185,15 @@ angular.module('RoomController', ['ngSanitize', 'mFileInput'])
}
}
else {
- // selectively update membership else it will nuke the picture and displayname too :/
+ // selectively update membership and presence else it will nuke the picture and displayname too :/
var member = $scope.members[target_user_id];
- member.content.membership = chunk.content.membership;
+ member.membership = chunk.content.membership;
+ if ("presence" in chunk.content) {
+ member.presence = chunk.content.presence;
+ }
+ if ("last_active_ago" in chunk.content) {
+ member.last_active_ago = chunk.content.last_active_ago;
+ }
}
};
@@ -221,13 +211,12 @@ angular.module('RoomController', ['ngSanitize', 'mFileInput'])
var member = $scope.members[chunk.content.user_id];
// XXX: why not just pass the chunk straight through?
- if ("state" in chunk.content) {
- member.presenceState = chunk.content.state;
+ if ("presence" in chunk.content) {
+ member.presence = chunk.content.presence;
}
- if ("mtime_age" in chunk.content) {
- // FIXME: should probably keep updating mtime_age in realtime like FB does
- member.mtime_age = chunk.content.mtime_age;
+ if ("last_active_ago" in chunk.content) {
+ member.last_active_ago = chunk.content.last_active_ago;
}
// this may also contain a new display name or avatar url, so check.
@@ -331,6 +320,11 @@ angular.module('RoomController', ['ngSanitize', 'mFileInput'])
// Make sure the initialSync has been before going further
eventHandlerService.waitForInitialSyncCompletion().then(
function() {
+
+ // Some data has been retrieved from the iniialSync request
+ // So, the relative time starts here
+ $scope.now = new Date().getTime();
+
var needsToJoin = true;
// The room members is available in the data fetched by initialSync
@@ -377,10 +371,22 @@ angular.module('RoomController', ['ngSanitize', 'mFileInput'])
// Make recents highlight the current room
$scope.recentsSelectedRoomID = $scope.room_id;
-
+
+ // Get the up-to-date the current member list
+ matrixService.getMemberList($scope.room_id).then(
+ function(response) {
+ for (var i = 0; i < response.data.chunk.length; i++) {
+ var chunk = response.data.chunk[i];
+ updateMemberList(chunk);
+ updateMemberListPresenceAge();
+ }
+ },
+ function(error) {
+ $scope.feedback = "Failed get member list: " + error.data.error;
+ }
+ );
+
paginate(MESSAGES_PER_PAGINATION);
-
- updateMemberListPresenceAge();
};
$scope.inviteUser = function(user_id) {
@@ -455,16 +461,10 @@ angular.module('RoomController', ['ngSanitize', 'mFileInput'])
$scope.startVoiceCall = function() {
var call = new MatrixCall($scope.room_id);
- call.onError = $scope.onCallError;
- call.onHangup = $scope.onCallHangup;
+ call.onError = $rootScope.onCallError;
+ call.onHangup = $rootScope.onCallHangup;
call.placeCall();
- $scope.currentCall = call;
+ $rootScope.currentCall = call;
}
- $scope.onCallError = function(errStr) {
- $scope.feedback = errStr;
- }
-
- $scope.onCallHangup = function() {
- }
}]);
diff --git a/webclient/room/room.html b/webclient/room/room.html
index e5e454864b..e25c837aa0 100644
--- a/webclient/room/room.html
+++ b/webclient/room/room.html
@@ -3,7 +3,7 @@
<div id="roomHeader">
<a href ng-click="goToPage('/')"><img src="img/logo-small.png" width="100" height="43" alt="[matrix]"/></a>
<div id="roomName">
- {{ room_alias || room_id }}
+ {{ room_id | roomName }}
</div>
</div>
@@ -26,8 +26,8 @@
<img class="userAvatarGradient" src="img/gradient.png" title="{{ member.id }}" width="80" height="24"/>
<div class="userName">{{ member.displayname || member.id.substr(0, member.id.indexOf(':')) }}<br/>{{ member.displayname ? "" : member.id.substr(member.id.indexOf(':')) }}</div>
</td>
- <td class="userPresence" ng-class="(member.presenceState === 'online' ? 'online' : (member.presenceState === 'unavailable' ? 'unavailable' : '')) + ' ' + (member.membership == 'invite' ? 'invited' : '')">
- <span ng-show="member.mtime_age">{{ member.mtime_age + (now - member.last_updated) | duration }}<br/>ago</span>
+ <td class="userPresence" ng-class="(member.presence === 'online' ? 'online' : (member.presence === 'unavailable' ? 'unavailable' : '')) + ' ' + (member.membership == 'invite' ? 'invited' : '')">
+ <span ng-show="member.last_active_ago">{{ member.last_active_ago + (now - member.last_updated) | duration }}<br/>ago</span>
</td>
</table>
</div>
@@ -100,18 +100,7 @@
<button ng-click="inviteUser(userIDToInvite)">Invite</button>
</span>
<button ng-click="leaveRoom()">Leave</button>
- <button ng-click="startVoiceCall()" ng-show="currentCall == undefined && memberCount() == 2">Voice Call</button>
- <div ng-show="currentCall.state == 'ringing'">
- Incoming call from {{ currentCall.user_id }}
- <button ng-click="answerCall()">Answer</button>
- <button ng-click="hangupCall()">Reject</button>
- </div>
- <button ng-click="hangupCall()" ng-show="currentCall && currentCall.state != 'ringing'">Hang up</button>
- <span ng-show="currentCall.state == 'invite_sent'">Calling...</span>
- <span ng-show="currentCall.state == 'connecting'">Call Connecting...</span>
- <span ng-show="currentCall.state == 'connected'">Call Connected</span>
- <span ng-show="currentCall.state == 'ended'">Call Ended</span>
- <span style="display: none; ">{{ currentCall.state }}</span>
+ <button ng-click="startVoiceCall()" ng-show="(currentCall == undefined || currentCall.state == 'ended') && memberCount() == 2">Voice Call</button>
</div>
{{ feedback }}
|