add stream chat theme draft
This commit is contained in:
@@ -9,14 +9,25 @@ void main() async {
|
|||||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo',
|
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo',
|
||||||
);
|
);
|
||||||
|
|
||||||
runApp(
|
runApp(MyApp(client));
|
||||||
StreamChat(
|
}
|
||||||
client: client,
|
|
||||||
child: MaterialApp(
|
class MyApp extends StatelessWidget {
|
||||||
home: ChannelListPage(),
|
final Client client;
|
||||||
|
|
||||||
|
MyApp(this.client);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Container(
|
||||||
|
child: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: ChannelListPage(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChannelListPage extends StatelessWidget {
|
class ChannelListPage extends StatelessWidget {
|
||||||
|
|||||||
@@ -9,14 +9,25 @@ void main() async {
|
|||||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo',
|
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo',
|
||||||
);
|
);
|
||||||
|
|
||||||
runApp(
|
runApp(MyApp(client));
|
||||||
StreamChat(
|
}
|
||||||
client: client,
|
|
||||||
child: MaterialApp(
|
class MyApp extends StatelessWidget {
|
||||||
home: ChannelListPage(),
|
final Client client;
|
||||||
|
|
||||||
|
MyApp(this.client);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Container(
|
||||||
|
child: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: ChannelListPage(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChannelListPage extends StatelessWidget {
|
class ChannelListPage extends StatelessWidget {
|
||||||
|
|||||||
@@ -9,14 +9,25 @@ void main() async {
|
|||||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo',
|
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo',
|
||||||
);
|
);
|
||||||
|
|
||||||
runApp(
|
runApp(MyApp(client));
|
||||||
StreamChat(
|
}
|
||||||
client: client,
|
|
||||||
child: MaterialApp(
|
class MyApp extends StatelessWidget {
|
||||||
home: ChannelListPage(),
|
final Client client;
|
||||||
|
|
||||||
|
MyApp(this.client);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Container(
|
||||||
|
child: StreamChat(
|
||||||
|
client: client,
|
||||||
|
child: ChannelListPage(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChannelListPage extends StatelessWidget {
|
class ChannelListPage extends StatelessWidget {
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ void main() async {
|
|||||||
channel.watch();
|
channel.watch();
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
StreamChat(
|
MaterialApp(
|
||||||
client: client,
|
home: StreamChat(
|
||||||
child: MaterialApp(
|
client: client,
|
||||||
home: StreamChannel(
|
child: StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: ChannelPage(),
|
child: ChannelPage(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -9,14 +9,34 @@ void main() async {
|
|||||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo',
|
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoid2lsZC1icmVlemUtNyJ9.VM2EX1EXOfgqa-bTH_3JzeY0T99ngWzWahSauP3dBMo',
|
||||||
);
|
);
|
||||||
|
|
||||||
runApp(
|
runApp(MyApp(client));
|
||||||
StreamChat(
|
}
|
||||||
client: client,
|
|
||||||
child: MaterialApp(
|
class MyApp extends StatelessWidget {
|
||||||
home: ChannelListPage(),
|
final Client client;
|
||||||
|
|
||||||
|
MyApp(this.client);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Container(
|
||||||
|
child: StreamChat(
|
||||||
|
streamChatThemeData: StreamChatThemeData(
|
||||||
|
accentColor: Colors.red,
|
||||||
|
channelTheme: ChannelTheme(
|
||||||
|
inputGradient: LinearGradient(colors: [
|
||||||
|
Colors.red,
|
||||||
|
Colors.yellow,
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
client: client,
|
||||||
|
child: ChannelListPage(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChannelListPage extends StatelessWidget {
|
class ChannelListPage extends StatelessWidget {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
import 'package:stream_chat_flutter/src/channel_name.dart';
|
import 'package:stream_chat_flutter/src/channel_name.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
import 'package:timeago/timeago.dart' as timeago;
|
import 'package:timeago/timeago.dart' as timeago;
|
||||||
|
|
||||||
import './channel_name.dart';
|
import './channel_name.dart';
|
||||||
@@ -22,7 +23,10 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final channel = StreamChannel.of(context).channel;
|
final channel = StreamChannel.of(context).channel;
|
||||||
return AppBar(
|
return AppBar(
|
||||||
|
elevation: 1,
|
||||||
leading: showBackButton ? _buildBackButton(context) : Container(),
|
leading: showBackButton ? _buildBackButton(context) : Container(),
|
||||||
|
backgroundColor:
|
||||||
|
StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color,
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 10.0),
|
padding: const EdgeInsets.only(right: 10.0),
|
||||||
@@ -39,6 +43,10 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
ChannelName(
|
ChannelName(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
|
textStyle: StreamChatTheme.of(context)
|
||||||
|
.channelTheme
|
||||||
|
.channelHeaderTheme
|
||||||
|
.title,
|
||||||
),
|
),
|
||||||
_buildLastActive(context, channel),
|
_buildLastActive(context, channel),
|
||||||
],
|
],
|
||||||
@@ -54,7 +62,10 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
return (snapshot.data != null)
|
return (snapshot.data != null)
|
||||||
? Text(
|
? Text(
|
||||||
'Active ${timeago.format(snapshot.data)}',
|
'Active ${timeago.format(snapshot.data)}',
|
||||||
style: Theme.of(context).textTheme.caption,
|
style: StreamChatTheme.of(context)
|
||||||
|
.channelTheme
|
||||||
|
.channelHeaderTheme
|
||||||
|
.lastMessageAt,
|
||||||
)
|
)
|
||||||
: Container();
|
: Container();
|
||||||
},
|
},
|
||||||
|
|||||||
+28
-11
@@ -1,16 +1,17 @@
|
|||||||
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/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
class ChannelImage extends StatelessWidget {
|
class ChannelImage extends StatelessWidget {
|
||||||
const ChannelImage({
|
const ChannelImage({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.channel,
|
@required this.channel,
|
||||||
this.radius = 20,
|
this.size = 40,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final Channel channel;
|
final Channel channel;
|
||||||
final double radius;
|
final double size;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -18,16 +19,32 @@ class ChannelImage extends StatelessWidget {
|
|||||||
stream: channel.extraDataStream,
|
stream: channel.extraDataStream,
|
||||||
initialData: channel.extraData,
|
initialData: channel.extraData,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
return CircleAvatar(
|
return Container(
|
||||||
radius: radius,
|
padding: const EdgeInsets.all(4),
|
||||||
backgroundImage: snapshot.data?.containsKey('image') ?? false
|
constraints: StreamChatTheme.of(context)
|
||||||
? CachedNetworkImageProvider(snapshot.data['image'])
|
.channelPreviewTheme
|
||||||
: null,
|
.avatarTheme
|
||||||
|
.constraints,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: StreamChatTheme.of(context)
|
||||||
|
.channelPreviewTheme
|
||||||
|
.avatarTheme
|
||||||
|
.borderRadius,
|
||||||
|
color: StreamChatTheme.of(context).accentColor,
|
||||||
|
),
|
||||||
child: snapshot.data?.containsKey('image') ?? false
|
child: snapshot.data?.containsKey('image') ?? false
|
||||||
? null
|
? CachedNetworkImage(
|
||||||
: Text(snapshot.data?.containsKey('name') ?? false
|
imageUrl: snapshot.data['image'],
|
||||||
? snapshot.data['name'][0]
|
errorWidget: (_, __, ___) {
|
||||||
: ''),
|
return Center(
|
||||||
|
child: Text(snapshot.data?.containsKey('name') ?? false
|
||||||
|
? snapshot.data['name'][0]
|
||||||
|
: ''),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
)
|
||||||
|
: SizedBox(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildQueryProgressIndicator(context, StreamChat streamChat) {
|
Widget _buildQueryProgressIndicator(context, StreamChatState streamChat) {
|
||||||
return StreamBuilder<bool>(
|
return StreamBuilder<bool>(
|
||||||
stream: streamChat.queryChannelsLoading,
|
stream: streamChat.queryChannelsLoading,
|
||||||
initialData: false,
|
initialData: false,
|
||||||
@@ -184,7 +184,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _listenChannelPagination(StreamChat streamChat) {
|
void _listenChannelPagination(StreamChatState streamChat) {
|
||||||
if (widget._scrollController.position.maxScrollExtent ==
|
if (widget._scrollController.position.maxScrollExtent ==
|
||||||
widget._scrollController.position.pixels) {
|
widget._scrollController.position.pixels) {
|
||||||
streamChat.queryChannels(
|
streamChat.queryChannels(
|
||||||
|
|||||||
+13
-10
@@ -5,22 +5,25 @@ class ChannelName extends StatelessWidget {
|
|||||||
const ChannelName({
|
const ChannelName({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.channel,
|
@required this.channel,
|
||||||
|
this.textStyle,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final Channel channel;
|
final Channel channel;
|
||||||
|
final TextStyle textStyle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return StreamBuilder<Map<String, dynamic>>(
|
return StreamBuilder<Map<String, dynamic>>(
|
||||||
stream: channel.extraDataStream,
|
stream: channel.extraDataStream,
|
||||||
initialData: channel.extraData,
|
initialData: channel.extraData,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
return Text(
|
return Text(
|
||||||
snapshot.data != null
|
snapshot.data != null
|
||||||
? (snapshot.data['name'] ?? channel.cid)
|
? (snapshot.data['name'] ?? channel.cid)
|
||||||
: channel.cid,
|
: channel.cid,
|
||||||
style: Theme.of(context).textTheme.body2,
|
style: textStyle,
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
channel: channel,
|
channel: channel,
|
||||||
),
|
),
|
||||||
title: ChannelName(
|
title: ChannelName(
|
||||||
|
textStyle: StreamChatTheme.of(context).channelPreviewTheme.title,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
),
|
),
|
||||||
subtitle: _buildSubtitle(),
|
subtitle: _buildSubtitle(),
|
||||||
@@ -62,7 +63,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
|
|
||||||
return Text(
|
return Text(
|
||||||
stringDate,
|
stringDate,
|
||||||
style: Theme.of(context).textTheme.caption,
|
style: StreamChatTheme.of(context).channelPreviewTheme.lastMessageAt,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -115,9 +116,14 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
text,
|
text,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: Theme.of(context).textTheme.caption.copyWith(
|
style:
|
||||||
color: Colors.black.withOpacity(opacity),
|
StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith(
|
||||||
),
|
color: StreamChatTheme.of(context)
|
||||||
|
.channelPreviewTheme
|
||||||
|
.subtitle
|
||||||
|
.color
|
||||||
|
.withOpacity(opacity),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -127,8 +133,12 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
return Text(
|
return Text(
|
||||||
'${typings.map((u) => u.extraData.containsKey('name') ? u.extraData['name'] : u.id).join(',')} ${typings.length == 1 ? 'is' : 'are'} typing...',
|
'${typings.map((u) => u.extraData.containsKey('name') ? u.extraData['name'] : u.id).join(',')} ${typings.length == 1 ? 'is' : 'are'} typing...',
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: Theme.of(context).textTheme.caption.copyWith(
|
style: StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith(
|
||||||
color: Colors.black.withOpacity(opacity),
|
color: StreamChatTheme.of(context)
|
||||||
|
.channelPreviewTheme
|
||||||
|
.subtitle
|
||||||
|
.color
|
||||||
|
.withOpacity(opacity),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-13
@@ -1,7 +1,6 @@
|
|||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
import 'stream_channel.dart';
|
import 'stream_channel.dart';
|
||||||
|
|
||||||
@@ -34,17 +33,17 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
gradient: _typingStarted
|
gradient: _typingStarted
|
||||||
? LinearGradient(colors: [Color(0xFF00AEFF), Color(0xFF0076FF)])
|
? StreamChatTheme.of(context).channelTheme.inputGradient
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).canvasColor,
|
color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.black.withAlpha(5),
|
color: StreamChatTheme.of(context).channelTheme.inputBackground,
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
border: Border.all(color: Colors.black.withOpacity(.2)),
|
border: Border.all(color: Colors.black.withOpacity(.2)),
|
||||||
),
|
),
|
||||||
@@ -84,7 +83,7 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
? CrossFadeState.showFirst
|
? CrossFadeState.showFirst
|
||||||
: CrossFadeState.showSecond,
|
: CrossFadeState.showSecond,
|
||||||
firstChild: _buildSendButton(context),
|
firstChild: _buildSendButton(context),
|
||||||
secondChild: Container(),
|
secondChild: SizedBox(),
|
||||||
duration: Duration(milliseconds: 300),
|
duration: Duration(milliseconds: 300),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
),
|
),
|
||||||
@@ -96,13 +95,17 @@ class _MessageInputState extends State<MessageInput> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton _buildSendButton(BuildContext context) {
|
Widget _buildSendButton(BuildContext context) {
|
||||||
return IconButton(
|
return IconTheme(
|
||||||
onPressed: () {
|
data:
|
||||||
_sendMessage(context);
|
StreamChatTheme.of(context).channelTheme.messageInputButtonIconTheme,
|
||||||
},
|
child: IconButton(
|
||||||
icon: Icon(
|
onPressed: () {
|
||||||
Icons.send,
|
_sendMessage(context);
|
||||||
|
},
|
||||||
|
icon: Icon(
|
||||||
|
Icons.send,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_widgets/flutter_widgets.dart';
|
import 'package:flutter_widgets/flutter_widgets.dart';
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
|
|
||||||
|
import '../stream_chat_flutter.dart';
|
||||||
import 'message_widget.dart';
|
import 'message_widget.dart';
|
||||||
import 'stream_channel.dart';
|
import 'stream_channel.dart';
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Text(
|
child: Text(
|
||||||
'Start of a new thread',
|
'Start of thread',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
color: Theme.of(context).primaryColorLight,
|
color: Theme.of(context).primaryColorLight,
|
||||||
|
|||||||
+27
-10
@@ -7,6 +7,7 @@ import 'package:flutter/widgets.dart';
|
|||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_channel.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';
|
import 'package:stream_chat_flutter/src/user_avatar.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
import 'package:video_player/video_player.dart';
|
import 'package:video_player/video_player.dart';
|
||||||
@@ -41,7 +42,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
super.build(context);
|
super.build(context);
|
||||||
|
|
||||||
final streamChat = StreamChat.of(context);
|
final streamChat = StreamChat.of(context);
|
||||||
final currentUserId = streamChat.user.id;
|
final currentUserId = streamChat.client.state.user.id;
|
||||||
final messageUserId = widget.message.user.id;
|
final messageUserId = widget.message.user.id;
|
||||||
final previousUserId = widget.previousMessage?.user?.id;
|
final previousUserId = widget.previousMessage?.user?.id;
|
||||||
final nextUserId = widget.nextMessage?.user?.id;
|
final nextUserId = widget.nextMessage?.user?.id;
|
||||||
@@ -116,7 +117,9 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'This message was deleted...',
|
'This message was deleted...',
|
||||||
style: TextStyle(fontStyle: FontStyle.italic),
|
style: StreamChatTheme.of(context).messageTheme.messageText.copyWith(
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -203,10 +206,13 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
Text(
|
Text(
|
||||||
attachment.title,
|
attachment.title,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: Theme.of(context)
|
style: StreamChatTheme.of(context)
|
||||||
.textTheme
|
.messageTheme
|
||||||
.subtitle
|
.messageText
|
||||||
.copyWith(color: Colors.blue),
|
.copyWith(
|
||||||
|
color: Colors.blue,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
Uri.parse(attachment.thumbUrl)
|
Uri.parse(attachment.thumbUrl)
|
||||||
@@ -218,8 +224,9 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
.reversed
|
.reversed
|
||||||
.join('.'),
|
.join('.'),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style:
|
style: StreamChatTheme.of(context)
|
||||||
Theme.of(context).textTheme.caption,
|
.messageTheme
|
||||||
|
.createdAt,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -298,7 +305,12 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
_launchURL(link);
|
_launchURL(link);
|
||||||
},
|
},
|
||||||
styleSheet:
|
styleSheet:
|
||||||
MarkdownStyleSheet.fromTheme(Theme.of(context)),
|
MarkdownStyleSheet.fromTheme(Theme.of(context))
|
||||||
|
.copyWith(
|
||||||
|
p: StreamChatTheme.of(context)
|
||||||
|
.messageTheme
|
||||||
|
.messageText,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -547,6 +559,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
padding: const EdgeInsets.only(top: 5.0),
|
padding: const EdgeInsets.only(top: 5.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
formatDate(widget.message.createdAt.toLocal(), [HH, ':', nn]),
|
formatDate(widget.message.createdAt.toLocal(), [HH, ':', nn]),
|
||||||
|
style: StreamChatTheme.of(context).messageTheme.createdAt,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -560,7 +573,11 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
topRight: Radius.circular((isMyMessage && isLastUser) ? 2 : 16),
|
topRight: Radius.circular((isMyMessage && isLastUser) ? 2 : 16),
|
||||||
bottomRight: Radius.circular(isMyMessage ? 2 : 16),
|
bottomRight: Radius.circular(isMyMessage ? 2 : 16),
|
||||||
),
|
),
|
||||||
color: isMyMessage ? Color(0xffebebeb) : Colors.white,
|
color: isMyMessage
|
||||||
|
? StreamChatTheme.of(context).messageTheme.ownMessageBackgroundColor
|
||||||
|
: StreamChatTheme.of(context)
|
||||||
|
.messageTheme
|
||||||
|
.otherMessageBackgroundColor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+204
-32
@@ -4,20 +4,210 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
class StreamChat extends InheritedWidget {
|
class StreamChat extends StatefulWidget {
|
||||||
final Client client;
|
final Client client;
|
||||||
final List<StreamSubscription> _subscriptions = [];
|
final Widget child;
|
||||||
|
final StreamChatThemeData streamChatThemeData;
|
||||||
|
|
||||||
StreamChat({
|
StreamChat({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.client,
|
@required this.client,
|
||||||
@required Widget child,
|
@required this.child,
|
||||||
|
this.streamChatThemeData,
|
||||||
}) : super(
|
}) : super(
|
||||||
key: key,
|
key: key,
|
||||||
child: child,
|
);
|
||||||
) {
|
|
||||||
_subscriptions.add(client.on('message.new').listen((Event e) {
|
@override
|
||||||
|
StreamChatState createState() => StreamChatState();
|
||||||
|
|
||||||
|
static StreamChatState of(BuildContext context) {
|
||||||
|
StreamChatState streamChatState;
|
||||||
|
|
||||||
|
streamChatState = context.findAncestorStateOfType<StreamChatState>();
|
||||||
|
|
||||||
|
if (streamChatState == null) {
|
||||||
|
throw Exception(
|
||||||
|
'You must have a StreamChat widget at the top of your widget tree');
|
||||||
|
}
|
||||||
|
|
||||||
|
return streamChatState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StreamChatState extends State<StreamChat> {
|
||||||
|
final List<StreamSubscription> _subscriptions = [];
|
||||||
|
Client get client => widget.client;
|
||||||
|
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final theme = _computeTheme(context);
|
||||||
|
return StreamChatTheme(
|
||||||
|
data: theme,
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) => Theme(
|
||||||
|
data: Theme.of(context).copyWith(
|
||||||
|
accentColor: StreamChatTheme.of(context).accentColor,
|
||||||
|
),
|
||||||
|
child: WillPopScope(
|
||||||
|
onWillPop: () async {
|
||||||
|
if (_navigatorKey.currentState.canPop()) {
|
||||||
|
_navigatorKey.currentState.pop();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Navigator(
|
||||||
|
initialRoute: '/',
|
||||||
|
key: _navigatorKey,
|
||||||
|
onGenerateRoute: (settings) {
|
||||||
|
return MaterialPageRoute(
|
||||||
|
settings: settings,
|
||||||
|
builder: (_) => widget.child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamChatThemeData _computeTheme(BuildContext context) {
|
||||||
|
final defaultTheme = _getDefaultTheme(context);
|
||||||
|
final theme = defaultTheme.copyWith(
|
||||||
|
primaryColor: widget.streamChatThemeData?.primaryColor,
|
||||||
|
channelTheme: defaultTheme.channelTheme.copyWith(
|
||||||
|
channelHeaderTheme:
|
||||||
|
widget.streamChatThemeData?.channelTheme?.channelHeaderTheme,
|
||||||
|
inputBackground:
|
||||||
|
widget.streamChatThemeData?.channelTheme?.inputBackground,
|
||||||
|
messageInputButtonIconTheme: widget
|
||||||
|
.streamChatThemeData?.channelTheme?.messageInputButtonIconTheme,
|
||||||
|
inputGradient: widget.streamChatThemeData?.channelTheme?.inputGradient,
|
||||||
|
messageInputButtonTheme:
|
||||||
|
widget.streamChatThemeData?.channelTheme?.messageInputButtonTheme,
|
||||||
|
),
|
||||||
|
messageTheme: defaultTheme.messageTheme.copyWith(
|
||||||
|
createdAt: widget.streamChatThemeData?.messageTheme?.createdAt,
|
||||||
|
messageText: widget.streamChatThemeData?.messageTheme?.messageText,
|
||||||
|
otherMessageBackgroundColor: widget
|
||||||
|
.streamChatThemeData?.messageTheme?.otherMessageBackgroundColor,
|
||||||
|
ownMessageBackgroundColor:
|
||||||
|
widget.streamChatThemeData?.messageTheme?.ownMessageBackgroundColor,
|
||||||
|
fontFamily: widget.streamChatThemeData?.messageTheme?.fontFamily,
|
||||||
|
messageAuthor: widget.streamChatThemeData?.messageTheme?.messageAuthor,
|
||||||
|
messageMention:
|
||||||
|
widget.streamChatThemeData?.messageTheme?.messageMention,
|
||||||
|
avatarTheme: defaultTheme.messageTheme.avatarTheme.copyWith(
|
||||||
|
constraints: widget
|
||||||
|
.streamChatThemeData?.messageTheme?.avatarTheme?.constraints,
|
||||||
|
borderRadius: widget
|
||||||
|
.streamChatThemeData?.messageTheme?.avatarTheme?.borderRadius,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
accentColor: widget.streamChatThemeData?.accentColor,
|
||||||
|
secondaryColor: widget.streamChatThemeData?.secondaryColor,
|
||||||
|
channelPreviewTheme: defaultTheme.channelPreviewTheme.copyWith(
|
||||||
|
avatarTheme: defaultTheme.channelPreviewTheme.avatarTheme.copyWith(
|
||||||
|
constraints: widget.streamChatThemeData?.channelPreviewTheme
|
||||||
|
?.avatarTheme?.constraints,
|
||||||
|
borderRadius: widget.streamChatThemeData?.channelPreviewTheme
|
||||||
|
?.avatarTheme?.borderRadius,
|
||||||
|
),
|
||||||
|
title: widget.streamChatThemeData?.channelPreviewTheme?.title,
|
||||||
|
lastMessageAt:
|
||||||
|
widget.streamChatThemeData?.channelPreviewTheme?.lastMessageAt,
|
||||||
|
subtitle: widget.streamChatThemeData?.channelPreviewTheme?.subtitle,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamChatThemeData _getDefaultTheme(BuildContext context) {
|
||||||
|
final accentColor = Color(0xff006cff);
|
||||||
|
return StreamChatThemeData(
|
||||||
|
accentColor: accentColor,
|
||||||
|
primaryColor: Colors.white,
|
||||||
|
channelPreviewTheme: ChannelPreviewTheme(
|
||||||
|
avatarTheme: AvatarTheme(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
constraints: BoxConstraints.tightFor(
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
subtitle: TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
lastMessageAt: TextStyle(
|
||||||
|
fontSize: 11,
|
||||||
|
color: Colors.black.withOpacity(.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
channelTheme: ChannelTheme(
|
||||||
|
messageInputButtonIconTheme: Theme.of(context).iconTheme.copyWith(
|
||||||
|
color: accentColor,
|
||||||
|
),
|
||||||
|
channelHeaderTheme: ChannelHeaderTheme(
|
||||||
|
avatarTheme: AvatarTheme(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
constraints: BoxConstraints.tightFor(
|
||||||
|
height: 40,
|
||||||
|
width: 40,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
color: Colors.white,
|
||||||
|
title: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
lastMessageAt: TextStyle(
|
||||||
|
fontSize: 11,
|
||||||
|
color: Colors.black.withOpacity(.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
inputBackground: Colors.black.withAlpha(12),
|
||||||
|
inputGradient: LinearGradient(colors: [
|
||||||
|
Color(0xFF00AEFF),
|
||||||
|
Color(0xFF0076FF),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
messageTheme: MessageTheme(
|
||||||
|
messageText: TextStyle(
|
||||||
|
fontSize: 15,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
createdAt: TextStyle(
|
||||||
|
color: Colors.black.withOpacity(.5),
|
||||||
|
fontSize: 11,
|
||||||
|
),
|
||||||
|
ownMessageBackgroundColor: Color(0xffebebeb),
|
||||||
|
otherMessageBackgroundColor: Colors.white,
|
||||||
|
avatarTheme: AvatarTheme(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
constraints: BoxConstraints.tightFor(
|
||||||
|
height: 32,
|
||||||
|
width: 32,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_subscriptions.add(widget.client.on('message.new').listen((Event e) {
|
||||||
final index = channels.indexWhere((c) => c.cid == e.cid);
|
final index = channels.indexWhere((c) => c.cid == e.cid);
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
final channel = channels.removeAt(index);
|
final channel = channels.removeAt(index);
|
||||||
@@ -27,12 +217,14 @@ class StreamChat extends InheritedWidget {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
User get user => client.state.user;
|
User get user => widget.client.state.user;
|
||||||
|
|
||||||
Stream<User> get userStream => client.state.userStream;
|
Stream<User> get userStream => widget.client.state.userStream;
|
||||||
|
|
||||||
Stream<List<Channel>> get channelsStream => _channelsController.stream;
|
Stream<List<Channel>> get channelsStream => _channelsController.stream;
|
||||||
|
|
||||||
final BehaviorSubject<List<Channel>> _channelsController = BehaviorSubject();
|
final BehaviorSubject<List<Channel>> _channelsController = BehaviorSubject();
|
||||||
|
|
||||||
final List<Channel> channels = [];
|
final List<Channel> channels = [];
|
||||||
|
|
||||||
final BehaviorSubject<bool> _queryChannelsLoadingController =
|
final BehaviorSubject<bool> _queryChannelsLoadingController =
|
||||||
@@ -53,7 +245,7 @@ class StreamChat extends InheritedWidget {
|
|||||||
_queryChannelsLoadingController.sink.add(true);
|
_queryChannelsLoadingController.sink.add(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final res = await client.queryChannels(
|
final res = await widget.client.queryChannels(
|
||||||
filter: filter,
|
filter: filter,
|
||||||
sort: sortOptions,
|
sort: sortOptions,
|
||||||
options: options,
|
options: options,
|
||||||
@@ -71,32 +263,12 @@ class StreamChat extends InheritedWidget {
|
|||||||
channels.clear();
|
channels.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
client.dispose();
|
widget.client.dispose();
|
||||||
_subscriptions.forEach((s) => s.cancel());
|
_subscriptions.forEach((s) => s.cancel());
|
||||||
_queryChannelsLoadingController.close();
|
_queryChannelsLoadingController.close();
|
||||||
_channelsController.close();
|
_channelsController.close();
|
||||||
}
|
super.dispose();
|
||||||
|
|
||||||
@override
|
|
||||||
bool updateShouldNotify(InheritedWidget oldWidget) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static StreamChat of(BuildContext context, [bool listen = false]) {
|
|
||||||
StreamChat streamChat;
|
|
||||||
|
|
||||||
if (listen) {
|
|
||||||
streamChat = context.dependOnInheritedWidgetOfExactType<StreamChat>();
|
|
||||||
} else {
|
|
||||||
streamChat = context.findAncestorWidgetOfExactType<StreamChat>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (streamChat == null) {
|
|
||||||
throw Exception(
|
|
||||||
'You must have a StreamChat widget at the top of your widget tree');
|
|
||||||
}
|
|
||||||
|
|
||||||
return streamChat;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,217 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class StreamChatTheme extends InheritedWidget {
|
||||||
|
final StreamChatThemeData data;
|
||||||
|
|
||||||
|
StreamChatTheme({
|
||||||
|
Key key,
|
||||||
|
@required this.data,
|
||||||
|
Widget child,
|
||||||
|
}) : super(
|
||||||
|
key: key,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool updateShouldNotify(StreamChatTheme old) {
|
||||||
|
return data != old.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StreamChatThemeData of(BuildContext context) {
|
||||||
|
return context.dependOnInheritedWidgetOfExactType<StreamChatTheme>().data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StreamChatThemeData {
|
||||||
|
final Color primaryColor;
|
||||||
|
final Color secondaryColor;
|
||||||
|
final Color accentColor;
|
||||||
|
final ChannelPreviewTheme channelPreviewTheme;
|
||||||
|
final ChannelTheme channelTheme;
|
||||||
|
final MessageTheme messageTheme;
|
||||||
|
|
||||||
|
StreamChatThemeData({
|
||||||
|
this.primaryColor,
|
||||||
|
this.secondaryColor,
|
||||||
|
this.accentColor,
|
||||||
|
this.channelPreviewTheme,
|
||||||
|
this.channelTheme,
|
||||||
|
this.messageTheme,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory StreamChatThemeData.fromTheme(ThemeData theme) {
|
||||||
|
return StreamChatThemeData(
|
||||||
|
accentColor: theme.accentColor,
|
||||||
|
primaryColor: theme.colorScheme.primary,
|
||||||
|
secondaryColor: theme.colorScheme.secondary,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamChatThemeData copyWith({
|
||||||
|
Color primaryColor,
|
||||||
|
Color secondaryColor,
|
||||||
|
Color accentColor,
|
||||||
|
ChannelPreviewTheme channelPreviewTheme,
|
||||||
|
ChannelTheme channelTheme,
|
||||||
|
MessageTheme messageTheme,
|
||||||
|
}) =>
|
||||||
|
StreamChatThemeData(
|
||||||
|
primaryColor: primaryColor ?? this.primaryColor,
|
||||||
|
secondaryColor: secondaryColor ?? this.secondaryColor,
|
||||||
|
accentColor: accentColor ?? this.accentColor,
|
||||||
|
channelPreviewTheme: channelPreviewTheme ?? this.channelPreviewTheme,
|
||||||
|
channelTheme: channelTheme ?? this.channelTheme,
|
||||||
|
messageTheme: messageTheme ?? this.messageTheme,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChannelTheme {
|
||||||
|
final ChannelHeaderTheme channelHeaderTheme;
|
||||||
|
final IconThemeData messageInputButtonIconTheme;
|
||||||
|
final ButtonThemeData messageInputButtonTheme;
|
||||||
|
final Gradient inputGradient;
|
||||||
|
final Color inputBackground;
|
||||||
|
|
||||||
|
ChannelTheme({
|
||||||
|
this.channelHeaderTheme,
|
||||||
|
this.messageInputButtonIconTheme,
|
||||||
|
this.messageInputButtonTheme,
|
||||||
|
this.inputBackground,
|
||||||
|
this.inputGradient,
|
||||||
|
});
|
||||||
|
|
||||||
|
ChannelTheme copyWith({
|
||||||
|
ChannelHeaderTheme channelHeaderTheme,
|
||||||
|
IconThemeData messageInputButtonIconTheme,
|
||||||
|
ButtonThemeData messageInputButtonTheme,
|
||||||
|
Gradient inputGradient,
|
||||||
|
Color inputBackground,
|
||||||
|
}) =>
|
||||||
|
ChannelTheme(
|
||||||
|
channelHeaderTheme: channelHeaderTheme ?? this.channelHeaderTheme,
|
||||||
|
messageInputButtonIconTheme:
|
||||||
|
messageInputButtonIconTheme ?? this.messageInputButtonIconTheme,
|
||||||
|
messageInputButtonTheme:
|
||||||
|
messageInputButtonTheme ?? this.messageInputButtonTheme,
|
||||||
|
inputGradient: inputGradient ?? this.inputGradient,
|
||||||
|
inputBackground: inputBackground ?? this.inputBackground,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class AvatarTheme {
|
||||||
|
final BoxConstraints constraints;
|
||||||
|
final BorderRadius borderRadius;
|
||||||
|
|
||||||
|
AvatarTheme({
|
||||||
|
this.constraints,
|
||||||
|
this.borderRadius,
|
||||||
|
});
|
||||||
|
|
||||||
|
AvatarTheme copyWith({
|
||||||
|
BoxConstraints constraints,
|
||||||
|
BorderRadius borderRadius,
|
||||||
|
}) =>
|
||||||
|
AvatarTheme(
|
||||||
|
constraints: constraints ?? this.constraints,
|
||||||
|
borderRadius: borderRadius ?? this.borderRadius,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageTheme {
|
||||||
|
final TextStyle messageText;
|
||||||
|
final TextStyle messageAuthor;
|
||||||
|
final TextStyle messageMention;
|
||||||
|
final TextStyle createdAt;
|
||||||
|
final String fontFamily;
|
||||||
|
final Color ownMessageBackgroundColor;
|
||||||
|
final Color otherMessageBackgroundColor;
|
||||||
|
final AvatarTheme avatarTheme;
|
||||||
|
|
||||||
|
const MessageTheme({
|
||||||
|
this.messageText,
|
||||||
|
this.messageAuthor,
|
||||||
|
this.messageMention,
|
||||||
|
this.fontFamily,
|
||||||
|
this.ownMessageBackgroundColor,
|
||||||
|
this.otherMessageBackgroundColor,
|
||||||
|
this.avatarTheme,
|
||||||
|
this.createdAt,
|
||||||
|
});
|
||||||
|
|
||||||
|
MessageTheme copyWith({
|
||||||
|
TextStyle messageText,
|
||||||
|
TextStyle messageAuthor,
|
||||||
|
TextStyle messageMention,
|
||||||
|
TextStyle createdAt,
|
||||||
|
String fontFamily,
|
||||||
|
Color ownMessageBackgroundColor,
|
||||||
|
Color otherMessageBackgroundColor,
|
||||||
|
AvatarTheme avatarTheme,
|
||||||
|
}) =>
|
||||||
|
MessageTheme(
|
||||||
|
messageText: messageText ?? this.messageText,
|
||||||
|
messageAuthor: messageAuthor ?? this.messageAuthor,
|
||||||
|
messageMention: messageMention ?? this.messageMention,
|
||||||
|
createdAt: createdAt ?? this.createdAt,
|
||||||
|
fontFamily: fontFamily ?? this.fontFamily,
|
||||||
|
ownMessageBackgroundColor:
|
||||||
|
ownMessageBackgroundColor ?? this.ownMessageBackgroundColor,
|
||||||
|
otherMessageBackgroundColor:
|
||||||
|
otherMessageBackgroundColor ?? this.otherMessageBackgroundColor,
|
||||||
|
avatarTheme: avatarTheme ?? this.avatarTheme,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChannelPreviewTheme {
|
||||||
|
final TextStyle title;
|
||||||
|
final TextStyle subtitle;
|
||||||
|
final TextStyle lastMessageAt;
|
||||||
|
final AvatarTheme avatarTheme;
|
||||||
|
|
||||||
|
const ChannelPreviewTheme({
|
||||||
|
this.title,
|
||||||
|
this.subtitle,
|
||||||
|
this.lastMessageAt,
|
||||||
|
this.avatarTheme,
|
||||||
|
});
|
||||||
|
|
||||||
|
ChannelPreviewTheme copyWith({
|
||||||
|
TextStyle title,
|
||||||
|
TextStyle subtitle,
|
||||||
|
TextStyle lastMessageAt,
|
||||||
|
AvatarTheme avatarTheme,
|
||||||
|
}) =>
|
||||||
|
ChannelPreviewTheme(
|
||||||
|
title: title ?? this.title,
|
||||||
|
subtitle: subtitle ?? this.subtitle,
|
||||||
|
lastMessageAt: lastMessageAt ?? this.lastMessageAt,
|
||||||
|
avatarTheme: avatarTheme ?? this.avatarTheme,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChannelHeaderTheme {
|
||||||
|
final TextStyle title;
|
||||||
|
final TextStyle lastMessageAt;
|
||||||
|
final AvatarTheme avatarTheme;
|
||||||
|
final Color color;
|
||||||
|
|
||||||
|
const ChannelHeaderTheme({
|
||||||
|
this.title,
|
||||||
|
this.lastMessageAt,
|
||||||
|
this.avatarTheme,
|
||||||
|
this.color,
|
||||||
|
});
|
||||||
|
|
||||||
|
ChannelHeaderTheme copyWith({
|
||||||
|
TextStyle title,
|
||||||
|
TextStyle lastMessageAt,
|
||||||
|
AvatarTheme avatarTheme,
|
||||||
|
Color color,
|
||||||
|
}) =>
|
||||||
|
ChannelHeaderTheme(
|
||||||
|
title: title ?? this.title,
|
||||||
|
lastMessageAt: lastMessageAt ?? this.lastMessageAt,
|
||||||
|
avatarTheme: avatarTheme ?? this.avatarTheme,
|
||||||
|
color: color ?? this.color,
|
||||||
|
);
|
||||||
|
}
|
||||||
+24
-10
@@ -2,6 +2,8 @@ import 'package:cached_network_image/cached_network_image.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat/stream_chat.dart';
|
import 'package:stream_chat/stream_chat.dart';
|
||||||
|
|
||||||
|
import '../stream_chat_flutter.dart';
|
||||||
|
|
||||||
class UserAvatar extends StatelessWidget {
|
class UserAvatar extends StatelessWidget {
|
||||||
const UserAvatar({
|
const UserAvatar({
|
||||||
Key key,
|
Key key,
|
||||||
@@ -14,16 +16,28 @@ class UserAvatar extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CircleAvatar(
|
return Container(
|
||||||
radius: radius,
|
padding: const EdgeInsets.all(4),
|
||||||
backgroundImage: user.extraData.containsKey('image')
|
constraints:
|
||||||
? CachedNetworkImageProvider(user.extraData['image'] as String)
|
StreamChatTheme.of(context).messageTheme.avatarTheme.constraints,
|
||||||
: null,
|
decoration: BoxDecoration(
|
||||||
child: user.extraData.containsKey('image')
|
borderRadius:
|
||||||
? null
|
StreamChatTheme.of(context).messageTheme.avatarTheme.borderRadius,
|
||||||
: Text(user?.extraData?.containsKey('name') ?? false
|
color: StreamChatTheme.of(context).accentColor,
|
||||||
? user.extraData['name'][0]
|
),
|
||||||
: ''),
|
child: user.extraData?.containsKey('image') ?? false
|
||||||
|
? CachedNetworkImage(
|
||||||
|
imageUrl: user.extraData['image'],
|
||||||
|
errorWidget: (_, __, ___) {
|
||||||
|
return Center(
|
||||||
|
child: Text(user.extraData?.containsKey('name') ?? false
|
||||||
|
? user.extraData['name'][0]
|
||||||
|
: ''),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
)
|
||||||
|
: SizedBox(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ export 'src/message_list_view.dart';
|
|||||||
export 'src/message_widget.dart';
|
export 'src/message_widget.dart';
|
||||||
export 'src/stream_channel.dart';
|
export 'src/stream_channel.dart';
|
||||||
export 'src/stream_chat.dart';
|
export 'src/stream_chat.dart';
|
||||||
|
export 'src/stream_chat_theme.dart';
|
||||||
|
|||||||
Reference in New Issue
Block a user