3535import com .vaadin .flow .internal .UsageStatistics ;
3636import com .vaadin .flow .server .AbstractStreamResource ;
3737import com .vaadin .flow .server .StreamResource ;
38+ import com .vaadin .flow .server .streams .DownloadHandler ;
3839
3940/**
4041 * Extension of the {@link AvatarGroup} component which integrates with the
@@ -55,8 +56,10 @@ public class CollaborationAvatarGroup extends Composite<AvatarGroup>
5556 * @see StreamResource
5657 * @see CollaborationAvatarGroup#setImageProvider(ImageProvider)
5758 * @since 1.0
59+ * @deprecated Use {@link #setImageHandler(ImageHandler)} instead.
5860 */
5961 @ FunctionalInterface
62+ @ Deprecated (since = "6.5" , forRemoval = true )
6063 public interface ImageProvider {
6164 /**
6265 * Gets a stream resource that provides the avatar image for the given
@@ -72,6 +75,30 @@ public interface ImageProvider {
7275 AbstractStreamResource getImageResource (UserInfo user );
7376 }
7477
78+ /**
79+ * Callback for creating a download handler for the avatar image for a
80+ * specific user. This allows loading the user image from a dynamic location
81+ * such as a database.
82+ *
83+ * @see DownloadHandler
84+ * @see CollaborationAvatarGroup#setImageHandler(ImageHandler)
85+ * @since 6.5
86+ */
87+ @ FunctionalInterface
88+ public interface ImageHandler {
89+ /**
90+ * Gets a download handler for the avatar image for the given user.
91+ *
92+ * @param user
93+ * the user for which to get a download handler with the
94+ * image, not <code>null</code>
95+ * @return the download handler to use for the image, or
96+ * <code>null</code> to not show use any avatar image for the
97+ * given user
98+ */
99+ DownloadHandler getDownloadHandler (UserInfo user );
100+ }
101+
75102 private final SerializableSupplier <CollaborationEngine > ceSupplier ;
76103
77104 private final UserInfo localUser ;
@@ -84,6 +111,8 @@ public interface ImageProvider {
84111
85112 private ImageProvider imageProvider ;
86113
114+ private ImageHandler imageHandler ;
115+
87116 private boolean ownAvatarVisible ;
88117
89118 static {
@@ -261,10 +290,12 @@ private AvatarGroupItem userToAvatarGroupItem(UserInfo user) {
261290 item .setName (user .getName ());
262291 item .setAbbreviation (user .getAbbreviation ());
263292
264- if (imageProvider = = null ) {
265- item .setImage ( user . getImage ( ));
266- } else {
293+ if (imageHandler ! = null ) {
294+ item .setImageHandler ( imageHandler . getDownloadHandler ( user ));
295+ } else if ( imageProvider != null ) {
267296 item .setImageResource (imageProvider .getImageResource (user ));
297+ } else {
298+ item .setImage (user .getImage ());
268299 }
269300
270301 item .setColorIndex (getCollaborationEngine ().getUserColorIndex (user ));
@@ -310,7 +341,9 @@ private boolean isNotLocalUser(UserInfo user) {
310341 * the image provider to use, or <code>null</code> to use image
311342 * URLs directly from the user info object
312343 * @since 1.0
344+ * @deprecated Use {@link #setImageHandler(ImageHandler)} instead.
313345 */
346+ @ Deprecated (since = "6.5" , forRemoval = true )
314347 public void setImageProvider (ImageProvider imageProvider ) {
315348 this .imageProvider = imageProvider ;
316349 refreshItems ();
@@ -324,11 +357,63 @@ public void setImageProvider(ImageProvider imageProvider) {
324357 * @return the current image provider callback, or <code>null</code> if no
325358 * callback is set
326359 * @since 1.0
360+ * @deprecated Use {@link #setImageHandler(ImageHandler)} instead.
327361 */
362+ @ Deprecated (since = "6.5" , forRemoval = true )
328363 public ImageProvider getImageProvider () {
329364 return imageProvider ;
330365 }
331366
367+ /**
368+ * Sets an image handler callback for dynamically loading avatar images for
369+ * a given user. The image can be loaded on-demand from a database or using
370+ * any other source of IO streams.
371+ * <p>
372+ * If no image handler callback is defined, then the image URL defined by
373+ * {@link UserInfo#getImage()} is directly passed to the browser. This means
374+ * that avatar images need to be available as static files or served
375+ * dynamically from a custom servlet. This is the default.
376+ *
377+ * Usage example:
378+ *
379+ * <pre>
380+ * collaborationAvatarGroup.setImageHandler(userInfo -> {
381+ * DownloadHandler downloadHandler = DownloadHandler
382+ * .fromInputStream(context -> {
383+ * User userEntity = userRepository
384+ * .findById(userInfo.getId());
385+ * byte[] profilePicture = userEntity.getProfilePicture();
386+ * return new DownloadResponse(
387+ * new ByteArrayInputStream(profilePicture),
388+ * "avatar_" + userInfo.getId(), "image/png", -1);
389+ * });
390+ * return downloadHandler;
391+ * });
392+ * </pre>
393+ *
394+ * @param imageHandler
395+ * the image handler to use, or <code>null</code> to use image
396+ * URLs directly from the user info object
397+ * @since 6.5
398+ */
399+ public void setImageHandler (ImageHandler imageHandler ) {
400+ this .imageHandler = imageHandler ;
401+ refreshItems ();
402+ }
403+
404+ /**
405+ * Gets the currently used image handler callback.
406+ *
407+ * @see #setImageHandler(ImageHandler)
408+ *
409+ * @return the current image handler callback, or <code>null</code> if no
410+ * callback is set
411+ * @since 6.5
412+ */
413+ public ImageHandler getImageHandler () {
414+ return imageHandler ;
415+ }
416+
332417 /**
333418 * Gets whether the user's own avatar is displayed in the avatar group or
334419 * not.
0 commit comments