@@ -8,87 +8,50 @@ import { getInboxProfileSocialsQueryConfig } from "@/queries/useInboxProfileSoci
8
8
import { $globalStyles } from "@/theme/styles" ;
9
9
import { ThemedStyle , useAppTheme } from "@/theme/useAppTheme" ;
10
10
import {
11
+ getPreferredInboxAddress ,
11
12
getPreferredInboxAvatar ,
12
13
getPreferredInboxName ,
13
14
} from "@/utils/profile" ;
14
15
import { useQueries } from "@tanstack/react-query" ;
15
- import { ConversationTopic } from "@xmtp/react-native-sdk" ;
16
+ import { ConversationTopic , InboxId } from "@xmtp/react-native-sdk" ;
16
17
import React , { memo , useMemo } from "react" ;
17
18
import { StyleProp , TextStyle , ViewStyle } from "react-native" ;
18
19
import { Avatar } from "./Avatar" ;
19
20
20
- const MAIN_CIRCLE_RADIUS = 50 ;
21
- const MAX_VISIBLE_MEMBERS = 4 ;
22
-
23
- type Position = { x : number ; y : number ; size : number } ;
24
-
25
- type IGroupAvatarMember = {
26
- address : string ;
27
- uri ?: string ;
28
- name ?: string ;
29
- } ;
30
-
31
- type IGroupAvatarDumbProps = {
32
- size ?: number ;
33
- style ?: StyleProp < ViewStyle > ;
34
- members ?: IGroupAvatarMember [ ] ;
35
- } ;
36
-
37
- export const GroupAvatarMembers = memo ( function GroupAvatarDumb (
38
- props : IGroupAvatarDumbProps
39
- ) {
40
- const { themed, theme } = useAppTheme ( ) ;
41
-
42
- const { size = theme . avatarSize . md , style, members = [ ] } = props ;
43
-
44
- const memberCount = members ?. length || 0 ;
21
+ /**
22
+ * Comp to render a group avatar from a list of inbox ids
23
+ */
24
+ export const GroupAvatarInboxIds = memo ( function GroupAvatarInboxIds ( props : {
25
+ inboxIds : InboxId [ ] ;
26
+ } ) {
27
+ const { inboxIds } = props ;
45
28
46
- const positions = useMemo (
47
- ( ) => calculatePositions ( memberCount , MAIN_CIRCLE_RADIUS ) ,
48
- [ memberCount ]
49
- ) ;
29
+ const socialsData = useQueries ( {
30
+ queries : inboxIds . map ( ( inboxId ) =>
31
+ getInboxProfileSocialsQueryConfig ( { inboxId } )
32
+ ) ,
33
+ } ) ;
50
34
51
- return (
52
- < Center style = { [ { width : size , height : size } , $container , style ] } >
53
- < Center style = { [ { width : size , height : size } , $container ] } >
54
- < VStack style = { themed ( $background ) } />
55
- < Center style = { $content } >
56
- { positions . map ( ( pos , index ) => {
57
- if ( index < MAX_VISIBLE_MEMBERS && index < memberCount ) {
58
- return (
59
- < Avatar
60
- key = { `avatar-${ index } ` }
61
- uri = { members [ index ] . uri }
62
- name = { members [ index ] . name }
63
- size = { ( pos . size / 100 ) * size }
64
- style = { {
65
- left : ( pos . x / 100 ) * size ,
66
- top : ( pos . y / 100 ) * size ,
67
- position : "absolute" ,
68
- } }
69
- />
70
- ) ;
71
- } else if (
72
- index === MAX_VISIBLE_MEMBERS &&
73
- memberCount > MAX_VISIBLE_MEMBERS
74
- ) {
75
- return (
76
- < ExtraMembersIndicator
77
- key = { `extra-${ index } ` }
78
- pos = { pos }
79
- extraMembersCount = { memberCount - MAX_VISIBLE_MEMBERS }
80
- size = { size }
81
- />
82
- ) ;
35
+ const members = useMemo ( ( ) => {
36
+ return socialsData
37
+ . map ( ( { data : socials } , index ) : IGroupAvatarMember | null =>
38
+ socials
39
+ ? {
40
+ address : getPreferredInboxAddress ( socials ) ?? "" ,
41
+ uri : getPreferredInboxAvatar ( socials ) ,
42
+ name : getPreferredInboxName ( socials ) ,
83
43
}
84
- return null ;
85
- } ) }
86
- </ Center >
87
- </ Center >
88
- </ Center >
89
- ) ;
44
+ : null
45
+ )
46
+ . filter ( Boolean ) ;
47
+ } , [ socialsData ] ) ;
48
+
49
+ return < GroupAvatarUI members = { members } /> ;
90
50
} ) ;
91
51
52
+ /**
53
+ * Comp to render a group avatar from a group topic (will render the group image if available)
54
+ */
92
55
export const GroupAvatar = memo ( function GroupAvatar ( props : {
93
56
groupTopic : ConversationTopic ;
94
57
size ?: "sm" | "md" | "lg" ;
@@ -166,7 +129,77 @@ export const GroupAvatar = memo(function GroupAvatar(props: {
166
129
return < Avatar uri = { group . imageUrlSquare } size = { sizeNumber } /> ;
167
130
}
168
131
169
- return < GroupAvatarMembers members = { memberData } size = { sizeNumber } /> ;
132
+ return < GroupAvatarUI members = { memberData } size = { sizeNumber } /> ;
133
+ } ) ;
134
+
135
+ const MAIN_CIRCLE_RADIUS = 50 ;
136
+ const MAX_VISIBLE_MEMBERS = 4 ;
137
+
138
+ type Position = { x : number ; y : number ; size : number } ;
139
+
140
+ type IGroupAvatarMember = {
141
+ address : string ;
142
+ uri ?: string ;
143
+ name ?: string ;
144
+ } ;
145
+
146
+ type IGroupAvatarUIProps = {
147
+ size ?: number ;
148
+ style ?: StyleProp < ViewStyle > ;
149
+ members ?: IGroupAvatarMember [ ] ;
150
+ } ;
151
+
152
+ const GroupAvatarUI = memo ( function GroupAvatarUI ( props : IGroupAvatarUIProps ) {
153
+ const { themed, theme } = useAppTheme ( ) ;
154
+
155
+ const { size = theme . avatarSize . md , style, members = [ ] } = props ;
156
+
157
+ const memberCount = members ?. length || 0 ;
158
+
159
+ const positions = useMemo (
160
+ ( ) => calculatePositions ( memberCount , MAIN_CIRCLE_RADIUS ) ,
161
+ [ memberCount ]
162
+ ) ;
163
+
164
+ return (
165
+ < Center style = { [ { width : size , height : size } , $container , style ] } >
166
+ < Center style = { [ { width : size , height : size } , $container ] } >
167
+ < VStack style = { themed ( $background ) } />
168
+ < Center style = { $content } >
169
+ { positions . map ( ( pos , index ) => {
170
+ if ( index < MAX_VISIBLE_MEMBERS && index < memberCount ) {
171
+ return (
172
+ < Avatar
173
+ key = { `avatar-${ index } ` }
174
+ uri = { members [ index ] . uri }
175
+ name = { members [ index ] . name }
176
+ size = { ( pos . size / 100 ) * size }
177
+ style = { {
178
+ left : ( pos . x / 100 ) * size ,
179
+ top : ( pos . y / 100 ) * size ,
180
+ position : "absolute" ,
181
+ } }
182
+ />
183
+ ) ;
184
+ } else if (
185
+ index === MAX_VISIBLE_MEMBERS &&
186
+ memberCount > MAX_VISIBLE_MEMBERS
187
+ ) {
188
+ return (
189
+ < ExtraMembersIndicator
190
+ key = { `extra-${ index } ` }
191
+ pos = { pos }
192
+ extraMembersCount = { memberCount - MAX_VISIBLE_MEMBERS }
193
+ size = { size }
194
+ />
195
+ ) ;
196
+ }
197
+ return null ;
198
+ } ) }
199
+ </ Center >
200
+ </ Center >
201
+ </ Center >
202
+ ) ;
170
203
} ) ;
171
204
172
205
const calculatePositions = (
@@ -256,7 +289,6 @@ const $background: ThemedStyle<ViewStyle> = ({ colors }) => ({
256
289
...$globalStyles . absoluteFill ,
257
290
backgroundColor : colors . fill . minimal ,
258
291
borderRadius : 999 ,
259
- opacity : 0.4 ,
260
292
} ) ;
261
293
262
294
const $extraMembersContainer : ThemedStyle < ViewStyle > = ( { colors } ) => ( {
0 commit comments