This commit is contained in:
Deven Joshi
2021-05-05 17:32:54 +05:30
parent 7b482fb5cd
commit 8a28f8c2b3
3 changed files with 167 additions and 140 deletions
@@ -3,107 +3,114 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/src/utils.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Widget to display URL attachment
class UrlAttachment extends StatelessWidget { class UrlAttachment extends StatelessWidget {
final Attachment urlAttachment; /// Constructor for creating a [UrlAttachment]
final String hostDisplayName;
final EdgeInsets textPadding;
const UrlAttachment({ const UrlAttachment({
Key? key,
required this.urlAttachment, required this.urlAttachment,
required this.hostDisplayName, required this.hostDisplayName,
this.textPadding = const EdgeInsets.symmetric( this.textPadding = const EdgeInsets.symmetric(
horizontal: 16, horizontal: 16,
vertical: 8, vertical: 8,
), ),
}); }) : super(key: key);
/// Attachment to be displayed
final Attachment urlAttachment;
/// Host name
final String hostDisplayName;
/// Padding for text
final EdgeInsets textPadding;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) => GestureDetector(
return GestureDetector( onTap: () {
onTap: () { launchURL(
launchURL( context,
context, urlAttachment.ogScrapeUrl,
urlAttachment.ogScrapeUrl, );
); },
}, child: Column(
child: Column( crossAxisAlignment: CrossAxisAlignment.stretch,
crossAxisAlignment: CrossAxisAlignment.stretch, children: [
children: [ if (urlAttachment.imageUrl != null)
if (urlAttachment.imageUrl != null) Container(
Container( clipBehavior: Clip.antiAliasWithSaveLayer,
clipBehavior: Clip.antiAliasWithSaveLayer, margin: const EdgeInsets.symmetric(horizontal: 8),
margin: EdgeInsets.symmetric(horizontal: 8), decoration: BoxDecoration(
decoration: BoxDecoration( borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(8), ),
), child: Stack(
child: Stack( children: [
children: [ CachedNetworkImage(
CachedNetworkImage( width: double.infinity,
width: double.infinity, imageUrl: urlAttachment.imageUrl!,
imageUrl: urlAttachment.imageUrl!, fit: BoxFit.cover,
fit: BoxFit.cover, ),
), Positioned(
Positioned( left: 0,
left: 0, bottom: -1,
bottom: -1, child: Container(
child: Container( decoration: BoxDecoration(
decoration: BoxDecoration( borderRadius: const BorderRadius.only(
borderRadius: BorderRadius.only( topRight: Radius.circular(16),
topRight: Radius.circular(16), ),
color:
StreamChatTheme.of(context).colorTheme.blueAlice,
), ),
color: StreamChatTheme.of(context).colorTheme.blueAlice, child: Padding(
), padding: const EdgeInsets.only(
child: Padding( top: 8,
padding: const EdgeInsets.only( left: 8,
top: 8, right: 8,
left: 8, ),
right: 8, child: Text(
), hostDisplayName,
child: Text( style: StreamChatTheme.of(context)
hostDisplayName, .textTheme
style: StreamChatTheme.of(context) .bodyBold
.textTheme .copyWith(
.bodyBold color: StreamChatTheme.of(context)
.copyWith( .colorTheme
color: StreamChatTheme.of(context) .accentBlue,
.colorTheme ),
.accentBlue, ),
),
), ),
), ),
), ),
), ],
),
),
Padding(
padding: textPadding,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (urlAttachment.title != null)
Text(
urlAttachment.title!.trim(),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: StreamChatTheme.of(context)
.textTheme
.body
.copyWith(fontWeight: FontWeight.w700),
),
if (urlAttachment.text != null)
Text(
urlAttachment.text!,
style: StreamChatTheme.of(context)
.textTheme
.body
.copyWith(fontWeight: FontWeight.w400),
),
], ],
), ),
), ),
Padding( ],
padding: textPadding, ),
child: Column( );
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (urlAttachment.title != null)
Text(
urlAttachment.title!.trim(),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: StreamChatTheme.of(context)
.textTheme
.body
.copyWith(fontWeight: FontWeight.w700),
),
if (urlAttachment.text != null)
Text(
urlAttachment.text!,
style: StreamChatTheme.of(context)
.textTheme
.body
.copyWith(fontWeight: FontWeight.w400),
),
],
),
),
],
),
);
}
} }
@@ -1,10 +1,11 @@
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import '../stream_chat_flutter.dart'; /// Widget that displays a user avatar
class UserAvatar extends StatelessWidget { class UserAvatar extends StatelessWidget {
/// Constructor to create a [UserAvatar]
const UserAvatar({ const UserAvatar({
Key? key, Key? key,
required this.user, required this.user,
@@ -20,16 +21,37 @@ class UserAvatar extends StatelessWidget {
this.selectionThickness = 4, this.selectionThickness = 4,
}) : super(key: key); }) : super(key: key);
/// User whose avatar is to displayed
final User user; final User user;
/// Alignment of the online indicator
final Alignment onlineIndicatorAlignment; final Alignment onlineIndicatorAlignment;
/// Size of the avatar
final BoxConstraints? constraints; final BoxConstraints? constraints;
/// [BorderRadius] of the image
final BorderRadius? borderRadius; final BorderRadius? borderRadius;
/// Size of the online indicator
final BoxConstraints? onlineIndicatorConstraints; final BoxConstraints? onlineIndicatorConstraints;
/// Callback when avatar is tapped
final void Function(User)? onTap; final void Function(User)? onTap;
/// Callback when avatar is long pressed
final void Function(User)? onLongPress; final void Function(User)? onLongPress;
/// Flag for showing online status
final bool showOnlineStatus; final bool showOnlineStatus;
/// Flag for if avatar is selected
final bool selected; final bool selected;
/// Color of selection
final Color? selectionColor; final Color? selectionColor;
/// Selection thickness around the avatar
final double selectionThickness; final double selectionThickness;
@override @override
@@ -53,10 +75,10 @@ class UserAvatar extends StatelessWidget {
child: hasImage child: hasImage
? CachedNetworkImage( ? CachedNetworkImage(
filterQuality: FilterQuality.high, filterQuality: FilterQuality.high,
// ignore: cast_nullable_to_non_nullable
imageUrl: user.extraData['image'] as String, imageUrl: user.extraData['image'] as String,
errorWidget: (_, __, ___) { errorWidget: (_, __, ___) =>
return streamChatTheme.defaultUserImage(context, user); streamChatTheme.defaultUserImage(context, user),
},
fit: BoxFit.cover, fit: BoxFit.cover,
) )
: streamChatTheme.defaultUserImage(context, user), : streamChatTheme.defaultUserImage(context, user),
@@ -98,12 +120,12 @@ class UserAvatar extends StatelessWidget {
child: Container( child: Container(
margin: const EdgeInsets.all(2), margin: const EdgeInsets.all(2),
constraints: onlineIndicatorConstraints ?? constraints: onlineIndicatorConstraints ??
BoxConstraints.tightFor( const BoxConstraints.tightFor(
width: 8, width: 8,
height: 8, height: 8,
), ),
child: Material( child: Material(
shape: CircleBorder(), shape: const CircleBorder(),
color: streamChatTheme.colorTheme.accentGreen, color: streamChatTheme.colorTheme.accentGreen,
), ),
), ),
@@ -5,16 +5,17 @@ import 'package:stream_chat_flutter/src/user_list_view.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'stream_chat_theme.dart';
/// ///
/// It shows the current [User] preview. /// It shows the current [User] preview.
/// ///
/// The widget uses a [StreamBuilder] to render the user information image as soon as it updates. /// The widget uses a [StreamBuilder] to render the user information
/// image as soon as it updates.
/// ///
/// Usually you don't use this widget as it's the default user preview used by [UserListView]. /// Usually you don't use this widget as it's the default user preview used
/// by [UserListView].
/// ///
/// The widget renders the ui based on the first ancestor of type [StreamChatTheme]. /// The widget renders the ui based on the first ancestor of type
/// [StreamChatTheme].
/// Modify it to change the widget appearance. /// Modify it to change the widget appearance.
class UserItem extends StatelessWidget { class UserItem extends StatelessWidget {
/// Instantiate a new UserItem /// Instantiate a new UserItem
@@ -47,50 +48,47 @@ class UserItem extends StatelessWidget {
final bool showLastOnline; final bool showLastOnline;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) => ListTile(
return ListTile( onTap: () {
onTap: () { if (onTap != null) {
if (onTap != null) { onTap!(user);
onTap!(user);
}
},
onLongPress: () {
if (onLongPress != null) {
onLongPress!(user);
}
},
leading: UserAvatar(
user: user,
onTap: (user) {
if (onImageTap != null) {
onImageTap!(user);
} }
}, },
constraints: BoxConstraints.tightFor( onLongPress: () {
height: 40, if (onLongPress != null) {
width: 40, onLongPress!(user);
}
},
leading: UserAvatar(
user: user,
onTap: (user) {
if (onImageTap != null) {
onImageTap!(user);
}
},
constraints: const BoxConstraints.tightFor(
height: 40,
width: 40,
),
), ),
), trailing: selected
trailing: selected ? StreamSvgIcon.checkSend(
? StreamSvgIcon.checkSend( color: StreamChatTheme.of(context).colorTheme.accentBlue,
color: StreamChatTheme.of(context).colorTheme.accentBlue, )
) : null,
: null, title: Text(
title: Text( user.name,
user.name, style: StreamChatTheme.of(context).textTheme.bodyBold,
style: StreamChatTheme.of(context).textTheme.bodyBold, ),
), subtitle: showLastOnline ? _buildLastActive(context) : null,
subtitle: showLastOnline ? _buildLastActive(context) : null, );
);
}
Widget _buildLastActive(context) { Widget _buildLastActive(context) => Text(
return Text( user.online == true
user.online == true ? 'Online'
? 'Online' : 'Last online ${Jiffy(user.lastActive).fromNow()}',
: 'Last online ${Jiffy(user.lastActive).fromNow()}', style: StreamChatTheme.of(context).textTheme.footnote.copyWith(
style: StreamChatTheme.of(context).textTheme.footnote.copyWith( color:
color: StreamChatTheme.of(context).colorTheme.black.withOpacity(.5)), StreamChatTheme.of(context).colorTheme.black.withOpacity(.5)),
); );
}
} }