mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-12-23 11:35:04 +01:00
Merge pull request #60 from vector-im/bwindels/room-avatars
Render room avatar images
This commit is contained in:
commit
7ea10ea2ea
@ -87,13 +87,24 @@ export class RoomViewModel extends ViewModel {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
get avatarInitials() {
|
get avatarLetter() {
|
||||||
return avatarInitials(this._room.name);
|
return avatarInitials(this._room.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
get avatarColorNumber() {
|
get avatarColorNumber() {
|
||||||
return getIdentifierColorNumber(this._room.id)
|
return getIdentifierColorNumber(this._room.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get avatarUrl() {
|
||||||
|
if (this._room.avatarUrl) {
|
||||||
|
return this._room.mediaRepository.mxcUrlThumbnail(this._room.avatarUrl, 32, 32, "crop");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get avatarTitle() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
async _sendMessage(message) {
|
async _sendMessage(message) {
|
||||||
if (message) {
|
if (message) {
|
||||||
|
@ -35,6 +35,7 @@ export class MessageTile extends SimpleTile {
|
|||||||
return this._entry.displayName || this._entry.sender;
|
return this._entry.displayName || this._entry.sender;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Avatar view model contract
|
||||||
get avatarColorNumber() {
|
get avatarColorNumber() {
|
||||||
return getIdentifierColorNumber(this._entry.sender);
|
return getIdentifierColorNumber(this._entry.sender);
|
||||||
}
|
}
|
||||||
@ -50,6 +51,10 @@ export class MessageTile extends SimpleTile {
|
|||||||
return avatarInitials(this.sender);
|
return avatarInitials(this.sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get avatarTitle() {
|
||||||
|
return this.sender;
|
||||||
|
}
|
||||||
|
|
||||||
get date() {
|
get date() {
|
||||||
return this._date && this._date.toLocaleDateString({}, {month: "numeric", day: "numeric"});
|
return this._date && this._date.toLocaleDateString({}, {month: "numeric", day: "numeric"});
|
||||||
}
|
}
|
||||||
|
@ -61,11 +61,23 @@ export class RoomTileViewModel extends ViewModel {
|
|||||||
return this._room.name;
|
return this._room.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
get avatarInitials() {
|
// Avatar view model contract
|
||||||
|
get avatarLetter() {
|
||||||
return avatarInitials(this._room.name);
|
return avatarInitials(this._room.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
get avatarColorNumber() {
|
get avatarColorNumber() {
|
||||||
return getIdentifierColorNumber(this._room.id)
|
return getIdentifierColorNumber(this._room.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get avatarUrl() {
|
||||||
|
if (this._room.avatarUrl) {
|
||||||
|
return this._room.mediaRepository.mxcUrlThumbnail(this._room.avatarUrl, 32, 32, "crop");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get avatarTitle() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,6 +180,10 @@ export class Room extends EventEmitter {
|
|||||||
return this._roomId;
|
return this._roomId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get avatarUrl() {
|
||||||
|
return this._summary.avatarUrl;
|
||||||
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
async openTimeline() {
|
async openTimeline() {
|
||||||
if (this._timeline) {
|
if (this._timeline) {
|
||||||
|
@ -34,6 +34,12 @@ function applySyncResponse(data, roomResponse, membership) {
|
|||||||
}
|
}
|
||||||
data = timeline.events.reduce(processEvent, data);
|
data = timeline.events.reduce(processEvent, data);
|
||||||
}
|
}
|
||||||
|
const unreadNotifications = roomResponse.unread_notifications;
|
||||||
|
if (unreadNotifications) {
|
||||||
|
data = data.cloneIfNeeded();
|
||||||
|
data.highlightCount = unreadNotifications.highlight_count;
|
||||||
|
data.notificationCount = unreadNotifications.notification_count;
|
||||||
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@ -46,15 +52,21 @@ function processEvent(data, event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (event.type === "m.room.name") {
|
if (event.type === "m.room.name") {
|
||||||
const newName = event.content && event.content.name;
|
const newName = event.content?.name;
|
||||||
if (newName !== data.name) {
|
if (newName !== data.name) {
|
||||||
data = data.cloneIfNeeded();
|
data = data.cloneIfNeeded();
|
||||||
data.name = newName;
|
data.name = newName;
|
||||||
}
|
}
|
||||||
|
} if (event.type === "m.room.avatar") {
|
||||||
|
const newUrl = event.content?.url;
|
||||||
|
if (newUrl !== data.avatarUrl) {
|
||||||
|
data = data.cloneIfNeeded();
|
||||||
|
data.avatarUrl = newUrl;
|
||||||
|
}
|
||||||
} else if (event.type === "m.room.message") {
|
} else if (event.type === "m.room.message") {
|
||||||
const content = event.content;
|
const {content} = event;
|
||||||
const body = content && content.body;
|
const body = content?.body;
|
||||||
const msgtype = content && content.msgtype;
|
const msgtype = content?.msgtype;
|
||||||
if (msgtype === "m.text") {
|
if (msgtype === "m.text") {
|
||||||
data = data.cloneIfNeeded();
|
data = data.cloneIfNeeded();
|
||||||
data.lastMessageBody = body;
|
data.lastMessageBody = body;
|
||||||
@ -105,6 +117,9 @@ class SummaryData {
|
|||||||
this.altAliases = copy ? copy.altAliases : null;
|
this.altAliases = copy ? copy.altAliases : null;
|
||||||
this.hasFetchedMembers = copy ? copy.hasFetchedMembers : false;
|
this.hasFetchedMembers = copy ? copy.hasFetchedMembers : false;
|
||||||
this.lastPaginationToken = copy ? copy.lastPaginationToken : null;
|
this.lastPaginationToken = copy ? copy.lastPaginationToken : null;
|
||||||
|
this.avatarUrl = copy ? copy.avatarUrl : null;
|
||||||
|
this.notificationCount = copy ? copy.notificationCount : 0;
|
||||||
|
this.highlightCount = copy ? copy.highlightCount : 0;
|
||||||
this.cloned = copy ? true : false;
|
this.cloned = copy ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +170,10 @@ export class RoomSummary {
|
|||||||
return this._data.joinCount;
|
return this._data.joinCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get avatarUrl() {
|
||||||
|
return this._data.avatarUrl;
|
||||||
|
}
|
||||||
|
|
||||||
get hasFetchedMembers() {
|
get hasFetchedMembers() {
|
||||||
return this._data.hasFetchedMembers;
|
return this._data.hasFetchedMembers;
|
||||||
}
|
}
|
||||||
|
@ -19,3 +19,23 @@ export function spinner(t, extraClasses = undefined) {
|
|||||||
t.circle({cx:"50%", cy:"50%", r:"45%", pathLength:"100"})
|
t.circle({cx:"50%", cy:"50%", r:"45%", pathLength:"100"})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {TemplateBuilder} t
|
||||||
|
* @param {Object} vm view model with {avatarUrl, avatarColorNumber, avatarTitle, avatarLetter}
|
||||||
|
* @param {Number} size
|
||||||
|
* @return {Element}
|
||||||
|
*/
|
||||||
|
export function renderAvatar(t, vm, size) {
|
||||||
|
const hasAvatar = !!vm.avatarUrl;
|
||||||
|
const avatarClasses = {
|
||||||
|
avatar: true,
|
||||||
|
[`usercolor${vm.avatarColorNumber}`]: !hasAvatar,
|
||||||
|
};
|
||||||
|
// TODO: handle updates from default to img or reverse
|
||||||
|
const sizeStr = size.toString();
|
||||||
|
const avatarContent = hasAvatar ?
|
||||||
|
t.img({src: vm => vm.avatarUrl, width: sizeStr, height: sizeStr, title: vm => vm.avatarTitle}) :
|
||||||
|
vm => vm.avatarLetter;
|
||||||
|
return t.div({className: avatarClasses}, [avatarContent]);
|
||||||
|
}
|
||||||
|
@ -15,11 +15,12 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {TemplateView} from "../general/TemplateView.js";
|
import {TemplateView} from "../general/TemplateView.js";
|
||||||
|
import {renderAvatar} from "../common.js";
|
||||||
|
|
||||||
export class RoomTile extends TemplateView {
|
export class RoomTile extends TemplateView {
|
||||||
render(t, vm) {
|
render(t, vm) {
|
||||||
return t.li({"className": {"active": vm => vm.isOpen}}, [
|
return t.li({"className": {"active": vm => vm.isOpen}}, [
|
||||||
t.div({className: `avatar medium usercolor${vm.avatarColorNumber}`}, vm => vm.avatarInitials),
|
renderAvatar(t, vm, 32),
|
||||||
t.div({className: "description"}, t.div({className: "name"}, vm => vm.name))
|
t.div({className: "description"}, t.div({className: "name"}, vm => vm.name))
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import {TemplateView} from "../../general/TemplateView.js";
|
|||||||
import {TimelineList} from "./TimelineList.js";
|
import {TimelineList} from "./TimelineList.js";
|
||||||
import {TimelineLoadingView} from "./TimelineLoadingView.js";
|
import {TimelineLoadingView} from "./TimelineLoadingView.js";
|
||||||
import {MessageComposer} from "./MessageComposer.js";
|
import {MessageComposer} from "./MessageComposer.js";
|
||||||
|
import {renderAvatar} from "../../common.js";
|
||||||
|
|
||||||
export class RoomView extends TemplateView {
|
export class RoomView extends TemplateView {
|
||||||
render(t, vm) {
|
render(t, vm) {
|
||||||
@ -26,7 +27,7 @@ export class RoomView extends TemplateView {
|
|||||||
t.div({className: "TimelinePanel"}, [
|
t.div({className: "TimelinePanel"}, [
|
||||||
t.div({className: "RoomHeader"}, [
|
t.div({className: "RoomHeader"}, [
|
||||||
t.button({className: "back", onClick: () => vm.close()}),
|
t.button({className: "back", onClick: () => vm.close()}),
|
||||||
t.div({className: `avatar usercolor${vm.avatarColorNumber}`}, vm => vm.avatarInitials),
|
renderAvatar(t, vm, 32),
|
||||||
t.div({className: "room-description"}, [
|
t.div({className: "room-description"}, [
|
||||||
t.h2(vm => vm.name),
|
t.h2(vm => vm.name),
|
||||||
]),
|
]),
|
||||||
|
@ -15,6 +15,8 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {renderAvatar} from "../../../common.js";
|
||||||
|
|
||||||
export function renderMessage(t, vm, children) {
|
export function renderMessage(t, vm, children) {
|
||||||
const classes = {
|
const classes = {
|
||||||
"TextMessageView": true,
|
"TextMessageView": true,
|
||||||
@ -23,16 +25,8 @@ export function renderMessage(t, vm, children) {
|
|||||||
continuation: vm => vm.isContinuation,
|
continuation: vm => vm.isContinuation,
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasAvatar = !!vm.avatarUrl;
|
|
||||||
const avatarClasses = {
|
|
||||||
avatar: true,
|
|
||||||
[`usercolor${vm.avatarColorNumber}`]: !hasAvatar,
|
|
||||||
};
|
|
||||||
const avatarContent = hasAvatar ?
|
|
||||||
t.img({src: vm.avatarUrl, width: "30", height: "30", title: vm.sender}) :
|
|
||||||
vm.avatarLetter;
|
|
||||||
const profile = t.div({className: "profile"}, [
|
const profile = t.div({className: "profile"}, [
|
||||||
t.div({className: avatarClasses}, [avatarContent]),
|
renderAvatar(t, vm, 30),
|
||||||
t.div({className: `sender usercolor${vm.avatarColorNumber}`}, vm.sender)
|
t.div({className: `sender usercolor${vm.avatarColorNumber}`}, vm.sender)
|
||||||
]);
|
]);
|
||||||
children = [profile].concat(children);
|
children = [profile].concat(children);
|
||||||
|
Loading…
Reference in New Issue
Block a user