Merge branch 'feature/new-ui' into hotfix/media-picker
This commit is contained in:
@@ -1,18 +1,15 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_icons.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
import 'package:stream_chat_flutter/src/unread_indicator.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
class StreamBackButton extends StatelessWidget {
|
||||
const StreamBackButton({
|
||||
Key key,
|
||||
this.onPressed,
|
||||
this.icon = Icons.arrow_back_ios_outlined,
|
||||
this.showUnreads = false,
|
||||
}) : super(key: key);
|
||||
|
||||
final VoidCallback onPressed;
|
||||
final IconData icon;
|
||||
final bool showUnreads;
|
||||
|
||||
@override
|
||||
@@ -36,8 +33,7 @@ class StreamBackButton extends StatelessWidget {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
child: Icon(
|
||||
icon ?? StreamIcons.left,
|
||||
child: StreamSvgIcon.left(
|
||||
size: 24,
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? Colors.white
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_icons.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
import 'package:stream_chat_flutter/src/utils.dart';
|
||||
|
||||
import 'channel_info.dart';
|
||||
@@ -73,8 +72,7 @@ class ChannelBottomSheet extends StatelessWidget {
|
||||
initialData: channel.isMuted,
|
||||
builder: (context, snapshot) {
|
||||
return ListTile(
|
||||
leading: Icon(
|
||||
StreamIcons.mute,
|
||||
leading: StreamSvgIcon.mute(
|
||||
size: 22,
|
||||
color: StreamChatTheme.of(context).primaryIconTheme.color,
|
||||
),
|
||||
@@ -94,8 +92,7 @@ class ChannelBottomSheet extends StatelessWidget {
|
||||
Divider(),
|
||||
if (channel.isGroup && !channel.isDistinct)
|
||||
ListTile(
|
||||
leading: Icon(
|
||||
StreamIcons.user_minus,
|
||||
leading: StreamSvgIcon.userRemove(
|
||||
size: 22,
|
||||
color: Colors.black,
|
||||
),
|
||||
|
||||
@@ -114,6 +114,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
.channelHeaderTheme
|
||||
.title,
|
||||
),
|
||||
SizedBox(height: 2),
|
||||
ChannelInfo(
|
||||
channel: channel,
|
||||
textStyle:
|
||||
|
||||
+103
-26
@@ -16,8 +16,35 @@ class ChannelInfo extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final client = StreamChat.of(context).client;
|
||||
return StreamBuilder<List<Member>>(
|
||||
stream: channel.state.membersStream,
|
||||
initialData: channel.state.members,
|
||||
builder: (context, snapshot) {
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: client.wsConnectionStatus,
|
||||
builder: (context, status, child) {
|
||||
switch (status) {
|
||||
case ConnectionStatus.connected:
|
||||
return _buildConnectedTitleState(context, snapshot.data);
|
||||
case ConnectionStatus.connecting:
|
||||
return _buildConnectingTitleState(context);
|
||||
case ConnectionStatus.disconnected:
|
||||
return _buildDisconnectedTitleState(context, client);
|
||||
default:
|
||||
return Offstage();
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildConnectedTitleState(BuildContext context, List<Member> members) {
|
||||
var alternativeWidget;
|
||||
|
||||
if (channel.memberCount != null && channel.memberCount > 2) {
|
||||
return Text(
|
||||
alternativeWidget = Text(
|
||||
'${channel.memberCount} Members, ${channel.state.watcherCount} Online',
|
||||
style: StreamChatTheme.of(context)
|
||||
.channelTheme
|
||||
@@ -25,35 +52,85 @@ class ChannelInfo extends StatelessWidget {
|
||||
.lastMessageAt,
|
||||
);
|
||||
} else {
|
||||
return StreamBuilder<List<Member>>(
|
||||
stream: channel.state.membersStream,
|
||||
initialData: channel.state.members,
|
||||
builder: (context, snapshot) {
|
||||
final otherMember = snapshot.data.firstWhere(
|
||||
(element) => element.userId != StreamChat.of(context).user.id,
|
||||
orElse: () => null,
|
||||
final otherMember = members.firstWhere(
|
||||
(element) => element.userId != StreamChat.of(context).user.id,
|
||||
orElse: () => null,
|
||||
);
|
||||
|
||||
if (otherMember != null) {
|
||||
if (otherMember.user.online) {
|
||||
alternativeWidget = Text(
|
||||
'Online',
|
||||
style: StreamChatTheme.of(context)
|
||||
.channelTheme
|
||||
.channelHeaderTheme
|
||||
.lastMessageAt,
|
||||
);
|
||||
|
||||
if (otherMember == null) {
|
||||
return SizedBox();
|
||||
}
|
||||
|
||||
if (otherMember.user.online) {
|
||||
return Text(
|
||||
'Online',
|
||||
style: StreamChatTheme.of(context)
|
||||
.channelTheme
|
||||
.channelHeaderTheme
|
||||
.lastMessageAt,
|
||||
);
|
||||
}
|
||||
|
||||
return Text(
|
||||
} else {
|
||||
alternativeWidget = Text(
|
||||
'Last seen ${Jiffy(otherMember.user.lastActive).fromNow()}',
|
||||
style: textStyle,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TypingIndicator(
|
||||
alignment: Alignment.center,
|
||||
alternativeWidget: alternativeWidget,
|
||||
style: textStyle,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildConnectingTitleState(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: 16,
|
||||
width: 16,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Text(
|
||||
'Searching for Network',
|
||||
style: textStyle,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDisconnectedTitleState(BuildContext context, Client client) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Offline...',
|
||||
style: textStyle,
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.all(0),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
visualDensity: VisualDensity(
|
||||
horizontal: VisualDensity.minimumDensity,
|
||||
vertical: VisualDensity.minimumDensity,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
await client.disconnect();
|
||||
return client.connect();
|
||||
},
|
||||
child: Text(
|
||||
'Try Again',
|
||||
style: textStyle.copyWith(
|
||||
color: Color(0xFF006CFF),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_neumorphic_button.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
import 'stream_chat.dart';
|
||||
|
||||
typedef _TitleBuilder = Widget Function(
|
||||
BuildContext context,
|
||||
ConnectionStatus status,
|
||||
Client client,
|
||||
);
|
||||
|
||||
///
|
||||
/// It shows the current [Client] status.
|
||||
///
|
||||
/// ```dart
|
||||
/// class MyApp extends StatelessWidget {
|
||||
/// final Client client;
|
||||
///
|
||||
/// MyApp(this.client);
|
||||
///
|
||||
/// @override
|
||||
/// Widget build(BuildContext context) {
|
||||
/// return MaterialApp(
|
||||
/// home: StreamChat(
|
||||
/// client: client,
|
||||
/// child: Scaffold(
|
||||
/// appBar: ChannelListHeader(),
|
||||
/// ),
|
||||
/// ),
|
||||
/// );
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Usually you would use this widget as an [AppBar] inside a [Scaffold].
|
||||
/// However you can also use it as a normal widget.
|
||||
///
|
||||
/// The widget by default uses the inherited [Client] to fetch information about the status.
|
||||
/// However you can also pass your own [Client] if you don't have it in the widget tree.
|
||||
///
|
||||
/// The widget components render the ui based on the first ancestor of type [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property.
|
||||
/// Modify it to change the widget appearance.
|
||||
class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
/// Instantiates a ChannelListHeader
|
||||
const ChannelListHeader({
|
||||
Key key,
|
||||
this.client,
|
||||
this.titleBuilder,
|
||||
this.onUserAvatarTap,
|
||||
this.onNewChatButtonTap,
|
||||
}) : super(key: key);
|
||||
|
||||
/// Pass this if you don't have a [Client] in your widget tree.
|
||||
final Client client;
|
||||
|
||||
/// Use this to build your own title as per different [ConnectionStatus]
|
||||
final _TitleBuilder titleBuilder;
|
||||
|
||||
/// Callback to call when pressing the user avatar button.
|
||||
/// By default it calls Scaffold.of(context).openDrawer()
|
||||
final Function(User) onUserAvatarTap;
|
||||
|
||||
/// Callback to call when pressing the new chat button.
|
||||
final VoidCallback onNewChatButtonTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _client = client ?? StreamChat.of(context).client;
|
||||
final user = _client.state.user;
|
||||
return AppBar(
|
||||
brightness: Theme.of(context).brightness,
|
||||
elevation: 1,
|
||||
backgroundColor:
|
||||
StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color,
|
||||
centerTitle: true,
|
||||
leading: Center(
|
||||
child: UserAvatar(
|
||||
user: user,
|
||||
showOnlineStatus: false,
|
||||
onTap: onUserAvatarTap ?? (_) => Scaffold.of(context).openDrawer(),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
constraints: BoxConstraints.tightFor(
|
||||
height: 40,
|
||||
width: 40,
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
StreamNeumorphicButton(
|
||||
child: IconButton(
|
||||
icon: ValueListenableBuilder<ConnectionStatus>(
|
||||
valueListenable: _client.wsConnectionStatus,
|
||||
builder: (context, status, child) {
|
||||
var color;
|
||||
switch (status) {
|
||||
case ConnectionStatus.connected:
|
||||
color = Color(0xFF006CFF);
|
||||
break;
|
||||
case ConnectionStatus.connecting:
|
||||
color = Colors.grey;
|
||||
break;
|
||||
case ConnectionStatus.disconnected:
|
||||
color = Colors.grey;
|
||||
break;
|
||||
}
|
||||
return SvgPicture.asset(
|
||||
'svgs/icon_pen_write.svg',
|
||||
package: 'stream_chat_flutter',
|
||||
width: 24.0,
|
||||
height: 24.0,
|
||||
color: color,
|
||||
);
|
||||
},
|
||||
),
|
||||
onPressed: onNewChatButtonTap,
|
||||
),
|
||||
)
|
||||
],
|
||||
title: ValueListenableBuilder<ConnectionStatus>(
|
||||
valueListenable: _client.wsConnectionStatus,
|
||||
builder: (context, status, child) {
|
||||
if (titleBuilder != null) {
|
||||
return titleBuilder(context, status, _client);
|
||||
}
|
||||
switch (status) {
|
||||
case ConnectionStatus.connected:
|
||||
return _buildConnectedTitleState(context);
|
||||
case ConnectionStatus.connecting:
|
||||
return _buildConnectingTitleState(context);
|
||||
case ConnectionStatus.disconnected:
|
||||
return _buildDisconnectedTitleState(context, _client);
|
||||
default:
|
||||
return Offstage();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildConnectedTitleState(BuildContext context) => Text(
|
||||
'Stream Chat',
|
||||
style: StreamChatTheme.of(context)
|
||||
.channelTheme
|
||||
.channelHeaderTheme
|
||||
.title
|
||||
.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildConnectingTitleState(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: 16,
|
||||
width: 16,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Text(
|
||||
'Searching for Network',
|
||||
style: StreamChatTheme.of(context)
|
||||
.channelTheme
|
||||
.channelHeaderTheme
|
||||
.title
|
||||
.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDisconnectedTitleState(BuildContext context, Client client) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Offline...',
|
||||
style: StreamChatTheme.of(context)
|
||||
.channelTheme
|
||||
.channelHeaderTheme
|
||||
.title
|
||||
.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await client.disconnect();
|
||||
return client.connect();
|
||||
},
|
||||
child: Text(
|
||||
'Try Again',
|
||||
style: StreamChatTheme.of(context)
|
||||
.channelTheme
|
||||
.channelHeaderTheme
|
||||
.title
|
||||
.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(0xFF006CFF),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Size get preferredSize => Size.fromHeight(kToolbarHeight);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/channels_bloc.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
import 'package:stream_chat_flutter/src/utils.dart';
|
||||
|
||||
import '../stream_chat_flutter.dart';
|
||||
@@ -184,26 +185,26 @@ class _ChannelListViewState extends State<ChannelListView>
|
||||
child = widget.emptyBuilder(context);
|
||||
}
|
||||
|
||||
if (channels.isEmpty && widget.emptyBuilder == null) {
|
||||
child = LayoutBuilder(
|
||||
builder: (context, viewportConstraints) {
|
||||
return SingleChildScrollView(
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
child: Stack(
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: viewportConstraints.maxHeight,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Icon(
|
||||
StreamIcons.message,
|
||||
size: 136,
|
||||
color: Color(0xffDBDBDB),
|
||||
if (channels.isEmpty && widget.emptyBuilder == null) {
|
||||
child = LayoutBuilder(
|
||||
builder: (context, viewportConstraints) {
|
||||
return SingleChildScrollView(
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
child: Stack(
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: viewportConstraints.maxHeight,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: StreamSvgIcon.message(
|
||||
size: 136,
|
||||
color: Color(0xffDBDBDB),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
@@ -518,7 +519,7 @@ class _ChannelListViewState extends State<ChannelListView>
|
||||
),
|
||||
IconSlideAction(
|
||||
color: backgroundColor,
|
||||
icon: StreamIcons.mute,
|
||||
iconWidget: StreamSvgIcon.mute(),
|
||||
onTap: () async {
|
||||
if (!channel.isMuted) {
|
||||
await channel.mute();
|
||||
@@ -530,7 +531,7 @@ class _ChannelListViewState extends State<ChannelListView>
|
||||
if (channel.isGroup && !channel.isDistinct)
|
||||
IconSlideAction(
|
||||
color: backgroundColor,
|
||||
icon: StreamIcons.user_minus,
|
||||
iconWidget: StreamSvgIcon.userRemove(),
|
||||
onTap: () async {
|
||||
final confirm = await showConfirmationDialog(
|
||||
context,
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:jiffy/jiffy.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
|
||||
import '../stream_chat_flutter.dart';
|
||||
import 'channel_name.dart';
|
||||
@@ -103,7 +104,7 @@ class ChannelPreview extends StatelessWidget {
|
||||
.isAfter(channel
|
||||
.state.lastMessage.createdAt))
|
||||
.length ==
|
||||
(channel.memberCount ?? 0) - 1,
|
||||
(channel.memberCount ?? 0),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -152,8 +153,7 @@ class ChannelPreview extends StatelessWidget {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
StreamIcons.mute,
|
||||
StreamSvgIcon.mute(
|
||||
size: 16,
|
||||
),
|
||||
Text(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
|
||||
import '../stream_chat_flutter.dart';
|
||||
import 'attachment_error.dart';
|
||||
@@ -111,8 +112,7 @@ class GiphyAttachment extends StatelessWidget {
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
StreamIcons.lightning,
|
||||
StreamSvgIcon.lightning(
|
||||
color: StreamChatTheme.of(context).accentColor,
|
||||
size: 16.0,
|
||||
),
|
||||
@@ -144,8 +144,7 @@ class GiphyAttachment extends StatelessWidget {
|
||||
child: IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
constraints: BoxConstraints.tight(Size(32, 32)),
|
||||
icon: Icon(
|
||||
StreamIcons.left,
|
||||
icon: StreamSvgIcon.left(
|
||||
size: 24.0,
|
||||
),
|
||||
splashRadius: 16,
|
||||
@@ -172,8 +171,7 @@ class GiphyAttachment extends StatelessWidget {
|
||||
child: IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
constraints: BoxConstraints.tight(Size(32, 32)),
|
||||
icon: Icon(
|
||||
StreamIcons.right,
|
||||
icon: StreamSvgIcon.right(
|
||||
size: 24.0,
|
||||
),
|
||||
splashRadius: 16,
|
||||
@@ -253,8 +251,7 @@ class GiphyAttachment extends StatelessWidget {
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
StreamIcons.eye,
|
||||
StreamSvgIcon.eye(
|
||||
color: Colors.black.withOpacity(0.5),
|
||||
size: 16.0,
|
||||
),
|
||||
@@ -326,8 +323,7 @@ class GiphyAttachment extends StatelessWidget {
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
StreamIcons.lightning,
|
||||
StreamSvgIcon.lightning(
|
||||
color: Colors.white,
|
||||
size: 16,
|
||||
),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:media_gallery/media_gallery.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_icons.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
|
||||
class MediaListView extends StatefulWidget {
|
||||
final List<String> selectedIds;
|
||||
@@ -71,8 +71,7 @@ class _MediaListViewState extends State<MediaListView> {
|
||||
child: CircleAvatar(
|
||||
radius: 12,
|
||||
backgroundColor: Colors.white,
|
||||
child: Icon(
|
||||
StreamIcons.check,
|
||||
child: StreamSvgIcon.check(
|
||||
size: 24,
|
||||
color: Colors.black,
|
||||
),
|
||||
|
||||
@@ -6,7 +6,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/reaction_picker.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_channel.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_icons.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
|
||||
import 'message_input.dart';
|
||||
import 'message_widget.dart';
|
||||
@@ -188,8 +188,7 @@ class MessageActionsModal extends StatelessWidget {
|
||||
style:
|
||||
Theme.of(context).textTheme.headline6.copyWith(color: Colors.red),
|
||||
),
|
||||
leading: Icon(
|
||||
StreamIcons.delete,
|
||||
leading: StreamSvgIcon.delete(
|
||||
color: Colors.red,
|
||||
),
|
||||
onTap: () {
|
||||
@@ -208,8 +207,7 @@ class MessageActionsModal extends StatelessWidget {
|
||||
'Copy message',
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
),
|
||||
leading: Icon(
|
||||
StreamIcons.copy,
|
||||
leading: StreamSvgIcon.copy(
|
||||
color: StreamChatTheme.of(context).primaryIconTheme.color,
|
||||
),
|
||||
onTap: () async {
|
||||
@@ -225,8 +223,7 @@ class MessageActionsModal extends StatelessWidget {
|
||||
'Edit message',
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
),
|
||||
leading: Icon(
|
||||
StreamIcons.edit,
|
||||
leading: StreamSvgIcon.edit(
|
||||
color: StreamChatTheme.of(context).primaryIconTheme.color,
|
||||
),
|
||||
onTap: () async {
|
||||
@@ -267,8 +264,7 @@ class MessageActionsModal extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
StreamIcons.edit,
|
||||
icon: StreamSvgIcon.edit(
|
||||
size: 22,
|
||||
color:
|
||||
StreamChatTheme.of(context).primaryIconTheme.color,
|
||||
@@ -323,8 +319,7 @@ class MessageActionsModal extends StatelessWidget {
|
||||
'Thread reply',
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
),
|
||||
leading: Icon(
|
||||
StreamIcons.sorting_up,
|
||||
leading: StreamSvgIcon.thread(
|
||||
color: StreamChatTheme.of(context).primaryIconTheme.color,
|
||||
),
|
||||
onTap: () {
|
||||
|
||||
+72
-93
@@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:emojis/emoji.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
@@ -18,6 +17,7 @@ import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/media_list_view.dart';
|
||||
import 'package:stream_chat_flutter/src/message_list_view.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
import 'package:stream_chat_flutter/src/user_avatar.dart';
|
||||
import 'package:stream_chat_flutter/src/video_thumbnail.dart';
|
||||
import 'package:substring_highlight/substring_highlight.dart';
|
||||
@@ -287,8 +287,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
crossFadeState: _sendAsDm
|
||||
? CrossFadeState.showFirst
|
||||
: CrossFadeState.showSecond,
|
||||
firstChild: Icon(
|
||||
StreamIcons.check,
|
||||
firstChild: StreamSvgIcon.check(
|
||||
size: 16.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
@@ -333,8 +332,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
_actionsShrunk = false;
|
||||
});
|
||||
},
|
||||
icon: Icon(
|
||||
StreamIcons.circle_left,
|
||||
icon: StreamSvgIcon.emptyCircleLeft(
|
||||
color: StreamChatTheme.of(context).accentColor,
|
||||
),
|
||||
),
|
||||
@@ -406,8 +404,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
_chosenCommand?.name ?? "",
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
avatar: Icon(
|
||||
StreamIcons.lightning,
|
||||
avatar: StreamSvgIcon.lightning(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
@@ -434,26 +431,36 @@ class MessageInputState extends State<MessageInput> {
|
||||
);
|
||||
}
|
||||
|
||||
Timer _debounce;
|
||||
void _onChanged(BuildContext context, String s) {
|
||||
StreamChannel.of(context).channel.keyStroke().catchError((e) {});
|
||||
if (_debounce?.isActive == true) _debounce.cancel();
|
||||
_debounce = Timer(
|
||||
const Duration(milliseconds: 350),
|
||||
() {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
StreamChannel.of(context).channel.keyStroke().catchError((e) {});
|
||||
|
||||
setState(() {
|
||||
_messageIsPresent = s.trim().isNotEmpty;
|
||||
_actionsShrunk = s.trim().isNotEmpty;
|
||||
});
|
||||
setState(() {
|
||||
_messageIsPresent = s.trim().isNotEmpty;
|
||||
_actionsShrunk = s.trim().isNotEmpty;
|
||||
});
|
||||
|
||||
_commandsOverlay?.remove();
|
||||
_commandsOverlay = null;
|
||||
_mentionsOverlay?.remove();
|
||||
_mentionsOverlay = null;
|
||||
_emojiOverlay?.remove();
|
||||
_emojiOverlay = null;
|
||||
_commandsOverlay?.remove();
|
||||
_commandsOverlay = null;
|
||||
_mentionsOverlay?.remove();
|
||||
_mentionsOverlay = null;
|
||||
_emojiOverlay?.remove();
|
||||
_emojiOverlay = null;
|
||||
|
||||
_checkCommands(s.trim(), context);
|
||||
_checkCommands(s.trim(), context);
|
||||
|
||||
_checkMentions(s, context);
|
||||
_checkMentions(s, context);
|
||||
|
||||
_checkEmoji(s, context);
|
||||
_checkEmoji(s, context);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
String _getHint() {
|
||||
@@ -582,9 +589,9 @@ class MessageInputState extends State<MessageInput> {
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0),
|
||||
child: Icon(
|
||||
StreamIcons.lightning,
|
||||
horizontal: 8.0,
|
||||
),
|
||||
child: StreamSvgIcon.lightning(
|
||||
color: StreamChatTheme.of(context)
|
||||
.accentColor,
|
||||
),
|
||||
@@ -622,8 +629,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
trailing: CircleAvatar(
|
||||
backgroundColor:
|
||||
StreamChatTheme.of(context).accentColor,
|
||||
child: Icon(
|
||||
StreamIcons.lightning,
|
||||
child: StreamSvgIcon.lightning(
|
||||
color: Colors.white,
|
||||
size: 12.5,
|
||||
),
|
||||
@@ -659,8 +665,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
StreamIcons.picture,
|
||||
icon: StreamSvgIcon.pictures(
|
||||
size: 24,
|
||||
color: _filePickerIndex == 0
|
||||
? StreamChatTheme.of(context).accentColor
|
||||
@@ -673,8 +678,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
StreamIcons.folder,
|
||||
icon: StreamSvgIcon.files(
|
||||
size: 24,
|
||||
color: _filePickerIndex == 1
|
||||
? StreamChatTheme.of(context).accentColor
|
||||
@@ -685,11 +689,8 @@ class MessageInputState extends State<MessageInput> {
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: SvgPicture.asset(
|
||||
'svgs/icon_camera.svg',
|
||||
package: 'stream_chat_flutter',
|
||||
height: 24,
|
||||
width: 24,
|
||||
icon: StreamSvgIcon.camera(
|
||||
size: 24,
|
||||
color: _filePickerIndex == 2
|
||||
? StreamChatTheme.of(context).accentColor
|
||||
: Colors.black.withOpacity(0.5),
|
||||
@@ -699,10 +700,9 @@ class MessageInputState extends State<MessageInput> {
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
StreamIcons.record,
|
||||
icon: StreamSvgIcon.record(
|
||||
size: 24,
|
||||
color: _filePickerIndex == 2
|
||||
color: _filePickerIndex == 3
|
||||
? StreamChatTheme.of(context).accentColor
|
||||
: Colors.black.withOpacity(0.5),
|
||||
),
|
||||
@@ -1054,8 +1054,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
subtitle: Text('@${m.userId}'),
|
||||
trailing: Icon(
|
||||
StreamIcons.at_mention,
|
||||
trailing: StreamSvgIcon.mentions(
|
||||
color: StreamChatTheme.of(context)
|
||||
.accentColor,
|
||||
),
|
||||
@@ -1152,8 +1151,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Icon(
|
||||
StreamIcons.smile,
|
||||
child: StreamSvgIcon.smile(
|
||||
color: StreamChatTheme.of(context).accentColor,
|
||||
),
|
||||
),
|
||||
@@ -1288,8 +1286,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
},
|
||||
fillColor: Colors.black.withOpacity(.5),
|
||||
child: Center(
|
||||
child: Icon(
|
||||
StreamIcons.close,
|
||||
child: StreamSvgIcon.close(
|
||||
size: 24,
|
||||
color: Colors.white,
|
||||
),
|
||||
@@ -1361,8 +1358,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 4.0, right: 8.0, top: 8.0, bottom: 8.0),
|
||||
child: Icon(
|
||||
StreamIcons.lightning,
|
||||
child: StreamSvgIcon.lightning(
|
||||
color: Color(0xFF000000).withAlpha(128),
|
||||
),
|
||||
),
|
||||
@@ -1385,8 +1381,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
child: Padding(
|
||||
padding:
|
||||
EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0),
|
||||
child: Icon(
|
||||
StreamIcons.attach,
|
||||
child: StreamSvgIcon.attach(
|
||||
color: _openFilePickerSection
|
||||
? StreamChatTheme.of(context).accentColor
|
||||
: Color(0xFF000000).withAlpha(128),
|
||||
@@ -1675,69 +1670,53 @@ class MessageInputState extends State<MessageInput> {
|
||||
}
|
||||
|
||||
Widget _buildIdleSendButton(BuildContext context) {
|
||||
return IconTheme(
|
||||
data:
|
||||
StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Center(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
sendMessage();
|
||||
},
|
||||
child: Icon(
|
||||
_getIdleSendIcon(),
|
||||
color: Colors.grey,
|
||||
),
|
||||
)),
|
||||
),
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Center(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
sendMessage();
|
||||
},
|
||||
child: StreamSvgIcon(
|
||||
assetName: _getIdleSendIcon(),
|
||||
color: Colors.grey,
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSendButton(BuildContext context) {
|
||||
return IconTheme(
|
||||
data:
|
||||
StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme,
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
sendMessage();
|
||||
},
|
||||
child: _getSendIcon(),
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
sendMessage();
|
||||
},
|
||||
child: StreamSvgIcon(
|
||||
assetName: _getSendIcon(),
|
||||
color: StreamChatTheme.of(context).accentColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
IconData _getIdleSendIcon() {
|
||||
String _getIdleSendIcon() {
|
||||
if (_commandEnabled) {
|
||||
return StreamIcons.search;
|
||||
return 'Icon_search.svg';
|
||||
} else {
|
||||
return StreamIcons.send_message;
|
||||
return 'Icon_circle_up.svg';
|
||||
}
|
||||
}
|
||||
|
||||
Widget _getSendIcon() {
|
||||
String _getSendIcon() {
|
||||
if (widget.editMessage != null) {
|
||||
return Icon(
|
||||
StreamIcons.check_send,
|
||||
color: StreamChatTheme.of(context).accentColor,
|
||||
);
|
||||
return 'Icon_circle_right.svg';
|
||||
} else if (_commandEnabled) {
|
||||
return Icon(
|
||||
StreamIcons.search,
|
||||
color: StreamChatTheme.of(context).accentColor,
|
||||
);
|
||||
return 'Icon_search.svg';
|
||||
} else {
|
||||
return Transform.rotate(
|
||||
angle: -pi / 2,
|
||||
child: Icon(
|
||||
StreamIcons.send_message,
|
||||
color: StreamChatTheme.of(context).accentColor,
|
||||
));
|
||||
return 'Icon_circle_right.svg';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:jiffy/jiffy.dart';
|
||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/message_widget.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
import 'package:stream_chat_flutter/src/system_message.dart';
|
||||
import 'package:visibility_detector/visibility_detector.dart';
|
||||
|
||||
@@ -374,8 +375,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
children: [
|
||||
FloatingActionButton(
|
||||
backgroundColor: Colors.white,
|
||||
child: Icon(
|
||||
StreamIcons.down,
|
||||
child: StreamSvgIcon.down(
|
||||
color: Colors.black,
|
||||
),
|
||||
onPressed: () {
|
||||
|
||||
@@ -426,12 +426,13 @@ class _MessageWidgetState extends State<MessageWidget> {
|
||||
top: 0,
|
||||
child: Material(
|
||||
color: Colors.white,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
shape: CircleBorder(),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(1.0),
|
||||
child: UserAvatar(
|
||||
user: e.user,
|
||||
constraints: BoxConstraints.loose(Size.fromRadius(16)),
|
||||
constraints: BoxConstraints.loose(Size.fromRadius(8)),
|
||||
showOnlineStatus: false,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:math';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:stream_chat_flutter/src/reaction_icon.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
class ReactionBubble extends StatelessWidget {
|
||||
@@ -99,14 +100,24 @@ class ReactionBubble extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 4.0,
|
||||
),
|
||||
child: Icon(
|
||||
reactionIcon?.iconData ?? Icons.help_outline_rounded,
|
||||
size: 16,
|
||||
color: (!highlightOwnReactions ||
|
||||
reaction.user.id == StreamChat.of(context).user.id)
|
||||
? StreamChatTheme.of(context).accentColor
|
||||
: Colors.black.withOpacity(.5),
|
||||
),
|
||||
child: reactionIcon != null
|
||||
? StreamSvgIcon(
|
||||
assetName: reactionIcon.assetName,
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: (!highlightOwnReactions ||
|
||||
reaction.user.id == StreamChat.of(context).user.id)
|
||||
? StreamChatTheme.of(context).accentColor
|
||||
: Colors.black.withOpacity(.5),
|
||||
)
|
||||
: Icon(
|
||||
Icons.help_outline_rounded,
|
||||
size: 16,
|
||||
color: (!highlightOwnReactions ||
|
||||
reaction.user.id == StreamChat.of(context).user.id)
|
||||
? StreamChatTheme.of(context).accentColor
|
||||
: Colors.black.withOpacity(.5),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ReactionIcon {
|
||||
final String type;
|
||||
final IconData iconData;
|
||||
final String assetName;
|
||||
|
||||
ReactionIcon({
|
||||
this.type,
|
||||
this.iconData,
|
||||
this.assetName,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:ezanimation/ezanimation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/physics.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
|
||||
import '../stream_chat_flutter.dart';
|
||||
|
||||
@@ -84,9 +84,10 @@ class _ReactionPickerState extends State<ReactionPicker>
|
||||
..scale(animations[index].value,
|
||||
animations[index].value)
|
||||
..rotateZ(1.0 - animations[index].value),
|
||||
child: Icon(
|
||||
reactionIcon.iconData,
|
||||
size: animations[index].value * 24.0,
|
||||
child: StreamSvgIcon(
|
||||
assetName: reactionIcon.assetName,
|
||||
height: animations[index].value * 24.0,
|
||||
width: animations[index].value * 24.0,
|
||||
color: ownReactionIndex != -1
|
||||
? StreamChatTheme.of(context).accentColor
|
||||
: Theme.of(context)
|
||||
|
||||
@@ -5,7 +5,6 @@ import 'package:stream_chat_flutter/src/channel_header.dart';
|
||||
import 'package:stream_chat_flutter/src/channel_preview.dart';
|
||||
import 'package:stream_chat_flutter/src/message_input.dart';
|
||||
import 'package:stream_chat_flutter/src/reaction_icon.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_icons.dart';
|
||||
import 'package:stream_chat_flutter/src/utils.dart';
|
||||
|
||||
/// Inherited widget providing the [StreamChatThemeData] to the widget tree
|
||||
@@ -353,23 +352,23 @@ class StreamChatThemeData {
|
||||
reactionIcons: [
|
||||
ReactionIcon(
|
||||
type: 'love',
|
||||
iconData: StreamIcons.love_reaction,
|
||||
assetName: 'Icon_love_reaction.svg',
|
||||
),
|
||||
ReactionIcon(
|
||||
type: 'thumbs_up',
|
||||
iconData: StreamIcons.thumbs_up_reaction,
|
||||
assetName: 'Icon_thumbs_up_reaction.svg',
|
||||
),
|
||||
ReactionIcon(
|
||||
type: 'thumbs_down',
|
||||
iconData: StreamIcons.thumbs_down_reaction,
|
||||
assetName: 'Icon_thumbs_down_reaction.svg',
|
||||
),
|
||||
ReactionIcon(
|
||||
type: 'lol',
|
||||
iconData: StreamIcons.LOL_reaction,
|
||||
assetName: 'Icon_LOL_reaction.svg',
|
||||
),
|
||||
ReactionIcon(
|
||||
type: 'wut',
|
||||
iconData: StreamIcons.wut_reaction,
|
||||
assetName: 'Icon_wut_reaction.svg',
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StreamNeumorphicButton extends StatelessWidget {
|
||||
final Widget child;
|
||||
final Color backgroundColor;
|
||||
|
||||
const StreamNeumorphicButton({
|
||||
Key key,
|
||||
@required this.child,
|
||||
this.backgroundColor = Colors.white,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: child,
|
||||
margin: EdgeInsets.all(8.0),
|
||||
height: 40,
|
||||
width: 40,
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor,
|
||||
shape: BoxShape.circle,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey[700],
|
||||
offset: Offset(0, 1.0),
|
||||
blurRadius: 0.5,
|
||||
spreadRadius: 0,
|
||||
),
|
||||
BoxShadow(
|
||||
color: Colors.white,
|
||||
offset: Offset.zero,
|
||||
blurRadius: 0.5,
|
||||
spreadRadius: 0,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
class StreamSvgIcon extends StatelessWidget {
|
||||
final String assetName;
|
||||
final double width;
|
||||
final double height;
|
||||
final Color color;
|
||||
|
||||
const StreamSvgIcon({
|
||||
this.assetName,
|
||||
this.width,
|
||||
this.height,
|
||||
this.color,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final key = Key('StreamSvgIcon-$assetName');
|
||||
return kIsWeb
|
||||
? Image.network(
|
||||
'packages/stream_chat_flutter/svgs/$assetName',
|
||||
width: width,
|
||||
height: height,
|
||||
key: key,
|
||||
color: color,
|
||||
alignment: Alignment.center,
|
||||
)
|
||||
: SvgPicture.asset(
|
||||
'lib/svgs/$assetName',
|
||||
package: 'stream_chat_flutter',
|
||||
key: key,
|
||||
width: width,
|
||||
height: height,
|
||||
color: color,
|
||||
alignment: Alignment.center,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.settings({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'settings.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.down({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_down.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.attach({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_attach.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.smile({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_smile.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.mentions({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'mentions.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.record({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_record.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.camera({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_camera.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.files({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'files.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.pictures({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'pictures.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.left({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_left.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.user({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_user.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.userAdd({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_User_add.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.check({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_check.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.penWrite({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_pen-write.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.contacts({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_contacts.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.close({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_close.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.search({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_search.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.right({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_right.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.mute({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_mute.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.userRemove({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_User_deselect.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.lightning({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_lightning-command runner.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.emptyCircleLeft({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_empty_circle_left.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.message({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_message.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.thread({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_Thread_Reply.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.edit({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_edit.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.copy({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_copy.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.delete({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_delete.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
|
||||
factory StreamSvgIcon.eye({
|
||||
double size,
|
||||
Color color,
|
||||
}) {
|
||||
return StreamSvgIcon(
|
||||
assetName: 'Icon_eye-off.svg',
|
||||
color: color,
|
||||
width: size,
|
||||
height: size,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/back_button.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
|
||||
/// 
|
||||
/// 
|
||||
@@ -84,9 +84,14 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
child: showBackButton
|
||||
? AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: StreamBackButton(
|
||||
onPressed: onBackPressed,
|
||||
icon: Icons.close,
|
||||
child: IconButton(
|
||||
onPressed: onBackPressed ?? () => Navigator.pop(context),
|
||||
icon: StreamSvgIcon.close(
|
||||
size: 24,
|
||||
color: Theme.of(context).brightness == Brightness.dark
|
||||
? Colors.white
|
||||
: Colors.black,
|
||||
),
|
||||
),
|
||||
)
|
||||
: SizedBox(),
|
||||
|
||||
@@ -8,7 +8,7 @@ class TypingIndicator extends StatelessWidget {
|
||||
const TypingIndicator({
|
||||
Key key,
|
||||
this.channel,
|
||||
this.alternativeWidget = const SizedBox(),
|
||||
this.alternativeWidget,
|
||||
this.style,
|
||||
this.alignment = Alignment.centerLeft,
|
||||
}) : super(key: key);
|
||||
@@ -48,7 +48,7 @@ class TypingIndicator extends StatelessWidget {
|
||||
key: Key('alternative'),
|
||||
alignment: alignment,
|
||||
child: Container(
|
||||
child: alternativeWidget,
|
||||
child: alternativeWidget ?? Offstage(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -40,6 +40,7 @@ class UserAvatar extends StatelessWidget {
|
||||
final streamChatTheme = StreamChatTheme.of(context);
|
||||
|
||||
Widget avatar = ClipRRect(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
borderRadius: borderRadius ??
|
||||
streamChatTheme.ownMessageTheme.avatarTheme.borderRadius,
|
||||
child: Container(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:jiffy/jiffy.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
import 'package:stream_chat_flutter/src/user_list_view.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
@@ -73,9 +74,9 @@ class UserItem extends StatelessWidget {
|
||||
),
|
||||
trailing: selected
|
||||
? CircleAvatar(
|
||||
child: Icon(
|
||||
StreamIcons.check,
|
||||
child: StreamSvgIcon.check(
|
||||
size: 20,
|
||||
color: Colors.white,
|
||||
),
|
||||
radius: 10,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user