11/*
2+ Copyright 2015, 2016 OpenMarket Ltd
3+ Copyright 2018 New Vector Ltd
24Copyright 2019 Michael Telatynski <[email protected] > 3- Copyright 2015, 2016, 2018, 2019, 2020, 2023 The Matrix.org Foundation C.I.C.
5+ Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
46
57Licensed under the Apache License, Version 2.0 (the "License");
68you may not use this file except in compliance with the License.
@@ -19,41 +21,34 @@ import React, { useCallback, useContext, useEffect, useState } from "react";
1921import classNames from "classnames" ;
2022import { ResizeMethod } from "matrix-js-sdk/src/@types/partials" ;
2123import { ClientEvent } from "matrix-js-sdk/src/client" ;
22- import { SyncState } from "matrix-js-sdk/src/sync" ;
2324
2425import * as AvatarLogic from "../../../Avatar" ;
26+ import SettingsStore from "../../../settings/SettingsStore" ;
2527import AccessibleButton from "../elements/AccessibleButton" ;
2628import RoomContext from "../../../contexts/RoomContext" ;
2729import MatrixClientContext from "../../../contexts/MatrixClientContext" ;
2830import { useTypedEventEmitter } from "../../../hooks/useEventEmitter" ;
2931import { toPx } from "../../../utils/units" ;
3032import { _t } from "../../../languageHandler" ;
31- import AccessibleTooltipButton from "../elements/AccessibleTooltipButton" ;
3233
3334interface IProps {
34- /** The name (first initial used as default) */
35- name : string ;
36- /** ID for generating hash colours */
37- idName ?: string ;
38- /** onHover title text */
39- title ?: string ;
40- /** highest priority of them all, shortcut to set in urls[0] */
41- url ?: string ;
42- /** [highest_priority, ... , lowest_priority] */
43- urls ?: string [ ] ;
35+ name : string ; // The name (first initial used as default)
36+ idName ?: string ; // ID for generating hash colours
37+ title ?: string ; // onHover title text
38+ url ?: string ; // highest priority of them all, shortcut to set in urls[0]
39+ urls ?: string [ ] ; // [highest_priority, ... , lowest_priority]
4440 width ?: number ;
4541 height ?: number ;
46- /** @deprecated not actually used */
42+ // XXX: resizeMethod not actually used.
4743 resizeMethod ?: ResizeMethod ;
48- /** true to add default url */
49- defaultToInitialLetter ?: boolean ;
50- onClick ?: React . ComponentPropsWithoutRef < typeof AccessibleTooltipButton > [ "onClick" ] ;
44+ defaultToInitialLetter ?: boolean ; // true to add default url
45+ onClick ?: React . MouseEventHandler ;
5146 inputRef ?: React . RefObject < HTMLImageElement & HTMLSpanElement > ;
5247 className ?: string ;
5348 tabIndex ?: number ;
5449}
5550
56- const calculateUrls = ( url : string | undefined , urls : string [ ] | undefined , lowBandwidth : boolean ) : string [ ] => {
51+ const calculateUrls = ( url : string , urls : string [ ] , lowBandwidth : boolean ) : string [ ] => {
5752 // work out the full set of urls to try to load. This is formed like so:
5853 // imageUrls: [ props.url, ...props.urls ]
5954
@@ -71,26 +66,11 @@ const calculateUrls = (url: string | undefined, urls: string[] | undefined, lowB
7166 return Array . from ( new Set ( _urls ) ) ;
7267} ;
7368
74- /**
75- * Hook for cycling through a changing set of images.
76- *
77- * The set of images is updated whenever `url` or `urls` change, the user's
78- * `lowBandwidth` preference changes, or the client reconnects.
79- *
80- * Returns `[imageUrl, onError]`. When `onError` is called, the next image in
81- * the set will be displayed.
82- */
83- const useImageUrl = ( {
84- url,
85- urls,
86- } : {
87- url : string | undefined ;
88- urls : string [ ] | undefined ;
89- } ) : [ string | undefined , ( ) => void ] => {
69+ const useImageUrl = ( { url, urls } ) : [ string , ( ) => void ] => {
9070 // Since this is a hot code path and the settings store can be slow, we
9171 // use the cached lowBandwidth value from the room context if it exists
9272 const roomContext = useContext ( RoomContext ) ;
93- const lowBandwidth = roomContext . lowBandwidth ;
73+ const lowBandwidth = roomContext ? roomContext . lowBandwidth : SettingsStore . getValue ( "lowBandwidth" ) ;
9474
9575 const [ imageUrls , setUrls ] = useState < string [ ] > ( calculateUrls ( url , urls , lowBandwidth ) ) ;
9676 const [ urlsIndex , setIndex ] = useState < number > ( 0 ) ;
@@ -105,10 +85,10 @@ const useImageUrl = ({
10585 } , [ url , JSON . stringify ( urls ) ] ) ; // eslint-disable-line react-hooks/exhaustive-deps
10686
10787 const cli = useContext ( MatrixClientContext ) ;
108- const onClientSync = useCallback ( ( syncState : SyncState , prevState : SyncState | null ) => {
88+ const onClientSync = useCallback ( ( syncState , prevState ) => {
10989 // Consider the client reconnected if there is no error with syncing.
11090 // This means the state could be RECONNECTING, SYNCING, PREPARED or CATCHUP.
111- const reconnected = syncState !== SyncState . Error && prevState !== syncState ;
91+ const reconnected = syncState !== "ERROR" && prevState !== syncState ;
11292 if ( reconnected ) {
11393 setIndex ( 0 ) ;
11494 }
@@ -128,18 +108,46 @@ const BaseAvatar: React.FC<IProps> = (props) => {
128108 urls,
129109 width = 40 ,
130110 height = 40 ,
111+ resizeMethod = "crop" , // eslint-disable-line @typescript-eslint/no-unused-vars
131112 defaultToInitialLetter = true ,
132113 onClick,
133114 inputRef,
134115 className,
135- resizeMethod : _unused , // to keep it from being in `otherProps`
136116 ...otherProps
137117 } = props ;
138118
139119 const [ imageUrl , onError ] = useImageUrl ( { url, urls } ) ;
140120
141121 if ( ! imageUrl && defaultToInitialLetter && name ) {
142- const avatar = < TextAvatar name = { name } idName = { idName } width = { width } height = { height } title = { title } /> ;
122+ const initialLetter = AvatarLogic . getInitialLetter ( name ) ;
123+ const textNode = (
124+ < span
125+ className = "mx_BaseAvatar_initial"
126+ aria-hidden = "true"
127+ style = { {
128+ fontSize : toPx ( width * 0.65 ) ,
129+ width : toPx ( width ) ,
130+ lineHeight : toPx ( height ) ,
131+ } }
132+ >
133+ { initialLetter }
134+ </ span >
135+ ) ;
136+ const imgNode = (
137+ < img
138+ className = "mx_BaseAvatar_image"
139+ src = { AvatarLogic . defaultAvatarUrlForString ( idName || name ) }
140+ alt = ""
141+ title = { title }
142+ onError = { onError }
143+ style = { {
144+ width : toPx ( width ) ,
145+ height : toPx ( height ) ,
146+ } }
147+ aria-hidden = "true"
148+ data-testid = "avatar-img"
149+ />
150+ ) ;
143151
144152 if ( onClick ) {
145153 return (
@@ -151,12 +159,9 @@ const BaseAvatar: React.FC<IProps> = (props) => {
151159 className = { classNames ( "mx_BaseAvatar" , className ) }
152160 onClick = { onClick }
153161 inputRef = { inputRef }
154- style = { {
155- width : toPx ( width ) ,
156- height : toPx ( height ) ,
157- } }
158162 >
159- { avatar }
163+ { textNode }
164+ { imgNode }
160165 </ AccessibleButton >
161166 ) ;
162167 } else {
@@ -165,13 +170,10 @@ const BaseAvatar: React.FC<IProps> = (props) => {
165170 className = { classNames ( "mx_BaseAvatar" , className ) }
166171 ref = { inputRef }
167172 { ...otherProps }
168- style = { {
169- width : toPx ( width ) ,
170- height : toPx ( height ) ,
171- } }
172173 role = "presentation"
173174 >
174- { avatar }
175+ { textNode }
176+ { imgNode }
175177 </ span >
176178 ) ;
177179 }
@@ -218,31 +220,3 @@ const BaseAvatar: React.FC<IProps> = (props) => {
218220
219221export default BaseAvatar ;
220222export type BaseAvatarType = React . FC < IProps > ;
221-
222- const TextAvatar : React . FC < {
223- name : string ;
224- idName ?: string ;
225- width : number ;
226- height : number ;
227- title ?: string ;
228- } > = ( { name, idName, width, height, title } ) => {
229- const initialLetter = AvatarLogic . getInitialLetter ( name ) ;
230-
231- return (
232- < span
233- className = "mx_BaseAvatar_image mx_BaseAvatar_initial"
234- aria-hidden = "true"
235- style = { {
236- backgroundColor : AvatarLogic . getColorForString ( idName || name ) ,
237- width : toPx ( width ) ,
238- height : toPx ( height ) ,
239- fontSize : toPx ( width * 0.65 ) ,
240- lineHeight : toPx ( height ) ,
241- } }
242- title = { title }
243- data-testid = "avatar-img"
244- >
245- { initialLetter }
246- </ span >
247- ) ;
248- } ;
0 commit comments