diff --git a/lib/shared/avatar-utils.js b/lib/shared/avatar-utils.js
--- a/lib/shared/avatar-utils.js
+++ b/lib/shared/avatar-utils.js
@@ -9,7 +9,10 @@
import { threadOtherMembers } from './thread-utils.js';
import genesis from '../facts/genesis.js';
import { useENSAvatar } from '../hooks/ens-cache.js';
-import { useFarcasterUserAvatarURL } from '../hooks/fc-cache.js';
+import {
+ useFarcasterUserAvatarURL,
+ useFarcasterChannelAvatarURL,
+} from '../hooks/fc-cache.js';
import type {
ClientAvatar,
ClientEmojiAvatar,
@@ -319,9 +322,12 @@
return getDefaultAvatar(thread.id, thread.color);
}
+type UsernameAndFID = { +username?: ?string, +farcasterID: ?string, ... };
+type FCChannelInfo = { +fcChannelID: ?string };
+
function useResolvedUserAvatar(
userAvatarInfo: ClientAvatar,
- usernameAndFID: ?{ +username?: ?string, +farcasterID?: ?string, ... },
+ usernameAndFID: ?UsernameAndFID,
): ResolvedClientAvatar {
const ethAddress = React.useMemo(
() => getETHAddressForUserInfo(usernameAndFID),
@@ -338,12 +344,14 @@
return userAvatarInfo;
}
- if (ensAvatarURI) {
+ if (ensAvatarURI && userAvatarInfo.type === 'ens') {
return {
type: 'image',
uri: ensAvatarURI,
};
- } else if (farcasterAvatarURL) {
+ }
+
+ if (farcasterAvatarURL && userAvatarInfo.type === 'farcaster') {
return {
type: 'image',
uri: farcasterAvatarURL,
@@ -358,12 +366,20 @@
function useResolvedThreadAvatar(
threadAvatarInfo: ClientAvatar,
- displayUser: ?{ +username?: ?string, +farcasterID?: ?string, ... },
+ params: {
+ +userProfileInfo: ?UsernameAndFID,
+ +channelInfo: FCChannelInfo,
+ },
): ResolvedClientAvatar {
+ const username = params.userProfileInfo?.username;
+ const farcasterID = params.userProfileInfo?.farcasterID;
+ const fcChannelID = params.channelInfo.fcChannelID;
+
const resolvedUserAvatar = useResolvedUserAvatar(
threadAvatarInfo,
- displayUser,
+ params.userProfileInfo,
);
+ const farcasterAvatarURL = useFarcasterChannelAvatarURL(fcChannelID);
if (
threadAvatarInfo.type !== 'ens' &&
@@ -372,7 +388,26 @@
return threadAvatarInfo;
}
- return resolvedUserAvatar;
+ // If both `userProfileInfo` and `channelInfo` are supplied, the former should
+ // supersede the latter.
+ if (username || farcasterID) {
+ return resolvedUserAvatar;
+ }
+
+ if (farcasterAvatarURL) {
+ return {
+ type: 'image',
+ uri: farcasterAvatarURL,
+ };
+ }
+
+ // If fetching a Farcaster channel avatar URL fails or is in-progress, we
+ // return a default anonymous avatar
+ return {
+ type: 'emoji',
+ color: selectedThreadColors[4],
+ emoji: '👥',
+ };
}
export {
diff --git a/native/avatars/thread-avatar.react.js b/native/avatars/thread-avatar.react.js
--- a/native/avatars/thread-avatar.react.js
+++ b/native/avatars/thread-avatar.react.js
@@ -55,7 +55,10 @@
};
});
- const resolvedThreadAvatar = useResolvedThreadAvatar(avatarInfo, displayUser);
+ const resolvedThreadAvatar = useResolvedThreadAvatar(avatarInfo, {
+ userProfileInfo: displayUser,
+ channelInfo: { fcChannelID: null },
+ });
return ;
}
diff --git a/web/avatars/thread-avatar.react.js b/web/avatars/thread-avatar.react.js
--- a/web/avatars/thread-avatar.react.js
+++ b/web/avatars/thread-avatar.react.js
@@ -55,7 +55,10 @@
};
});
- const resolvedThreadAvatar = useResolvedThreadAvatar(avatarInfo, displayUser);
+ const resolvedThreadAvatar = useResolvedThreadAvatar(avatarInfo, {
+ userProfileInfo: displayUser,
+ channelInfo: { fcChannelID: null },
+ });
return (