@@ -6,156 +6,91 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
6
6
Please see LICENSE files in the repository root for full details.
7
7
*/
8
8
9
- import React , { type ComponentProps } from "react" ;
10
- import {
11
- type Room ,
12
- RoomStateEvent ,
13
- type MatrixEvent ,
14
- EventType ,
15
- RoomType ,
16
- KnownMembership ,
17
- } from "matrix-js-sdk/src/matrix" ;
9
+ import React , { useCallback , useMemo , type ComponentProps } from "react" ;
10
+ import { type Room , RoomType , KnownMembership , EventType } from "matrix-js-sdk/src/matrix" ;
11
+ import { type RoomAvatarEventContent } from "matrix-js-sdk/src/types" ;
18
12
19
13
import BaseAvatar from "./BaseAvatar" ;
20
14
import ImageView from "../elements/ImageView" ;
21
- import { MatrixClientPeg } from "../../../MatrixClientPeg" ;
22
15
import Modal from "../../../Modal" ;
23
16
import * as Avatar from "../../../Avatar" ;
24
- import DMRoomMap from "../../../utils/DMRoomMap" ;
25
17
import { mediaFromMxc } from "../../../customisations/Media" ;
26
18
import { type IOOBData } from "../../../stores/ThreepidInviteStore" ;
27
- import { LocalRoom } from "../../../models/LocalRoom" ;
28
19
import { filterBoolean } from "../../../utils/arrays" ;
29
- import SettingsStore from "../../../settings/SettingsStore" ;
20
+ import { useSettingValue } from "../../../hooks/useSettings" ;
21
+ import { useRoomState } from "../../../hooks/useRoomState" ;
22
+ import { useRoomIdName } from "../../../hooks/room/useRoomIdName" ;
30
23
31
- interface IProps extends Omit < ComponentProps < typeof BaseAvatar > , "name" | "idName" | "url" | "onClick" > {
24
+ interface IProps extends Omit < ComponentProps < typeof BaseAvatar > , "name" | "idName" | "url" | "onClick" | "size" > {
32
25
// Room may be left unset here, but if it is,
33
26
// oobData.avatarUrl should be set (else there
34
27
// would be nowhere to get the avatar from)
35
28
room ?: Room ;
36
- oobData : IOOBData & {
29
+ // Optional here.
30
+ size ?: ComponentProps < typeof BaseAvatar > [ "size" ] ;
31
+ oobData ?: IOOBData & {
37
32
roomId ?: string ;
38
33
} ;
39
34
viewAvatarOnClick ?: boolean ;
40
35
onClick ?( ) : void ;
41
36
}
42
37
43
- interface IState {
44
- urls : string [ ] ;
45
- }
46
-
47
- export function idNameForRoom ( room : Room ) : string {
48
- const dmMapUserId = DMRoomMap . shared ( ) . getUserIdForRoomId ( room . roomId ) ;
49
- // If the room is a DM, we use the other user's ID for the color hash
50
- // in order to match the room avatar with their avatar
51
- if ( dmMapUserId ) return dmMapUserId ;
52
-
53
- if ( room instanceof LocalRoom && room . targets . length === 1 ) {
54
- return room . targets [ 0 ] . userId ;
55
- }
56
-
57
- return room . roomId ;
58
- }
59
-
60
- export default class RoomAvatar extends React . Component < IProps , IState > {
61
- public static defaultProps = {
62
- size : "36px" ,
63
- oobData : { } ,
64
- } ;
65
-
66
- public constructor ( props : IProps ) {
67
- super ( props ) ;
68
-
69
- this . state = {
70
- urls : RoomAvatar . getImageUrls ( this . props ) ,
71
- } ;
72
- }
38
+ const RoomAvatar : React . FC < IProps > = ( { room, viewAvatarOnClick, onClick, oobData, size = "36px" , ...otherProps } ) => {
39
+ const roomName = room ?. name ?? oobData ?. name ?? "?" ;
40
+ const avatarEvent = useRoomState ( room , ( state ) => state . getStateEvents ( EventType . RoomAvatar , "" ) ) ;
41
+ const roomIdName = useRoomIdName ( room , oobData ) ;
73
42
74
- public componentDidMount ( ) : void {
75
- MatrixClientPeg . safeGet ( ) . on ( RoomStateEvent . Events , this . onRoomStateEvents ) ;
76
- }
43
+ const showAvatarsOnInvites = useSettingValue ( "showAvatarsOnInvites" , room ?. roomId ) ;
77
44
78
- public componentWillUnmount ( ) : void {
79
- MatrixClientPeg . get ( ) ?. removeListener ( RoomStateEvent . Events , this . onRoomStateEvents ) ;
80
- }
81
-
82
- public static getDerivedStateFromProps ( nextProps : IProps ) : IState {
83
- return {
84
- urls : RoomAvatar . getImageUrls ( nextProps ) ,
85
- } ;
86
- }
87
-
88
- private onRoomStateEvents = ( ev : MatrixEvent ) : void => {
89
- if ( ev . getRoomId ( ) !== this . props . room ?. roomId || ev . getType ( ) !== EventType . RoomAvatar ) return ;
90
-
91
- this . setState ( {
92
- urls : RoomAvatar . getImageUrls ( this . props ) ,
93
- } ) ;
94
- } ;
95
-
96
- private static getImageUrls ( props : IProps ) : string [ ] {
97
- const myMembership = props . room ?. getMyMembership ( ) ;
98
- if ( myMembership === KnownMembership . Invite || ! myMembership ) {
99
- if ( SettingsStore . getValue ( "showAvatarsOnInvites" ) === false ) {
100
- // The user has opted out of showing avatars, so return no urls here.
101
- return [ ] ;
102
- }
103
- }
104
- let oobAvatar : string | null = null ;
105
- if ( props . oobData . avatarUrl ) {
106
- oobAvatar = mediaFromMxc ( props . oobData . avatarUrl ) . getThumbnailOfSourceHttp (
107
- parseInt ( props . size , 10 ) ,
108
- parseInt ( props . size , 10 ) ,
109
- "crop" ,
110
- ) ;
111
- }
112
-
113
- return filterBoolean ( [
114
- oobAvatar , // highest priority
115
- RoomAvatar . getRoomAvatarUrl ( props ) ,
116
- ] ) ;
117
- }
118
-
119
- private static getRoomAvatarUrl ( props : IProps ) : string | null {
120
- if ( ! props . room ) return null ;
121
-
122
- return Avatar . avatarUrlForRoom ( props . room , parseInt ( props . size , 10 ) , parseInt ( props . size , 10 ) , "crop" ) ;
123
- }
124
-
125
- private onRoomAvatarClick = ( ) : void => {
126
- const avatarUrl = Avatar . avatarUrlForRoom ( this . props . room ?? null , undefined , undefined , undefined ) ;
45
+ const onRoomAvatarClick = useCallback ( ( ) => {
46
+ const avatarUrl = Avatar . avatarUrlForRoom ( room ?? null ) ;
127
47
if ( ! avatarUrl ) return ;
128
48
const params = {
129
49
src : avatarUrl ,
130
- name : this . props . room ?. name ,
50
+ name : room ?. name ,
131
51
} ;
132
52
133
53
Modal . createDialog ( ImageView , params , "mx_Dialog_lightbox" , undefined , true ) ;
134
- } ;
54
+ } , [ room ] ) ;
135
55
136
- private get roomIdName ( ) : string | undefined {
137
- const room = this . props . room ;
138
-
139
- if ( room ) {
140
- return idNameForRoom ( room ) ;
141
- } else {
142
- return this . props . oobData ?. roomId ;
56
+ const urls = useMemo ( ( ) => {
57
+ const myMembership = room ?. getMyMembership ( ) ;
58
+ if ( ! showAvatarsOnInvites && ( myMembership === KnownMembership . Invite || ! myMembership ) ) {
59
+ // The user has opted out of showing avatars, so return no urls here.
60
+ return [ ] ;
143
61
}
144
- }
145
62
146
- public render ( ) : React . ReactNode {
147
- const { room , oobData , viewAvatarOnClick , onClick , ... otherProps } = this . props ;
148
- const roomName = room ?. name ?? oobData . name ?? "?" ;
63
+ // parseInt ignores suffixes.
64
+ const sizeInt = parseInt ( size , 10 ) ;
65
+ let oobAvatar : string | null = null ;
149
66
150
- return (
151
- < BaseAvatar
152
- { ...otherProps }
153
- type = { ( room ?. getType ( ) ?? this . props . oobData ?. roomType ) === RoomType . Space ? "square" : "round" }
154
- name = { roomName }
155
- idName = { this . roomIdName }
156
- urls = { this . state . urls }
157
- onClick = { viewAvatarOnClick && this . state . urls [ 0 ] ? this . onRoomAvatarClick : onClick }
158
- />
159
- ) ;
160
- }
161
- }
67
+ if ( oobData ?. avatarUrl ) {
68
+ oobAvatar = mediaFromMxc ( oobData ?. avatarUrl ) . getThumbnailOfSourceHttp ( sizeInt , sizeInt , "crop" ) ;
69
+ }
70
+
71
+ return filterBoolean ( [
72
+ oobAvatar , // highest priority
73
+ Avatar . avatarUrlForRoom (
74
+ room ?? null ,
75
+ sizeInt ,
76
+ sizeInt ,
77
+ "crop" ,
78
+ avatarEvent ?. getContent < RoomAvatarEventContent > ( ) . url ,
79
+ ) ,
80
+ ] ) ;
81
+ } , [ showAvatarsOnInvites , room , size , avatarEvent , oobData ] ) ;
82
+
83
+ return (
84
+ < BaseAvatar
85
+ { ...otherProps }
86
+ size = { size }
87
+ type = { ( room ?. getType ( ) ?? oobData ?. roomType ) === RoomType . Space ? "square" : "round" }
88
+ name = { roomName }
89
+ idName = { roomIdName }
90
+ urls = { urls }
91
+ onClick = { viewAvatarOnClick && urls [ 0 ] ? onRoomAvatarClick : onClick }
92
+ />
93
+ ) ;
94
+ } ;
95
+
96
+ export default RoomAvatar ;
0 commit comments