import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/group_image.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_image.png) /// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_image_paint.png) /// /// It shows the current [Channel] image. /// /// ```dart /// class MyApp extends StatelessWidget { /// final StreamChatClient client; /// final Channel channel; /// /// MyApp(this.client, this.channel); /// /// @override /// Widget build(BuildContext context) { /// return MaterialApp( /// debugShowCheckedModeBanner: false, /// home: StreamChat( /// client: client, /// child: StreamChannel( /// channel: channel, /// child: Center( /// child: ChannelImage( /// channel: channel, /// ), /// ), /// ), /// ), /// ); /// } /// } /// ``` /// /// The widget uses a [StreamBuilder] to render the channel information /// image as soon as it updates. /// /// By default the widget radius size is 40x40 pixels. /// Set the property [constraints] to set a custom dimension. /// /// The widget renders the ui based on the first ancestor of type /// [StreamChatTheme]. /// Modify it to change the widget appearance. class ChannelImage extends StatelessWidget { /// Instantiate a new ChannelImage const ChannelImage({ Key? key, this.channel, this.constraints, this.onTap, this.borderRadius, this.selected = false, this.selectionColor, this.selectionThickness = 4, }) : super(key: key); /// [BorderRadius] to display the widget final BorderRadius? borderRadius; /// The channel to show the image of final Channel? channel; /// The diameter of the image final BoxConstraints? constraints; /// The function called when the image is tapped final VoidCallback? onTap; /// If image is selected final bool selected; /// Selection color for image final Color? selectionColor; /// Thickness of selection image final double selectionThickness; @override Widget build(BuildContext context) { final streamChat = StreamChat.of(context); final channel = this.channel ?? StreamChannel.of(context).channel; return BetterStreamBuilder>( stream: channel.extraDataStream, initialData: channel.extraData, builder: (context, snapshot) { String? image; final chatThemeData = StreamChatTheme.of(context); if (snapshot.containsKey('image') == true) { image = snapshot['image']; } else if (channel.state?.members.length == 2) { final otherMember = channel.state?.members .firstWhere((member) => member.user?.id != streamChat.user?.id); return StreamBuilder( stream: streamChat.client.state.usersStream.map( (users) => users[otherMember?.userId] ?? otherMember!.user!), initialData: otherMember!.user, builder: (context, snapshot) => UserAvatar( borderRadius: borderRadius ?? chatThemeData .channelPreviewTheme.avatarTheme?.borderRadius, user: snapshot.data ?? otherMember.user!, constraints: constraints ?? chatThemeData .channelPreviewTheme.avatarTheme?.constraints, onTap: onTap != null ? (_) => onTap!() : null, selected: selected, selectionColor: selectionColor ?? chatThemeData.colorTheme.accentBlue, selectionThickness: selectionThickness, )); } else { final images = channel.state?.members .where((member) => member.user?.id != streamChat.user?.id && member.user?.extraData['image'] != null) .take(4) // ignore: cast_nullable_to_non_nullable .map((e) => e.user?.extraData['image'] as String) .toList(); return GroupImage( images: images ?? [], borderRadius: borderRadius ?? chatThemeData.channelPreviewTheme.avatarTheme?.borderRadius, constraints: constraints ?? chatThemeData.channelPreviewTheme.avatarTheme?.constraints, onTap: onTap, selected: selected, selectionColor: selectionColor ?? chatThemeData.colorTheme.accentBlue, selectionThickness: selectionThickness, ); } Widget child = ClipRRect( borderRadius: borderRadius ?? chatThemeData.channelPreviewTheme.avatarTheme?.borderRadius, child: Container( constraints: constraints ?? chatThemeData.channelPreviewTheme.avatarTheme?.constraints, decoration: BoxDecoration( color: chatThemeData.colorTheme.accentBlue, ), child: Stack( alignment: Alignment.center, fit: StackFit.expand, children: [ if (image != null) CachedNetworkImage( imageUrl: image, errorWidget: (_, __, ___) => Center( child: Text( snapshot.containsKey('name') ? snapshot['name'][0] : '', style: TextStyle( color: chatThemeData.colorTheme.white, fontWeight: FontWeight.bold, ), ), ), fit: BoxFit.cover, ) else chatThemeData.defaultChannelImage( context, channel, ), Material( color: Colors.transparent, child: InkWell( onTap: onTap, ), ), ], ), ), ); if (selected) { child = ClipRRect( key: const Key('selectedImage'), borderRadius: (borderRadius ?? chatThemeData.ownMessageTheme.avatarTheme?.borderRadius ?? BorderRadius.zero) + BorderRadius.circular(selectionThickness), child: Container( constraints: constraints ?? chatThemeData.ownMessageTheme.avatarTheme?.constraints, color: selectionColor ?? chatThemeData.colorTheme.accentBlue, child: Padding( padding: EdgeInsets.all(selectionThickness), child: child, ), ), ); } return child; }, ); } }