diff --git a/lib/src/channel_header.dart b/lib/src/channel_header.dart index 6c6ab6e4..c645832c 100644 --- a/lib/src/channel_header.dart +++ b/lib/src/channel_header.dart @@ -14,7 +14,6 @@ import 'stream_channel.dart'; /// It shows the current [Channel] information. /// /// ```dart -/// /// class MyApp extends StatelessWidget { /// final Client client; /// final Channel channel; @@ -36,7 +35,6 @@ import 'stream_channel.dart'; /// ); /// } /// } -/// /// ``` /// /// Usually you would use this widget as an [AppBar] inside a [Scaffold]. @@ -52,9 +50,14 @@ import 'stream_channel.dart'; /// 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 ChannelHeader extends StatelessWidget implements PreferredSizeWidget { + /// True if this header shows the leading back button final bool showBackButton; + + /// Callback to call when pressing the back button. + /// By default it calls [Navigator.pop] final VoidCallback onBackPressed; + /// Creates a channel header ChannelHeader({ Key key, this.showBackButton = true, diff --git a/lib/src/channel_image.dart b/lib/src/channel_image.dart index 5d0a6693..f1c98add 100644 --- a/lib/src/channel_image.dart +++ b/lib/src/channel_image.dart @@ -3,6 +3,45 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.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 Client 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 [size] 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 { const ChannelImage({ Key key, @@ -10,7 +49,10 @@ class ChannelImage extends StatelessWidget { this.size = 40, }) : super(key: key); + /// The channel to show the image of final Channel channel; + + /// The diameter of the image final double size; @override diff --git a/lib/src/channel_list_view.dart b/lib/src/channel_list_view.dart index b34bc9d1..fbb30978 100644 --- a/lib/src/channel_list_view.dart +++ b/lib/src/channel_list_view.dart @@ -6,9 +6,45 @@ import 'channel_preview.dart'; import 'stream_channel.dart'; import 'stream_chat.dart'; +/// Callback called when tapping on a channel typedef ChannelTapCallback = void Function(Channel, Widget); + +/// Builder used to create a custom [ChannelPreview] from a [Channel] typedef ChannelPreviewBuilder = Widget Function(BuildContext, Channel); +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view.png) +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_list_view_paint.png) +/// +/// It shows the list of current channels. +/// +/// ```dart +/// class ChannelListPage extends StatelessWidget { +/// @override +/// Widget build(BuildContext context) { +/// return Scaffold( +/// body: ChannelListView( +/// filter: { +/// 'members': { +/// '\$in': [StreamChat.of(context).user.id], +/// } +/// }, +/// sort: [SortOption('last_message_at')], +/// pagination: PaginationParams( +/// limit: 20, +/// ), +/// channelWidget: ChannelPage(), +/// ), +/// ); +/// } +/// } +/// ``` +/// +/// +/// Make sure to have a [StreamChat] ancestor in order to provide the information about the channels. +/// The widget uses a [ListView.custom] to render the list of channels. +/// +/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// Modify it to change the widget appearance. class ChannelListView extends StatefulWidget { ChannelListView({ Key key, @@ -21,12 +57,38 @@ class ChannelListView extends StatefulWidget { this.channelPreviewBuilder, }) : super(key: key); + /// The query filters to use. + /// You can query on any of the custom fields you've defined on the [Channel]. + /// You can also filter other built-in channel fields. final Map filter; + + /// Query channels options. + /// + /// state: if true returns the Channel state + /// watch: if true listen to changes to this Channel in real time. final Map options; + + /// The sorting used for the channels matching the filters. + /// Sorting is based on field and direction, multiple sorting options can be provided. + /// You can sort based on last_updated, last_message_at, updated_at, created_at or member_count. + /// Direction can be ascending or descending. final List sort; + + /// Pagination parameters + /// limit: the number of channels to return (max is 30) + /// offset: the offset (max is 1000) + /// message_limit: how many messages should be included to each channel final PaginationParams pagination; + + /// Function called when tapping on a channel + /// By default it calls [Navigator.push] building a [MaterialPageRoute] + /// with the widget [channelWidget] as child. final ChannelTapCallback onChannelTap; + + /// Widget used when opening a channel final Widget channelWidget; + + /// Builder used to create a custom channel preview final ChannelPreviewBuilder channelPreviewBuilder; @override diff --git a/lib/src/channel_name.dart b/lib/src/channel_name.dart index bb211f6d..63f332d5 100644 --- a/lib/src/channel_name.dart +++ b/lib/src/channel_name.dart @@ -1,6 +1,9 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +/// It shows the current [Channel] name using a [Text] widget. +/// +/// The widget uses a [StreamBuilder] to render the channel information image as soon as it updates. class ChannelName extends StatelessWidget { const ChannelName({ Key key, @@ -8,7 +11,10 @@ class ChannelName extends StatelessWidget { this.textStyle, }) : super(key: key); + /// The channel to show the name of final Channel channel; + + /// The style of the text displayed final TextStyle textStyle; @override diff --git a/lib/src/channel_preview.dart b/lib/src/channel_preview.dart index 669c608b..92664339 100644 --- a/lib/src/channel_preview.dart +++ b/lib/src/channel_preview.dart @@ -6,8 +6,22 @@ import 'package:stream_chat/stream_chat.dart'; import '../stream_chat_flutter.dart'; import 'channel_name.dart'; +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_preview.png) +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/channel_preview_paint.png) +/// +/// It shows the current [Channel] preview. +/// +/// The widget uses a [StreamBuilder] to render the channel information image as soon as it updates. +/// +/// Usually you don't use this widget as it's the default channel preview used by [ChannelListView]. +/// +/// The widget renders the ui based on the first ancestor of type [StreamChatTheme]. +/// Modify it to change the widget appearance. class ChannelPreview extends StatelessWidget { + /// Function called when tapping this widget final void Function(Channel) onTap; + + /// Channel displayed final Channel channel; ChannelPreview({ diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index fa78357a..6db8a574 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -5,10 +5,51 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/message_list_view.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'stream_channel.dart'; +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_input.png) +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_input_paint.png) +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_input2.png) +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_input2_paint.png) +/// +/// Widget used to enter the message and add attachments +/// +/// ```dart +/// class ChannelPage extends StatelessWidget { +/// const ChannelPage({ +/// Key key, +/// }) : super(key: key); +/// +/// @override +/// Widget build(BuildContext context) { +/// return Scaffold( +/// appBar: ChannelHeader(), +/// body: Column( +/// children: [ +/// Expanded( +/// child: MessageListView( +/// threadBuilder: (_, parentMessage) { +/// return ThreadPage( +/// parent: parentMessage, +/// ); +/// }, +/// ), +/// ), +/// MessageInput(), +/// ], +/// ), +/// ); +/// } +/// } +/// ``` +/// +/// You usually put this widget in the same page of a [MessageListView] as the bottom widget. +/// +/// The widget renders the ui based on the first ancestor of type [StreamChatTheme]. +/// Modify it to change the widget appearance. class MessageInput extends StatefulWidget { MessageInput({ Key key, @@ -16,7 +57,10 @@ class MessageInput extends StatefulWidget { this.parentMessage, }) : super(key: key); + /// Function called after sending the message final void Function(Message) onMessageSent; + + /// Parent message in case of a thread final Message parentMessage; @override diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 08830143..45945e30 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -13,6 +13,46 @@ typedef ParentMessageBuilder = Widget Function(BuildContext, Message); typedef ThreadBuilder = Widget Function(BuildContext context, Message parent); typedef ThreadTapCallback = void Function(Message, Widget); +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview.png) +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_listview_paint.png) +/// +/// It shows the list of messages of the current channel. +/// +/// ```dart +/// class ChannelPage extends StatelessWidget { +/// const ChannelPage({ +/// Key key, +/// }) : super(key: key); +/// +/// @override +/// Widget build(BuildContext context) { +/// return Scaffold( +/// appBar: ChannelHeader(), +/// body: Column( +/// children: [ +/// Expanded( +/// child: MessageListView( +/// threadBuilder: (_, parentMessage) { +/// return ThreadPage( +/// parent: parentMessage, +/// ); +/// }, +/// ), +/// ), +/// MessageInput(), +/// ], +/// ), +/// ); +/// } +/// } +/// ``` +/// +/// +/// Make sure to have a [StreamChannel] ancestor in order to provide the information about the channels. +/// The widget uses a [ListView.custom] to render the list of channels. +/// +/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// Modify it to change the widget appearance. class MessageListView extends StatefulWidget { MessageListView({ Key key, @@ -23,10 +63,20 @@ class MessageListView extends StatefulWidget { this.onThreadTap, }) : super(key: key); + /// Function used to build a custom message widget final MessageBuilder messageBuilder; + + /// Function used to build a custom parent message widget final ParentMessageBuilder parentMessageBuilder; + + /// Function used to build a custom thread widget final ThreadBuilder threadBuilder; + + /// Function called when tapping on a thread + /// By default it calls [Navigator.push] using the widget built using [threadBuilder] final ThreadTapCallback onThreadTap; + + /// Parent message in case of a thread final Message parentMessage; @override diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index b1481698..7cb737ad 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter/src/message_list_view.dart'; import 'package:stream_chat_flutter/src/stream_channel.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; @@ -16,6 +17,15 @@ import 'package:video_player/video_player.dart'; import 'stream_chat.dart'; +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_widget.png) +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/message_widget_paint.png) +/// +/// It shows a message with reactions, replies and user avatar. +/// +/// Usually you don't use this widget as it's the default message widget used by [MessageListView]. +/// +/// The widget components render the ui based on the first ancestor of type [StreamChatTheme]. +/// Modify it to change the widget appearance. class MessageWidget extends StatefulWidget { const MessageWidget({ Key key, @@ -26,10 +36,19 @@ class MessageWidget extends StatefulWidget { this.isParent = false, }) : super(key: key); - final Message previousMessage; + /// This message final Message message; + + /// The previous message + final Message previousMessage; + + /// The next message final Message nextMessage; + + /// The function called when tapping on replies final void Function(Message) onThreadTap; + + /// True if this is the parent of the thread being showed final bool isParent; @override diff --git a/lib/src/stream_channel.dart b/lib/src/stream_channel.dart index 25b77794..983c7020 100644 --- a/lib/src/stream_channel.dart +++ b/lib/src/stream_channel.dart @@ -4,6 +4,9 @@ import 'package:flutter/material.dart'; import 'package:rxdart/rxdart.dart'; import 'package:stream_chat/stream_chat.dart'; +/// Widget used to provide information about the channel to the widget tree +/// +/// Use [StreamChannel.of] to get the current [StreamChannelState] instance. class StreamChannel extends StatefulWidget { StreamChannel({ Key key, @@ -16,6 +19,7 @@ class StreamChannel extends StatefulWidget { final Widget child; final Channel channel; + /// Use this method to get the current [StreamChannelState] instance static StreamChannelState of(BuildContext context) { StreamChannelState streamChannelState; @@ -34,17 +38,19 @@ class StreamChannel extends StatefulWidget { } class StreamChannelState extends State { - StreamChannelState(); - + /// Current channel Channel get channel => widget.channel; + /// Current channel state stream Stream get channelStateStream => widget.channel.state.channelStateStream; final BehaviorSubject _queryMessageController = BehaviorSubject(); + /// The stream notifying the state of queryMessage call Stream get queryMessage => _queryMessageController.stream; + /// Calls [channel.query] updating [queryMessage] stream void queryMessages() { _queryMessageController.add(true); @@ -67,6 +73,7 @@ class StreamChannelState extends State { }); } + /// Calls [channel.getReplies] updating [queryMessage] stream Future getReplies(String parentId) async { _queryMessageController.add(true); print('PARENT $parentId'); diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index fddf42de..58dfab14 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -6,6 +6,27 @@ import 'package:rxdart/rxdart.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +/// Widget used to provide information about the chat to the widget tree +/// +/// class MyApp extends StatelessWidget { +/// final Client client; +/// +/// MyApp(this.client); +/// +/// @override +/// Widget build(BuildContext context) { +/// return MaterialApp( +/// home: Container( +/// child: StreamChat( +/// client: client, +/// child: ChannelListPage(), +/// ), +/// ), +/// ); +/// } +/// } +/// +/// Use [StreamChat.of] to get the current [StreamChatState] instance. class StreamChat extends StatefulWidget { final Client client; final Widget child; @@ -23,6 +44,7 @@ class StreamChat extends StatefulWidget { @override StreamChatState createState() => StreamChatState(); + /// Use this method to get the current [StreamChatState] instance static StreamChatState of(BuildContext context) { StreamChatState streamChatState; @@ -162,22 +184,28 @@ class StreamChatState extends State { })); } + /// The current user User get user => widget.client.state.user; + /// The current user as a stream Stream get userStream => widget.client.state.userStream; + /// The current channel list + final List channels = []; + + /// The current channel list as a stream Stream> get channelsStream => _channelsController.stream; final BehaviorSubject> _channelsController = BehaviorSubject(); - final List channels = []; - final BehaviorSubject _queryChannelsLoadingController = BehaviorSubject.seeded(false); + /// The stream notifying the state of queryChannel call Stream get queryChannelsLoading => _queryChannelsLoadingController.stream; + /// Calls [client.queryChannels] updating [queryChannelsLoading] stream Future queryChannels({ Map filter, List sortOptions, @@ -204,6 +232,7 @@ class StreamChatState extends State { } } + /// Clear the current channel list void clearChannels() { channels.clear(); } diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 6deb8370..eedc499b 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -1,5 +1,9 @@ import 'package:flutter/material.dart'; +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'; +/// Inherited widget providing the [StreamChatThemeData] to the widget tree class StreamChatTheme extends InheritedWidget { final StreamChatThemeData data; @@ -17,20 +21,36 @@ class StreamChatTheme extends InheritedWidget { return data != old.data; } + /// Use this method to get the current [StreamChatThemeData] instance static StreamChatThemeData of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType().data; } } +/// Theme data class StreamChatThemeData { + /// Primary color of the chat widgets final Color primaryColor; + + /// Secondary color of the chat widgets final Color secondaryColor; + + /// Accent color of the chat widgets final Color accentColor; + + /// Theme of the [ChannelPreview] final ChannelPreviewTheme channelPreviewTheme; + + /// Theme of the chat widgets dedicated to a channel final ChannelTheme channelTheme; + + /// Theme of the current user messages final MessageTheme ownMessageTheme; + + /// Theme of other users messages final MessageTheme otherMessageTheme; + /// Create a theme from scratch StreamChatThemeData({ this.primaryColor, this.secondaryColor, @@ -41,6 +61,7 @@ class StreamChatThemeData { this.ownMessageTheme, }); + /// Create a theme from a Material [Theme] factory StreamChatThemeData.fromTheme(ThemeData theme) { final defaultTheme = getDefaultTheme(theme); @@ -67,6 +88,7 @@ class StreamChatThemeData { ); } + /// Creates a copy of [StreamChatThemeData] with specified attributes overridden. StreamChatThemeData copyWith({ Color primaryColor, Color secondaryColor, @@ -141,6 +163,7 @@ class StreamChatThemeData { this.otherMessageTheme, ); + /// Get the default Stream Chat theme static StreamChatThemeData getDefaultTheme(ThemeData theme) { final accentColor = Color(0xff006cff); return StreamChatThemeData( @@ -245,11 +268,21 @@ class StreamChatThemeData { } } +/// Channel theme data class ChannelTheme { + /// Theme of the [ChannelHeader] widget final ChannelHeaderTheme channelHeaderTheme; + + /// IconTheme of the send button in [MessageInput] final IconThemeData messageInputButtonIconTheme; + + /// Theme of the send button in [MessageInput] final ButtonThemeData messageInputButtonTheme; + + /// Gradient of [MessageInput] final Gradient inputGradient; + + /// Background color of [MessageInput] final Color inputBackground; ChannelTheme({ @@ -260,6 +293,7 @@ class ChannelTheme { this.inputGradient, }); + /// Creates a copy of [ChannelTheme] with specified attributes overridden. ChannelTheme copyWith({ ChannelHeaderTheme channelHeaderTheme, IconThemeData messageInputButtonIconTheme, diff --git a/lib/src/thread_header.dart b/lib/src/thread_header.dart index 0e83cfd2..fc45fde8 100644 --- a/lib/src/thread_header.dart +++ b/lib/src/thread_header.dart @@ -2,9 +2,64 @@ import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/thread_header.png) +/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/thread_header_paint.png) +/// +/// It shows the current thread information. +/// +/// ```dart +/// class ThreadPage extends StatelessWidget { +/// final Message parent; +/// +/// ThreadPage({ +/// Key key, +/// this.parent, +/// }) : super(key: key); +/// +/// @override +/// Widget build(BuildContext context) { +/// return Scaffold( +/// appBar: ThreadHeader( +/// parent: parent, +/// ), +/// body: Column( +/// children: [ +/// Expanded( +/// child: MessageListView( +/// parentMessage: parent, +/// ), +/// ), +/// MessageInput( +/// parentMessage: parent, +/// ), +/// ], +/// ), +/// ); +/// } +/// } +/// ``` +/// +/// Usually you would use this widget as an [AppBar] inside a [Scaffold]. +/// However you can also use it as a normal widget. +/// +/// Make sure to have a [StreamChannel] ancestor in order to provide the information about the channel. +/// Every part of the widget uses a [StreamBuilder] to render the channel information as soon as it updates. +/// +/// By default the widget shows a backButton that calls [Navigator.pop]. +/// You can disable this button using the [showBackButton] property of just override the behaviour +/// with [onBackPressed]. +/// +/// 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 ThreadHeader extends StatelessWidget implements PreferredSizeWidget { + /// True if this header shows the leading back button final bool showBackButton; + + /// Callback to call when pressing the back button. + /// By default it calls [Navigator.pop] final VoidCallback onBackPressed; + + /// The message parent of this thread final Message parent; ThreadHeader({ diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart index 344fdaa8..478ae3b3 100644 --- a/lib/src/user_avatar.dart +++ b/lib/src/user_avatar.dart @@ -30,9 +30,15 @@ class UserAvatar extends StatelessWidget { imageUrl: user.extraData['image'], errorWidget: (_, __, ___) { return Center( - child: Text(user.extraData?.containsKey('name') ?? false - ? user.extraData['name'][0] - : ''), + child: Text( + user.extraData?.containsKey('name') ?? false + ? user.extraData['name'][0] + : '', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + ), + ), ); }, fit: BoxFit.cover, diff --git a/screenshots/channel_image.png b/screenshots/channel_image.png new file mode 100644 index 00000000..230c2b61 Binary files /dev/null and b/screenshots/channel_image.png differ diff --git a/screenshots/channel_image_paint.png b/screenshots/channel_image_paint.png new file mode 100644 index 00000000..d4c5ca37 Binary files /dev/null and b/screenshots/channel_image_paint.png differ diff --git a/screenshots/channel_list_view.png b/screenshots/channel_list_view.png new file mode 100644 index 00000000..fd04fa47 Binary files /dev/null and b/screenshots/channel_list_view.png differ diff --git a/screenshots/channel_list_view_paint.png b/screenshots/channel_list_view_paint.png new file mode 100644 index 00000000..c1d49780 Binary files /dev/null and b/screenshots/channel_list_view_paint.png differ diff --git a/screenshots/channel_preview.png b/screenshots/channel_preview.png new file mode 100644 index 00000000..04058387 Binary files /dev/null and b/screenshots/channel_preview.png differ diff --git a/screenshots/channel_preview_paint.png b/screenshots/channel_preview_paint.png new file mode 100644 index 00000000..c2f822a3 Binary files /dev/null and b/screenshots/channel_preview_paint.png differ diff --git a/screenshots/message_input.png b/screenshots/message_input.png new file mode 100644 index 00000000..9dab6cce Binary files /dev/null and b/screenshots/message_input.png differ diff --git a/screenshots/message_input2.png b/screenshots/message_input2.png new file mode 100644 index 00000000..61b75deb Binary files /dev/null and b/screenshots/message_input2.png differ diff --git a/screenshots/message_input2_paint.png b/screenshots/message_input2_paint.png new file mode 100644 index 00000000..9bb5da11 Binary files /dev/null and b/screenshots/message_input2_paint.png differ diff --git a/screenshots/message_input_paint.png b/screenshots/message_input_paint.png new file mode 100644 index 00000000..555ce941 Binary files /dev/null and b/screenshots/message_input_paint.png differ diff --git a/screenshots/message_listview.png b/screenshots/message_listview.png new file mode 100644 index 00000000..adf3f087 Binary files /dev/null and b/screenshots/message_listview.png differ diff --git a/screenshots/message_listview_paint.png b/screenshots/message_listview_paint.png new file mode 100644 index 00000000..1618cd40 Binary files /dev/null and b/screenshots/message_listview_paint.png differ diff --git a/screenshots/message_widget.png b/screenshots/message_widget.png new file mode 100644 index 00000000..d333c03a Binary files /dev/null and b/screenshots/message_widget.png differ diff --git a/screenshots/message_widget_paint.png b/screenshots/message_widget_paint.png new file mode 100644 index 00000000..4eee610b Binary files /dev/null and b/screenshots/message_widget_paint.png differ diff --git a/screenshots/thread_header.png b/screenshots/thread_header.png new file mode 100644 index 00000000..45707fde Binary files /dev/null and b/screenshots/thread_header.png differ diff --git a/screenshots/thread_header_paint.png b/screenshots/thread_header_paint.png new file mode 100644 index 00000000..41e2b0dc Binary files /dev/null and b/screenshots/thread_header_paint.png differ