Merge pull request #1002 from GetStream/refactor/deprecate-v3
refactor(ui, core): deprecate v3
This commit is contained in:
@@ -15,6 +15,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
analyze:
|
analyze:
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: "Git Checkout"
|
- name: "Git Checkout"
|
||||||
@@ -45,6 +46,7 @@ jobs:
|
|||||||
|
|
||||||
format:
|
format:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
steps:
|
steps:
|
||||||
- name: "Git Checkout"
|
- name: "Git Checkout"
|
||||||
@@ -73,6 +75,7 @@ jobs:
|
|||||||
|
|
||||||
test:
|
test:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
steps:
|
steps:
|
||||||
- name: "Git Checkout"
|
- name: "Git Checkout"
|
||||||
@@ -123,3 +126,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: packages/stream_chat_flutter/coverage/lcov.info
|
path: packages/stream_chat_flutter/coverage/lcov.info
|
||||||
min_coverage: 67
|
min_coverage: 67
|
||||||
|
|
||||||
|
draft-build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event.pull_request.draft == true
|
||||||
|
timeout-minutes: 1
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Run a one-line script
|
||||||
|
run: echo Draft PR, you are good.
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
## 3.5.1
|
||||||
|
|
||||||
|
🐞 Fixed
|
||||||
|
- `channel.unreadCount` was being set as using global unread count on a very specific case.
|
||||||
|
- The reconnection logic for the WebSocket connection is now more robust.
|
||||||
|
|
||||||
## 3.5.0
|
## 3.5.0
|
||||||
|
|
||||||
✅ Added
|
✅ Added
|
||||||
|
|||||||
@@ -1926,7 +1926,6 @@ class ChannelClientState {
|
|||||||
readList.add(Read(
|
readList.add(Read(
|
||||||
user: event.user!,
|
user: event.user!,
|
||||||
lastRead: event.createdAt,
|
lastRead: event.createdAt,
|
||||||
unreadMessages: event.totalUnreadCount ?? 0,
|
|
||||||
));
|
));
|
||||||
_channelState = _channelState.copyWith(read: readList);
|
_channelState = _channelState.copyWith(read: readList);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,8 +190,12 @@ class WebSocket with TimerHelper {
|
|||||||
_connectionStatus = ConnectionStatus.connecting;
|
_connectionStatus = ConnectionStatus.connecting;
|
||||||
connectionCompleter = Completer<Event>();
|
connectionCompleter = Completer<Event>();
|
||||||
|
|
||||||
final uri = await _buildUri();
|
try {
|
||||||
_initWebSocketChannel(uri);
|
final uri = await _buildUri();
|
||||||
|
_initWebSocketChannel(uri);
|
||||||
|
} catch (e, stk) {
|
||||||
|
_onConnectionError(e, stk);
|
||||||
|
}
|
||||||
|
|
||||||
return connectionCompleter!.future;
|
return connectionCompleter!.future;
|
||||||
}
|
}
|
||||||
@@ -216,7 +220,11 @@ class WebSocket with TimerHelper {
|
|||||||
Duration(milliseconds: delay),
|
Duration(milliseconds: delay),
|
||||||
() async {
|
() async {
|
||||||
final uri = await _buildUri(refreshToken: refreshToken);
|
final uri = await _buildUri(refreshToken: refreshToken);
|
||||||
_initWebSocketChannel(uri);
|
try {
|
||||||
|
_initWebSocketChannel(uri);
|
||||||
|
} catch (e, stk) {
|
||||||
|
_onConnectionError(e, stk);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ import 'package:stream_chat/src/client/client.dart';
|
|||||||
/// Current package version
|
/// Current package version
|
||||||
/// Used in [StreamChatClient] to build the `x-stream-client` header
|
/// Used in [StreamChatClient] to build the `x-stream-client` header
|
||||||
// ignore: constant_identifier_names
|
// ignore: constant_identifier_names
|
||||||
const PACKAGE_VERSION = '3.5.0';
|
const PACKAGE_VERSION = '3.5.1';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: stream_chat
|
name: stream_chat
|
||||||
homepage: https://getstream.io/
|
homepage: https://getstream.io/
|
||||||
description: The official Dart client for Stream Chat, a service for building chat applications.
|
description: The official Dart client for Stream Chat, a service for building chat applications.
|
||||||
version: 3.5.0
|
version: 3.5.1
|
||||||
repository: https://github.com/GetStream/stream-chat-flutter
|
repository: https://github.com/GetStream/stream-chat-flutter
|
||||||
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
||||||
|
|
||||||
@@ -30,5 +30,5 @@ dev_dependencies:
|
|||||||
dart_code_metrics: ^4.4.0
|
dart_code_metrics: ^4.4.0
|
||||||
freezed: ^1.0.0
|
freezed: ^1.0.0
|
||||||
json_serializable: ^6.0.1
|
json_serializable: ^6.0.1
|
||||||
mocktail: ^0.2.0
|
mocktail: ^0.3.0
|
||||||
test: ^1.17.12
|
test: ^1.17.12
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
## Upcoming
|
## 3.5.1
|
||||||
|
|
||||||
🛑️ Breaking Changes
|
🛑️ Breaking Changes
|
||||||
|
|
||||||
@@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
🐞 Fixed
|
🐞 Fixed
|
||||||
|
|
||||||
- Mentions overlay now doesn't overflow when not enough height available
|
- Mentions overlay now doesn't overflow when there is not enough height available
|
||||||
|
- Updated `stream_chat_flutter_core` dependency to [`3.5.1`](https://pub.dev/packages/stream_chat_flutter_core/changelog).
|
||||||
|
|
||||||
## 3.5.0
|
## 3.5.0
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
/// A list of messages sent in the current channel.
|
/// A list of messages sent in the current channel.
|
||||||
///
|
///
|
||||||
/// This is implemented using [MessageListView], a widget that provides query
|
/// This is implemented using [StreamMessageListView], a widget that provides query
|
||||||
/// functionalities fetching the messages from the api and showing them in a
|
/// functionalities fetching the messages from the api and showing them in a
|
||||||
/// listView.
|
/// listView.
|
||||||
class ChannelPage extends StatelessWidget {
|
class ChannelPage extends StatelessWidget {
|
||||||
@@ -98,13 +98,13 @@ class ChannelPage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
appBar: const ChannelHeader(),
|
appBar: const StreamChannelHeader(),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: const <Widget>[
|
children: const <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MessageListView(),
|
child: StreamMessageListView(),
|
||||||
),
|
),
|
||||||
MessageInput(attachmentLimit: 3),
|
StreamMessageInput(attachmentLimit: 3),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -125,15 +125,15 @@ class ChannelPage extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) => Navigator(
|
Widget build(BuildContext context) => Navigator(
|
||||||
onGenerateRoute: (settings) => MaterialPageRoute(
|
onGenerateRoute: (settings) => MaterialPageRoute(
|
||||||
builder: (context) => Scaffold(
|
builder: (context) => Scaffold(
|
||||||
appBar: const ChannelHeader(
|
appBar: const StreamChannelHeader(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: const <Widget>[
|
children: const <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MessageListView(),
|
child: StreamMessageListView(),
|
||||||
),
|
),
|
||||||
MessageInput(),
|
StreamMessageInput(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
/// - We make [StreamChat] the root Widget of our application
|
/// - We make [StreamChat] the root Widget of our application
|
||||||
///
|
///
|
||||||
/// - We create a single [ChannelPage] widget under [StreamChat] with three
|
/// - We create a single [ChannelPage] widget under [StreamChat] with three
|
||||||
/// widgets: [ChannelHeader], [MessageListView] and [MessageInput]
|
/// widgets: [StreamChannelHeader], [StreamMessageListView] and [StreamMessageInput]
|
||||||
///
|
///
|
||||||
/// If you now run the simulator you will see a single channel UI.
|
/// If you now run the simulator you will see a single channel UI.
|
||||||
void main() async {
|
void main() async {
|
||||||
@@ -91,13 +91,13 @@ class ChannelPage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
appBar: const ChannelHeader(),
|
appBar: const StreamChannelHeader(),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: const <Widget>[
|
children: const <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MessageListView(),
|
child: StreamMessageListView(),
|
||||||
),
|
),
|
||||||
MessageInput(),
|
StreamMessageInput(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
/// The [ChannelListPage] widget retrieves the list of channels based on a
|
/// The [ChannelListPage] widget retrieves the list of channels based on a
|
||||||
/// custom query and ordering. In this case we are showing the list of
|
/// custom query and ordering. In this case we are showing the list of
|
||||||
/// channels in which the current user is a member and we order them based
|
/// channels in which the current user is a member and we order them based
|
||||||
/// on the time they had a new message. [ChannelListView] handles pagination
|
/// on the time they had a new message. [StreamChannelListView] handles pagination
|
||||||
/// and updates automatically when new channels are created or when a new
|
/// and updates automatically when new channels are created or when a new
|
||||||
/// message is added to a channel.
|
/// message is added to a channel.
|
||||||
void main() async {
|
void main() async {
|
||||||
@@ -118,13 +118,13 @@ class ChannelPage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
appBar: const ChannelHeader(),
|
appBar: const StreamChannelHeader(),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: const <Widget>[
|
children: const <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MessageListView(),
|
child: StreamMessageListView(),
|
||||||
),
|
),
|
||||||
MessageInput(),
|
StreamMessageInput(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
/// We start by changing how channel previews are shown in the channel list
|
/// We start by changing how channel previews are shown in the channel list
|
||||||
/// and include the number of unread messages for each.
|
/// and include the number of unread messages for each.
|
||||||
///
|
///
|
||||||
/// We're passing a custom widget to [ChannelListView.channelPreviewBuilder];
|
/// We're passing a custom widget to [StreamChannelListView.channelPreviewBuilder];
|
||||||
/// this will override the default [ChannelPreview] and allows you to create
|
/// this will override the default [StreamChannelPreview] and allows you to create
|
||||||
/// one yourself.
|
/// one yourself.
|
||||||
///
|
///
|
||||||
/// There are a couple interesting things we do in this widget:
|
/// There are a couple interesting things we do in this widget:
|
||||||
@@ -134,7 +134,7 @@ class _ChannelListPageState extends State<ChannelListPage> {
|
|||||||
channel: channel,
|
channel: channel,
|
||||||
),
|
),
|
||||||
title: StreamChannelName(
|
title: StreamChannelName(
|
||||||
textStyle: ChannelPreviewTheme.of(context).titleStyle!.copyWith(
|
textStyle: StreamChannelPreviewTheme.of(context).titleStyle!.copyWith(
|
||||||
color: StreamChatTheme.of(context)
|
color: StreamChatTheme.of(context)
|
||||||
.colorTheme
|
.colorTheme
|
||||||
.textHighEmphasis
|
.textHighEmphasis
|
||||||
@@ -162,13 +162,13 @@ class ChannelPage extends StatelessWidget {
|
|||||||
// ignore: prefer_expression_function_bodies
|
// ignore: prefer_expression_function_bodies
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: const ChannelHeader(),
|
appBar: const StreamChannelHeader(),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: const <Widget>[
|
children: const <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MessageListView(),
|
child: StreamMessageListView(),
|
||||||
),
|
),
|
||||||
MessageInput(),
|
StreamMessageInput(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
/// to create sub-conversations inside the same channel.
|
/// to create sub-conversations inside the same channel.
|
||||||
///
|
///
|
||||||
/// Using threaded conversations is very simple and mostly a matter of
|
/// Using threaded conversations is very simple and mostly a matter of
|
||||||
/// plugging the [MessageListView] to another widget that renders the widget.
|
/// plugging the [StreamMessageListView] to another widget that renders the widget.
|
||||||
/// To make this simple, such a widget only needs to build [MessageListView]
|
/// To make this simple, such a widget only needs to build [StreamMessageListView]
|
||||||
/// with the parent attribute set to the thread’s root message.
|
/// with the parent attribute set to the thread’s root message.
|
||||||
///
|
///
|
||||||
/// Now we can open threads and create new ones as well. If you long-press a
|
/// Now we can open threads and create new ones as well. If you long-press a
|
||||||
@@ -98,17 +98,17 @@ class ChannelPage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
appBar: const ChannelHeader(),
|
appBar: const StreamChannelHeader(),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MessageListView(
|
child: StreamMessageListView(
|
||||||
threadBuilder: (_, parentMessage) => ThreadPage(
|
threadBuilder: (_, parentMessage) => ThreadPage(
|
||||||
parent: parentMessage,
|
parent: parentMessage,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const MessageInput(),
|
const StreamMessageInput(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -126,17 +126,17 @@ class ThreadPage extends StatelessWidget {
|
|||||||
// ignore: prefer_expression_function_bodies
|
// ignore: prefer_expression_function_bodies
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: ThreadHeader(
|
appBar: StreamThreadHeader(
|
||||||
parent: parent!,
|
parent: parent!,
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MessageListView(
|
child: StreamMessageListView(
|
||||||
parentMessage: parent,
|
parentMessage: parent,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
MessageInput(
|
StreamMessageInput(
|
||||||
messageInputController: MessageInputController(
|
messageInputController: MessageInputController(
|
||||||
message: Message(parentId: parent!.id),
|
message: Message(parentId: parent!.id),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
/// the SDK supports easily.
|
/// the SDK supports easily.
|
||||||
///
|
///
|
||||||
/// Replacing the built-in message component with your own is done by passing
|
/// Replacing the built-in message component with your own is done by passing
|
||||||
/// it as a builder function to the [MessageListView] widget.
|
/// it as a builder function to the [StreamMessageListView] widget.
|
||||||
///
|
///
|
||||||
/// The message builder function will get the usual [BuildContext] argument
|
/// The message builder function will get the usual [BuildContext] argument
|
||||||
/// as well as the [Message] object and its position inside the list.
|
/// as well as the [Message] object and its position inside the list.
|
||||||
@@ -106,15 +106,15 @@ class ChannelPage extends StatelessWidget {
|
|||||||
// ignore: prefer_expression_function_bodies
|
// ignore: prefer_expression_function_bodies
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: const ChannelHeader(),
|
appBar: const StreamChannelHeader(),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MessageListView(
|
child: StreamMessageListView(
|
||||||
messageBuilder: _messageBuilder,
|
messageBuilder: _messageBuilder,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const MessageInput(),
|
const StreamMessageInput(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -124,7 +124,7 @@ class ChannelPage extends StatelessWidget {
|
|||||||
BuildContext context,
|
BuildContext context,
|
||||||
MessageDetails details,
|
MessageDetails details,
|
||||||
List<Message> messages,
|
List<Message> messages,
|
||||||
MessageWidget _,
|
StreamMessageWidget _,
|
||||||
) {
|
) {
|
||||||
final message = details.message;
|
final message = details.message;
|
||||||
final isCurrentUser =
|
final isCurrentUser =
|
||||||
|
|||||||
@@ -58,24 +58,24 @@ class MyApp extends StatelessWidget {
|
|||||||
final defaultTheme = StreamChatThemeData.fromTheme(themeData);
|
final defaultTheme = StreamChatThemeData.fromTheme(themeData);
|
||||||
final colorTheme = defaultTheme.colorTheme;
|
final colorTheme = defaultTheme.colorTheme;
|
||||||
final customTheme = defaultTheme.merge(StreamChatThemeData(
|
final customTheme = defaultTheme.merge(StreamChatThemeData(
|
||||||
channelPreviewTheme: ChannelPreviewThemeData(
|
channelPreviewTheme: StreamChannelPreviewThemeData(
|
||||||
avatarTheme: AvatarThemeData(
|
avatarTheme: StreamAvatarThemeData(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
messageListViewTheme: const MessageListViewThemeData(
|
messageListViewTheme: const StreamMessageListViewThemeData(
|
||||||
backgroundColor: Colors.grey,
|
backgroundColor: Colors.grey,
|
||||||
backgroundImage: DecorationImage(
|
backgroundImage: DecorationImage(
|
||||||
image: AssetImage('assets/background_doodle.png'),
|
image: AssetImage('assets/background_doodle.png'),
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
otherMessageTheme: MessageThemeData(
|
otherMessageTheme: StreamMessageThemeData(
|
||||||
messageBackgroundColor: colorTheme.textHighEmphasis,
|
messageBackgroundColor: colorTheme.textHighEmphasis,
|
||||||
messageTextStyle: TextStyle(
|
messageTextStyle: TextStyle(
|
||||||
color: colorTheme.barsBg,
|
color: colorTheme.barsBg,
|
||||||
),
|
),
|
||||||
avatarTheme: AvatarThemeData(
|
avatarTheme: StreamAvatarThemeData(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -137,17 +137,17 @@ class ChannelPage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Scaffold(
|
Widget build(BuildContext context) => Scaffold(
|
||||||
appBar: const ChannelHeader(),
|
appBar: const StreamChannelHeader(),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MessageListView(
|
child: StreamMessageListView(
|
||||||
threadBuilder: (_, parentMessage) => ThreadPage(
|
threadBuilder: (_, parentMessage) => ThreadPage(
|
||||||
parent: parentMessage,
|
parent: parentMessage,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const MessageInput(),
|
const StreamMessageInput(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -165,17 +165,17 @@ class ThreadPage extends StatelessWidget {
|
|||||||
// ignore: prefer_expression_function_bodies
|
// ignore: prefer_expression_function_bodies
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: ThreadHeader(
|
appBar: StreamThreadHeader(
|
||||||
parent: parent!,
|
parent: parent!,
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MessageListView(
|
child: StreamMessageListView(
|
||||||
parentMessage: parent,
|
parentMessage: parent,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
MessageInput(
|
StreamMessageInput(
|
||||||
messageInputController: MessageInputController(
|
messageInputController: MessageInputController(
|
||||||
message: Message(parentId: parent!.id),
|
message: Message(parentId: parent!.id),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro attachment_title}
|
||||||
|
@Deprecated("Use 'StreamAttachmentTitle' instead")
|
||||||
|
typedef AttachmentTitle = StreamAttachmentTitle;
|
||||||
|
|
||||||
|
/// {@template attachment_title}
|
||||||
/// Title for attachments
|
/// Title for attachments
|
||||||
class AttachmentTitle extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamAttachmentTitle extends StatelessWidget {
|
||||||
/// Supply attachment and theme for constructing title
|
/// Supply attachment and theme for constructing title
|
||||||
const AttachmentTitle({
|
const StreamAttachmentTitle({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.attachment,
|
required this.attachment,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
/// Theme to apply to text
|
/// Theme to apply to text
|
||||||
final MessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|
||||||
/// Attachment data to display
|
/// Attachment data to display
|
||||||
final Attachment attachment;
|
final Attachment attachment;
|
||||||
|
|||||||
+11
-5
@@ -9,10 +9,16 @@ typedef InProgressBuilder = Widget Function(BuildContext, int, int);
|
|||||||
/// Widget to build on failure
|
/// Widget to build on failure
|
||||||
typedef FailedBuilder = Widget Function(BuildContext, String);
|
typedef FailedBuilder = Widget Function(BuildContext, String);
|
||||||
|
|
||||||
|
/// {@macro attachment_upload_state_builder}
|
||||||
|
@Deprecated("Use 'StreamAttachmentsUploadStateBuilder' instead")
|
||||||
|
typedef AttachmentUploadStateBuilder = StreamAttachmentUploadStateBuilder;
|
||||||
|
|
||||||
|
/// {@template attachment_upload_state_builder}
|
||||||
/// Widget to display attachment upload state
|
/// Widget to display attachment upload state
|
||||||
class AttachmentUploadStateBuilder extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating an [AttachmentUploadStateBuilder] widget
|
class StreamAttachmentUploadStateBuilder extends StatelessWidget {
|
||||||
const AttachmentUploadStateBuilder({
|
/// Constructor for creating an [StreamAttachmentUploadStateBuilder] widget
|
||||||
|
const StreamAttachmentUploadStateBuilder({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.attachment,
|
required this.attachment,
|
||||||
@@ -137,7 +143,7 @@ class _PreparingState extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.topRight,
|
alignment: Alignment.topRight,
|
||||||
child: UploadProgressIndicator(
|
child: StreamUploadProgressIndicator(
|
||||||
uploaded: 0,
|
uploaded: 0,
|
||||||
total: double.maxFinite.toInt(),
|
total: double.maxFinite.toInt(),
|
||||||
),
|
),
|
||||||
@@ -177,7 +183,7 @@ class _InProgressState extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.topRight,
|
alignment: Alignment.topRight,
|
||||||
child: UploadProgressIndicator(
|
child: StreamUploadProgressIndicator(
|
||||||
uploaded: sent,
|
uploaded: sent,
|
||||||
total: total,
|
total: total,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -28,10 +28,16 @@ extension AttachmentSourceX on AttachmentSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro attachment_widget}
|
||||||
|
@Deprecated("Use 'StreamAttachmentWidget' instead")
|
||||||
|
typedef AttachmentWidget = StreamAttachmentWidget;
|
||||||
|
|
||||||
|
/// {@template attachment_widget}
|
||||||
/// Abstract class for deriving attachment types
|
/// Abstract class for deriving attachment types
|
||||||
abstract class AttachmentWidget extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
|
abstract class StreamAttachmentWidget extends StatelessWidget {
|
||||||
/// Constructor for creating attachment widget
|
/// Constructor for creating attachment widget
|
||||||
const AttachmentWidget({
|
const StreamAttachmentWidget({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.attachment,
|
required this.attachment,
|
||||||
|
|||||||
@@ -10,10 +10,16 @@ import 'package:stream_chat_flutter/src/utils.dart';
|
|||||||
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
|
||||||
|
/// {@macro file_attachment}
|
||||||
|
@Deprecated("Use 'StreamFileAttachment' instead")
|
||||||
|
typedef FileAttachment = StreamFileAttachment;
|
||||||
|
|
||||||
|
/// {@template file_attachment}
|
||||||
/// Widget for displaying file attachments
|
/// Widget for displaying file attachments
|
||||||
class FileAttachment extends AttachmentWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamFileAttachment extends StreamAttachmentWidget {
|
||||||
/// Constructor for creating a widget when attachment is of type 'file'
|
/// Constructor for creating a widget when attachment is of type 'file'
|
||||||
const FileAttachment({
|
const StreamFileAttachment({
|
||||||
Key? key,
|
Key? key,
|
||||||
required Message message,
|
required Message message,
|
||||||
required Attachment attachment,
|
required Attachment attachment,
|
||||||
@@ -157,7 +163,7 @@ class FileAttachment extends AttachmentWidget {
|
|||||||
type: MaterialType.transparency,
|
type: MaterialType.transparency,
|
||||||
shape: _getDefaultShape(context),
|
shape: _getDefaultShape(context),
|
||||||
child: source.when(
|
child: source.when(
|
||||||
local: () => VideoThumbnailImage(
|
local: () => StreamVideoThumbnailImage(
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
video: attachment.file!.path!,
|
video: attachment.file!.path!,
|
||||||
placeholderBuilder: (_) => const Center(
|
placeholderBuilder: (_) => const Center(
|
||||||
@@ -168,7 +174,7 @@ class FileAttachment extends AttachmentWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
network: () => VideoThumbnailImage(
|
network: () => StreamVideoThumbnailImage(
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
video: attachment.assetUrl!,
|
video: attachment.assetUrl!,
|
||||||
placeholderBuilder: (_) => const Center(
|
placeholderBuilder: (_) => const Center(
|
||||||
@@ -278,7 +284,7 @@ class FileAttachment extends AttachmentWidget {
|
|||||||
);
|
);
|
||||||
return attachment.uploadState.when(
|
return attachment.uploadState.when(
|
||||||
preparing: () => Text(fileSize(size), style: textStyle),
|
preparing: () => Text(fileSize(size), style: textStyle),
|
||||||
inProgress: (sent, total) => UploadProgressIndicator(
|
inProgress: (sent, total) => StreamUploadProgressIndicator(
|
||||||
uploaded: sent,
|
uploaded: sent,
|
||||||
total: total,
|
total: total,
|
||||||
showBackground: false,
|
showBackground: false,
|
||||||
|
|||||||
@@ -5,10 +5,16 @@ import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro giphy_attachment}
|
||||||
|
@Deprecated("Use 'StreamGiphyAttachment' instead")
|
||||||
|
typedef GiphyAttachment = StreamGiphyAttachment;
|
||||||
|
|
||||||
|
/// {@template giphy_attachment}
|
||||||
/// Widget for showing a GIF attachment
|
/// Widget for showing a GIF attachment
|
||||||
class GiphyAttachment extends AttachmentWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [GiphyAttachment] widget
|
class StreamGiphyAttachment extends StreamAttachmentWidget {
|
||||||
const GiphyAttachment({
|
/// Constructor for creating a [StreamGiphyAttachment] widget
|
||||||
|
const StreamGiphyAttachment({
|
||||||
Key? key,
|
Key? key,
|
||||||
required Message message,
|
required Message message,
|
||||||
required Attachment attachment,
|
required Attachment attachment,
|
||||||
@@ -228,7 +234,7 @@ class GiphyAttachment extends AttachmentWidget {
|
|||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
child: VisibleFootnote(),
|
child: StreamVisibleFootnote(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -243,7 +249,7 @@ class GiphyAttachment extends AttachmentWidget {
|
|||||||
final channel = StreamChannel.of(context).channel;
|
final channel = StreamChannel.of(context).channel;
|
||||||
return StreamChannel(
|
return StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: FullScreenMedia(
|
child: StreamFullScreenMedia(
|
||||||
mediaAttachments: message.attachments,
|
mediaAttachments: message.attachments,
|
||||||
startIndex: message.attachments.indexOf(attachment),
|
startIndex: message.attachments.indexOf(attachment),
|
||||||
userName: message.user?.name,
|
userName: message.user?.name,
|
||||||
|
|||||||
@@ -5,10 +5,16 @@ import 'package:stream_chat_flutter/src/attachment/attachment_title.dart';
|
|||||||
import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart';
|
import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro image_attachment}
|
||||||
|
@Deprecated("use 'StreamImageAttachment' instead")
|
||||||
|
typedef ImageAttachment = StreamImageAttachment;
|
||||||
|
|
||||||
|
/// {@template image_attachment}
|
||||||
/// Widget for showing an image attachment
|
/// Widget for showing an image attachment
|
||||||
class ImageAttachment extends AttachmentWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [ImageAttachment] widget
|
class StreamImageAttachment extends StreamAttachmentWidget {
|
||||||
const ImageAttachment({
|
/// Constructor for creating a [StreamImageAttachment] widget
|
||||||
|
const StreamImageAttachment({
|
||||||
Key? key,
|
Key? key,
|
||||||
required Message message,
|
required Message message,
|
||||||
required Attachment attachment,
|
required Attachment attachment,
|
||||||
@@ -25,8 +31,8 @@ class ImageAttachment extends AttachmentWidget {
|
|||||||
size: size,
|
size: size,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// [MessageThemeData] for showing image title
|
/// [StreamMessageThemeData] for showing image title
|
||||||
final MessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|
||||||
/// Flag for showing title
|
/// Flag for showing title
|
||||||
final bool showTitle;
|
final bool showTitle;
|
||||||
@@ -137,7 +143,7 @@ class ImageAttachment extends AttachmentWidget {
|
|||||||
StreamChannel.of(context).channel;
|
StreamChannel.of(context).channel;
|
||||||
return StreamChannel(
|
return StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: FullScreenMedia(
|
child: StreamFullScreenMedia(
|
||||||
mediaAttachments: message.attachments,
|
mediaAttachments: message.attachments,
|
||||||
startIndex:
|
startIndex:
|
||||||
message.attachments.indexOf(attachment),
|
message.attachments.indexOf(attachment),
|
||||||
@@ -155,7 +161,7 @@ class ImageAttachment extends AttachmentWidget {
|
|||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: AttachmentUploadStateBuilder(
|
child: StreamAttachmentUploadStateBuilder(
|
||||||
message: message,
|
message: message,
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
),
|
),
|
||||||
@@ -166,7 +172,7 @@ class ImageAttachment extends AttachmentWidget {
|
|||||||
if (showTitle && attachment.title != null)
|
if (showTitle && attachment.title != null)
|
||||||
Material(
|
Material(
|
||||||
color: messageTheme.messageBackgroundColor,
|
color: messageTheme.messageBackgroundColor,
|
||||||
child: AttachmentTitle(
|
child: StreamAttachmentTitle(
|
||||||
messageTheme: messageTheme,
|
messageTheme: messageTheme,
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,10 +2,16 @@ import 'package:cached_network_image/cached_network_image.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro url_attachment}
|
||||||
|
@Deprecated("Use 'StreamUrlAttachment' instead")
|
||||||
|
typedef UrlAttachment = StreamUrlAttachment;
|
||||||
|
|
||||||
|
/// {@template url_attachment}
|
||||||
/// Widget to display URL attachment
|
/// Widget to display URL attachment
|
||||||
class UrlAttachment extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [UrlAttachment]
|
class StreamUrlAttachment extends StatelessWidget {
|
||||||
const UrlAttachment({
|
/// Constructor for creating a [StreamUrlAttachment]
|
||||||
|
const StreamUrlAttachment({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.urlAttachment,
|
required this.urlAttachment,
|
||||||
required this.hostDisplayName,
|
required this.hostDisplayName,
|
||||||
@@ -25,8 +31,8 @@ class UrlAttachment extends StatelessWidget {
|
|||||||
/// Padding for text
|
/// Padding for text
|
||||||
final EdgeInsets textPadding;
|
final EdgeInsets textPadding;
|
||||||
|
|
||||||
/// [MessageThemeData] for showing image title
|
/// [StreamMessageThemeData] for showing image title
|
||||||
final MessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|||||||
@@ -4,10 +4,16 @@ import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart';
|
|||||||
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro video_attachment}
|
||||||
|
@Deprecated("Use 'StreamVideoAttachment' instead")
|
||||||
|
typedef VideoAttachment = StreamVideoAttachment;
|
||||||
|
|
||||||
|
/// {@template video_attachment}
|
||||||
/// Widget for showing a video attachment
|
/// Widget for showing a video attachment
|
||||||
class VideoAttachment extends AttachmentWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [VideoAttachment] widget
|
class StreamVideoAttachment extends StreamAttachmentWidget {
|
||||||
const VideoAttachment({
|
/// Constructor for creating a [StreamVideoAttachment] widget
|
||||||
|
const StreamVideoAttachment({
|
||||||
Key? key,
|
Key? key,
|
||||||
required Message message,
|
required Message message,
|
||||||
required Attachment attachment,
|
required Attachment attachment,
|
||||||
@@ -23,8 +29,8 @@ class VideoAttachment extends AttachmentWidget {
|
|||||||
size: size,
|
size: size,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// [MessageThemeData] for showing title
|
/// [StreamMessageThemeData] for showing title
|
||||||
final MessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|
||||||
/// Callback when show message is tapped
|
/// Callback when show message is tapped
|
||||||
final ShowMessageCallback? onShowMessage;
|
final ShowMessageCallback? onShowMessage;
|
||||||
@@ -43,7 +49,7 @@ class VideoAttachment extends AttachmentWidget {
|
|||||||
}
|
}
|
||||||
return _buildVideoAttachment(
|
return _buildVideoAttachment(
|
||||||
context,
|
context,
|
||||||
VideoThumbnailImage(
|
StreamVideoThumbnailImage(
|
||||||
video: attachment.file!.path!,
|
video: attachment.file!.path!,
|
||||||
height: size?.height,
|
height: size?.height,
|
||||||
width: size?.width,
|
width: size?.width,
|
||||||
@@ -58,7 +64,7 @@ class VideoAttachment extends AttachmentWidget {
|
|||||||
}
|
}
|
||||||
return _buildVideoAttachment(
|
return _buildVideoAttachment(
|
||||||
context,
|
context,
|
||||||
VideoThumbnailImage(
|
StreamVideoThumbnailImage(
|
||||||
video: attachment.assetUrl!,
|
video: attachment.assetUrl!,
|
||||||
height: size?.height,
|
height: size?.height,
|
||||||
width: size?.width,
|
width: size?.width,
|
||||||
@@ -84,7 +90,7 @@ class VideoAttachment extends AttachmentWidget {
|
|||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (_) => StreamChannel(
|
builder: (_) => StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: FullScreenMedia(
|
child: StreamFullScreenMedia(
|
||||||
mediaAttachments: message.attachments,
|
mediaAttachments: message.attachments,
|
||||||
startIndex:
|
startIndex:
|
||||||
message.attachments.indexOf(attachment),
|
message.attachments.indexOf(attachment),
|
||||||
@@ -111,7 +117,7 @@ class VideoAttachment extends AttachmentWidget {
|
|||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: AttachmentUploadStateBuilder(
|
child: StreamAttachmentUploadStateBuilder(
|
||||||
message: message,
|
message: message,
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
),
|
),
|
||||||
@@ -123,7 +129,7 @@ class VideoAttachment extends AttachmentWidget {
|
|||||||
if (attachment.title != null)
|
if (attachment.title != null)
|
||||||
Material(
|
Material(
|
||||||
color: messageTheme.messageBackgroundColor,
|
color: messageTheme.messageBackgroundColor,
|
||||||
child: AttachmentTitle(
|
child: StreamAttachmentTitle(
|
||||||
messageTheme: messageTheme,
|
messageTheme: messageTheme,
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class AttachmentActionsModal extends StatelessWidget {
|
|||||||
/// List of custom actions
|
/// List of custom actions
|
||||||
final List<AttachmentAction> customActions;
|
final List<AttachmentAction> customActions;
|
||||||
|
|
||||||
/// Creates a copy of [MessageWidget] with specified attributes overridden.
|
/// Creates a copy of [StreamMessageWidget] with specified attributes overridden.
|
||||||
AttachmentActionsModal copyWith({
|
AttachmentActionsModal copyWith({
|
||||||
Key? key,
|
Key? key,
|
||||||
int? currentIndex,
|
int? currentIndex,
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class StreamBackButton extends StatelessWidget {
|
|||||||
Positioned(
|
Positioned(
|
||||||
top: 7,
|
top: 7,
|
||||||
right: 7,
|
right: 7,
|
||||||
child: UnreadIndicator(
|
child: StreamUnreadIndicator(
|
||||||
cid: cid,
|
cid: cid,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ class ChannelAvatar extends StatelessWidget {
|
|||||||
return BetterStreamBuilder<User>(
|
return BetterStreamBuilder<User>(
|
||||||
stream: streamChat.client.state.currentUserStream.map((it) => it!),
|
stream: streamChat.client.state.currentUserStream.map((it) => it!),
|
||||||
initialData: currentUser,
|
initialData: currentUser,
|
||||||
builder: (context, user) => UserAvatar(
|
builder: (context, user) => StreamUserAvatar(
|
||||||
borderRadius: borderRadius ?? previewTheme?.borderRadius,
|
borderRadius: borderRadius ?? previewTheme?.borderRadius,
|
||||||
user: user,
|
user: user,
|
||||||
constraints: constraints ?? previewTheme?.constraints,
|
constraints: constraints ?? previewTheme?.constraints,
|
||||||
@@ -175,7 +175,7 @@ class ChannelAvatar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
initialData: member,
|
initialData: member,
|
||||||
builder: (context, member) => UserAvatar(
|
builder: (context, member) => StreamUserAvatar(
|
||||||
borderRadius: borderRadius ?? previewTheme?.borderRadius,
|
borderRadius: borderRadius ?? previewTheme?.borderRadius,
|
||||||
user: member.user!,
|
user: member.user!,
|
||||||
constraints: constraints ?? previewTheme?.constraints,
|
constraints: constraints ?? previewTheme?.constraints,
|
||||||
@@ -188,7 +188,7 @@ class ChannelAvatar extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Group conversation
|
// Group conversation
|
||||||
return GroupAvatar(
|
return StreamGroupAvatar(
|
||||||
members: otherMembers,
|
members: otherMembers,
|
||||||
borderRadius: borderRadius ?? previewTheme?.borderRadius,
|
borderRadius: borderRadius ?? previewTheme?.borderRadius,
|
||||||
constraints: constraints ?? previewTheme?.constraints,
|
constraints: constraints ?? previewTheme?.constraints,
|
||||||
|
|||||||
@@ -4,10 +4,7 @@ import 'package:stream_chat_flutter/src/extension.dart';
|
|||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
/// Bottom Sheet with options
|
/// Bottom Sheet with options
|
||||||
@Deprecated(
|
@Deprecated("Use 'StreamChannelInfoBottomSheet' instead")
|
||||||
"'ChannelBottomSheet' is deprecated and shouldn't be used. "
|
|
||||||
"Please use 'StreamChannelBottomSheet' instead.",
|
|
||||||
)
|
|
||||||
class ChannelBottomSheet extends StatefulWidget {
|
class ChannelBottomSheet extends StatefulWidget {
|
||||||
/// Constructor for creating bottom sheet
|
/// Constructor for creating bottom sheet
|
||||||
const ChannelBottomSheet({Key? key, this.onViewInfoTap}) : super(key: key);
|
const ChannelBottomSheet({Key? key, this.onViewInfoTap}) : super(key: key);
|
||||||
@@ -24,7 +21,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
bool _showActions = true;
|
bool _showActions = true;
|
||||||
|
|
||||||
late StreamChannelState _streamChannelState;
|
late StreamChannelState _streamChannelState;
|
||||||
late ChannelPreviewThemeData _channelPreviewThemeData;
|
late StreamChannelPreviewThemeData _channelPreviewThemeData;
|
||||||
late StreamChatThemeData _streamChatThemeData;
|
late StreamChatThemeData _streamChatThemeData;
|
||||||
late StreamChatState _streamChatState;
|
late StreamChatState _streamChatState;
|
||||||
|
|
||||||
@@ -58,7 +55,8 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
Center(
|
Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: ChannelName(
|
child: StreamChannelName(
|
||||||
|
channel: channel,
|
||||||
textStyle: _streamChatThemeData.textTheme.headlineBold,
|
textStyle: _streamChatThemeData.textTheme.headlineBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -67,7 +65,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
height: 5,
|
height: 5,
|
||||||
),
|
),
|
||||||
Center(
|
Center(
|
||||||
child: ChannelInfo(
|
child: StreamChannelInfo(
|
||||||
showTypingIndicator: false,
|
showTypingIndicator: false,
|
||||||
channel: _streamChannelState.channel,
|
channel: _streamChannelState.channel,
|
||||||
textStyle: _channelPreviewThemeData.subtitleStyle,
|
textStyle: _channelPreviewThemeData.subtitleStyle,
|
||||||
@@ -79,7 +77,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
if (channel.isDistinct && channel.memberCount == 2)
|
if (channel.isDistinct && channel.memberCount == 2)
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
UserAvatar(
|
StreamUserAvatar(
|
||||||
user: members
|
user: members
|
||||||
.firstWhere(
|
.firstWhere(
|
||||||
(e) => e.user?.id != userAsMember.user?.id,
|
(e) => e.user?.id != userAsMember.user?.id,
|
||||||
@@ -122,7 +120,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
UserAvatar(
|
StreamUserAvatar(
|
||||||
user: members[index].user!,
|
user: members[index].user!,
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
height: 64,
|
height: 64,
|
||||||
@@ -150,7 +148,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
OptionListTile(
|
StreamOptionListTile(
|
||||||
leading: Padding(
|
leading: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: StreamSvgIcon.user(
|
child: StreamSvgIcon.user(
|
||||||
@@ -163,7 +161,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
if (!channel.isDistinct &&
|
if (!channel.isDistinct &&
|
||||||
channel.ownCapabilities
|
channel.ownCapabilities
|
||||||
.contains(PermissionType.leaveChannel))
|
.contains(PermissionType.leaveChannel))
|
||||||
OptionListTile(
|
StreamOptionListTile(
|
||||||
leading: Padding(
|
leading: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: StreamSvgIcon.userRemove(
|
child: StreamSvgIcon.userRemove(
|
||||||
@@ -184,7 +182,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
if (isOwner &&
|
if (isOwner &&
|
||||||
channel.ownCapabilities
|
channel.ownCapabilities
|
||||||
.contains(PermissionType.deleteChannel))
|
.contains(PermissionType.deleteChannel))
|
||||||
OptionListTile(
|
StreamOptionListTile(
|
||||||
leading: Padding(
|
leading: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: StreamSvgIcon.delete(
|
child: StreamSvgIcon.delete(
|
||||||
@@ -203,7 +201,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
OptionListTile(
|
StreamOptionListTile(
|
||||||
leading: Padding(
|
leading: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: StreamSvgIcon.closeSmall(
|
child: StreamSvgIcon.closeSmall(
|
||||||
@@ -224,7 +222,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
_streamChannelState = StreamChannel.of(context);
|
_streamChannelState = StreamChannel.of(context);
|
||||||
_streamChatThemeData = StreamChatTheme.of(context);
|
_streamChatThemeData = StreamChatTheme.of(context);
|
||||||
_channelPreviewThemeData = ChannelPreviewTheme.of(context);
|
_channelPreviewThemeData = StreamChannelPreviewTheme.of(context);
|
||||||
_streamChatState = StreamChat.of(context);
|
_streamChatState = StreamChat.of(context);
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ import 'package:stream_chat_flutter/src/channel_info.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
///{@macro template_name}
|
||||||
|
@Deprecated("Use 'StreamChannelHeader' instead")
|
||||||
|
typedef ChannelHeader = StreamChannelHeader;
|
||||||
|
|
||||||
|
/// {@template channel_header}
|
||||||
/// 
|
/// 
|
||||||
/// 
|
/// 
|
||||||
///
|
///
|
||||||
@@ -49,9 +54,11 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
/// The widget components render the ui based on the first ancestor of type
|
/// The widget components render the ui based on the first ancestor of type
|
||||||
/// [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property.
|
/// [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property.
|
||||||
/// Modify it to change the widget appearance.
|
/// Modify it to change the widget appearance.
|
||||||
class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamChannelHeader extends StatelessWidget
|
||||||
|
implements PreferredSizeWidget {
|
||||||
/// Creates a channel header
|
/// Creates a channel header
|
||||||
const ChannelHeader({
|
const StreamChannelHeader({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.showBackButton = true,
|
this.showBackButton = true,
|
||||||
this.onBackPressed,
|
this.onBackPressed,
|
||||||
@@ -96,16 +103,16 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
final Widget? leading;
|
final Widget? leading;
|
||||||
|
|
||||||
/// AppBar actions
|
/// AppBar actions
|
||||||
/// By default it shows the [ChannelAvatar]
|
/// By default it shows the [StreamChannelAvatar]
|
||||||
final List<Widget>? actions;
|
final List<Widget>? actions;
|
||||||
|
|
||||||
/// The background color for this [ChannelHeader].
|
/// The background color for this [StreamChannelHeader].
|
||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final channel = StreamChannel.of(context).channel;
|
final channel = StreamChannel.of(context).channel;
|
||||||
final channelHeaderTheme = ChannelHeaderTheme.of(context);
|
final channelHeaderTheme = StreamChannelHeaderTheme.of(context);
|
||||||
|
|
||||||
final leadingWidget = leading ??
|
final leadingWidget = leading ??
|
||||||
(showBackButton
|
(showBackButton
|
||||||
@@ -115,7 +122,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
)
|
)
|
||||||
: const SizedBox());
|
: const SizedBox());
|
||||||
|
|
||||||
return ConnectionStatusBuilder(
|
return StreamConnectionStatusBuilder(
|
||||||
statusBuilder: (context, status) {
|
statusBuilder: (context, status) {
|
||||||
var statusString = '';
|
var statusString = '';
|
||||||
var showStatus = true;
|
var showStatus = true;
|
||||||
@@ -135,7 +142,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
|
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
return InfoTile(
|
return StreamInfoTile(
|
||||||
showMessage: showConnectionStateTile && showStatus,
|
showMessage: showConnectionStateTile && showStatus,
|
||||||
message: statusString,
|
message: statusString,
|
||||||
child: AppBar(
|
child: AppBar(
|
||||||
@@ -152,7 +159,8 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 10),
|
padding: const EdgeInsets.only(right: 10),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: ChannelAvatar(
|
child: StreamChannelAvatar(
|
||||||
|
channel: channel,
|
||||||
borderRadius:
|
borderRadius:
|
||||||
channelHeaderTheme.avatarTheme?.borderRadius,
|
channelHeaderTheme.avatarTheme?.borderRadius,
|
||||||
constraints:
|
constraints:
|
||||||
@@ -172,12 +180,13 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
title ??
|
title ??
|
||||||
ChannelName(
|
StreamChannelName(
|
||||||
|
channel: channel,
|
||||||
textStyle: channelHeaderTheme.titleStyle,
|
textStyle: channelHeaderTheme.titleStyle,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
subtitle ??
|
subtitle ??
|
||||||
ChannelInfo(
|
StreamChannelInfo(
|
||||||
showTypingIndicator: showTypingIndicator,
|
showTypingIndicator: showTypingIndicator,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
textStyle: channelHeaderTheme.subtitleStyle,
|
textStyle: channelHeaderTheme.subtitleStyle,
|
||||||
|
|||||||
@@ -3,10 +3,16 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro channel_info}
|
||||||
|
@Deprecated("Use 'StreamChannelInfo' instead")
|
||||||
|
typedef ChannelInfo = StreamChannelInfo;
|
||||||
|
|
||||||
|
/// {@template channel_info}
|
||||||
/// Widget which shows channel info
|
/// Widget which shows channel info
|
||||||
class ChannelInfo extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor which creates a [ChannelInfo] widget
|
class StreamChannelInfo extends StatelessWidget {
|
||||||
const ChannelInfo({
|
/// Constructor which creates a [StreamChannelInfo] widget
|
||||||
|
const StreamChannelInfo({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.channel,
|
required this.channel,
|
||||||
this.textStyle,
|
this.textStyle,
|
||||||
@@ -32,7 +38,7 @@ class ChannelInfo extends StatelessWidget {
|
|||||||
return BetterStreamBuilder<List<Member>>(
|
return BetterStreamBuilder<List<Member>>(
|
||||||
stream: channel.state!.membersStream,
|
stream: channel.state!.membersStream,
|
||||||
initialData: channel.state!.members,
|
initialData: channel.state!.members,
|
||||||
builder: (context, data) => ConnectionStatusBuilder(
|
builder: (context, data) => StreamConnectionStatusBuilder(
|
||||||
statusBuilder: (context, status) {
|
statusBuilder: (context, status) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case ConnectionStatus.connected:
|
case ConnectionStatus.connected:
|
||||||
@@ -66,7 +72,7 @@ class ChannelInfo extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
alternativeWidget = Text(
|
alternativeWidget = Text(
|
||||||
text,
|
text,
|
||||||
style: ChannelHeaderTheme.of(context).subtitleStyle,
|
style: StreamChannelHeaderTheme.of(context).subtitleStyle,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final userId = StreamChat.of(context).currentUser?.id;
|
final userId = StreamChat.of(context).currentUser?.id;
|
||||||
@@ -95,7 +101,7 @@ class ChannelInfo extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Align(
|
return Align(
|
||||||
child: TypingIndicator(
|
child: StreamTypingIndicator(
|
||||||
parentId: parentId,
|
parentId: parentId,
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
alternativeWidget: alternativeWidget,
|
alternativeWidget: alternativeWidget,
|
||||||
|
|||||||
@@ -11,7 +11,11 @@ typedef TitleBuilder = Widget Function(
|
|||||||
StreamChatClient client,
|
StreamChatClient client,
|
||||||
);
|
);
|
||||||
|
|
||||||
///
|
/// {@macro channel_list_header}
|
||||||
|
@Deprecated("Use 'StreamChannelListHeader' instead")
|
||||||
|
typedef ChannelListHeader = StreamChannelListHeader;
|
||||||
|
|
||||||
|
/// {@template channel_list_header}
|
||||||
/// It shows the current [StreamChatClient] status.
|
/// It shows the current [StreamChatClient] status.
|
||||||
///
|
///
|
||||||
/// ```dart
|
/// ```dart
|
||||||
@@ -43,11 +47,13 @@ typedef TitleBuilder = Widget Function(
|
|||||||
/// if you don't have it in the widget tree.
|
/// if you don't have it in the widget tree.
|
||||||
///
|
///
|
||||||
/// The widget components render the ui based on the first ancestor of type
|
/// The widget components render the ui based on the first ancestor of type
|
||||||
/// [StreamChatTheme] and on its [ChannelListHeaderThemeData] property.
|
/// [StreamChatTheme] and on its [StreamChannelListHeaderThemeData] property.
|
||||||
/// Modify it to change the widget appearance.
|
/// Modify it to change the widget appearance.
|
||||||
class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamChannelListHeader extends StatelessWidget
|
||||||
|
implements PreferredSizeWidget {
|
||||||
/// Instantiates a ChannelListHeader
|
/// Instantiates a ChannelListHeader
|
||||||
const ChannelListHeader({
|
const StreamChannelListHeader({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.client,
|
this.client,
|
||||||
this.titleBuilder,
|
this.titleBuilder,
|
||||||
@@ -91,14 +97,14 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
/// By default it shows the new chat button
|
/// By default it shows the new chat button
|
||||||
final List<Widget>? actions;
|
final List<Widget>? actions;
|
||||||
|
|
||||||
/// The background color for this [ChannelListHeader].
|
/// The background color for this [StreamChannelListHeader].
|
||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _client = client ?? StreamChat.of(context).client;
|
final _client = client ?? StreamChat.of(context).client;
|
||||||
final user = _client.state.currentUser;
|
final user = _client.state.currentUser;
|
||||||
return ConnectionStatusBuilder(
|
return StreamConnectionStatusBuilder(
|
||||||
statusBuilder: (context, status) {
|
statusBuilder: (context, status) {
|
||||||
var statusString = '';
|
var statusString = '';
|
||||||
var showStatus = true;
|
var showStatus = true;
|
||||||
@@ -117,9 +123,10 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
final chatThemeData = StreamChatTheme.of(context);
|
||||||
final channelListHeaderThemeData = ChannelListHeaderTheme.of(context);
|
final channelListHeaderThemeData =
|
||||||
|
StreamChannelListHeaderTheme.of(context);
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
return InfoTile(
|
return StreamInfoTile(
|
||||||
showMessage: showConnectionStateTile && showStatus,
|
showMessage: showConnectionStateTile && showStatus,
|
||||||
message: statusString,
|
message: statusString,
|
||||||
child: AppBar(
|
child: AppBar(
|
||||||
@@ -135,7 +142,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
leading: leading ??
|
leading: leading ??
|
||||||
Center(
|
Center(
|
||||||
child: user != null
|
child: user != null
|
||||||
? UserAvatar(
|
? StreamUserAvatar(
|
||||||
user: user,
|
user: user,
|
||||||
showOnlineStatus: false,
|
showOnlineStatus: false,
|
||||||
onTap: onUserAvatarTap ??
|
onTap: onUserAvatarTap ??
|
||||||
@@ -156,7 +163,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
[
|
[
|
||||||
StreamNeumorphicButton(
|
StreamNeumorphicButton(
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: ConnectionStatusBuilder(
|
icon: StreamConnectionStatusBuilder(
|
||||||
statusBuilder: (context, status) {
|
statusBuilder: (context, status) {
|
||||||
Color? color;
|
Color? color;
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@@ -234,10 +241,11 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Text(
|
Text(
|
||||||
context.translations.searchingForNetworkText,
|
context.translations.searchingForNetworkText,
|
||||||
style: ChannelListHeaderTheme.of(context).titleStyle?.copyWith(
|
style:
|
||||||
fontSize: 16,
|
StreamChannelListHeaderTheme.of(context).titleStyle?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontSize: 16,
|
||||||
),
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -247,7 +255,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
StreamChatClient client,
|
StreamChatClient client,
|
||||||
) {
|
) {
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
final chatThemeData = StreamChatTheme.of(context);
|
||||||
final channelListHeaderTheme = ChannelListHeaderTheme.of(context);
|
final channelListHeaderTheme = StreamChannelListHeaderTheme.of(context);
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||||
import 'package:shimmer/shimmer.dart';
|
import 'package:shimmer/shimmer.dart';
|
||||||
import 'package:stream_chat_flutter/src/channel_bottom_sheet.dart';
|
|
||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
@@ -11,7 +10,7 @@ typedef ChannelTapCallback = void Function(Channel, Widget?);
|
|||||||
/// Callback called when tapping on a channel
|
/// Callback called when tapping on a channel
|
||||||
typedef ChannelInfoCallback = void Function(Channel);
|
typedef ChannelInfoCallback = void Function(Channel);
|
||||||
|
|
||||||
/// Builder used to create a custom [ChannelPreview] from a [Channel]
|
/// Builder used to create a custom [StreamChannelPreview] from a [Channel]
|
||||||
typedef ChannelPreviewBuilder = Widget Function(BuildContext, Channel);
|
typedef ChannelPreviewBuilder = Widget Function(BuildContext, Channel);
|
||||||
|
|
||||||
/// Callback for when 'View Info' is tapped
|
/// Callback for when 'View Info' is tapped
|
||||||
@@ -52,10 +51,7 @@ typedef ViewInfoCallback = void Function(Channel);
|
|||||||
/// The widget components render the ui based on the first ancestor of
|
/// The widget components render the ui based on the first ancestor of
|
||||||
/// type [StreamChatTheme].
|
/// type [StreamChatTheme].
|
||||||
/// Modify it to change the widget appearance.
|
/// Modify it to change the widget appearance.
|
||||||
@Deprecated(
|
@Deprecated("Use 'StreamChannelListView' instead")
|
||||||
"'ChannelListView' is deprecated and shouldn't be used. "
|
|
||||||
"Please use 'StreamChannelListView' instead.",
|
|
||||||
)
|
|
||||||
class ChannelListView extends StatefulWidget {
|
class ChannelListView extends StatefulWidget {
|
||||||
/// Instantiate a new ChannelListView
|
/// Instantiate a new ChannelListView
|
||||||
ChannelListView({
|
ChannelListView({
|
||||||
@@ -248,7 +244,8 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
|
|
||||||
final backgroundColor = ChannelListViewTheme.of(context).backgroundColor;
|
final backgroundColor =
|
||||||
|
StreamChannelListViewTheme.of(context).backgroundColor;
|
||||||
|
|
||||||
if (backgroundColor != null) {
|
if (backgroundColor != null) {
|
||||||
return ColoredBox(
|
return ColoredBox(
|
||||||
@@ -550,7 +547,8 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
context: context,
|
context: context,
|
||||||
builder: (context) => StreamChannel(
|
builder: (context) => StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: ChannelBottomSheet(
|
child: StreamChannelInfoBottomSheet(
|
||||||
|
channel: channel,
|
||||||
onViewInfoTap: () {
|
onViewInfoTap: () {
|
||||||
widget.onViewInfoTap?.call(channel);
|
widget.onViewInfoTap?.call(channel);
|
||||||
},
|
},
|
||||||
@@ -639,7 +637,7 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
ChannelAvatar(
|
StreamChannelAvatar(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
borderRadius: BorderRadius.circular(32),
|
borderRadius: BorderRadius.circular(32),
|
||||||
selected: selected,
|
selected: selected,
|
||||||
@@ -654,8 +652,9 @@ class _ChannelListViewState extends State<ChannelListView> {
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
child: StreamChannel(
|
child: StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: const ChannelName(
|
child: StreamChannelName(
|
||||||
textStyle: TextStyle(
|
channel: channel,
|
||||||
|
textStyle: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -6,10 +6,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
///
|
///
|
||||||
/// The widget uses a [StreamBuilder] to render the channel information
|
/// The widget uses a [StreamBuilder] to render the channel information
|
||||||
/// image as soon as it updates.
|
/// image as soon as it updates.
|
||||||
@Deprecated(
|
@Deprecated("Use 'StreamChannelName' instead")
|
||||||
"'ChannelName' is deprecated and shouldn't be used. "
|
|
||||||
"Please use 'StreamChannelName' instead.",
|
|
||||||
)
|
|
||||||
class ChannelName extends StatelessWidget {
|
class ChannelName extends StatelessWidget {
|
||||||
/// Instantiate a new ChannelName
|
/// Instantiate a new ChannelName
|
||||||
const ChannelName({
|
const ChannelName({
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@template channel_preview}
|
||||||
/// 
|
/// 
|
||||||
/// 
|
/// 
|
||||||
///
|
///
|
||||||
@@ -13,11 +14,13 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
/// image as soon as it updates.
|
/// image as soon as it updates.
|
||||||
///
|
///
|
||||||
/// Usually you don't use this widget as it's the default channel preview
|
/// Usually you don't use this widget as it's the default channel preview
|
||||||
/// used by [ChannelListView].
|
/// used by [StreamChannelListView].
|
||||||
///
|
///
|
||||||
/// The widget renders the ui based on the first ancestor of type
|
/// The widget renders the ui based on the first ancestor of type
|
||||||
/// [StreamChatTheme].
|
/// [StreamChatTheme].
|
||||||
/// Modify it to change the widget appearance.
|
/// Modify it to change the widget appearance.
|
||||||
|
/// {@endtemplate}
|
||||||
|
@Deprecated("Use 'StreamChannelListTile' instead")
|
||||||
class ChannelPreview extends StatelessWidget {
|
class ChannelPreview extends StatelessWidget {
|
||||||
/// Constructor for creating [ChannelPreview]
|
/// Constructor for creating [ChannelPreview]
|
||||||
const ChannelPreview({
|
const ChannelPreview({
|
||||||
@@ -52,7 +55,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
final Widget? subtitle;
|
final Widget? subtitle;
|
||||||
|
|
||||||
/// Widget rendering the leading element, by default
|
/// Widget rendering the leading element, by default
|
||||||
/// it shows the [ChannelAvatar]
|
/// it shows the [StreamChannelAvatar]
|
||||||
final Widget? leading;
|
final Widget? leading;
|
||||||
|
|
||||||
/// Widget rendering the trailing element,
|
/// Widget rendering the trailing element,
|
||||||
@@ -60,7 +63,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
final Widget? trailing;
|
final Widget? trailing;
|
||||||
|
|
||||||
/// Widget rendering the sending indicator,
|
/// Widget rendering the sending indicator,
|
||||||
/// by default it uses the [SendingIndicator] widget
|
/// by default it uses the [StreamSendingIndicator] widget
|
||||||
final Widget? sendingIndicator;
|
final Widget? sendingIndicator;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -80,13 +83,18 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
onTap: () => onTap?.call(channel),
|
onTap: () => onTap?.call(channel),
|
||||||
onLongPress: () => onLongPress?.call(channel),
|
onLongPress: () => onLongPress?.call(channel),
|
||||||
leading: leading ?? ChannelAvatar(onTap: onImageTap),
|
leading: leading ??
|
||||||
|
StreamChannelAvatar(
|
||||||
|
channel: channel,
|
||||||
|
onTap: onImageTap,
|
||||||
|
),
|
||||||
title: Row(
|
title: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Flexible(
|
Flexible(
|
||||||
child: title ??
|
child: title ??
|
||||||
ChannelName(
|
StreamChannelName(
|
||||||
|
channel: channel,
|
||||||
textStyle: channelPreviewTheme.titleStyle,
|
textStyle: channelPreviewTheme.titleStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -100,7 +108,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
e.user!.id == channel.client.state.currentUser?.id)) {
|
e.user!.id == channel.client.state.currentUser?.id)) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
return UnreadIndicator(
|
return StreamUnreadIndicator(
|
||||||
cid: channel.cid,
|
cid: channel.cid,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -136,7 +144,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
)));
|
)));
|
||||||
final isMessageRead = readList.length >=
|
final isMessageRead = readList.length >=
|
||||||
(channel.memberCount ?? 0) - 1;
|
(channel.memberCount ?? 0) - 1;
|
||||||
return SendingIndicator(
|
return StreamSendingIndicator(
|
||||||
message: lastMessage!,
|
message: lastMessage!,
|
||||||
size: channelPreviewTheme.indicatorIconSize,
|
size: channelPreviewTheme.indicatorIconSize,
|
||||||
isMessageRead: isMessageRead,
|
isMessageRead: isMessageRead,
|
||||||
@@ -204,7 +212,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return TypingIndicator(
|
return StreamTypingIndicator(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
alternativeWidget: _buildLastMessage(context),
|
alternativeWidget: _buildLastMessage(context),
|
||||||
style: channelPreviewTheme.subtitleStyle,
|
style: channelPreviewTheme.subtitleStyle,
|
||||||
|
|||||||
@@ -2,10 +2,17 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro commands_overlay}
|
||||||
|
@Deprecated("Use 'StreamCommandsOverlay' instead")
|
||||||
|
typedef CommandsOverlay = StreamCommandsOverlay;
|
||||||
|
|
||||||
|
/// {@template commands_overlay}
|
||||||
/// Overlay for displaying commands that can be used
|
/// Overlay for displaying commands that can be used
|
||||||
class CommandsOverlay extends StatelessWidget {
|
/// to interact with the channel.
|
||||||
/// Constructor for creating a [CommandsOverlay]
|
/// {@endtemplate}
|
||||||
const CommandsOverlay({
|
class StreamCommandsOverlay extends StatelessWidget {
|
||||||
|
/// Constructor for creating a [StreamCommandsOverlay]
|
||||||
|
const StreamCommandsOverlay({
|
||||||
required this.text,
|
required this.text,
|
||||||
required this.onCommandResult,
|
required this.onCommandResult,
|
||||||
required this.size,
|
required this.size,
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro connection_status_builder}
|
||||||
|
@Deprecated("Use 'StreamConnectionStatusBuilder' instead")
|
||||||
|
typedef ConnectionStatusBuilder = StreamConnectionStatusBuilder;
|
||||||
|
|
||||||
|
/// {@template connection_status_builder}
|
||||||
/// Widget that builds itself based on the latest snapshot of interaction with
|
/// Widget that builds itself based on the latest snapshot of interaction with
|
||||||
/// a [Stream] of type [ConnectionStatus].
|
/// a [Stream] of type [ConnectionStatus].
|
||||||
///
|
///
|
||||||
/// The widget will use the closest [StreamChatClient.wsConnectionStatusStream]
|
/// The widget will use the closest [StreamChatClient.wsConnectionStatusStream]
|
||||||
/// in case no stream is provided.
|
/// in case no stream is provided.
|
||||||
class ConnectionStatusBuilder extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamConnectionStatusBuilder extends StatelessWidget {
|
||||||
/// Creates a new ConnectionStatusBuilder
|
/// Creates a new ConnectionStatusBuilder
|
||||||
const ConnectionStatusBuilder({
|
const StreamConnectionStatusBuilder({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.statusBuilder,
|
required this.statusBuilder,
|
||||||
this.connectionStatusStream,
|
this.connectionStatusStream,
|
||||||
|
|||||||
@@ -3,10 +3,16 @@ import 'package:jiffy/jiffy.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
|
/// {@macro date_divider}
|
||||||
|
@Deprecated("Use 'StreamDateDivider' instead")
|
||||||
|
typedef DateDivider = StreamDateDivider;
|
||||||
|
|
||||||
|
/// {@template date_divider}
|
||||||
/// It shows a date divider depending on the date difference
|
/// It shows a date divider depending on the date difference
|
||||||
class DateDivider extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [DateDivider]
|
class StreamDateDivider extends StatelessWidget {
|
||||||
const DateDivider({
|
/// Constructor for creating a [StreamDateDivider]
|
||||||
|
const StreamDateDivider({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.dateTime,
|
required this.dateTime,
|
||||||
this.uppercase = false,
|
this.uppercase = false,
|
||||||
|
|||||||
@@ -3,10 +3,16 @@ import 'package:stream_chat_flutter/src/extension.dart';
|
|||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
||||||
|
|
||||||
/// Widget to display deleted message
|
/// {@macro deleted_message}
|
||||||
class DeletedMessage extends StatelessWidget {
|
@Deprecated("Use 'StreamDeletedMessage' instead")
|
||||||
/// Constructor to create [DeletedMessage]
|
typedef DeletedMessage = StreamDeletedMessage;
|
||||||
const DeletedMessage({
|
|
||||||
|
/// {@template deleted_message}
|
||||||
|
/// Widget to display deleted message.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class StreamDeletedMessage extends StatelessWidget {
|
||||||
|
/// Constructor to create [StreamDeletedMessage]
|
||||||
|
const StreamDeletedMessage({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
this.borderRadiusGeometry,
|
this.borderRadiusGeometry,
|
||||||
@@ -16,7 +22,7 @@ class DeletedMessage extends StatelessWidget {
|
|||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
/// The theme of the message
|
/// The theme of the message
|
||||||
final MessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|
||||||
/// The border radius of the message text
|
/// The border radius of the message text
|
||||||
final BorderRadiusGeometry? borderRadiusGeometry;
|
final BorderRadiusGeometry? borderRadiusGeometry;
|
||||||
|
|||||||
@@ -4,10 +4,16 @@ import 'package:stream_chat_flutter/src/extension.dart';
|
|||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:substring_highlight/substring_highlight.dart';
|
import 'package:substring_highlight/substring_highlight.dart';
|
||||||
|
|
||||||
|
/// {@macro emoji_overlay}
|
||||||
|
@Deprecated("Use 'StreamEmojiOverlay' instead")
|
||||||
|
typedef EmojiOverlay = StreamEmojiOverlay;
|
||||||
|
|
||||||
|
/// {@template emoji_overlay}
|
||||||
/// Overlay for displaying emoji that can be used
|
/// Overlay for displaying emoji that can be used
|
||||||
class EmojiOverlay extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [EmojiOverlay]
|
class StreamEmojiOverlay extends StatelessWidget {
|
||||||
const EmojiOverlay({
|
/// Constructor for creating a [StreamEmojiOverlay]
|
||||||
|
const StreamEmojiOverlay({
|
||||||
required this.query,
|
required this.query,
|
||||||
required this.onEmojiResult,
|
required this.onEmojiResult,
|
||||||
required this.size,
|
required this.size,
|
||||||
|
|||||||
@@ -225,3 +225,50 @@ extension UserListX on List<User> {
|
|||||||
return entries.map((e) => e.key).toList(growable: false);
|
return entries.map((e) => e.key).toList(growable: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extensions on Message
|
||||||
|
extension MessageX on Message {
|
||||||
|
/// It replaces the user mentions with the actual user names.
|
||||||
|
Message replaceMentions({bool linkify = true}) {
|
||||||
|
var messageTextToRender = text;
|
||||||
|
for (final user in mentionedUsers.toSet()) {
|
||||||
|
final userId = user.id;
|
||||||
|
final userName = user.name;
|
||||||
|
if (linkify) {
|
||||||
|
messageTextToRender = messageTextToRender?.replaceAll(
|
||||||
|
'@$userId',
|
||||||
|
'[@$userName](@${userName.replaceAll(' ', '')})',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
messageTextToRender = messageTextToRender?.replaceAll(
|
||||||
|
'@$userId',
|
||||||
|
'@$userName',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return copyWith(text: messageTextToRender);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// It returns the message with the translated text if available locally
|
||||||
|
Message translate(String language) =>
|
||||||
|
copyWith(text: i18n?['${language}_text'] ?? text);
|
||||||
|
|
||||||
|
/// It returns the message replacing the mentioned user names with
|
||||||
|
/// the respective user ids
|
||||||
|
Message replaceMentionsWithId() {
|
||||||
|
if (mentionedUsers.isEmpty) return this;
|
||||||
|
|
||||||
|
var messageTextToSend = text;
|
||||||
|
if (messageTextToSend == null) return this;
|
||||||
|
|
||||||
|
for (final user in mentionedUsers.toSet()) {
|
||||||
|
final userName = user.name;
|
||||||
|
messageTextToSend = messageTextToSend!.replaceAll(
|
||||||
|
'@$userName',
|
||||||
|
'@${user.id}',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return copyWith(text: messageTextToSend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,10 +21,16 @@ enum ReturnActionType {
|
|||||||
/// Callback when show message is tapped
|
/// Callback when show message is tapped
|
||||||
typedef ShowMessageCallback = void Function(Message message, Channel channel);
|
typedef ShowMessageCallback = void Function(Message message, Channel channel);
|
||||||
|
|
||||||
|
/// {@macro full_screen_media}
|
||||||
|
@Deprecated("Use 'StreamFullScreenMedia' instead")
|
||||||
|
typedef FullScreenMedia = StreamFullScreenMedia;
|
||||||
|
|
||||||
|
/// {@template full_screen_media}
|
||||||
/// A full screen image widget
|
/// A full screen image widget
|
||||||
class FullScreenMedia extends StatefulWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamFullScreenMedia extends StatefulWidget {
|
||||||
/// Instantiate a new FullScreenImage
|
/// Instantiate a new FullScreenImage
|
||||||
const FullScreenMedia({
|
const StreamFullScreenMedia({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.mediaAttachments,
|
required this.mediaAttachments,
|
||||||
required this.message,
|
required this.message,
|
||||||
@@ -60,10 +66,10 @@ class FullScreenMedia extends StatefulWidget {
|
|||||||
final bool autoplayVideos;
|
final bool autoplayVideos;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_FullScreenMediaState createState() => _FullScreenMediaState();
|
_StreamFullScreenMediaState createState() => _StreamFullScreenMediaState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FullScreenMediaState extends State<FullScreenMedia>
|
class _StreamFullScreenMediaState extends State<StreamFullScreenMedia>
|
||||||
with SingleTickerProviderStateMixin {
|
with SingleTickerProviderStateMixin {
|
||||||
late final AnimationController _animationController;
|
late final AnimationController _animationController;
|
||||||
late final PageController _pageController;
|
late final PageController _pageController;
|
||||||
@@ -172,7 +178,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
|
|||||||
),
|
),
|
||||||
backgroundDecoration: BoxDecoration(
|
backgroundDecoration: BoxDecoration(
|
||||||
color: ColorTween(
|
color: ColorTween(
|
||||||
begin: ChannelHeaderTheme.of(context).color,
|
begin: StreamChannelHeaderTheme.of(context).color,
|
||||||
end: Colors.black,
|
end: Colors.black,
|
||||||
).lerp(_curvedAnimation.value),
|
).lerp(_curvedAnimation.value),
|
||||||
),
|
),
|
||||||
@@ -221,7 +227,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
|
|||||||
builder: (context, value, child) => Column(
|
builder: (context, value, child) => Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
GalleryHeader(
|
StreamGalleryHeader(
|
||||||
userName: widget.userName,
|
userName: widget.userName,
|
||||||
sentAt: context.translations.sentAtText(
|
sentAt: context.translations.sentAtText(
|
||||||
date: widget.message.createdAt,
|
date: widget.message.createdAt,
|
||||||
@@ -242,7 +248,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
|
|||||||
widget.attachmentActionsModalBuilder,
|
widget.attachmentActionsModalBuilder,
|
||||||
),
|
),
|
||||||
if (!widget.message.isEphemeral)
|
if (!widget.message.isEphemeral)
|
||||||
GalleryFooter(
|
StreamGalleryFooter(
|
||||||
currentPage: value,
|
currentPage: value,
|
||||||
totalPages: widget.mediaAttachments.length,
|
totalPages: widget.mediaAttachments.length,
|
||||||
mediaAttachments: widget.mediaAttachments,
|
mediaAttachments: widget.mediaAttachments,
|
||||||
|
|||||||
@@ -9,10 +9,17 @@ import 'package:stream_chat_flutter/src/extension.dart';
|
|||||||
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro gallery_footer}
|
||||||
|
@Deprecated("Use 'StreamGalleryFooter' instead")
|
||||||
|
typedef GalleryFooter = StreamGalleryFooter;
|
||||||
|
|
||||||
|
/// {@template gallery_footer}
|
||||||
/// Footer widget for media display
|
/// Footer widget for media display
|
||||||
class GalleryFooter extends StatefulWidget implements PreferredSizeWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamGalleryFooter extends StatefulWidget
|
||||||
|
implements PreferredSizeWidget {
|
||||||
/// Creates a channel header
|
/// Creates a channel header
|
||||||
const GalleryFooter({
|
const StreamGalleryFooter({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
this.onBackPressed,
|
this.onBackPressed,
|
||||||
@@ -51,22 +58,22 @@ class GalleryFooter extends StatefulWidget implements PreferredSizeWidget {
|
|||||||
/// Callback when media is selected
|
/// Callback when media is selected
|
||||||
final ValueChanged<int>? mediaSelectedCallBack;
|
final ValueChanged<int>? mediaSelectedCallBack;
|
||||||
|
|
||||||
/// The background color of this [GalleryFooter].
|
/// The background color of this [StreamGalleryFooter].
|
||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_GalleryFooterState createState() => _GalleryFooterState();
|
_StreamGalleryFooterState createState() => _StreamGalleryFooterState();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final Size preferredSize;
|
final Size preferredSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _GalleryFooterState extends State<GalleryFooter> {
|
class _StreamGalleryFooterState extends State<StreamGalleryFooter> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const showShareButton = !kIsWeb;
|
const showShareButton = !kIsWeb;
|
||||||
final mediaQueryData = MediaQuery.of(context);
|
final mediaQueryData = MediaQuery.of(context);
|
||||||
final galleryFooterThemeData = GalleryFooterTheme.of(context);
|
final galleryFooterThemeData = StreamGalleryFooterTheme.of(context);
|
||||||
return SizedBox.fromSize(
|
return SizedBox.fromSize(
|
||||||
size: Size(
|
size: Size(
|
||||||
mediaQueryData.size.width,
|
mediaQueryData.size.width,
|
||||||
@@ -149,7 +156,7 @@ class _GalleryFooterState extends State<GalleryFooter> {
|
|||||||
|
|
||||||
void _showPhotosModal(context) {
|
void _showPhotosModal(context) {
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
final chatThemeData = StreamChatTheme.of(context);
|
||||||
final galleryFooterThemeData = GalleryFooterTheme.of(context);
|
final galleryFooterThemeData = StreamGalleryFooterTheme.of(context);
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
barrierColor: galleryFooterThemeData.bottomSheetBarrierColor,
|
barrierColor: galleryFooterThemeData.bottomSheetBarrierColor,
|
||||||
@@ -222,7 +229,7 @@ class _GalleryFooterState extends State<GalleryFooter> {
|
|||||||
onTap: () => widget.mediaSelectedCallBack!(index),
|
onTap: () => widget.mediaSelectedCallBack!(index),
|
||||||
child: FittedBox(
|
child: FittedBox(
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
child: VideoThumbnailImage(
|
child: StreamVideoThumbnailImage(
|
||||||
video: (attachment.file?.path ??
|
video: (attachment.file?.path ??
|
||||||
attachment.assetUrl)!,
|
attachment.assetUrl)!,
|
||||||
),
|
),
|
||||||
@@ -264,7 +271,7 @@ class _GalleryFooterState extends State<GalleryFooter> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: UserAvatar(
|
child: StreamUserAvatar(
|
||||||
user: widget.message.user!,
|
user: widget.message.user!,
|
||||||
constraints:
|
constraints:
|
||||||
BoxConstraints.tight(const Size(24, 24)),
|
BoxConstraints.tight(const Size(24, 24)),
|
||||||
|
|||||||
@@ -15,10 +15,17 @@ typedef AttachmentActionsBuilder = Widget Function(
|
|||||||
AttachmentActionsModal defaultActionsModal,
|
AttachmentActionsModal defaultActionsModal,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// {@macro gallery_header}
|
||||||
|
@Deprecated("Use 'StreamGalleryHeader' instead")
|
||||||
|
typedef GalleryHeader = StreamGalleryHeader;
|
||||||
|
|
||||||
|
/// {@template gallery_header}
|
||||||
/// Header/AppBar widget for media display screen
|
/// Header/AppBar widget for media display screen
|
||||||
class GalleryHeader extends StatelessWidget implements PreferredSizeWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamGalleryHeader extends StatelessWidget
|
||||||
|
implements PreferredSizeWidget {
|
||||||
/// Creates a channel header
|
/// Creates a channel header
|
||||||
const GalleryHeader({
|
const StreamGalleryHeader({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
this.currentIndex = 0,
|
this.currentIndex = 0,
|
||||||
@@ -62,7 +69,7 @@ class GalleryHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
/// Stores the current index of media shown
|
/// Stores the current index of media shown
|
||||||
final int currentIndex;
|
final int currentIndex;
|
||||||
|
|
||||||
/// The background color of this [GalleryHeader].
|
/// The background color of this [StreamGalleryHeader].
|
||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
|
|
||||||
/// Widget builder for attachment actions modal
|
/// Widget builder for attachment actions modal
|
||||||
@@ -72,7 +79,7 @@ class GalleryHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final galleryHeaderThemeData = GalleryHeaderTheme.of(context);
|
final galleryHeaderThemeData = StreamGalleryHeaderTheme.of(context);
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
return AppBar(
|
return AppBar(
|
||||||
toolbarTextStyle: theme.textTheme.bodyText2,
|
toolbarTextStyle: theme.textTheme.bodyText2,
|
||||||
|
|||||||
@@ -3,10 +3,16 @@ import 'dart:ui' as ui;
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// {@macro gradient_avatar}
|
||||||
|
@Deprecated("Use 'StreamGradientAvatar' instead")
|
||||||
|
typedef GradientAvatar = StreamGradientAvatar;
|
||||||
|
|
||||||
|
/// {@template gradient_avatar}
|
||||||
/// Fallback user avatar with a polygon gradient overlayed with text
|
/// Fallback user avatar with a polygon gradient overlayed with text
|
||||||
class GradientAvatar extends StatefulWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for [GradientAvatar]
|
class StreamGradientAvatar extends StatefulWidget {
|
||||||
const GradientAvatar({
|
/// Constructor for [StreamGradientAvatar]
|
||||||
|
const StreamGradientAvatar({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.userId,
|
required this.userId,
|
||||||
@@ -19,10 +25,10 @@ class GradientAvatar extends StatefulWidget {
|
|||||||
final String userId;
|
final String userId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_GradientAvatarState createState() => _GradientAvatarState();
|
_StreamGradientAvatarState createState() => _StreamGradientAvatarState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _GradientAvatarState extends State<GradientAvatar> {
|
class _StreamGradientAvatarState extends State<StreamGradientAvatar> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Center(
|
Widget build(BuildContext context) => Center(
|
||||||
child: RepaintBoundary(
|
child: RepaintBoundary(
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro group_avatar}
|
||||||
|
@Deprecated("Use 'StreamGroupAvatar' instead")
|
||||||
|
typedef GroupAvatar = StreamGroupAvatar;
|
||||||
|
|
||||||
|
/// {@template group_avatar}
|
||||||
/// Widget for constructing a group of images
|
/// Widget for constructing a group of images
|
||||||
class GroupAvatar extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [GroupAvatar]
|
class StreamGroupAvatar extends StatelessWidget {
|
||||||
const GroupAvatar({
|
/// Constructor for creating a [StreamGroupAvatar]
|
||||||
|
const StreamGroupAvatar({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.channel,
|
this.channel,
|
||||||
required this.members,
|
required this.members,
|
||||||
@@ -84,7 +90,7 @@ class GroupAvatar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
initialData: member,
|
initialData: member,
|
||||||
builder: (context, member) => UserAvatar(
|
builder: (context, member) => StreamUserAvatar(
|
||||||
showOnlineStatus: false,
|
showOnlineStatus: false,
|
||||||
user: member.user!,
|
user: member.user!,
|
||||||
borderRadius: BorderRadius.zero,
|
borderRadius: BorderRadius.zero,
|
||||||
@@ -122,7 +128,8 @@ class GroupAvatar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
initialData: member,
|
initialData: member,
|
||||||
builder: (context, member) => UserAvatar(
|
builder: (context, member) =>
|
||||||
|
StreamUserAvatar(
|
||||||
showOnlineStatus: false,
|
showOnlineStatus: false,
|
||||||
user: member.user!,
|
user: member.user!,
|
||||||
borderRadius: BorderRadius.zero,
|
borderRadius: BorderRadius.zero,
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro image_group}
|
||||||
|
@Deprecated("Use 'StreamImageGroup' instead")
|
||||||
|
typedef ImageGroup = StreamImageGroup;
|
||||||
|
|
||||||
|
/// {@template image_group}
|
||||||
/// Widget for constructing a group of images in message
|
/// Widget for constructing a group of images in message
|
||||||
class ImageGroup extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating [ImageGroup] widget
|
class StreamImageGroup extends StatelessWidget {
|
||||||
const ImageGroup({
|
/// Constructor for creating [StreamImageGroup] widget
|
||||||
|
const StreamImageGroup({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.images,
|
required this.images,
|
||||||
required this.message,
|
required this.message,
|
||||||
@@ -27,8 +33,8 @@ class ImageGroup extends StatelessWidget {
|
|||||||
/// Message which images are attached to
|
/// Message which images are attached to
|
||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
/// [MessageThemeData] to apply to message
|
/// [StreamMessageThemeData] to apply to message
|
||||||
final MessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|
||||||
/// Size of iamges
|
/// Size of iamges
|
||||||
final Size size;
|
final Size size;
|
||||||
@@ -129,7 +135,7 @@ class ImageGroup extends StatelessWidget {
|
|||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => StreamChannel(
|
builder: (context) => StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: FullScreenMedia(
|
child: StreamFullScreenMedia(
|
||||||
mediaAttachments: images,
|
mediaAttachments: images,
|
||||||
startIndex: index,
|
startIndex: index,
|
||||||
userName: message.user?.name,
|
userName: message.user?.name,
|
||||||
@@ -142,7 +148,7 @@ class ImageGroup extends StatelessWidget {
|
|||||||
if (res != null) onReturnAction?.call(res);
|
if (res != null) onReturnAction?.call(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildImage(BuildContext context, int index) => ImageAttachment(
|
Widget _buildImage(BuildContext context, int index) => StreamImageAttachment(
|
||||||
attachment: images[index],
|
attachment: images[index],
|
||||||
size: size,
|
size: size,
|
||||||
message: message,
|
message: message,
|
||||||
|
|||||||
@@ -2,10 +2,16 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_portal/flutter_portal.dart';
|
import 'package:flutter_portal/flutter_portal.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
|
/// {@macro info_tile}
|
||||||
|
@Deprecated("Use 'StreamInfoTile' instead")
|
||||||
|
typedef InfoTile = StreamInfoTile;
|
||||||
|
|
||||||
|
/// {@template info_tile}
|
||||||
/// Tile to display a message, used in stream chat to display connection status
|
/// Tile to display a message, used in stream chat to display connection status
|
||||||
class InfoTile extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating an [InfoTile] widget
|
class StreamInfoTile extends StatelessWidget {
|
||||||
const InfoTile({
|
/// Constructor for creating an [StreamInfoTile] widget
|
||||||
|
const StreamInfoTile({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.child,
|
required this.child,
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ abstract class Translations {
|
|||||||
/// The error shown when loading messages fails
|
/// The error shown when loading messages fails
|
||||||
String get loadingMessagesError;
|
String get loadingMessagesError;
|
||||||
|
|
||||||
/// The text for showing the result count in [MessageSearchListView]
|
/// The text for showing the result count in [StreamMessageSearchListView]
|
||||||
String resultCountText(int count);
|
String resultCountText(int count);
|
||||||
|
|
||||||
/// The text for showing the message is deleted
|
/// The text for showing the message is deleted
|
||||||
@@ -74,20 +74,20 @@ abstract class Translations {
|
|||||||
/// The text for showing there are no chats
|
/// The text for showing there are no chats
|
||||||
String get emptyChatMessagesText;
|
String get emptyChatMessagesText;
|
||||||
|
|
||||||
/// The text for showing the thread separator in case [MessageListView]
|
/// The text for showing the thread separator in case [StreamMessageListView]
|
||||||
/// contains a parent message
|
/// contains a parent message
|
||||||
String threadSeparatorText(int replyCount);
|
String threadSeparatorText(int replyCount);
|
||||||
|
|
||||||
/// The label for "connected" in [ConnectionStatusBuilder]
|
/// The label for "connected" in [StreamConnectionStatusBuilder]
|
||||||
String get connectedLabel;
|
String get connectedLabel;
|
||||||
|
|
||||||
/// The label for "disconnected" in [ConnectionStatusBuilder]
|
/// The label for "disconnected" in [StreamConnectionStatusBuilder]
|
||||||
String get disconnectedLabel;
|
String get disconnectedLabel;
|
||||||
|
|
||||||
/// The label for "reconnecting" in [ConnectionStatusBuilder]
|
/// The label for "reconnecting" in [StreamConnectionStatusBuilder]
|
||||||
String get reconnectingLabel;
|
String get reconnectingLabel;
|
||||||
|
|
||||||
/// The label for also send as direct message "checkbox"" in [MessageInput]
|
/// The label for also send as direct message "checkbox"" in [StreamMessageInput]
|
||||||
String get alsoSendAsDirectMessageLabel;
|
String get alsoSendAsDirectMessageLabel;
|
||||||
|
|
||||||
/// The label for search Gif
|
/// The label for search Gif
|
||||||
@@ -97,24 +97,24 @@ abstract class Translations {
|
|||||||
String get sendMessagePermissionError;
|
String get sendMessagePermissionError;
|
||||||
|
|
||||||
/// The label for add a comment or send in case of
|
/// The label for add a comment or send in case of
|
||||||
/// attachments inside [MessageInput]
|
/// attachments inside [StreamMessageInput]
|
||||||
String get addACommentOrSendLabel;
|
String get addACommentOrSendLabel;
|
||||||
|
|
||||||
/// The label for write a message in [MessageInput]
|
/// The label for write a message in [StreamMessageInput]
|
||||||
String get writeAMessageLabel;
|
String get writeAMessageLabel;
|
||||||
|
|
||||||
/// The label for slow mode enabled in [MessageInput]
|
/// The label for slow mode enabled in [StreamMessageInput]
|
||||||
String get slowModeOnLabel;
|
String get slowModeOnLabel;
|
||||||
|
|
||||||
/// The label for instant commands in [MessageInput]
|
/// The label for instant commands in [StreamMessageInput]
|
||||||
String get instantCommandsLabel;
|
String get instantCommandsLabel;
|
||||||
|
|
||||||
/// The error shown in case the fi"le is too large even after compression
|
/// The error shown in case the fi"le is too large even after compression
|
||||||
/// while uploading via [MessageInput]
|
/// while uploading via [StreamMessageInput]
|
||||||
String fileTooLargeAfterCompressionError(double limitInMB);
|
String fileTooLargeAfterCompressionError(double limitInMB);
|
||||||
|
|
||||||
/// The error shown in case the file is too large
|
/// The error shown in case the file is too large
|
||||||
/// while uploading via [MessageInput]
|
/// while uploading via [StreamMessageInput]
|
||||||
String fileTooLargeError(double limitInMB);
|
String fileTooLargeError(double limitInMB);
|
||||||
|
|
||||||
/// The text for showing the query while searching for emojis
|
/// The text for showing the query while searching for emojis
|
||||||
|
|||||||
@@ -7,21 +7,16 @@ import 'package:flutter_svg/flutter_svg.dart';
|
|||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
extension on Duration {
|
/// {@macro media_list_view}
|
||||||
String format() {
|
@Deprecated("Use 'StreamMediaListView' instead")
|
||||||
final s = '$this'.split('.')[0].padLeft(8, '0');
|
typedef MediaListView = StreamMediaListView;
|
||||||
if (s.startsWith('00:')) {
|
|
||||||
return s.replaceFirst('00:', '');
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// {@template media_list_view}
|
||||||
/// Constructs a list of media
|
/// Constructs a list of media
|
||||||
class MediaListView extends StatefulWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [MediaListView] widget
|
class StreamMediaListView extends StatefulWidget {
|
||||||
const MediaListView({
|
/// Constructor for creating a [StreamMediaListView] widget
|
||||||
|
const StreamMediaListView({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.selectedIds = const [],
|
this.selectedIds = const [],
|
||||||
this.onSelect,
|
this.onSelect,
|
||||||
@@ -34,10 +29,10 @@ class MediaListView extends StatefulWidget {
|
|||||||
final void Function(AssetEntity media)? onSelect;
|
final void Function(AssetEntity media)? onSelect;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MediaListViewState createState() => _MediaListViewState();
|
_StreamMediaListViewState createState() => _StreamMediaListViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MediaListViewState extends State<MediaListView> {
|
class _StreamMediaListViewState extends State<StreamMediaListView> {
|
||||||
final _media = <AssetEntity>[];
|
final _media = <AssetEntity>[];
|
||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
int _currentPage = 0;
|
int _currentPage = 0;
|
||||||
@@ -158,7 +153,10 @@ class _MediaListViewState extends State<MediaListView> {
|
|||||||
))
|
))
|
||||||
.firstOrNull;
|
.firstOrNull;
|
||||||
|
|
||||||
final media = await assetList?.getAssetListPaged(_currentPage, 50);
|
final media = await assetList?.getAssetListPaged(
|
||||||
|
page: _currentPage,
|
||||||
|
size: 50,
|
||||||
|
);
|
||||||
|
|
||||||
if (media?.isNotEmpty == true) {
|
if (media?.isNotEmpty == true) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -197,7 +195,7 @@ class MediaThumbnailProvider extends ImageProvider<MediaThumbnailProvider> {
|
|||||||
DecoderCallback decode,
|
DecoderCallback decode,
|
||||||
) async {
|
) async {
|
||||||
assert(key == this, 'Checks MediaThumbnailProvider');
|
assert(key == this, 'Checks MediaThumbnailProvider');
|
||||||
final bytes = await media.thumbData;
|
final bytes = await media.thumbnailData;
|
||||||
|
|
||||||
return decode(bytes!);
|
return decode(bytes!);
|
||||||
}
|
}
|
||||||
@@ -219,3 +217,14 @@ class MediaThumbnailProvider extends ImageProvider<MediaThumbnailProvider> {
|
|||||||
@override
|
@override
|
||||||
String toString() => '$runtimeType("${media.id}")';
|
String toString() => '$runtimeType("${media.id}")';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension on Duration {
|
||||||
|
String format() {
|
||||||
|
final s = '$this'.split('.')[0].padLeft(8, '0');
|
||||||
|
if (s.startsWith('00:')) {
|
||||||
|
return s.replaceFirst('00:', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|
||||||
|
|
||||||
/// This widget is used for showing user tiles for mentions
|
|
||||||
/// Use [title], [subtitle], [leading], [trailing] for
|
|
||||||
/// substituting widgets in respective positions
|
|
||||||
@Deprecated('Use `UserMentionTile` instead. Will be removed in future release')
|
|
||||||
class MentionTile extends StatelessWidget {
|
|
||||||
/// Constructor for creating a [MentionTile] widget
|
|
||||||
const MentionTile(
|
|
||||||
this.member, {
|
|
||||||
Key? key,
|
|
||||||
this.title,
|
|
||||||
this.subtitle,
|
|
||||||
this.leading,
|
|
||||||
this.trailing,
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
/// Member to display in the tile
|
|
||||||
final Member member;
|
|
||||||
|
|
||||||
/// Widget to display as title
|
|
||||||
final Widget? title;
|
|
||||||
|
|
||||||
/// Widget to display below [title]
|
|
||||||
final Widget? subtitle;
|
|
||||||
|
|
||||||
/// Widget at the start of the tile
|
|
||||||
final Widget? leading;
|
|
||||||
|
|
||||||
/// Widget at the end of tile
|
|
||||||
final Widget? trailing;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
|
||||||
return SizedBox(
|
|
||||||
height: 56,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const SizedBox(
|
|
||||||
width: 16,
|
|
||||||
),
|
|
||||||
leading ??
|
|
||||||
UserAvatar(
|
|
||||||
constraints: BoxConstraints.tight(
|
|
||||||
const Size(
|
|
||||||
40,
|
|
||||||
40,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
user: member.user!,
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
width: 8,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Align(
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
title ??
|
|
||||||
Text(
|
|
||||||
member.user!.name,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: chatThemeData.textTheme.bodyBold,
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 2,
|
|
||||||
),
|
|
||||||
subtitle ??
|
|
||||||
Text(
|
|
||||||
'@${member.userId}',
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: chatThemeData.textTheme.footnoteBold.copyWith(
|
|
||||||
color: chatThemeData.colorTheme.textLowEmphasis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
trailing ??
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
right: 18,
|
|
||||||
left: 8,
|
|
||||||
),
|
|
||||||
child: StreamSvgIcon.mentions(
|
|
||||||
color: chatThemeData.colorTheme.accentPrimary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,16 @@
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro message_action}
|
||||||
|
@Deprecated("Use 'StreamMessageActions' instead")
|
||||||
|
typedef MessageAction = StreamMessageAction;
|
||||||
|
|
||||||
|
/// {@template message_action}
|
||||||
/// Class describing a message action
|
/// Class describing a message action
|
||||||
class MessageAction {
|
/// {@endtemplate}
|
||||||
/// returns a new instance of a [MessageAction]
|
class StreamMessageAction {
|
||||||
MessageAction({
|
/// returns a new instance of a [StreamMessageAction]
|
||||||
|
StreamMessageAction({
|
||||||
this.leading,
|
this.leading,
|
||||||
this.title,
|
this.title,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
|
|||||||
@@ -3,10 +3,16 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro message_actions_modal}
|
||||||
|
@Deprecated("Use 'StreamMessageActionsModal' instead")
|
||||||
|
typedef MessageActionsModal = StreamMessageActionsModal;
|
||||||
|
|
||||||
|
/// {@template message_actions_modal}
|
||||||
/// Constructs a modal with actions for a message
|
/// Constructs a modal with actions for a message
|
||||||
class MessageActionsModal extends StatefulWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [MessageActionsModal] widget
|
class StreamMessageActionsModal extends StatefulWidget {
|
||||||
const MessageActionsModal({
|
/// Constructor for creating a [StreamMessageActionsModal] widget
|
||||||
|
const StreamMessageActionsModal({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.messageWidget,
|
required this.messageWidget,
|
||||||
@@ -43,8 +49,8 @@ class MessageActionsModal extends StatefulWidget {
|
|||||||
/// Message in focus for actions
|
/// Message in focus for actions
|
||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
/// [MessageThemeData] for message
|
/// [StreamMessageThemeData] for message
|
||||||
final MessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|
||||||
/// Flag for showing reactions
|
/// Flag for showing reactions
|
||||||
final bool? showReactions;
|
final bool? showReactions;
|
||||||
@@ -80,13 +86,14 @@ class MessageActionsModal extends StatefulWidget {
|
|||||||
final bool reverse;
|
final bool reverse;
|
||||||
|
|
||||||
/// List of custom actions
|
/// List of custom actions
|
||||||
final List<MessageAction> customActions;
|
final List<StreamMessageAction> customActions;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MessageActionsModalState createState() => _MessageActionsModalState();
|
_StreamMessageActionsModalState createState() =>
|
||||||
|
_StreamMessageActionsModalState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MessageActionsModalState extends State<MessageActionsModal> {
|
class _StreamMessageActionsModalState extends State<StreamMessageActionsModal> {
|
||||||
bool _showActions = true;
|
bool _showActions = true;
|
||||||
late List<String> _userPermissions;
|
late List<String> _userPermissions;
|
||||||
late bool _isMyMessage;
|
late bool _isMyMessage;
|
||||||
@@ -159,7 +166,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
: -(1.2 - divFactor)),
|
: -(1.2 - divFactor)),
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
child: ReactionPicker(
|
child: StreamReactionPicker(
|
||||||
message: widget.message,
|
message: widget.message,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -268,7 +275,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
|
|
||||||
InkWell _buildCustomAction(
|
InkWell _buildCustomAction(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
MessageAction messageAction,
|
StreamMessageAction messageAction,
|
||||||
) =>
|
) =>
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -589,7 +596,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
elevation: 2,
|
elevation: 2,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
backgroundColor: MessageInputTheme.of(context).inputBackgroundColor,
|
backgroundColor: StreamMessageInputTheme.of(context).inputBackgroundColor,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(16),
|
topLeft: Radius.circular(16),
|
||||||
@@ -631,7 +638,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
if (widget.editMessageInputBuilder != null)
|
if (widget.editMessageInputBuilder != null)
|
||||||
widget.editMessageInputBuilder!(context, widget.message)
|
widget.editMessageInputBuilder!(context, widget.message)
|
||||||
else
|
else
|
||||||
MessageInput(
|
StreamMessageInput(
|
||||||
messageInputController: MessageInputController(
|
messageInputController: MessageInputController(
|
||||||
message: widget.message,
|
message: widget.message,
|
||||||
),
|
),
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,9 +2,9 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
/// Button for showing visual component of slow mode.
|
/// Button for showing visual component of slow mode.
|
||||||
class CountdownButton extends StatelessWidget {
|
class StreamCountdownButton extends StatelessWidget {
|
||||||
/// Constructor for creating [CountdownButton].
|
/// Constructor for creating [StreamCountdownButton].
|
||||||
const CountdownButton({
|
const StreamCountdownButton({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.count,
|
required this.count,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|||||||
@@ -18,17 +18,13 @@ import 'package:stream_chat_flutter/src/message_input/tld.dart';
|
|||||||
import 'package:stream_chat_flutter/src/multi_overlay.dart';
|
import 'package:stream_chat_flutter/src/multi_overlay.dart';
|
||||||
import 'package:stream_chat_flutter/src/quoted_message_widget.dart';
|
import 'package:stream_chat_flutter/src/quoted_message_widget.dart';
|
||||||
import 'package:stream_chat_flutter/src/user_mentions_overlay.dart';
|
import 'package:stream_chat_flutter/src/user_mentions_overlay.dart';
|
||||||
import 'package:stream_chat_flutter/src/video_service.dart';
|
|
||||||
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:video_compress/video_compress.dart';
|
|
||||||
|
|
||||||
export 'package:video_compress/video_compress.dart' show VideoQuality;
|
|
||||||
|
|
||||||
/// A function that returns true if the message is valid and can be sent.
|
/// A function that returns true if the message is valid and can be sent.
|
||||||
typedef MessageValidator = bool Function(Message message);
|
typedef MessageValidator = bool Function(Message message);
|
||||||
|
|
||||||
/// A callback that can be passed to [MessageInput.onError].
|
/// A callback that can be passed to [StreamMessageInput.onError].
|
||||||
///
|
///
|
||||||
/// This callback should not throw.
|
/// This callback should not throw.
|
||||||
///
|
///
|
||||||
@@ -38,7 +34,7 @@ typedef ErrorListener = void Function(
|
|||||||
StackTrace? stackTrace,
|
StackTrace? stackTrace,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// A callback that can be passed to [MessageInput.onAttachmentLimitExceed].
|
/// A callback that can be passed to [StreamMessageInput.onAttachmentLimitExceed].
|
||||||
///
|
///
|
||||||
/// This callback should not throw.
|
/// This callback should not throw.
|
||||||
///
|
///
|
||||||
@@ -63,7 +59,7 @@ typedef MentionTileBuilder = Widget Function(
|
|||||||
|
|
||||||
/// Builder function for building a user mention tile.
|
/// Builder function for building a user mention tile.
|
||||||
///
|
///
|
||||||
/// Use [UserMentionTile] for the default implementation.
|
/// Use [StreamUserMentionTile] for the default implementation.
|
||||||
typedef UserMentionTileBuilder = Widget Function(
|
typedef UserMentionTileBuilder = Widget Function(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
User user,
|
User user,
|
||||||
@@ -92,7 +88,7 @@ typedef AttachmentsPickerBuilder = Widget Function(
|
|||||||
StreamAttachmentPicker defaultPicker,
|
StreamAttachmentPicker defaultPicker,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Location for actions on the [MessageInput].
|
/// Location for actions on the [StreamMessageInput].
|
||||||
enum ActionsLocation {
|
enum ActionsLocation {
|
||||||
/// Align to left
|
/// Align to left
|
||||||
left,
|
left,
|
||||||
@@ -173,14 +169,14 @@ const _kDefaultMaxAttachmentSize = 20971520; // 20MB in Bytes
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// You usually put this widget in the same page of a [MessageListView]
|
/// You usually put this widget in the same page of a [StreamMessageListView]
|
||||||
/// as the bottom widget.
|
/// as the bottom widget.
|
||||||
///
|
///
|
||||||
/// The widget renders the ui based on the first ancestor of
|
/// The widget renders the ui based on the first ancestor of
|
||||||
/// type [StreamChatTheme]. Modify it to change the widget appearance.
|
/// type [StreamChatTheme]. Modify it to change the widget appearance.
|
||||||
class MessageInput extends StatefulWidget {
|
class StreamMessageInput extends StatefulWidget {
|
||||||
/// Instantiate a new MessageInput
|
/// Instantiate a new MessageInput
|
||||||
const MessageInput({
|
const StreamMessageInput({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.onMessageSent,
|
this.onMessageSent,
|
||||||
this.preMessageSending,
|
this.preMessageSending,
|
||||||
@@ -202,8 +198,6 @@ class MessageInput extends StatefulWidget {
|
|||||||
this.mentionsTileBuilder,
|
this.mentionsTileBuilder,
|
||||||
this.userMentionsTileBuilder,
|
this.userMentionsTileBuilder,
|
||||||
this.maxAttachmentSize = _kDefaultMaxAttachmentSize,
|
this.maxAttachmentSize = _kDefaultMaxAttachmentSize,
|
||||||
this.compressedVideoQuality = VideoQuality.DefaultQuality,
|
|
||||||
this.compressedVideoFrameRate = 30,
|
|
||||||
this.onError,
|
this.onError,
|
||||||
this.attachmentLimit = 10,
|
this.attachmentLimit = 10,
|
||||||
this.onAttachmentLimitExceed,
|
this.onAttachmentLimitExceed,
|
||||||
@@ -224,12 +218,6 @@ class MessageInput extends StatefulWidget {
|
|||||||
/// List of options for showing overlays.
|
/// List of options for showing overlays.
|
||||||
final List<OverlayOptions> customOverlays;
|
final List<OverlayOptions> customOverlays;
|
||||||
|
|
||||||
/// Video quality to use when compressing the videos.
|
|
||||||
final VideoQuality compressedVideoQuality;
|
|
||||||
|
|
||||||
/// Frame rate to use when compressing the videos.
|
|
||||||
final int compressedVideoFrameRate;
|
|
||||||
|
|
||||||
/// Max attachment size in bytes:
|
/// Max attachment size in bytes:
|
||||||
/// - Defaults to 20 MB
|
/// - Defaults to 20 MB
|
||||||
/// - Do not set it if you're using our default CDN
|
/// - Do not set it if you're using our default CDN
|
||||||
@@ -325,7 +313,7 @@ class MessageInput extends StatefulWidget {
|
|||||||
/// Builder for creating send button
|
/// Builder for creating send button
|
||||||
final MessageRelatedBuilder? sendButtonBuilder;
|
final MessageRelatedBuilder? sendButtonBuilder;
|
||||||
|
|
||||||
/// Defines if the [MessageInput] loses focuses after a message is sent.
|
/// Defines if the [StreamMessageInput] loses focuses after a message is sent.
|
||||||
/// The default behaviour keeps focus until a command is enabled.
|
/// The default behaviour keeps focus until a command is enabled.
|
||||||
final bool? shouldKeepFocusAfterMessage;
|
final bool? shouldKeepFocusAfterMessage;
|
||||||
|
|
||||||
@@ -335,25 +323,25 @@ class MessageInput extends StatefulWidget {
|
|||||||
/// Restoration ID to save and restore the state of the MessageInput.
|
/// Restoration ID to save and restore the state of the MessageInput.
|
||||||
final String? restorationId;
|
final String? restorationId;
|
||||||
|
|
||||||
/// Wrap [MessageInput] with a [SafeArea widget]
|
/// Wrap [StreamMessageInput] with a [SafeArea widget]
|
||||||
final bool? enableSafeArea;
|
final bool? enableSafeArea;
|
||||||
|
|
||||||
/// Elevation of the [MessageInput]
|
/// Elevation of the [StreamMessageInput]
|
||||||
final double? elevation;
|
final double? elevation;
|
||||||
|
|
||||||
/// Shadow for the [MessageInput] widget
|
/// Shadow for the [StreamMessageInput] widget
|
||||||
final BoxShadow? shadow;
|
final BoxShadow? shadow;
|
||||||
|
|
||||||
static bool _defaultValidator(Message message) =>
|
static bool _defaultValidator(Message message) =>
|
||||||
message.text?.isNotEmpty == true || message.attachments.isNotEmpty;
|
message.text?.isNotEmpty == true || message.attachments.isNotEmpty;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MessageInputState createState() => MessageInputState();
|
StreamMessageInputState createState() => StreamMessageInputState();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// State of [MessageInput]
|
/// State of [StreamMessageInput]
|
||||||
class MessageInputState extends State<MessageInput>
|
class StreamMessageInputState extends State<StreamMessageInput>
|
||||||
with RestorationMixin<MessageInput> {
|
with RestorationMixin<StreamMessageInput> {
|
||||||
final _imagePicker = ImagePicker();
|
final _imagePicker = ImagePicker();
|
||||||
late FocusNode _focusNode = widget.focusNode ?? FocusNode();
|
late FocusNode _focusNode = widget.focusNode ?? FocusNode();
|
||||||
late final _isInternalFocusNode = widget.focusNode == null;
|
late final _isInternalFocusNode = widget.focusNode == null;
|
||||||
@@ -367,7 +355,7 @@ class MessageInputState extends State<MessageInput>
|
|||||||
bool _openFilePickerSection = false;
|
bool _openFilePickerSection = false;
|
||||||
|
|
||||||
late StreamChatThemeData _streamChatTheme;
|
late StreamChatThemeData _streamChatTheme;
|
||||||
late MessageInputThemeData _messageInputTheme;
|
late StreamMessageInputThemeData _messageInputTheme;
|
||||||
|
|
||||||
bool get _hasQuotedMessage =>
|
bool get _hasQuotedMessage =>
|
||||||
_effectiveController.value.quotedMessage != null;
|
_effectiveController.value.quotedMessage != null;
|
||||||
@@ -410,7 +398,7 @@ class MessageInputState extends State<MessageInput>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(covariant MessageInput oldWidget) {
|
void didUpdateWidget(covariant StreamMessageInput oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
if (widget.messageInputController == null &&
|
if (widget.messageInputController == null &&
|
||||||
oldWidget.messageInputController != null) {
|
oldWidget.messageInputController != null) {
|
||||||
@@ -596,7 +584,7 @@ class MessageInputState extends State<MessageInput>
|
|||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return MultiOverlay(
|
return StreamMultiOverlay(
|
||||||
childAnchor: Alignment.topCenter,
|
childAnchor: Alignment.topCenter,
|
||||||
overlayAnchor: Alignment.bottomCenter,
|
overlayAnchor: Alignment.bottomCenter,
|
||||||
overlayOptions: [
|
overlayOptions: [
|
||||||
@@ -1109,7 +1097,7 @@ class MessageInputState extends State<MessageInput>
|
|||||||
if (renderObject == null) {
|
if (renderObject == null) {
|
||||||
return const Offstage();
|
return const Offstage();
|
||||||
}
|
}
|
||||||
return CommandsOverlay(
|
return StreamCommandsOverlay(
|
||||||
channel: StreamChannel.of(context).channel,
|
channel: StreamChannel.of(context).channel,
|
||||||
size: Size(renderObject.size.width - 16, 400),
|
size: Size(renderObject.size.width - 16, 400),
|
||||||
text: text,
|
text: text,
|
||||||
@@ -1126,8 +1114,6 @@ class MessageInputState extends State<MessageInput>
|
|||||||
attachmentLimit: widget.attachmentLimit,
|
attachmentLimit: widget.attachmentLimit,
|
||||||
onAttachmentLimitExceeded: widget.onAttachmentLimitExceed,
|
onAttachmentLimitExceeded: widget.onAttachmentLimitExceed,
|
||||||
maxAttachmentSize: widget.maxAttachmentSize,
|
maxAttachmentSize: widget.maxAttachmentSize,
|
||||||
compressedVideoQuality: widget.compressedVideoQuality,
|
|
||||||
compressedVideoFrameRate: widget.compressedVideoFrameRate,
|
|
||||||
onError: _showErrorAlert,
|
onError: _showErrorAlert,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1170,7 +1156,7 @@ class MessageInputState extends State<MessageInput>
|
|||||||
}
|
}
|
||||||
|
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, snapshot) => UserMentionsOverlay(
|
builder: (context, snapshot) => StreamUserMentionsOverlay(
|
||||||
query: query,
|
query: query,
|
||||||
mentionAllAppUsers: widget.mentionAllAppUsers,
|
mentionAllAppUsers: widget.mentionAllAppUsers,
|
||||||
client: StreamChat.of(context).client,
|
client: StreamChat.of(context).client,
|
||||||
@@ -1185,10 +1171,10 @@ class MessageInputState extends State<MessageInput>
|
|||||||
splits[splits.length - 1] = user.name;
|
splits[splits.length - 1] = user.name;
|
||||||
final rejoin = splits.join('@');
|
final rejoin = splits.join('@');
|
||||||
|
|
||||||
_effectiveController.text = rejoin +
|
_effectiveController.text =
|
||||||
_effectiveController.text.substring(
|
'$rejoin${_effectiveController.text.substring(
|
||||||
_effectiveController.selectionStart,
|
_effectiveController.selectionStart,
|
||||||
);
|
)}';
|
||||||
|
|
||||||
_onChangedDebounced.cancel();
|
_onChangedDebounced.cancel();
|
||||||
setState(() => _showMentionsOverlay = false);
|
setState(() => _showMentionsOverlay = false);
|
||||||
@@ -1210,7 +1196,7 @@ class MessageInputState extends State<MessageInput>
|
|||||||
// ignore: cast_nullable_to_non_nullable
|
// ignore: cast_nullable_to_non_nullable
|
||||||
final renderObject = context.findRenderObject() as RenderBox;
|
final renderObject = context.findRenderObject() as RenderBox;
|
||||||
|
|
||||||
return EmojiOverlay(
|
return StreamEmojiOverlay(
|
||||||
size: Size(renderObject.size.width - 16, 200),
|
size: Size(renderObject.size.width - 16, 200),
|
||||||
query: query,
|
query: query,
|
||||||
onEmojiResult: (emoji) {
|
onEmojiResult: (emoji) {
|
||||||
@@ -1241,7 +1227,7 @@ class MessageInputState extends State<MessageInput>
|
|||||||
if (!_hasQuotedMessage) return const Offstage();
|
if (!_hasQuotedMessage) return const Offstage();
|
||||||
final containsUrl = _effectiveController.value.quotedMessage!.attachments
|
final containsUrl = _effectiveController.value.quotedMessage!.attachments
|
||||||
.any((element) => element.titleLink != null);
|
.any((element) => element.titleLink != null);
|
||||||
return QuotedMessageWidget(
|
return StreamQuotedMessageWidget(
|
||||||
reverse: true,
|
reverse: true,
|
||||||
showBorder: !containsUrl,
|
showBorder: !containsUrl,
|
||||||
message: _effectiveController.value.quotedMessage!,
|
message: _effectiveController.value.quotedMessage!,
|
||||||
@@ -1275,7 +1261,7 @@ class MessageInputState extends State<MessageInput>
|
|||||||
.map<Widget>(
|
.map<Widget>(
|
||||||
(e) => ClipRRect(
|
(e) => ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
child: FileAttachment(
|
child: StreamFileAttachment(
|
||||||
message: Message(), // dummy message
|
message: Message(), // dummy message
|
||||||
attachment: e,
|
attachment: e,
|
||||||
size: Size(
|
size: Size(
|
||||||
@@ -1397,7 +1383,7 @@ class MessageInputState extends State<MessageInput>
|
|||||||
case 'video':
|
case 'video':
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
VideoThumbnailImage(
|
StreamVideoThumbnailImage(
|
||||||
height: 104,
|
height: 104,
|
||||||
width: 104,
|
width: 104,
|
||||||
video: (attachment.file?.path ?? attachment.assetUrl)!,
|
video: (attachment.file?.path ?? attachment.assetUrl)!,
|
||||||
@@ -1639,33 +1625,11 @@ class MessageInputState extends State<MessageInput>
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (file.size! > widget.maxAttachmentSize) {
|
if (file.size! > widget.maxAttachmentSize) {
|
||||||
if (attachmentType == 'video' && file.path != null) {
|
return _showErrorAlert(
|
||||||
final mediaInfo = await (VideoService.compressVideo(
|
context.translations.fileTooLargeError(
|
||||||
file.path!,
|
|
||||||
frameRate: widget.compressedVideoFrameRate,
|
|
||||||
quality: widget.compressedVideoQuality,
|
|
||||||
) as FutureOr<MediaInfo>);
|
|
||||||
|
|
||||||
if (mediaInfo.filesize! > widget.maxAttachmentSize) {
|
|
||||||
_showErrorAlert(
|
|
||||||
context.translations.fileTooLargeAfterCompressionError(
|
|
||||||
widget.maxAttachmentSize / (1024 * 1024),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
file = AttachmentFile(
|
|
||||||
name: file.name,
|
|
||||||
size: mediaInfo.filesize,
|
|
||||||
bytes: await mediaInfo.file!.readAsBytes(),
|
|
||||||
path: mediaInfo.path,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
_showErrorAlert(context.translations.fileTooLargeError(
|
|
||||||
widget.maxAttachmentSize / (1024 * 1024),
|
widget.maxAttachmentSize / (1024 * 1024),
|
||||||
));
|
),
|
||||||
return;
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_addAttachments([
|
_addAttachments([
|
||||||
@@ -1715,6 +1679,8 @@ class MessageInputState extends State<MessageInput>
|
|||||||
await streamChannel.reloadChannel();
|
await streamChannel.reloadChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message = message.replaceMentionsWithId();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Future sendingFuture;
|
Future sendingFuture;
|
||||||
if (_isEditing) {
|
if (_isEditing) {
|
||||||
@@ -1831,7 +1797,7 @@ class MessageInputState extends State<MessageInput>
|
|||||||
@override
|
@override
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
_streamChatTheme = StreamChatTheme.of(context);
|
_streamChatTheme = StreamChatTheme.of(context);
|
||||||
_messageInputTheme = MessageInputTheme.of(context);
|
_messageInputTheme = StreamMessageInputTheme.of(context);
|
||||||
|
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ import 'package:flutter_svg/flutter_svg.dart';
|
|||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/src/media_list_view.dart';
|
import 'package:stream_chat_flutter/src/media_list_view.dart';
|
||||||
import 'package:stream_chat_flutter/src/video_service.dart';
|
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:video_compress/video_compress.dart';
|
|
||||||
|
|
||||||
/// Callback for when a file has to be picked.
|
/// Callback for when a file has to be picked.
|
||||||
typedef FilePickerCallback = void Function(
|
typedef FilePickerCallback = void Function(
|
||||||
@@ -34,8 +32,6 @@ class StreamAttachmentPicker extends StatefulWidget {
|
|||||||
this.attachmentLimit = 10,
|
this.attachmentLimit = 10,
|
||||||
this.onAttachmentLimitExceeded,
|
this.onAttachmentLimitExceeded,
|
||||||
this.maxAttachmentSize = 20971520,
|
this.maxAttachmentSize = 20971520,
|
||||||
this.compressedVideoQuality = VideoQuality.DefaultQuality,
|
|
||||||
this.compressedVideoFrameRate = 30,
|
|
||||||
this.onError,
|
this.onError,
|
||||||
this.allowedAttachmentTypes = const [
|
this.allowedAttachmentTypes = const [
|
||||||
DefaultAttachmentTypes.image,
|
DefaultAttachmentTypes.image,
|
||||||
@@ -66,12 +62,6 @@ class StreamAttachmentPicker extends StatefulWidget {
|
|||||||
/// Callback for when file is picked.
|
/// Callback for when file is picked.
|
||||||
final FilePickerCallback onFilePicked;
|
final FilePickerCallback onFilePicked;
|
||||||
|
|
||||||
/// Video quality to use when compressing the videos.
|
|
||||||
final VideoQuality compressedVideoQuality;
|
|
||||||
|
|
||||||
/// Frame rate to use when compressing the videos.
|
|
||||||
final int compressedVideoFrameRate;
|
|
||||||
|
|
||||||
/// Max attachment size in bytes:
|
/// Max attachment size in bytes:
|
||||||
/// - Defaults to 20 MB
|
/// - Defaults to 20 MB
|
||||||
/// - Do not set it if you're using our default CDN
|
/// - Do not set it if you're using our default CDN
|
||||||
@@ -94,8 +84,6 @@ class StreamAttachmentPicker extends StatefulWidget {
|
|||||||
int? attachmentLimit,
|
int? attachmentLimit,
|
||||||
AttachmentLimitExceedListener? onAttachmentLimitExceeded,
|
AttachmentLimitExceedListener? onAttachmentLimitExceeded,
|
||||||
int? maxAttachmentSize,
|
int? maxAttachmentSize,
|
||||||
VideoQuality? compressedVideoQuality,
|
|
||||||
int? compressedVideoFrameRate,
|
|
||||||
ValueChanged<bool>? onChangeInputState,
|
ValueChanged<bool>? onChangeInputState,
|
||||||
ValueChanged<String>? onError,
|
ValueChanged<String>? onError,
|
||||||
List<DefaultAttachmentTypes>? allowedAttachmentTypes,
|
List<DefaultAttachmentTypes>? allowedAttachmentTypes,
|
||||||
@@ -112,10 +100,6 @@ class StreamAttachmentPicker extends StatefulWidget {
|
|||||||
onAttachmentLimitExceeded:
|
onAttachmentLimitExceeded:
|
||||||
onAttachmentLimitExceeded ?? this.onAttachmentLimitExceeded,
|
onAttachmentLimitExceeded ?? this.onAttachmentLimitExceeded,
|
||||||
maxAttachmentSize: maxAttachmentSize ?? this.maxAttachmentSize,
|
maxAttachmentSize: maxAttachmentSize ?? this.maxAttachmentSize,
|
||||||
compressedVideoQuality:
|
|
||||||
compressedVideoQuality ?? this.compressedVideoQuality,
|
|
||||||
compressedVideoFrameRate:
|
|
||||||
compressedVideoFrameRate ?? this.compressedVideoFrameRate,
|
|
||||||
onError: onError ?? this.onError,
|
onError: onError ?? this.onError,
|
||||||
allowedAttachmentTypes:
|
allowedAttachmentTypes:
|
||||||
allowedAttachmentTypes ?? this.allowedAttachmentTypes,
|
allowedAttachmentTypes ?? this.allowedAttachmentTypes,
|
||||||
@@ -375,33 +359,11 @@ class _StreamAttachmentPickerState extends State<StreamAttachmentPicker> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (file.size! > widget.maxAttachmentSize) {
|
if (file.size! > widget.maxAttachmentSize) {
|
||||||
if (medium.type == AssetType.video && file.path != null) {
|
return widget.onError?.call(
|
||||||
final mediaInfo = await (VideoService.compressVideo(
|
context.translations.fileTooLargeError(
|
||||||
file.path!,
|
|
||||||
frameRate: widget.compressedVideoFrameRate,
|
|
||||||
quality: widget.compressedVideoQuality,
|
|
||||||
) as FutureOr<MediaInfo>);
|
|
||||||
|
|
||||||
if (mediaInfo.filesize! > widget.maxAttachmentSize) {
|
|
||||||
widget.onError?.call(
|
|
||||||
context.translations.fileTooLargeAfterCompressionError(
|
|
||||||
widget.maxAttachmentSize / (1024 * 1024),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
file = AttachmentFile(
|
|
||||||
name: file.name,
|
|
||||||
size: mediaInfo.filesize,
|
|
||||||
bytes: await mediaInfo.file?.readAsBytes(),
|
|
||||||
path: mediaInfo.path,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
widget.onError?.call(context.translations.fileTooLargeError(
|
|
||||||
widget.maxAttachmentSize / (1024 * 1024),
|
widget.maxAttachmentSize / (1024 * 1024),
|
||||||
));
|
),
|
||||||
return;
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -507,7 +469,7 @@ class _PickerWidgetState extends State<_PickerWidget> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return MediaListView(
|
return StreamMediaListView(
|
||||||
selectedIds: widget.selectedMedias,
|
selectedIds: widget.selectedMedias,
|
||||||
onSelect: widget.onMediaSelected,
|
onSelect: widget.onMediaSelected,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class StreamMessageSendButton extends StatelessWidget {
|
|||||||
|
|
||||||
late Widget sendButton;
|
late Widget sendButton;
|
||||||
if (timeOut > 0) {
|
if (timeOut > 0) {
|
||||||
sendButton = CountdownButton(count: timeOut);
|
sendButton = StreamCountdownButton(count: timeOut);
|
||||||
} else if (isIdle) {
|
} else if (isIdle) {
|
||||||
sendButton = idleSendButton ?? _buildIdleSendButton(context);
|
sendButton = idleSendButton ?? _buildIdleSendButton(context);
|
||||||
} else {
|
} else {
|
||||||
@@ -63,7 +63,7 @@ class StreamMessageSendButton extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildIdleSendButton(BuildContext context) {
|
Widget _buildIdleSendButton(BuildContext context) {
|
||||||
final _messageInputTheme = MessageInputTheme.of(context);
|
final _messageInputTheme = StreamMessageInputTheme.of(context);
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
@@ -75,7 +75,7 @@ class StreamMessageSendButton extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSendButton(BuildContext context) {
|
Widget _buildSendButton(BuildContext context) {
|
||||||
final _messageInputTheme = MessageInputTheme.of(context);
|
final _messageInputTheme = StreamMessageInputTheme.of(context);
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
|
|||||||
@@ -11,22 +11,22 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
import 'package:visibility_detector/visibility_detector.dart';
|
import 'package:visibility_detector/visibility_detector.dart';
|
||||||
|
|
||||||
/// Widget builder for message
|
/// Widget builder for message
|
||||||
/// [defaultMessageWidget] is the default [MessageWidget] configuration
|
/// [defaultMessageWidget] is the default [StreamMessageWidget] configuration
|
||||||
/// Use [defaultMessageWidget.copyWith] to easily customize it
|
/// Use [defaultMessageWidget.copyWith] to easily customize it
|
||||||
typedef MessageBuilder = Widget Function(
|
typedef MessageBuilder = Widget Function(
|
||||||
BuildContext,
|
BuildContext,
|
||||||
MessageDetails,
|
MessageDetails,
|
||||||
List<Message>,
|
List<Message>,
|
||||||
MessageWidget defaultMessageWidget,
|
StreamMessageWidget defaultMessageWidget,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Widget builder for parent message
|
/// Widget builder for parent message
|
||||||
/// [defaultMessageWidget] is the default [MessageWidget] configuration
|
/// [defaultMessageWidget] is the default [StreamMessageWidget] configuration
|
||||||
/// Use [defaultMessageWidget.copyWith] to easily customize it
|
/// Use [defaultMessageWidget.copyWith] to easily customize it
|
||||||
typedef ParentMessageBuilder = Widget Function(
|
typedef ParentMessageBuilder = Widget Function(
|
||||||
BuildContext,
|
BuildContext,
|
||||||
Message?,
|
Message?,
|
||||||
MessageWidget defaultMessageWidget,
|
StreamMessageWidget defaultMessageWidget,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Widget builder for system message
|
/// Widget builder for system message
|
||||||
@@ -123,6 +123,11 @@ class MessageDetails {
|
|||||||
final int index;
|
final int index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro message_list_view}
|
||||||
|
@Deprecated("Use 'StreamMessageListView' instead")
|
||||||
|
typedef MessageListView = StreamMessageListView;
|
||||||
|
|
||||||
|
/// {@template message_list_view}
|
||||||
/// 
|
/// 
|
||||||
/// 
|
/// 
|
||||||
///
|
///
|
||||||
@@ -165,9 +170,10 @@ class MessageDetails {
|
|||||||
/// The widget components render the ui based on the first
|
/// The widget components render the ui based on the first
|
||||||
/// ancestor of type [StreamChatTheme].
|
/// ancestor of type [StreamChatTheme].
|
||||||
/// Modify it to change the widget appearance.
|
/// Modify it to change the widget appearance.
|
||||||
class MessageListView extends StatefulWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamMessageListView extends StatefulWidget {
|
||||||
/// Instantiate a new MessageListView
|
/// Instantiate a new MessageListView
|
||||||
const MessageListView({
|
const StreamMessageListView({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.showScrollToBottom = true,
|
this.showScrollToBottom = true,
|
||||||
this.messageBuilder,
|
this.messageBuilder,
|
||||||
@@ -330,10 +336,10 @@ class MessageListView extends StatefulWidget {
|
|||||||
final SpacingWidgetBuilder? spacingWidgetBuilder;
|
final SpacingWidgetBuilder? spacingWidgetBuilder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MessageListViewState createState() => _MessageListViewState();
|
_StreamMessageListViewState createState() => _StreamMessageListViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MessageListViewState extends State<MessageListView> {
|
class _StreamMessageListViewState extends State<StreamMessageListView> {
|
||||||
ItemScrollController? _scrollController;
|
ItemScrollController? _scrollController;
|
||||||
void Function(Message)? _onThreadTap;
|
void Function(Message)? _onThreadTap;
|
||||||
final ValueNotifier<bool> _showScrollToBottom = ValueNotifier(false);
|
final ValueNotifier<bool> _showScrollToBottom = ValueNotifier(false);
|
||||||
@@ -461,7 +467,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
final child = Stack(
|
final child = Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
ConnectionStatusBuilder(
|
StreamConnectionStatusBuilder(
|
||||||
statusBuilder: (context, status) {
|
statusBuilder: (context, status) {
|
||||||
var statusString = '';
|
var statusString = '';
|
||||||
var showStatus = true;
|
var showStatus = true;
|
||||||
@@ -478,7 +484,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return InfoTile(
|
return StreamInfoTile(
|
||||||
showMessage: widget.showConnectionStateTile && showStatus,
|
showMessage: widget.showConnectionStateTile && showStatus,
|
||||||
tileAnchor: Alignment.topCenter,
|
tileAnchor: Alignment.topCenter,
|
||||||
childAnchor: Alignment.topCenter,
|
childAnchor: Alignment.topCenter,
|
||||||
@@ -592,7 +598,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
)
|
)
|
||||||
: Padding(
|
: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
child: DateDivider(
|
child: StreamDateDivider(
|
||||||
dateTime: nextMessage.createdAt.toLocal(),
|
dateTime: nextMessage.createdAt.toLocal(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -730,8 +736,10 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
final backgroundColor = MessageListViewTheme.of(context).backgroundColor;
|
final backgroundColor =
|
||||||
final backgroundImage = MessageListViewTheme.of(context).backgroundImage;
|
StreamMessageListViewTheme.of(context).backgroundColor;
|
||||||
|
final backgroundImage =
|
||||||
|
StreamMessageListViewTheme.of(context).backgroundImage;
|
||||||
|
|
||||||
if (backgroundColor != null || backgroundImage != null) {
|
if (backgroundColor != null || backgroundImage != null) {
|
||||||
return Container(
|
return Container(
|
||||||
@@ -761,7 +769,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
context.translations.threadSeparatorText(replyCount),
|
context.translations.threadSeparatorText(replyCount),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: ChannelHeaderTheme.of(context).subtitleStyle,
|
style: StreamChannelHeaderTheme.of(context).subtitleStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -815,7 +823,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
final message = messages[index - 2];
|
final message = messages[index - 2];
|
||||||
return widget.dateDividerBuilder != null
|
return widget.dateDividerBuilder != null
|
||||||
? widget.dateDividerBuilder!(message.createdAt.toLocal())
|
? widget.dateDividerBuilder!(message.createdAt.toLocal())
|
||||||
: DateDivider(dateTime: message.createdAt.toLocal());
|
: StreamDateDivider(dateTime: message.createdAt.toLocal());
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -976,7 +984,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
final currentUserMember =
|
final currentUserMember =
|
||||||
members.firstWhereOrNull((e) => e.user!.id == currentUser!.id);
|
members.firstWhereOrNull((e) => e.user!.id == currentUser!.id);
|
||||||
|
|
||||||
final defaultMessageWidget = MessageWidget(
|
final defaultMessageWidget = StreamMessageWidget(
|
||||||
showReplyMessage: false,
|
showReplyMessage: false,
|
||||||
showResendMessage: false,
|
showResendMessage: false,
|
||||||
showThreadReplyMessage: false,
|
showThreadReplyMessage: false,
|
||||||
@@ -1040,7 +1048,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
if ((message.type == 'system' || message.type == 'error') &&
|
if ((message.type == 'system' || message.type == 'error') &&
|
||||||
message.text?.isNotEmpty == true) {
|
message.text?.isNotEmpty == true) {
|
||||||
return widget.systemMessageBuilder?.call(context, message) ??
|
return widget.systemMessageBuilder?.call(context, message) ??
|
||||||
SystemMessage(
|
StreamSystemMessage(
|
||||||
message: message,
|
message: message,
|
||||||
onMessageTap: (message) {
|
onMessageTap: (message) {
|
||||||
if (widget.onSystemMessageTap != null) {
|
if (widget.onSystemMessageTap != null) {
|
||||||
@@ -1110,7 +1118,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
final currentUserMember =
|
final currentUserMember =
|
||||||
members.firstWhereOrNull((e) => e.user!.id == currentUser!.id);
|
members.firstWhereOrNull((e) => e.user!.id == currentUser!.id);
|
||||||
|
|
||||||
Widget messageWidget = MessageWidget(
|
Widget messageWidget = StreamMessageWidget(
|
||||||
message: message,
|
message: message,
|
||||||
reverse: isMyMessage,
|
reverse: isMyMessage,
|
||||||
showReactions: !message.isDeleted,
|
showReactions: !message.isDeleted,
|
||||||
@@ -1226,7 +1234,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
index,
|
index,
|
||||||
),
|
),
|
||||||
messages,
|
messages,
|
||||||
messageWidget as MessageWidget,
|
messageWidget as StreamMessageWidget,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,16 @@ import 'package:stream_chat_flutter/src/extension.dart';
|
|||||||
import 'package:stream_chat_flutter/src/reaction_bubble.dart';
|
import 'package:stream_chat_flutter/src/reaction_bubble.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro message_reactions_modal}
|
||||||
|
@Deprecated("Use 'StreamMessageReactionsModal' instead")
|
||||||
|
typedef MessageReactionsModal = StreamMessageReactionsModal;
|
||||||
|
|
||||||
|
/// {@template message_reactions_modal}
|
||||||
/// Modal widget for displaying message reactions
|
/// Modal widget for displaying message reactions
|
||||||
class MessageReactionsModal extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [MessageReactionsModal] reactions
|
class StreamMessageReactionsModal extends StatelessWidget {
|
||||||
const MessageReactionsModal({
|
/// Constructor for creating a [StreamMessageReactionsModal] reactions
|
||||||
|
const StreamMessageReactionsModal({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.messageWidget,
|
required this.messageWidget,
|
||||||
@@ -24,8 +30,8 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
/// Message to display reactions of
|
/// Message to display reactions of
|
||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
/// [MessageThemeData] to apply to [message]
|
/// [StreamMessageThemeData] to apply to [message]
|
||||||
final MessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|
||||||
/// Flag to reverse message
|
/// Flag to reverse message
|
||||||
final bool reverse;
|
final bool reverse;
|
||||||
@@ -88,7 +94,7 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
: -(1.2 - divFactor)),
|
: -(1.2 - divFactor)),
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
child: ReactionPicker(
|
child: StreamReactionPicker(
|
||||||
message: message,
|
message: message,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -200,7 +206,7 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
Stack(
|
Stack(
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
UserAvatar(
|
StreamUserAvatar(
|
||||||
onTap: onUserAvatarTap,
|
onTap: onUserAvatarTap,
|
||||||
user: reaction.user!,
|
user: reaction.user!,
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
@@ -220,7 +226,7 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
child: Align(
|
child: Align(
|
||||||
alignment:
|
alignment:
|
||||||
reverse ? Alignment.centerRight : Alignment.centerLeft,
|
reverse ? Alignment.centerRight : Alignment.centerLeft,
|
||||||
child: ReactionBubble(
|
child: StreamReactionBubble(
|
||||||
reactions: [reaction],
|
reactions: [reaction],
|
||||||
flipTail: !reverse,
|
flipTail: !reverse,
|
||||||
borderColor:
|
borderColor:
|
||||||
|
|||||||
@@ -2,17 +2,23 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro message_search_item}
|
||||||
|
@Deprecated("Use 'StreamMessageSearchItem' instead")
|
||||||
|
typedef MessageSearchItem = StreamMessageSearchItem;
|
||||||
|
|
||||||
|
/// {@template message_search_item}
|
||||||
/// It shows the current [Message] preview.
|
/// It shows the current [Message] preview.
|
||||||
///
|
///
|
||||||
/// Usually you don't use this widget as it's the default item used by
|
/// Usually you don't use this widget as it's the default item used by
|
||||||
/// [MessageSearchListView].
|
/// [StreamMessageSearchListView].
|
||||||
///
|
///
|
||||||
/// The widget renders the ui based on the first ancestor of type
|
/// The widget renders the ui based on the first ancestor of type
|
||||||
/// [StreamChatTheme].
|
/// [StreamChatTheme].
|
||||||
/// Modify it to change the widget appearance.
|
/// Modify it to change the widget appearance.
|
||||||
class MessageSearchItem extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamMessageSearchItem extends StatelessWidget {
|
||||||
/// Instantiate a new MessageSearchItem
|
/// Instantiate a new MessageSearchItem
|
||||||
const MessageSearchItem({
|
const StreamMessageSearchItem({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.getMessageResponse,
|
required this.getMessageResponse,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
@@ -25,7 +31,7 @@ class MessageSearchItem extends StatelessWidget {
|
|||||||
/// Function called when tapping this widget
|
/// Function called when tapping this widget
|
||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
|
|
||||||
/// If true the [MessageSearchItem] will show the current online Status
|
/// If true the [StreamMessageSearchItem] will show the current online Status
|
||||||
final bool showOnlineStatus;
|
final bool showOnlineStatus;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -34,10 +40,10 @@ class MessageSearchItem extends StatelessWidget {
|
|||||||
final channel = getMessageResponse.channel;
|
final channel = getMessageResponse.channel;
|
||||||
final channelName = channel?.extraData['name'];
|
final channelName = channel?.extraData['name'];
|
||||||
final user = message.user!;
|
final user = message.user!;
|
||||||
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
final channelPreviewTheme = StreamChannelPreviewTheme.of(context);
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
leading: UserAvatar(
|
leading: StreamUserAvatar(
|
||||||
user: user,
|
user: user,
|
||||||
showOnlineStatus: showOnlineStatus,
|
showOnlineStatus: showOnlineStatus,
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
@@ -120,7 +126,7 @@ class MessageSearchItem extends StatelessWidget {
|
|||||||
text = parts.join(' ');
|
text = parts.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
final channelPreviewTheme = StreamChannelPreviewTheme.of(context);
|
||||||
return Text.rich(
|
return Text.rich(
|
||||||
_getDisplayText(
|
_getDisplayText(
|
||||||
text!,
|
text!,
|
||||||
|
|||||||
@@ -11,13 +11,17 @@ typedef MessageSearchItemBuilder = Widget Function(
|
|||||||
GetMessageResponse,
|
GetMessageResponse,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Builder used when [MessageSearchListView] is empty
|
/// Builder used when [StreamMessageSearchListView] is empty
|
||||||
typedef EmptyMessageSearchBuilder = Widget Function(
|
typedef EmptyMessageSearchBuilder = Widget Function(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
String searchQuery,
|
String searchQuery,
|
||||||
);
|
);
|
||||||
|
|
||||||
///
|
/// {@macro message_search_list_view}
|
||||||
|
@Deprecated("Use 'StreamMessageSearchListView' instead")
|
||||||
|
typedef MessageSearchListView = StreamMessageSearchListView;
|
||||||
|
|
||||||
|
/// {@template message_search_list_view}
|
||||||
/// It shows the list of searched messages.
|
/// It shows the list of searched messages.
|
||||||
///
|
///
|
||||||
/// ```dart
|
/// ```dart
|
||||||
@@ -47,9 +51,10 @@ typedef EmptyMessageSearchBuilder = Widget Function(
|
|||||||
/// The widget components render the ui based on the first ancestor of type
|
/// The widget components render the ui based on the first ancestor of type
|
||||||
/// [StreamChatTheme].
|
/// [StreamChatTheme].
|
||||||
/// Modify it to change the widget appearance.
|
/// Modify it to change the widget appearance.
|
||||||
class MessageSearchListView extends StatefulWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamMessageSearchListView extends StatefulWidget {
|
||||||
/// Instantiate a new MessageSearchListView
|
/// Instantiate a new MessageSearchListView
|
||||||
const MessageSearchListView({
|
const StreamMessageSearchListView({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.filters,
|
required this.filters,
|
||||||
this.messageQuery,
|
this.messageQuery,
|
||||||
@@ -96,7 +101,7 @@ class MessageSearchListView extends StatefulWidget {
|
|||||||
/// Builder used to create a custom item preview
|
/// Builder used to create a custom item preview
|
||||||
final MessageSearchItemBuilder? itemBuilder;
|
final MessageSearchItemBuilder? itemBuilder;
|
||||||
|
|
||||||
/// Function called when tapping on a [MessageSearchItem]
|
/// Function called when tapping on a [StreamMessageSearchItem]
|
||||||
final MessageSearchItemTapCallback? onItemTap;
|
final MessageSearchItemTapCallback? onItemTap;
|
||||||
|
|
||||||
/// Builder used to create a custom item separator
|
/// Builder used to create a custom item separator
|
||||||
@@ -130,10 +135,12 @@ class MessageSearchListView extends StatefulWidget {
|
|||||||
final MessageSearchListController? messageSearchListController;
|
final MessageSearchListController? messageSearchListController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MessageSearchListViewState createState() => _MessageSearchListViewState();
|
_StreamMessageSearchListViewState createState() =>
|
||||||
|
_StreamMessageSearchListViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MessageSearchListViewState extends State<MessageSearchListView> {
|
class _StreamMessageSearchListViewState
|
||||||
|
extends State<StreamMessageSearchListView> {
|
||||||
late final _defaultController = MessageSearchListController();
|
late final _defaultController = MessageSearchListController();
|
||||||
|
|
||||||
MessageSearchListController get _messageSearchListController =>
|
MessageSearchListController get _messageSearchListController =>
|
||||||
@@ -168,7 +175,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
|||||||
if (error is Error) {
|
if (error is Error) {
|
||||||
print(error.stackTrace);
|
print(error.stackTrace);
|
||||||
}
|
}
|
||||||
return InfoTile(
|
return StreamInfoTile(
|
||||||
showMessage: widget.showErrorTile,
|
showMessage: widget.showErrorTile,
|
||||||
tileAnchor: Alignment.topCenter,
|
tileAnchor: Alignment.topCenter,
|
||||||
childAnchor: Alignment.topCenter,
|
childAnchor: Alignment.topCenter,
|
||||||
@@ -195,7 +202,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
final backgroundColor =
|
final backgroundColor =
|
||||||
MessageSearchListViewTheme.of(context).backgroundColor;
|
StreamMessageSearchListViewTheme.of(context).backgroundColor;
|
||||||
|
|
||||||
if (backgroundColor != null) {
|
if (backgroundColor != null) {
|
||||||
return ColoredBox(
|
return ColoredBox(
|
||||||
@@ -219,7 +226,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
|
|||||||
if (widget.itemBuilder != null) {
|
if (widget.itemBuilder != null) {
|
||||||
return widget.itemBuilder!(context, getMessageResponse);
|
return widget.itemBuilder!(context, getMessageResponse);
|
||||||
}
|
}
|
||||||
return MessageSearchItem(
|
return StreamMessageSearchItem(
|
||||||
getMessageResponse: getMessageResponse,
|
getMessageResponse: getMessageResponse,
|
||||||
onTap: () => widget.onItemTap!(getMessageResponse),
|
onTap: () => widget.onItemTap!(getMessageResponse),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
import 'package:collection/collection.dart' show IterableExtension;
|
import 'package:collection/collection.dart' show IterableExtension;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro message_text}
|
||||||
|
@Deprecated("Use 'StreamMessageText' instead")
|
||||||
|
typedef MessageText = StreamMessageText;
|
||||||
|
|
||||||
|
/// {@template message_text}
|
||||||
/// Text widget to display in message
|
/// Text widget to display in message
|
||||||
class MessageText extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [MessageText] widget
|
class StreamMessageText extends StatelessWidget {
|
||||||
const MessageText({
|
/// Constructor for creating a [StreamMessageText] widget
|
||||||
|
const StreamMessageText({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
@@ -23,8 +30,8 @@ class MessageText extends StatelessWidget {
|
|||||||
/// Callback for when link is tapped
|
/// Callback for when link is tapped
|
||||||
final void Function(String)? onLinkTap;
|
final void Function(String)? onLinkTap;
|
||||||
|
|
||||||
/// [MessageThemeData] whose text theme is to be applied
|
/// [StreamMessageThemeData] whose text theme is to be applied
|
||||||
final MessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -34,13 +41,14 @@ class MessageText extends StatelessWidget {
|
|||||||
stream: streamChat.currentUserStream.map((it) => it!.language ?? 'en'),
|
stream: streamChat.currentUserStream.map((it) => it!.language ?? 'en'),
|
||||||
initialData: streamChat.currentUser!.language ?? 'en',
|
initialData: streamChat.currentUser!.language ?? 'en',
|
||||||
builder: (context, language) {
|
builder: (context, language) {
|
||||||
final translatedText =
|
final messageText = message
|
||||||
message.i18n?['${language}_text'] ?? message.text;
|
.translate(language)
|
||||||
final messageText =
|
.replaceMentions()
|
||||||
_replaceMentions(translatedText ?? '').replaceAll('\n', '\n\n');
|
.text
|
||||||
|
?.replaceAll('\n', '\n\n');
|
||||||
final themeData = Theme.of(context);
|
final themeData = Theme.of(context);
|
||||||
return MarkdownBody(
|
return MarkdownBody(
|
||||||
data: messageText,
|
data: messageText ?? '',
|
||||||
onTapLink: (
|
onTapLink: (
|
||||||
String link,
|
String link,
|
||||||
String? href,
|
String? href,
|
||||||
@@ -80,17 +88,4 @@ class MessageText extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String _replaceMentions(String text) {
|
|
||||||
var messageTextToRender = text;
|
|
||||||
for (final user in message.mentionedUsers.toSet()) {
|
|
||||||
final userId = user.id;
|
|
||||||
final userName = user.name;
|
|
||||||
messageTextToRender = messageTextToRender.replaceAll(
|
|
||||||
'@$userId',
|
|
||||||
'[@$userName](@${userName.replaceAll(' ', '')})',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return messageTextToRender;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,20 +32,26 @@ enum DisplayWidget {
|
|||||||
show,
|
show,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro message_widget}
|
||||||
|
@Deprecated("Use 'StreamMessageWidget' instead")
|
||||||
|
typedef MessageWidget = StreamMessageWidget;
|
||||||
|
|
||||||
|
/// {@template message_widget}
|
||||||
/// 
|
/// 
|
||||||
/// 
|
/// 
|
||||||
///
|
///
|
||||||
/// It shows a message with reactions, replies and user avatar.
|
/// 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
|
/// Usually you don't use this widget as it's the default message widget used by
|
||||||
/// [MessageListView].
|
/// [StreamMessageListView].
|
||||||
///
|
///
|
||||||
/// The widget components render the ui based on the first ancestor of type
|
/// The widget components render the ui based on the first ancestor of type
|
||||||
/// [StreamChatTheme].
|
/// [StreamChatTheme].
|
||||||
/// Modify it to change the widget appearance.
|
/// Modify it to change the widget appearance.
|
||||||
class MessageWidget extends StatefulWidget {
|
/// {@endtemplate}
|
||||||
///
|
class StreamMessageWidget extends StatefulWidget {
|
||||||
MessageWidget({
|
/// Creates a new instance of the message widget.
|
||||||
|
StreamMessageWidget({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
@@ -121,7 +127,7 @@ class MessageWidget extends StatefulWidget {
|
|||||||
context,
|
context,
|
||||||
Material(
|
Material(
|
||||||
color: messageTheme.messageBackgroundColor,
|
color: messageTheme.messageBackgroundColor,
|
||||||
child: ImageGroup(
|
child: StreamImageGroup(
|
||||||
size: Size(
|
size: Size(
|
||||||
mediaQueryData.size.width * 0.8,
|
mediaQueryData.size.width * 0.8,
|
||||||
mediaQueryData.size.height * 0.3,
|
mediaQueryData.size.height * 0.3,
|
||||||
@@ -142,7 +148,7 @@ class MessageWidget extends StatefulWidget {
|
|||||||
|
|
||||||
return wrapAttachmentWidget(
|
return wrapAttachmentWidget(
|
||||||
context,
|
context,
|
||||||
ImageAttachment(
|
StreamImageAttachment(
|
||||||
attachment: attachments[0],
|
attachment: attachments[0],
|
||||||
message: message,
|
message: message,
|
||||||
messageTheme: messageTheme,
|
messageTheme: messageTheme,
|
||||||
@@ -172,7 +178,7 @@ class MessageWidget extends StatefulWidget {
|
|||||||
Column(
|
Column(
|
||||||
children: attachments.map((attachment) {
|
children: attachments.map((attachment) {
|
||||||
final mediaQueryData = MediaQuery.of(context);
|
final mediaQueryData = MediaQuery.of(context);
|
||||||
return VideoAttachment(
|
return StreamVideoAttachment(
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
messageTheme: messageTheme,
|
messageTheme: messageTheme,
|
||||||
size: Size(
|
size: Size(
|
||||||
@@ -204,7 +210,7 @@ class MessageWidget extends StatefulWidget {
|
|||||||
Column(
|
Column(
|
||||||
children: attachments.map((attachment) {
|
children: attachments.map((attachment) {
|
||||||
final mediaQueryData = MediaQuery.of(context);
|
final mediaQueryData = MediaQuery.of(context);
|
||||||
return GiphyAttachment(
|
return StreamGiphyAttachment(
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
message: message,
|
message: message,
|
||||||
size: Size(
|
size: Size(
|
||||||
@@ -240,7 +246,7 @@ class MessageWidget extends StatefulWidget {
|
|||||||
final mediaQueryData = MediaQuery.of(context);
|
final mediaQueryData = MediaQuery.of(context);
|
||||||
return wrapAttachmentWidget(
|
return wrapAttachmentWidget(
|
||||||
context,
|
context,
|
||||||
FileAttachment(
|
StreamFileAttachment(
|
||||||
message: message,
|
message: message,
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
size: Size(
|
size: Size(
|
||||||
@@ -300,7 +306,7 @@ class MessageWidget extends StatefulWidget {
|
|||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
/// The message theme
|
/// The message theme
|
||||||
final MessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|
||||||
/// If true the widget will be mirrored
|
/// If true the widget will be mirrored
|
||||||
final bool reverse;
|
final bool reverse;
|
||||||
@@ -356,7 +362,7 @@ class MessageWidget extends StatefulWidget {
|
|||||||
/// The function called when tapping on a link
|
/// The function called when tapping on a link
|
||||||
final void Function(String)? onLinkTap;
|
final void Function(String)? onLinkTap;
|
||||||
|
|
||||||
/// Used in [MessageReactionsModal] and [MessageActionsModal]
|
/// Used in [StreamMessageReactionsModal] and [StreamMessageActionsModal]
|
||||||
final bool showReactionPickerIndicator;
|
final bool showReactionPickerIndicator;
|
||||||
|
|
||||||
/// List of users who read
|
/// List of users who read
|
||||||
@@ -417,13 +423,13 @@ class MessageWidget extends StatefulWidget {
|
|||||||
final void Function(Message)? onMessageTap;
|
final void Function(Message)? onMessageTap;
|
||||||
|
|
||||||
/// List of custom actions shown on message long tap
|
/// List of custom actions shown on message long tap
|
||||||
final List<MessageAction> customActions;
|
final List<StreamMessageAction> customActions;
|
||||||
|
|
||||||
/// Customize onTap on attachment
|
/// Customize onTap on attachment
|
||||||
final void Function(Message message, Attachment attachment)? onAttachmentTap;
|
final void Function(Message message, Attachment attachment)? onAttachmentTap;
|
||||||
|
|
||||||
/// Creates a copy of [MessageWidget] with specified attributes overridden.
|
/// Creates a copy of [StreamMessageWidget] with specified attributes overridden.
|
||||||
MessageWidget copyWith({
|
StreamMessageWidget copyWith({
|
||||||
Key? key,
|
Key? key,
|
||||||
void Function(User)? onMentionTap,
|
void Function(User)? onMentionTap,
|
||||||
void Function(Message)? onThreadTap,
|
void Function(Message)? onThreadTap,
|
||||||
@@ -435,7 +441,7 @@ class MessageWidget extends StatefulWidget {
|
|||||||
Widget Function(BuildContext, Message)? deletedBottomRowBuilder,
|
Widget Function(BuildContext, Message)? deletedBottomRowBuilder,
|
||||||
void Function(BuildContext, Message)? onMessageActions,
|
void Function(BuildContext, Message)? onMessageActions,
|
||||||
Message? message,
|
Message? message,
|
||||||
MessageThemeData? messageTheme,
|
StreamMessageThemeData? messageTheme,
|
||||||
bool? reverse,
|
bool? reverse,
|
||||||
ShapeBorder? shape,
|
ShapeBorder? shape,
|
||||||
ShapeBorder? attachmentShape,
|
ShapeBorder? attachmentShape,
|
||||||
@@ -473,11 +479,11 @@ class MessageWidget extends StatefulWidget {
|
|||||||
bool? translateUserAvatar,
|
bool? translateUserAvatar,
|
||||||
OnQuotedMessageTap? onQuotedMessageTap,
|
OnQuotedMessageTap? onQuotedMessageTap,
|
||||||
void Function(Message)? onMessageTap,
|
void Function(Message)? onMessageTap,
|
||||||
List<MessageAction>? customActions,
|
List<StreamMessageAction>? customActions,
|
||||||
void Function(Message message, Attachment attachment)? onAttachmentTap,
|
void Function(Message message, Attachment attachment)? onAttachmentTap,
|
||||||
Widget Function(BuildContext, User)? userAvatarBuilder,
|
Widget Function(BuildContext, User)? userAvatarBuilder,
|
||||||
}) =>
|
}) =>
|
||||||
MessageWidget(
|
StreamMessageWidget(
|
||||||
key: key ?? this.key,
|
key: key ?? this.key,
|
||||||
onMentionTap: onMentionTap ?? this.onMentionTap,
|
onMentionTap: onMentionTap ?? this.onMentionTap,
|
||||||
onThreadTap: onThreadTap ?? this.onThreadTap,
|
onThreadTap: onThreadTap ?? this.onThreadTap,
|
||||||
@@ -539,11 +545,11 @@ class MessageWidget extends StatefulWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_MessageWidgetState createState() => _MessageWidgetState();
|
_StreamMessageWidgetState createState() => _StreamMessageWidgetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MessageWidgetState extends State<MessageWidget>
|
class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
||||||
with AutomaticKeepAliveClientMixin<MessageWidget> {
|
with AutomaticKeepAliveClientMixin<StreamMessageWidget> {
|
||||||
bool get showThreadReplyIndicator => widget.showThreadReplyIndicator;
|
bool get showThreadReplyIndicator => widget.showThreadReplyIndicator;
|
||||||
|
|
||||||
bool get showSendingIndicator => widget.showSendingIndicator;
|
bool get showSendingIndicator => widget.showSendingIndicator;
|
||||||
@@ -717,7 +723,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
? 0
|
? 0
|
||||||
: 4.0,
|
: 4.0,
|
||||||
),
|
),
|
||||||
child: DeletedMessage(
|
child: StreamDeletedMessage(
|
||||||
borderRadiusGeometry: widget
|
borderRadiusGeometry: widget
|
||||||
.borderRadiusGeometry,
|
.borderRadiusGeometry,
|
||||||
borderSide:
|
borderSide:
|
||||||
@@ -854,7 +860,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
? () => widget.onQuotedMessageTap!(widget.message.quotedMessageId)
|
? () => widget.onQuotedMessageTap!(widget.message.quotedMessageId)
|
||||||
: null;
|
: null;
|
||||||
final chatThemeData = _streamChatTheme;
|
final chatThemeData = _streamChatTheme;
|
||||||
return QuotedMessageWidget(
|
return StreamQuotedMessageWidget(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
message: widget.message.quotedMessage!,
|
message: widget.message.quotedMessage!,
|
||||||
messageTheme: isMyMessage
|
messageTheme: isMyMessage
|
||||||
@@ -1008,7 +1014,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
getWebsiteName(hostName.toLowerCase()) ??
|
getWebsiteName(hostName.toLowerCase()) ??
|
||||||
hostName.capitalize();
|
hostName.capitalize();
|
||||||
|
|
||||||
return UrlAttachment(
|
return StreamUrlAttachment(
|
||||||
urlAttachment: urlAttachment,
|
urlAttachment: urlAttachment,
|
||||||
hostDisplayName: hostDisplayName,
|
hostDisplayName: hostDisplayName,
|
||||||
textPadding: widget.textPadding,
|
textPadding: widget.textPadding,
|
||||||
@@ -1041,7 +1047,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
child: _shouldShowReactions
|
child: _shouldShowReactions
|
||||||
? GestureDetector(
|
? GestureDetector(
|
||||||
onTap: () => _showMessageReactionsModalBottomSheet(context),
|
onTap: () => _showMessageReactionsModalBottomSheet(context),
|
||||||
child: ReactionBubble(
|
child: StreamReactionBubble(
|
||||||
key: ValueKey('${widget.message.id}.reactions'),
|
key: ValueKey('${widget.message.id}.reactions'),
|
||||||
reverse: widget.reverse,
|
reverse: widget.reverse,
|
||||||
flipTail: widget.reverse,
|
flipTail: widget.reverse,
|
||||||
@@ -1072,7 +1078,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
barrierColor: _streamChatTheme.colorTheme.overlay,
|
barrierColor: _streamChatTheme.colorTheme.overlay,
|
||||||
builder: (context) => StreamChannel(
|
builder: (context) => StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: MessageActionsModal(
|
child: StreamMessageActionsModal(
|
||||||
messageWidget: widget.copyWith(
|
messageWidget: widget.copyWith(
|
||||||
key: const Key('MessageWidget'),
|
key: const Key('MessageWidget'),
|
||||||
message: widget.message.copyWith(
|
message: widget.message.copyWith(
|
||||||
@@ -1129,7 +1135,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
barrierColor: _streamChatTheme.colorTheme.overlay,
|
barrierColor: _streamChatTheme.colorTheme.overlay,
|
||||||
builder: (context) => StreamChannel(
|
builder: (context) => StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: MessageReactionsModal(
|
child: StreamMessageReactionsModal(
|
||||||
messageWidget: widget.copyWith(
|
messageWidget: widget.copyWith(
|
||||||
key: const Key('MessageWidget'),
|
key: const Key('MessageWidget'),
|
||||||
message: widget.message.copyWith(
|
message: widget.message.copyWith(
|
||||||
@@ -1246,7 +1252,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
final channel = StreamChannel.of(context).channel;
|
final channel = StreamChannel.of(context).channel;
|
||||||
|
|
||||||
if (!channel.ownCapabilities.contains(PermissionType.readEvents)) {
|
if (!channel.ownCapabilities.contains(PermissionType.readEvents)) {
|
||||||
return SendingIndicator(
|
return StreamSendingIndicator(
|
||||||
message: message,
|
message: message,
|
||||||
size: style!.fontSize,
|
size: style!.fontSize,
|
||||||
);
|
);
|
||||||
@@ -1261,7 +1267,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
(it.lastRead.isAfter(message.createdAt) ||
|
(it.lastRead.isAfter(message.createdAt) ||
|
||||||
it.lastRead.isAtSameMomentAs(message.createdAt)));
|
it.lastRead.isAtSameMomentAs(message.createdAt)));
|
||||||
final isMessageRead = readList.length >= (channel.memberCount ?? 0) - 1;
|
final isMessageRead = readList.length >= (channel.memberCount ?? 0) - 1;
|
||||||
Widget child = SendingIndicator(
|
Widget child = StreamSendingIndicator(
|
||||||
message: message,
|
message: message,
|
||||||
isMessageRead: isMessageRead,
|
isMessageRead: isMessageRead,
|
||||||
size: style!.fontSize,
|
size: style!.fontSize,
|
||||||
@@ -1295,7 +1301,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
: 0,
|
: 0,
|
||||||
),
|
),
|
||||||
child: widget.userAvatarBuilder?.call(context, widget.message.user!) ??
|
child: widget.userAvatarBuilder?.call(context, widget.message.user!) ??
|
||||||
UserAvatar(
|
StreamUserAvatar(
|
||||||
user: widget.message.user!,
|
user: widget.message.user!,
|
||||||
onTap: widget.onUserAvatarTap,
|
onTap: widget.onUserAvatarTap,
|
||||||
constraints: widget.messageTheme.avatarTheme!.constraints,
|
constraints: widget.messageTheme.avatarTheme!.constraints,
|
||||||
@@ -1313,7 +1319,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
padding: isOnlyEmoji ? EdgeInsets.zero : widget.textPadding,
|
padding: isOnlyEmoji ? EdgeInsets.zero : widget.textPadding,
|
||||||
child: widget.textBuilder != null
|
child: widget.textBuilder != null
|
||||||
? widget.textBuilder!(context, widget.message)
|
? widget.textBuilder!(context, widget.message)
|
||||||
: MessageText(
|
: StreamMessageText(
|
||||||
onLinkTap: widget.onLinkTap,
|
onLinkTap: widget.onLinkTap,
|
||||||
message: widget.message,
|
message: widget.message,
|
||||||
onMentionTap: widget.onMentionTap,
|
onMentionTap: widget.onMentionTap,
|
||||||
@@ -1430,7 +1436,7 @@ class _ThreadParticipants extends StatelessWidget {
|
|||||||
color: _streamChatTheme.colorTheme.barsBg,
|
color: _streamChatTheme.colorTheme.barsBg,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(1),
|
padding: const EdgeInsets.all(1),
|
||||||
child: UserAvatar(
|
child: StreamUserAvatar(
|
||||||
user: user,
|
user: user,
|
||||||
constraints: BoxConstraints.loose(const Size.fromRadius(7)),
|
constraints: BoxConstraints.loose(const Size.fromRadius(7)),
|
||||||
showOnlineStatus: false,
|
showOnlineStatus: false,
|
||||||
|
|||||||
@@ -2,15 +2,21 @@ import 'package:collection/collection.dart';
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_portal/flutter_portal.dart';
|
import 'package:flutter_portal/flutter_portal.dart';
|
||||||
|
|
||||||
|
/// {@macro multi_overlay}
|
||||||
|
@Deprecated("Use 'StreamMultiOverlay' instead")
|
||||||
|
typedef MultiOverlay = StreamMultiOverlay;
|
||||||
|
|
||||||
|
/// {@template multi_overlay}
|
||||||
/// Widget that renders a single overlay widget from a list of [overlayOptions]
|
/// Widget that renders a single overlay widget from a list of [overlayOptions]
|
||||||
/// It shows the first one that is visible
|
/// It shows the first one that is visible
|
||||||
class MultiOverlay extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamMultiOverlay extends StatelessWidget {
|
||||||
/// Constructs a new MultiOverlay widget
|
/// Constructs a new MultiOverlay widget
|
||||||
/// [overlayOptions] - the list of overlay options
|
/// [overlayOptions] - the list of overlay options
|
||||||
/// [overlayAnchor] - the anchor relative to the overlay
|
/// [overlayAnchor] - the anchor relative to the overlay
|
||||||
/// [childAnchor] - the anchor relative to the child
|
/// [childAnchor] - the anchor relative to the child
|
||||||
/// [child] - the child widget
|
/// [child] - the child widget
|
||||||
const MultiOverlay({
|
const StreamMultiOverlay({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.overlayOptions,
|
required this.overlayOptions,
|
||||||
required this.child,
|
required this.child,
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
|
/// {@macro option_list_tile}
|
||||||
|
@Deprecated("Use 'StreamOptionListTile' instead")
|
||||||
|
typedef OptionListTile = StreamOptionListTile;
|
||||||
|
|
||||||
|
/// {@template option_list_tile}
|
||||||
/// List tile for [ChannelBottomSheet]
|
/// List tile for [ChannelBottomSheet]
|
||||||
class OptionListTile extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating [OptionListTile]
|
class StreamOptionListTile extends StatelessWidget {
|
||||||
const OptionListTile({
|
/// Constructor for creating [StreamOptionListTile]
|
||||||
|
const StreamOptionListTile({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.title,
|
required this.title,
|
||||||
this.leading,
|
this.leading,
|
||||||
|
|||||||
@@ -10,54 +10,14 @@ typedef QuotedMessageAttachmentThumbnailBuilder = Widget Function(
|
|||||||
Attachment,
|
Attachment,
|
||||||
);
|
);
|
||||||
|
|
||||||
class _VideoAttachmentThumbnail extends StatefulWidget {
|
/// Widget for the quoted message.
|
||||||
const _VideoAttachmentThumbnail({
|
@Deprecated("Use 'StreamQuotedMessageWidget' instead")
|
||||||
Key? key,
|
typedef QuotedMessageWidget = StreamQuotedMessageWidget;
|
||||||
required this.attachment,
|
|
||||||
this.size = const Size(32, 32),
|
|
||||||
}) : super(key: key);
|
|
||||||
|
|
||||||
final Size size;
|
/// Widget for the quoted message.
|
||||||
final Attachment attachment;
|
class StreamQuotedMessageWidget extends StatelessWidget {
|
||||||
|
/// Creates a new instance of the widget.
|
||||||
@override
|
const StreamQuotedMessageWidget({
|
||||||
_VideoAttachmentThumbnailState createState() =>
|
|
||||||
_VideoAttachmentThumbnailState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _VideoAttachmentThumbnailState extends State<_VideoAttachmentThumbnail> {
|
|
||||||
late VideoPlayerController _controller;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_controller = VideoPlayerController.network(widget.attachment.assetUrl!)
|
|
||||||
..initialize().then((_) {
|
|
||||||
// ignore: no-empty-block
|
|
||||||
setState(() {}); //when your thumbnail will show.
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
_controller.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => SizedBox(
|
|
||||||
height: widget.size.height,
|
|
||||||
width: widget.size.width,
|
|
||||||
child: _controller.value.isInitialized
|
|
||||||
? VideoPlayer(_controller)
|
|
||||||
: const CircularProgressIndicator(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
class QuotedMessageWidget extends StatelessWidget {
|
|
||||||
///
|
|
||||||
const QuotedMessageWidget({
|
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
@@ -73,7 +33,7 @@ class QuotedMessageWidget extends StatelessWidget {
|
|||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
/// The message theme
|
/// The message theme
|
||||||
final MessageThemeData messageTheme;
|
final StreamMessageThemeData messageTheme;
|
||||||
|
|
||||||
/// If true the widget will be mirrored
|
/// If true the widget will be mirrored
|
||||||
final bool reverse;
|
final bool reverse;
|
||||||
@@ -134,7 +94,7 @@ class QuotedMessageWidget extends StatelessWidget {
|
|||||||
if (_hasAttachments) _parseAttachments(context),
|
if (_hasAttachments) _parseAttachments(context),
|
||||||
if (msg.text!.isNotEmpty)
|
if (msg.text!.isNotEmpty)
|
||||||
Flexible(
|
Flexible(
|
||||||
child: MessageText(
|
child: StreamMessageText(
|
||||||
message: msg,
|
message: msg,
|
||||||
messageTheme: isOnlyEmoji && _containsText
|
messageTheme: isOnlyEmoji && _containsText
|
||||||
? messageTheme.copyWith(
|
? messageTheme.copyWith(
|
||||||
@@ -231,7 +191,7 @@ class QuotedMessageWidget extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildUserAvatar() => UserAvatar(
|
Widget _buildUserAvatar() => StreamUserAvatar(
|
||||||
user: message.user!,
|
user: message.user!,
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
height: 24,
|
height: 24,
|
||||||
@@ -242,7 +202,7 @@ class QuotedMessageWidget extends StatelessWidget {
|
|||||||
|
|
||||||
Map<String, QuotedMessageAttachmentThumbnailBuilder>
|
Map<String, QuotedMessageAttachmentThumbnailBuilder>
|
||||||
get _defaultAttachmentBuilder => {
|
get _defaultAttachmentBuilder => {
|
||||||
'image': (_, attachment) => ImageAttachment(
|
'image': (_, attachment) => StreamImageAttachment(
|
||||||
attachment: attachment,
|
attachment: attachment,
|
||||||
message: message,
|
message: message,
|
||||||
messageTheme: messageTheme,
|
messageTheme: messageTheme,
|
||||||
@@ -288,3 +248,47 @@ class QuotedMessageWidget extends StatelessWidget {
|
|||||||
return messageTheme.messageBackgroundColor;
|
return messageTheme.messageBackgroundColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _VideoAttachmentThumbnail extends StatefulWidget {
|
||||||
|
const _VideoAttachmentThumbnail({
|
||||||
|
Key? key,
|
||||||
|
required this.attachment,
|
||||||
|
this.size = const Size(32, 32),
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final Size size;
|
||||||
|
final Attachment attachment;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_VideoAttachmentThumbnailState createState() =>
|
||||||
|
_VideoAttachmentThumbnailState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoAttachmentThumbnailState extends State<_VideoAttachmentThumbnail> {
|
||||||
|
late VideoPlayerController _controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_controller = VideoPlayerController.network(widget.attachment.assetUrl!)
|
||||||
|
..initialize().then((_) {
|
||||||
|
// ignore: no-empty-block
|
||||||
|
setState(() {}); //when your thumbnail will show.
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
_controller.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => SizedBox(
|
||||||
|
height: widget.size.height,
|
||||||
|
width: widget.size.width,
|
||||||
|
child: _controller.value.isInitialized
|
||||||
|
? VideoPlayer(_controller)
|
||||||
|
: const CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,10 +4,16 @@ import 'package:collection/collection.dart' show IterableExtension;
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro reaction_bubble}
|
||||||
|
@Deprecated("Use 'StreamReactionBubble' instead")
|
||||||
|
typedef ReactionBubble = StreamReactionBubble;
|
||||||
|
|
||||||
|
/// {@template reaction_bubble}
|
||||||
/// Creates reaction bubble widget for displaying over messages
|
/// Creates reaction bubble widget for displaying over messages
|
||||||
class ReactionBubble extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [ReactionBubble]
|
class StreamReactionBubble extends StatelessWidget {
|
||||||
const ReactionBubble({
|
/// Constructor for creating a [StreamReactionBubble]
|
||||||
|
const StreamReactionBubble({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.reactions,
|
required this.reactions,
|
||||||
required this.borderColor,
|
required this.borderColor,
|
||||||
@@ -111,7 +117,7 @@ class ReactionBubble extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildReaction(
|
Widget _buildReaction(
|
||||||
List<ReactionIcon> reactionIcons,
|
List<StreamReactionIcon> reactionIcons,
|
||||||
Reaction reaction,
|
Reaction reaction,
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
/// Reaction icon data
|
/// Reaction icon data
|
||||||
class ReactionIcon {
|
@Deprecated("Use 'StreamReactionIcon' instead")
|
||||||
/// Constructor for creating [ReactionIcon]
|
typedef ReactionIcon = StreamReactionIcon;
|
||||||
ReactionIcon({
|
|
||||||
|
/// Reaction icon data
|
||||||
|
class StreamReactionIcon {
|
||||||
|
/// Constructor for creating [StreamReactionIcon]
|
||||||
|
StreamReactionIcon({
|
||||||
required this.type,
|
required this.type,
|
||||||
required this.builder,
|
required this.builder,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,16 +3,22 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro reaction_picker}
|
||||||
|
@Deprecated("Use 'StreamReactionPicker' instead")
|
||||||
|
typedef ReactionPicker = StreamReactionPicker;
|
||||||
|
|
||||||
|
/// {@template reaction_picker}
|
||||||
/// 
|
/// 
|
||||||
/// 
|
/// 
|
||||||
///
|
///
|
||||||
/// It shows a reaction picker
|
/// It shows a reaction picker
|
||||||
///
|
///
|
||||||
/// Usually you don't use this widget as it's one of the default widgets used
|
/// Usually you don't use this widget as it's one of the default widgets used
|
||||||
/// by [MessageWidget.onMessageActions].
|
/// by [StreamMessageWidget.onMessageActions].
|
||||||
class ReactionPicker extends StatefulWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [ReactionPicker] widget
|
class StreamReactionPicker extends StatefulWidget {
|
||||||
const ReactionPicker({
|
/// Constructor for creating a [StreamReactionPicker] widget
|
||||||
|
const StreamReactionPicker({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
@@ -21,10 +27,10 @@ class ReactionPicker extends StatefulWidget {
|
|||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ReactionPickerState createState() => _ReactionPickerState();
|
_StreamReactionPickerState createState() => _StreamReactionPickerState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ReactionPickerState extends State<ReactionPicker>
|
class _StreamReactionPickerState extends State<StreamReactionPicker>
|
||||||
with TickerProviderStateMixin {
|
with TickerProviderStateMixin {
|
||||||
List<EzAnimation> animations = [];
|
List<EzAnimation> animations = [];
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro sending_indicator}
|
||||||
|
@Deprecated("Use 'StreamSendingIndicator' instead")
|
||||||
|
typedef SendingIndicator = StreamSendingIndicator;
|
||||||
|
|
||||||
|
/// {@template sending_indicator}
|
||||||
/// Used to show the sending status of the message
|
/// Used to show the sending status of the message
|
||||||
class SendingIndicator extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [SendingIndicator] widget
|
class StreamSendingIndicator extends StatelessWidget {
|
||||||
const SendingIndicator({
|
/// Constructor for creating a [StreamSendingIndicator] widget
|
||||||
|
const StreamSendingIndicator({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
this.isMessageRead = false,
|
this.isMessageRead = false,
|
||||||
|
|||||||
@@ -38,29 +38,29 @@ class StreamChatThemeData {
|
|||||||
/// Create a theme from scratch
|
/// Create a theme from scratch
|
||||||
factory StreamChatThemeData({
|
factory StreamChatThemeData({
|
||||||
Brightness? brightness,
|
Brightness? brightness,
|
||||||
TextTheme? textTheme,
|
StreamTextTheme? textTheme,
|
||||||
ColorTheme? colorTheme,
|
StreamColorTheme? colorTheme,
|
||||||
ChannelListHeaderThemeData? channelListHeaderTheme,
|
StreamChannelListHeaderThemeData? channelListHeaderTheme,
|
||||||
ChannelPreviewThemeData? channelPreviewTheme,
|
StreamChannelPreviewThemeData? channelPreviewTheme,
|
||||||
ChannelHeaderThemeData? channelHeaderTheme,
|
StreamChannelHeaderThemeData? channelHeaderTheme,
|
||||||
MessageThemeData? otherMessageTheme,
|
StreamMessageThemeData? otherMessageTheme,
|
||||||
MessageThemeData? ownMessageTheme,
|
StreamMessageThemeData? ownMessageTheme,
|
||||||
MessageInputThemeData? messageInputTheme,
|
StreamMessageInputThemeData? messageInputTheme,
|
||||||
Widget Function(BuildContext, User)? defaultUserImage,
|
Widget Function(BuildContext, User)? defaultUserImage,
|
||||||
Widget Function(BuildContext, User)? placeholderUserImage,
|
Widget Function(BuildContext, User)? placeholderUserImage,
|
||||||
IconThemeData? primaryIconTheme,
|
IconThemeData? primaryIconTheme,
|
||||||
List<ReactionIcon>? reactionIcons,
|
List<StreamReactionIcon>? reactionIcons,
|
||||||
GalleryHeaderThemeData? imageHeaderTheme,
|
StreamGalleryHeaderThemeData? imageHeaderTheme,
|
||||||
GalleryFooterThemeData? imageFooterTheme,
|
StreamGalleryFooterThemeData? imageFooterTheme,
|
||||||
MessageListViewThemeData? messageListViewTheme,
|
StreamMessageListViewThemeData? messageListViewTheme,
|
||||||
ChannelListViewThemeData? channelListViewTheme,
|
StreamChannelListViewThemeData? channelListViewTheme,
|
||||||
UserListViewThemeData? userListViewTheme,
|
StreamUserListViewThemeData? userListViewTheme,
|
||||||
MessageSearchListViewThemeData? messageSearchListViewTheme,
|
StreamMessageSearchListViewThemeData? messageSearchListViewTheme,
|
||||||
}) {
|
}) {
|
||||||
brightness ??= colorTheme?.brightness ?? Brightness.light;
|
brightness ??= colorTheme?.brightness ?? Brightness.light;
|
||||||
final isDark = brightness == Brightness.dark;
|
final isDark = brightness == Brightness.dark;
|
||||||
textTheme ??= isDark ? TextTheme.dark() : TextTheme.light();
|
textTheme ??= isDark ? StreamTextTheme.dark() : StreamTextTheme.light();
|
||||||
colorTheme ??= isDark ? ColorTheme.dark() : ColorTheme.light();
|
colorTheme ??= isDark ? StreamColorTheme.dark() : StreamColorTheme.light();
|
||||||
|
|
||||||
final defaultData = StreamChatThemeData.fromColorAndTextTheme(
|
final defaultData = StreamChatThemeData.fromColorAndTextTheme(
|
||||||
colorTheme,
|
colorTheme,
|
||||||
@@ -133,14 +133,14 @@ class StreamChatThemeData {
|
|||||||
|
|
||||||
/// Create theme from color and text theme
|
/// Create theme from color and text theme
|
||||||
factory StreamChatThemeData.fromColorAndTextTheme(
|
factory StreamChatThemeData.fromColorAndTextTheme(
|
||||||
ColorTheme colorTheme,
|
StreamColorTheme colorTheme,
|
||||||
TextTheme textTheme,
|
StreamTextTheme textTheme,
|
||||||
) {
|
) {
|
||||||
final accentColor = colorTheme.accentPrimary;
|
final accentColor = colorTheme.accentPrimary;
|
||||||
final iconTheme =
|
final iconTheme =
|
||||||
IconThemeData(color: colorTheme.textHighEmphasis.withOpacity(0.5));
|
IconThemeData(color: colorTheme.textHighEmphasis.withOpacity(0.5));
|
||||||
final channelHeaderTheme = ChannelHeaderThemeData(
|
final channelHeaderTheme = StreamChannelHeaderThemeData(
|
||||||
avatarTheme: AvatarThemeData(
|
avatarTheme: StreamAvatarThemeData(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
height: 40,
|
height: 40,
|
||||||
@@ -153,9 +153,9 @@ class StreamChatThemeData {
|
|||||||
color: const Color(0xff7A7A7A),
|
color: const Color(0xff7A7A7A),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
final channelPreviewTheme = ChannelPreviewThemeData(
|
final channelPreviewTheme = StreamChannelPreviewThemeData(
|
||||||
unreadCounterColor: colorTheme.accentError,
|
unreadCounterColor: colorTheme.accentError,
|
||||||
avatarTheme: AvatarThemeData(
|
avatarTheme: StreamAvatarThemeData(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
height: 40,
|
height: 40,
|
||||||
@@ -176,14 +176,14 @@ class StreamChatThemeData {
|
|||||||
colorTheme: colorTheme,
|
colorTheme: colorTheme,
|
||||||
primaryIconTheme: iconTheme,
|
primaryIconTheme: iconTheme,
|
||||||
defaultUserImage: (context, user) => Center(
|
defaultUserImage: (context, user) => Center(
|
||||||
child: GradientAvatar(
|
child: StreamGradientAvatar(
|
||||||
name: user.name,
|
name: user.name,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
channelPreviewTheme: channelPreviewTheme,
|
channelPreviewTheme: channelPreviewTheme,
|
||||||
channelListHeaderTheme: ChannelListHeaderThemeData(
|
channelListHeaderTheme: StreamChannelListHeaderThemeData(
|
||||||
avatarTheme: AvatarThemeData(
|
avatarTheme: StreamAvatarThemeData(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
height: 40,
|
height: 40,
|
||||||
@@ -194,7 +194,7 @@ class StreamChatThemeData {
|
|||||||
titleStyle: textTheme.headlineBold,
|
titleStyle: textTheme.headlineBold,
|
||||||
),
|
),
|
||||||
channelHeaderTheme: channelHeaderTheme,
|
channelHeaderTheme: channelHeaderTheme,
|
||||||
ownMessageTheme: MessageThemeData(
|
ownMessageTheme: StreamMessageThemeData(
|
||||||
messageAuthorStyle:
|
messageAuthorStyle:
|
||||||
textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis),
|
textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis),
|
||||||
messageTextStyle: textTheme.body,
|
messageTextStyle: textTheme.body,
|
||||||
@@ -206,7 +206,7 @@ class StreamChatThemeData {
|
|||||||
reactionsBorderColor: colorTheme.borders,
|
reactionsBorderColor: colorTheme.borders,
|
||||||
reactionsMaskColor: colorTheme.appBg,
|
reactionsMaskColor: colorTheme.appBg,
|
||||||
messageBorderColor: colorTheme.disabled,
|
messageBorderColor: colorTheme.disabled,
|
||||||
avatarTheme: AvatarThemeData(
|
avatarTheme: StreamAvatarThemeData(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
height: 32,
|
height: 32,
|
||||||
@@ -218,7 +218,7 @@ class StreamChatThemeData {
|
|||||||
),
|
),
|
||||||
linkBackgroundColor: colorTheme.linkBg,
|
linkBackgroundColor: colorTheme.linkBg,
|
||||||
),
|
),
|
||||||
otherMessageTheme: MessageThemeData(
|
otherMessageTheme: StreamMessageThemeData(
|
||||||
reactionsBackgroundColor: colorTheme.disabled,
|
reactionsBackgroundColor: colorTheme.disabled,
|
||||||
reactionsBorderColor: colorTheme.barsBg,
|
reactionsBorderColor: colorTheme.barsBg,
|
||||||
reactionsMaskColor: colorTheme.appBg,
|
reactionsMaskColor: colorTheme.appBg,
|
||||||
@@ -233,7 +233,7 @@ class StreamChatThemeData {
|
|||||||
),
|
),
|
||||||
messageBackgroundColor: colorTheme.barsBg,
|
messageBackgroundColor: colorTheme.barsBg,
|
||||||
messageBorderColor: colorTheme.borders,
|
messageBorderColor: colorTheme.borders,
|
||||||
avatarTheme: AvatarThemeData(
|
avatarTheme: StreamAvatarThemeData(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
height: 32,
|
height: 32,
|
||||||
@@ -242,7 +242,7 @@ class StreamChatThemeData {
|
|||||||
),
|
),
|
||||||
linkBackgroundColor: colorTheme.linkBg,
|
linkBackgroundColor: colorTheme.linkBg,
|
||||||
),
|
),
|
||||||
messageInputTheme: MessageInputThemeData(
|
messageInputTheme: StreamMessageInputThemeData(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
sendAnimationDuration: const Duration(milliseconds: 300),
|
sendAnimationDuration: const Duration(milliseconds: 300),
|
||||||
actionButtonColor: colorTheme.accentPrimary,
|
actionButtonColor: colorTheme.accentPrimary,
|
||||||
@@ -267,7 +267,7 @@ class StreamChatThemeData {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
reactionIcons: [
|
reactionIcons: [
|
||||||
ReactionIcon(
|
StreamReactionIcon(
|
||||||
type: 'love',
|
type: 'love',
|
||||||
builder: (context, highlighted, size) {
|
builder: (context, highlighted, size) {
|
||||||
final theme = StreamChatTheme.of(context);
|
final theme = StreamChatTheme.of(context);
|
||||||
@@ -279,7 +279,7 @@ class StreamChatThemeData {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ReactionIcon(
|
StreamReactionIcon(
|
||||||
type: 'like',
|
type: 'like',
|
||||||
builder: (context, highlighted, size) {
|
builder: (context, highlighted, size) {
|
||||||
final theme = StreamChatTheme.of(context);
|
final theme = StreamChatTheme.of(context);
|
||||||
@@ -291,7 +291,7 @@ class StreamChatThemeData {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ReactionIcon(
|
StreamReactionIcon(
|
||||||
type: 'sad',
|
type: 'sad',
|
||||||
builder: (context, highlighted, size) {
|
builder: (context, highlighted, size) {
|
||||||
final theme = StreamChatTheme.of(context);
|
final theme = StreamChatTheme.of(context);
|
||||||
@@ -303,7 +303,7 @@ class StreamChatThemeData {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ReactionIcon(
|
StreamReactionIcon(
|
||||||
type: 'haha',
|
type: 'haha',
|
||||||
builder: (context, highlighted, size) {
|
builder: (context, highlighted, size) {
|
||||||
final theme = StreamChatTheme.of(context);
|
final theme = StreamChatTheme.of(context);
|
||||||
@@ -315,7 +315,7 @@ class StreamChatThemeData {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ReactionIcon(
|
StreamReactionIcon(
|
||||||
type: 'wow',
|
type: 'wow',
|
||||||
builder: (context, highlighted, size) {
|
builder: (context, highlighted, size) {
|
||||||
final theme = StreamChatTheme.of(context);
|
final theme = StreamChatTheme.of(context);
|
||||||
@@ -328,7 +328,7 @@ class StreamChatThemeData {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
galleryHeaderTheme: GalleryHeaderThemeData(
|
galleryHeaderTheme: StreamGalleryHeaderThemeData(
|
||||||
closeButtonColor: colorTheme.textHighEmphasis,
|
closeButtonColor: colorTheme.textHighEmphasis,
|
||||||
backgroundColor: channelHeaderTheme.color,
|
backgroundColor: channelHeaderTheme.color,
|
||||||
iconMenuPointColor: colorTheme.textHighEmphasis,
|
iconMenuPointColor: colorTheme.textHighEmphasis,
|
||||||
@@ -336,7 +336,7 @@ class StreamChatThemeData {
|
|||||||
subtitleTextStyle: channelPreviewTheme.subtitleStyle,
|
subtitleTextStyle: channelPreviewTheme.subtitleStyle,
|
||||||
bottomSheetBarrierColor: colorTheme.overlay,
|
bottomSheetBarrierColor: colorTheme.overlay,
|
||||||
),
|
),
|
||||||
galleryFooterTheme: GalleryFooterThemeData(
|
galleryFooterTheme: StreamGalleryFooterThemeData(
|
||||||
backgroundColor: colorTheme.barsBg,
|
backgroundColor: colorTheme.barsBg,
|
||||||
shareIconColor: colorTheme.textHighEmphasis,
|
shareIconColor: colorTheme.textHighEmphasis,
|
||||||
titleTextStyle: textTheme.headlineBold,
|
titleTextStyle: textTheme.headlineBold,
|
||||||
@@ -346,52 +346,52 @@ class StreamChatThemeData {
|
|||||||
bottomSheetPhotosTextStyle: textTheme.headlineBold,
|
bottomSheetPhotosTextStyle: textTheme.headlineBold,
|
||||||
bottomSheetCloseIconColor: colorTheme.textHighEmphasis,
|
bottomSheetCloseIconColor: colorTheme.textHighEmphasis,
|
||||||
),
|
),
|
||||||
messageListViewTheme: MessageListViewThemeData(
|
messageListViewTheme: StreamMessageListViewThemeData(
|
||||||
backgroundColor: colorTheme.barsBg,
|
backgroundColor: colorTheme.barsBg,
|
||||||
),
|
),
|
||||||
channelListViewTheme: ChannelListViewThemeData(
|
channelListViewTheme: StreamChannelListViewThemeData(
|
||||||
backgroundColor: colorTheme.appBg,
|
backgroundColor: colorTheme.appBg,
|
||||||
),
|
),
|
||||||
userListViewTheme: UserListViewThemeData(
|
userListViewTheme: StreamUserListViewThemeData(
|
||||||
backgroundColor: colorTheme.appBg,
|
backgroundColor: colorTheme.appBg,
|
||||||
),
|
),
|
||||||
messageSearchListViewTheme: MessageSearchListViewThemeData(
|
messageSearchListViewTheme: StreamMessageSearchListViewThemeData(
|
||||||
backgroundColor: colorTheme.appBg,
|
backgroundColor: colorTheme.appBg,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The text themes used in the widgets
|
/// The text themes used in the widgets
|
||||||
final TextTheme textTheme;
|
final StreamTextTheme textTheme;
|
||||||
|
|
||||||
/// The color themes used in the widgets
|
/// The color themes used in the widgets
|
||||||
final ColorTheme colorTheme;
|
final StreamColorTheme colorTheme;
|
||||||
|
|
||||||
/// Theme of the [ChannelPreview]
|
/// Theme of the [StreamChannelPreview]
|
||||||
final ChannelPreviewThemeData channelPreviewTheme;
|
final StreamChannelPreviewThemeData channelPreviewTheme;
|
||||||
|
|
||||||
/// Theme of the [ChannelListHeader]
|
/// Theme of the [StreamChannelListHeader]
|
||||||
final ChannelListHeaderThemeData channelListHeaderTheme;
|
final StreamChannelListHeaderThemeData channelListHeaderTheme;
|
||||||
|
|
||||||
/// Theme of the chat widgets dedicated to a channel header
|
/// Theme of the chat widgets dedicated to a channel header
|
||||||
final ChannelHeaderThemeData channelHeaderTheme;
|
final StreamChannelHeaderThemeData channelHeaderTheme;
|
||||||
|
|
||||||
/// The default style for [GalleryHeader]s below the overall
|
/// The default style for [StreamGalleryHeader]s below the overall
|
||||||
/// [StreamChatTheme].
|
/// [StreamChatTheme].
|
||||||
final GalleryHeaderThemeData galleryHeaderTheme;
|
final StreamGalleryHeaderThemeData galleryHeaderTheme;
|
||||||
|
|
||||||
/// The default style for [GalleryFooter]s below the overall
|
/// The default style for [StreamGalleryFooter]s below the overall
|
||||||
/// [StreamChatTheme].
|
/// [StreamChatTheme].
|
||||||
final GalleryFooterThemeData galleryFooterTheme;
|
final StreamGalleryFooterThemeData galleryFooterTheme;
|
||||||
|
|
||||||
/// Theme of the current user messages
|
/// Theme of the current user messages
|
||||||
final MessageThemeData ownMessageTheme;
|
final StreamMessageThemeData ownMessageTheme;
|
||||||
|
|
||||||
/// Theme of other users messages
|
/// Theme of other users messages
|
||||||
final MessageThemeData otherMessageTheme;
|
final StreamMessageThemeData otherMessageTheme;
|
||||||
|
|
||||||
/// Theme dedicated to the [MessageInput] widget
|
/// Theme dedicated to the [StreamMessageInput] widget
|
||||||
final MessageInputThemeData messageInputTheme;
|
final StreamMessageInputThemeData messageInputTheme;
|
||||||
|
|
||||||
/// The widget that will be built when the user image is unavailable
|
/// The widget that will be built when the user image is unavailable
|
||||||
final Widget Function(BuildContext, User) defaultUserImage;
|
final Widget Function(BuildContext, User) defaultUserImage;
|
||||||
@@ -403,41 +403,41 @@ class StreamChatThemeData {
|
|||||||
final IconThemeData primaryIconTheme;
|
final IconThemeData primaryIconTheme;
|
||||||
|
|
||||||
/// Assets used for rendering reactions
|
/// Assets used for rendering reactions
|
||||||
final List<ReactionIcon> reactionIcons;
|
final List<StreamReactionIcon> reactionIcons;
|
||||||
|
|
||||||
/// Theme configuration for the [MessageListView] widget.
|
/// Theme configuration for the [StreamMessageListView] widget.
|
||||||
final MessageListViewThemeData messageListViewTheme;
|
final StreamMessageListViewThemeData messageListViewTheme;
|
||||||
|
|
||||||
/// Theme configuration for the [ChannelListView] widget.
|
/// Theme configuration for the [StreamChannelListView] widget.
|
||||||
final ChannelListViewThemeData channelListViewTheme;
|
final StreamChannelListViewThemeData channelListViewTheme;
|
||||||
|
|
||||||
/// Theme configuration for the [UserListView] widget.
|
/// Theme configuration for the [StreamUserListView] widget.
|
||||||
final UserListViewThemeData userListViewTheme;
|
final StreamUserListViewThemeData userListViewTheme;
|
||||||
|
|
||||||
/// Theme configuration for the [MessageSearchListView] widget.
|
/// Theme configuration for the [StreamMessageSearchListView] widget.
|
||||||
final MessageSearchListViewThemeData messageSearchListViewTheme;
|
final StreamMessageSearchListViewThemeData messageSearchListViewTheme;
|
||||||
|
|
||||||
/// Creates a copy of [StreamChatThemeData] with specified attributes
|
/// Creates a copy of [StreamChatThemeData] with specified attributes
|
||||||
/// overridden.
|
/// overridden.
|
||||||
StreamChatThemeData copyWith({
|
StreamChatThemeData copyWith({
|
||||||
TextTheme? textTheme,
|
StreamTextTheme? textTheme,
|
||||||
ColorTheme? colorTheme,
|
StreamColorTheme? colorTheme,
|
||||||
ChannelPreviewThemeData? channelPreviewTheme,
|
StreamChannelPreviewThemeData? channelPreviewTheme,
|
||||||
ChannelHeaderThemeData? channelHeaderTheme,
|
StreamChannelHeaderThemeData? channelHeaderTheme,
|
||||||
MessageThemeData? ownMessageTheme,
|
StreamMessageThemeData? ownMessageTheme,
|
||||||
MessageThemeData? otherMessageTheme,
|
StreamMessageThemeData? otherMessageTheme,
|
||||||
MessageInputThemeData? messageInputTheme,
|
StreamMessageInputThemeData? messageInputTheme,
|
||||||
Widget Function(BuildContext, User)? defaultUserImage,
|
Widget Function(BuildContext, User)? defaultUserImage,
|
||||||
Widget Function(BuildContext, User)? placeholderUserImage,
|
Widget Function(BuildContext, User)? placeholderUserImage,
|
||||||
IconThemeData? primaryIconTheme,
|
IconThemeData? primaryIconTheme,
|
||||||
ChannelListHeaderThemeData? channelListHeaderTheme,
|
StreamChannelListHeaderThemeData? channelListHeaderTheme,
|
||||||
List<ReactionIcon>? reactionIcons,
|
List<StreamReactionIcon>? reactionIcons,
|
||||||
GalleryHeaderThemeData? galleryHeaderTheme,
|
StreamGalleryHeaderThemeData? galleryHeaderTheme,
|
||||||
GalleryFooterThemeData? galleryFooterTheme,
|
StreamGalleryFooterThemeData? galleryFooterTheme,
|
||||||
MessageListViewThemeData? messageListViewTheme,
|
StreamMessageListViewThemeData? messageListViewTheme,
|
||||||
ChannelListViewThemeData? channelListViewTheme,
|
StreamChannelListViewThemeData? channelListViewTheme,
|
||||||
UserListViewThemeData? userListViewTheme,
|
StreamUserListViewThemeData? userListViewTheme,
|
||||||
MessageSearchListViewThemeData? messageSearchListViewTheme,
|
StreamMessageSearchListViewThemeData? messageSearchListViewTheme,
|
||||||
}) =>
|
}) =>
|
||||||
StreamChatThemeData.raw(
|
StreamChatThemeData.raw(
|
||||||
channelListHeaderTheme:
|
channelListHeaderTheme:
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
/// It shows a date divider depending on the date difference
|
/// {@macro system_message}
|
||||||
class SystemMessage extends StatelessWidget {
|
@Deprecated("Use 'StreamSystemMessage' instead")
|
||||||
/// Constructor for creating a [SystemMessage]
|
typedef SystemMessage = StreamSystemMessage;
|
||||||
const SystemMessage({
|
|
||||||
|
/// {@template system_message}
|
||||||
|
/// It shows a widget for the message with a system message type.
|
||||||
|
/// {@endtemplate}
|
||||||
|
class StreamSystemMessage extends StatelessWidget {
|
||||||
|
/// Constructor for creating a [StreamSystemMessage]
|
||||||
|
const StreamSystemMessage({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
this.onMessageTap,
|
this.onMessageTap,
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// {@macro avatar_theme_data}
|
||||||
|
@Deprecated("Use 'StreamAvatarThemeData' instead")
|
||||||
|
typedef AvatarThemeData = StreamAvatarThemeData;
|
||||||
|
|
||||||
|
/// {@template avatar_theme_data}
|
||||||
/// A style that overrides the default appearance of various avatar widgets.
|
/// A style that overrides the default appearance of various avatar widgets.
|
||||||
|
/// {@endtemplate}
|
||||||
// ignore: prefer-match-file-name
|
// ignore: prefer-match-file-name
|
||||||
class AvatarThemeData with Diagnosticable {
|
class StreamAvatarThemeData with Diagnosticable {
|
||||||
/// Creates an [AvatarThemeData].
|
/// Creates an [StreamAvatarThemeData].
|
||||||
const AvatarThemeData({
|
const StreamAvatarThemeData({
|
||||||
BoxConstraints? constraints,
|
BoxConstraints? constraints,
|
||||||
BorderRadius? borderRadius,
|
BorderRadius? borderRadius,
|
||||||
}) : _constraints = constraints,
|
}) : _constraints = constraints,
|
||||||
@@ -25,12 +31,12 @@ class AvatarThemeData with Diagnosticable {
|
|||||||
/// Get border radius
|
/// Get border radius
|
||||||
BorderRadius get borderRadius => _borderRadius ?? BorderRadius.circular(20);
|
BorderRadius get borderRadius => _borderRadius ?? BorderRadius.circular(20);
|
||||||
|
|
||||||
/// Copy this [AvatarThemeData] to another.
|
/// Copy this [StreamAvatarThemeData] to another.
|
||||||
AvatarThemeData copyWith({
|
StreamAvatarThemeData copyWith({
|
||||||
BoxConstraints? constraints,
|
BoxConstraints? constraints,
|
||||||
BorderRadius? borderRadius,
|
BorderRadius? borderRadius,
|
||||||
}) =>
|
}) =>
|
||||||
AvatarThemeData(
|
StreamAvatarThemeData(
|
||||||
constraints: constraints ?? _constraints,
|
constraints: constraints ?? _constraints,
|
||||||
borderRadius: borderRadius ?? _borderRadius,
|
borderRadius: borderRadius ?? _borderRadius,
|
||||||
);
|
);
|
||||||
@@ -38,12 +44,12 @@ class AvatarThemeData with Diagnosticable {
|
|||||||
/// Linearly interpolate between two [UserAvatar] themes.
|
/// Linearly interpolate between two [UserAvatar] themes.
|
||||||
///
|
///
|
||||||
/// All the properties must be non-null.
|
/// All the properties must be non-null.
|
||||||
AvatarThemeData lerp(
|
StreamAvatarThemeData lerp(
|
||||||
AvatarThemeData a,
|
StreamAvatarThemeData a,
|
||||||
AvatarThemeData b,
|
StreamAvatarThemeData b,
|
||||||
double t,
|
double t,
|
||||||
) =>
|
) =>
|
||||||
AvatarThemeData(
|
StreamAvatarThemeData(
|
||||||
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
|
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
|
||||||
constraints: BoxConstraints.lerp(a.constraints, b.constraints, t),
|
constraints: BoxConstraints.lerp(a.constraints, b.constraints, t),
|
||||||
);
|
);
|
||||||
@@ -51,7 +57,7 @@ class AvatarThemeData with Diagnosticable {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is AvatarThemeData &&
|
other is StreamAvatarThemeData &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
_constraints == other._constraints &&
|
_constraints == other._constraints &&
|
||||||
_borderRadius == other._borderRadius;
|
_borderRadius == other._borderRadius;
|
||||||
@@ -59,8 +65,8 @@ class AvatarThemeData with Diagnosticable {
|
|||||||
@override
|
@override
|
||||||
int get hashCode => _constraints.hashCode ^ _borderRadius.hashCode;
|
int get hashCode => _constraints.hashCode ^ _borderRadius.hashCode;
|
||||||
|
|
||||||
/// Merges one [AvatarThemeData] with the another
|
/// Merges one [StreamAvatarThemeData] with the another
|
||||||
AvatarThemeData merge(AvatarThemeData? other) {
|
StreamAvatarThemeData merge(StreamAvatarThemeData? other) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
constraints: other._constraints,
|
constraints: other._constraints,
|
||||||
|
|||||||
@@ -4,27 +4,33 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
|||||||
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
|
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
|
||||||
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
||||||
|
|
||||||
|
/// {@macro channel_header_theme}
|
||||||
|
@Deprecated("Use 'StreamChannelHeaderTheme' instead")
|
||||||
|
typedef ChannelHeaderTheme = StreamChannelHeaderTheme;
|
||||||
|
|
||||||
|
/// {@template channel_header_theme}
|
||||||
/// Overrides the default style of [ChannelHeader] descendants.
|
/// Overrides the default style of [ChannelHeader] descendants.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [ChannelHeaderThemeData], which is used to configure this theme.
|
/// * [StreamChannelHeaderThemeData], which is used to configure this theme.
|
||||||
class ChannelHeaderTheme extends InheritedTheme {
|
/// {@endtemplate}
|
||||||
/// Creates a [ChannelHeaderTheme].
|
class StreamChannelHeaderTheme extends InheritedTheme {
|
||||||
|
/// Creates a [StreamChannelHeaderTheme].
|
||||||
///
|
///
|
||||||
/// The [data] parameter must not be null.
|
/// The [data] parameter must not be null.
|
||||||
const ChannelHeaderTheme({
|
const StreamChannelHeaderTheme({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.data,
|
required this.data,
|
||||||
required Widget child,
|
required Widget child,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
/// The configuration of this theme.
|
/// The configuration of this theme.
|
||||||
final ChannelHeaderThemeData data;
|
final StreamChannelHeaderThemeData data;
|
||||||
|
|
||||||
/// The closest instance of this class that encloses the given context.
|
/// The closest instance of this class that encloses the given context.
|
||||||
///
|
///
|
||||||
/// If there is no enclosing [ChannelHeaderTheme] widget, then
|
/// If there is no enclosing [StreamChannelHeaderTheme] widget, then
|
||||||
/// [StreamChatThemeData.channelTheme.channelHeaderTheme] is used.
|
/// [StreamChatThemeData.channelTheme.channelHeaderTheme] is used.
|
||||||
///
|
///
|
||||||
/// Typical usage is as follows:
|
/// Typical usage is as follows:
|
||||||
@@ -32,34 +38,40 @@ class ChannelHeaderTheme extends InheritedTheme {
|
|||||||
/// ```dart
|
/// ```dart
|
||||||
/// final theme = ChannelHeaderTheme.of(context);
|
/// final theme = ChannelHeaderTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static ChannelHeaderThemeData of(BuildContext context) {
|
static StreamChannelHeaderThemeData of(BuildContext context) {
|
||||||
final channelHeaderTheme =
|
final channelHeaderTheme =
|
||||||
context.dependOnInheritedWidgetOfExactType<ChannelHeaderTheme>();
|
context.dependOnInheritedWidgetOfExactType<StreamChannelHeaderTheme>();
|
||||||
return channelHeaderTheme?.data ??
|
return channelHeaderTheme?.data ??
|
||||||
StreamChatTheme.of(context).channelHeaderTheme;
|
StreamChatTheme.of(context).channelHeaderTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget wrap(BuildContext context, Widget child) =>
|
Widget wrap(BuildContext context, Widget child) =>
|
||||||
ChannelHeaderTheme(data: data, child: child);
|
StreamChannelHeaderTheme(data: data, child: child);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool updateShouldNotify(ChannelHeaderTheme oldWidget) =>
|
bool updateShouldNotify(StreamChannelHeaderTheme oldWidget) =>
|
||||||
data != oldWidget.data;
|
data != oldWidget.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro channel_header_theme_data}
|
||||||
|
@Deprecated("Use 'StreamChannelHeaderThemeData' instead")
|
||||||
|
typedef ChannelHeaderThemeData = StreamChannelHeaderThemeData;
|
||||||
|
|
||||||
|
/// {@template channel_header_theme_data}
|
||||||
/// A style that overrides the default appearance of [ChannelHeader]s when used
|
/// A style that overrides the default appearance of [ChannelHeader]s when used
|
||||||
/// with [ChannelHeaderTheme] or with the overall [StreamChatTheme]'s
|
/// with [StreamChannelHeaderTheme] or with the overall [StreamChatTheme]'s
|
||||||
/// [StreamChatThemeData.channelHeaderTheme].
|
/// [StreamChatThemeData.channelHeaderTheme].
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [ChannelHeaderTheme], the theme which is configured with this class.
|
/// * [StreamChannelHeaderTheme], the theme which is configured with this class.
|
||||||
/// * [StreamChatThemeData.channelHeaderTheme], which can be used to override
|
/// * [StreamChatThemeData.channelHeaderTheme], which can be used to override
|
||||||
/// the default style for [ChannelHeader]s below the overall [StreamChatTheme].
|
/// the default style for [ChannelHeader]s below the overall [StreamChatTheme].
|
||||||
class ChannelHeaderThemeData with Diagnosticable {
|
/// {@endtemplate}
|
||||||
/// Creates a [ChannelHeaderThemeData]
|
class StreamChannelHeaderThemeData with Diagnosticable {
|
||||||
const ChannelHeaderThemeData({
|
/// Creates a [StreamChannelHeaderThemeData]
|
||||||
|
const StreamChannelHeaderThemeData({
|
||||||
this.titleStyle,
|
this.titleStyle,
|
||||||
this.subtitleStyle,
|
this.subtitleStyle,
|
||||||
this.avatarTheme,
|
this.avatarTheme,
|
||||||
@@ -73,43 +85,43 @@ class ChannelHeaderThemeData with Diagnosticable {
|
|||||||
final TextStyle? subtitleStyle;
|
final TextStyle? subtitleStyle;
|
||||||
|
|
||||||
/// Theme for avatar
|
/// Theme for avatar
|
||||||
final AvatarThemeData? avatarTheme;
|
final StreamAvatarThemeData? avatarTheme;
|
||||||
|
|
||||||
/// Color for [ChannelHeaderThemeData]
|
/// Color for [StreamChannelHeaderThemeData]
|
||||||
final Color? color;
|
final Color? color;
|
||||||
|
|
||||||
/// Copy with theme
|
/// Copy with theme
|
||||||
ChannelHeaderThemeData copyWith({
|
StreamChannelHeaderThemeData copyWith({
|
||||||
TextStyle? titleStyle,
|
TextStyle? titleStyle,
|
||||||
TextStyle? subtitleStyle,
|
TextStyle? subtitleStyle,
|
||||||
AvatarThemeData? avatarTheme,
|
StreamAvatarThemeData? avatarTheme,
|
||||||
Color? color,
|
Color? color,
|
||||||
}) =>
|
}) =>
|
||||||
ChannelHeaderThemeData(
|
StreamChannelHeaderThemeData(
|
||||||
titleStyle: titleStyle ?? this.titleStyle,
|
titleStyle: titleStyle ?? this.titleStyle,
|
||||||
subtitleStyle: subtitleStyle ?? this.subtitleStyle,
|
subtitleStyle: subtitleStyle ?? this.subtitleStyle,
|
||||||
avatarTheme: avatarTheme ?? this.avatarTheme,
|
avatarTheme: avatarTheme ?? this.avatarTheme,
|
||||||
color: color ?? this.color,
|
color: color ?? this.color,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Linearly interpolate between two [ChannelHeaderThemeData].
|
/// Linearly interpolate between two [StreamChannelHeaderThemeData].
|
||||||
///
|
///
|
||||||
/// All the properties must be non-null.
|
/// All the properties must be non-null.
|
||||||
ChannelHeaderThemeData lerp(
|
StreamChannelHeaderThemeData lerp(
|
||||||
ChannelHeaderThemeData a,
|
StreamChannelHeaderThemeData a,
|
||||||
ChannelHeaderThemeData b,
|
StreamChannelHeaderThemeData b,
|
||||||
double t,
|
double t,
|
||||||
) =>
|
) =>
|
||||||
ChannelHeaderThemeData(
|
StreamChannelHeaderThemeData(
|
||||||
titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t),
|
titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t),
|
||||||
subtitleStyle: TextStyle.lerp(a.subtitleStyle, b.subtitleStyle, t),
|
subtitleStyle: TextStyle.lerp(a.subtitleStyle, b.subtitleStyle, t),
|
||||||
avatarTheme:
|
avatarTheme: const StreamAvatarThemeData()
|
||||||
const AvatarThemeData().lerp(a.avatarTheme!, b.avatarTheme!, t),
|
.lerp(a.avatarTheme!, b.avatarTheme!, t),
|
||||||
color: Color.lerp(a.color, b.color, t),
|
color: Color.lerp(a.color, b.color, t),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Merge with other [ChannelHeaderThemeData]
|
/// Merge with other [StreamChannelHeaderThemeData]
|
||||||
ChannelHeaderThemeData merge(ChannelHeaderThemeData? other) {
|
StreamChannelHeaderThemeData merge(StreamChannelHeaderThemeData? other) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle,
|
titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle,
|
||||||
@@ -123,7 +135,7 @@ class ChannelHeaderThemeData with Diagnosticable {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is ChannelHeaderThemeData &&
|
other is StreamChannelHeaderThemeData &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
titleStyle == other.titleStyle &&
|
titleStyle == other.titleStyle &&
|
||||||
subtitleStyle == other.subtitleStyle &&
|
subtitleStyle == other.subtitleStyle &&
|
||||||
|
|||||||
@@ -3,27 +3,33 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
|
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
|
||||||
|
|
||||||
|
/// {@macro channel_list_header_theme}
|
||||||
|
@Deprecated("Use 'StreamChannelListHeaderTheme' instead")
|
||||||
|
typedef ChannelListHeaderTheme = StreamChannelListHeaderTheme;
|
||||||
|
|
||||||
|
/// {@template channel_list_header_theme}
|
||||||
/// Overrides the default style of [ChannelListHeader] descendants.
|
/// Overrides the default style of [ChannelListHeader] descendants.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [ChannelListHeaderThemeData], which is used to configure this theme.
|
/// * [StreamChannelListHeaderThemeData], which is used to configure this theme.
|
||||||
class ChannelListHeaderTheme extends InheritedTheme {
|
/// {@endtemplate}
|
||||||
/// Creates a [ChannelListHeaderTheme].
|
class StreamChannelListHeaderTheme extends InheritedTheme {
|
||||||
|
/// Creates a [StreamChannelListHeaderTheme].
|
||||||
///
|
///
|
||||||
/// The [data] parameter must not be null.
|
/// The [data] parameter must not be null.
|
||||||
const ChannelListHeaderTheme({
|
const StreamChannelListHeaderTheme({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.data,
|
required this.data,
|
||||||
required Widget child,
|
required Widget child,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
/// The configuration of this theme.
|
/// The configuration of this theme.
|
||||||
final ChannelListHeaderThemeData data;
|
final StreamChannelListHeaderThemeData data;
|
||||||
|
|
||||||
/// The closest instance of this class that encloses the given context.
|
/// The closest instance of this class that encloses the given context.
|
||||||
///
|
///
|
||||||
/// If there is no enclosing [ChannelListHeaderTheme] widget, then
|
/// If there is no enclosing [StreamChannelListHeaderTheme] widget, then
|
||||||
/// [StreamChatThemeData.channelListHeaderTheme] is used.
|
/// [StreamChatThemeData.channelListHeaderTheme] is used.
|
||||||
///
|
///
|
||||||
/// Typical usage is as follows:
|
/// Typical usage is as follows:
|
||||||
@@ -31,26 +37,32 @@ class ChannelListHeaderTheme extends InheritedTheme {
|
|||||||
/// ```dart
|
/// ```dart
|
||||||
/// final theme = ChannelListHeaderTheme.of(context);
|
/// final theme = ChannelListHeaderTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static ChannelListHeaderThemeData of(BuildContext context) {
|
static StreamChannelListHeaderThemeData of(BuildContext context) {
|
||||||
final channelListHeaderTheme =
|
final channelListHeaderTheme = context
|
||||||
context.dependOnInheritedWidgetOfExactType<ChannelListHeaderTheme>();
|
.dependOnInheritedWidgetOfExactType<StreamChannelListHeaderTheme>();
|
||||||
return channelListHeaderTheme?.data ??
|
return channelListHeaderTheme?.data ??
|
||||||
StreamChatTheme.of(context).channelListHeaderTheme;
|
StreamChatTheme.of(context).channelListHeaderTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget wrap(BuildContext context, Widget child) =>
|
Widget wrap(BuildContext context, Widget child) =>
|
||||||
ChannelListHeaderTheme(data: data, child: child);
|
StreamChannelListHeaderTheme(data: data, child: child);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool updateShouldNotify(ChannelListHeaderTheme oldWidget) =>
|
bool updateShouldNotify(StreamChannelListHeaderTheme oldWidget) =>
|
||||||
data != oldWidget.data;
|
data != oldWidget.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro channel_list_header_theme_data}
|
||||||
|
@Deprecated("Use ''StreamChannelListHeaderThemeData' instead")
|
||||||
|
typedef ChannelListHeaderThemeData = StreamChannelListHeaderThemeData;
|
||||||
|
|
||||||
|
/// {@template channel_list_header_theme_data}
|
||||||
/// Theme dedicated to the [ChannelListHeader]
|
/// Theme dedicated to the [ChannelListHeader]
|
||||||
class ChannelListHeaderThemeData with Diagnosticable {
|
/// {@endtemplate}
|
||||||
/// Returns a new [ChannelListHeaderThemeData]
|
class StreamChannelListHeaderThemeData with Diagnosticable {
|
||||||
const ChannelListHeaderThemeData({
|
/// Returns a new [StreamChannelListHeaderThemeData]
|
||||||
|
const StreamChannelListHeaderThemeData({
|
||||||
this.titleStyle,
|
this.titleStyle,
|
||||||
this.avatarTheme,
|
this.avatarTheme,
|
||||||
this.color,
|
this.color,
|
||||||
@@ -60,39 +72,41 @@ class ChannelListHeaderThemeData with Diagnosticable {
|
|||||||
final TextStyle? titleStyle;
|
final TextStyle? titleStyle;
|
||||||
|
|
||||||
/// Theme dedicated to the userAvatar
|
/// Theme dedicated to the userAvatar
|
||||||
final AvatarThemeData? avatarTheme;
|
final StreamAvatarThemeData? avatarTheme;
|
||||||
|
|
||||||
/// Background color of the appbar
|
/// Background color of the appbar
|
||||||
final Color? color;
|
final Color? color;
|
||||||
|
|
||||||
/// Returns a new [ChannelListHeaderThemeData] replacing some of its
|
/// Returns a new [StreamChannelListHeaderThemeData] replacing some of its
|
||||||
/// properties
|
/// properties
|
||||||
ChannelListHeaderThemeData copyWith({
|
StreamChannelListHeaderThemeData copyWith({
|
||||||
TextStyle? titleStyle,
|
TextStyle? titleStyle,
|
||||||
AvatarThemeData? avatarTheme,
|
StreamAvatarThemeData? avatarTheme,
|
||||||
Color? color,
|
Color? color,
|
||||||
}) =>
|
}) =>
|
||||||
ChannelListHeaderThemeData(
|
StreamChannelListHeaderThemeData(
|
||||||
titleStyle: titleStyle ?? this.titleStyle,
|
titleStyle: titleStyle ?? this.titleStyle,
|
||||||
avatarTheme: avatarTheme ?? this.avatarTheme,
|
avatarTheme: avatarTheme ?? this.avatarTheme,
|
||||||
color: color ?? this.color,
|
color: color ?? this.color,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Linearly interpolate from one [ChannelListHeaderThemeData] to another.
|
/// Linearly interpolate from one [StreamChannelListHeaderThemeData] to another.
|
||||||
ChannelListHeaderThemeData lerp(
|
StreamChannelListHeaderThemeData lerp(
|
||||||
ChannelListHeaderThemeData a,
|
StreamChannelListHeaderThemeData a,
|
||||||
ChannelListHeaderThemeData b,
|
StreamChannelListHeaderThemeData b,
|
||||||
double t,
|
double t,
|
||||||
) =>
|
) =>
|
||||||
ChannelListHeaderThemeData(
|
StreamChannelListHeaderThemeData(
|
||||||
avatarTheme:
|
avatarTheme: const StreamAvatarThemeData()
|
||||||
const AvatarThemeData().lerp(a.avatarTheme!, b.avatarTheme!, t),
|
.lerp(a.avatarTheme!, b.avatarTheme!, t),
|
||||||
color: Color.lerp(a.color, b.color, t),
|
color: Color.lerp(a.color, b.color, t),
|
||||||
titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t),
|
titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Merges [this] [ChannelListHeaderThemeData] with the [other]
|
/// Merges [this] [StreamChannelListHeaderThemeData] with the [other]
|
||||||
ChannelListHeaderThemeData merge(ChannelListHeaderThemeData? other) {
|
StreamChannelListHeaderThemeData merge(
|
||||||
|
StreamChannelListHeaderThemeData? other,
|
||||||
|
) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle,
|
titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle,
|
||||||
@@ -104,7 +118,7 @@ class ChannelListHeaderThemeData with Diagnosticable {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is ChannelListHeaderThemeData &&
|
other is StreamChannelListHeaderThemeData &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
titleStyle == other.titleStyle &&
|
titleStyle == other.titleStyle &&
|
||||||
avatarTheme == other.avatarTheme &&
|
avatarTheme == other.avatarTheme &&
|
||||||
|
|||||||
@@ -2,27 +2,33 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
|
/// {@macro channel_list_view_theme}
|
||||||
|
@Deprecated("Use 'StreamChannelListViewTheme' instead")
|
||||||
|
typedef ChannelListViewTheme = StreamChannelListViewTheme;
|
||||||
|
|
||||||
|
/// {@template channel_list_view_theme}
|
||||||
/// Overrides the default style of [ChannelListView] descendants.
|
/// Overrides the default style of [ChannelListView] descendants.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [ChannelListViewThemeData], which is used to configure this theme.
|
/// * [StreamChannelListViewThemeData], which is used to configure this theme.
|
||||||
class ChannelListViewTheme extends InheritedTheme {
|
/// {@endtemplate}
|
||||||
/// Creates a [ChannelListViewTheme].
|
class StreamChannelListViewTheme extends InheritedTheme {
|
||||||
|
/// Creates a [StreamChannelListViewTheme].
|
||||||
///
|
///
|
||||||
/// The [data] parameter must not be null.
|
/// The [data] parameter must not be null.
|
||||||
const ChannelListViewTheme({
|
const StreamChannelListViewTheme({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.data,
|
required this.data,
|
||||||
required Widget child,
|
required Widget child,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
/// The configuration of this theme.
|
/// The configuration of this theme.
|
||||||
final ChannelListViewThemeData data;
|
final StreamChannelListViewThemeData data;
|
||||||
|
|
||||||
/// The closest instance of this class that encloses the given context.
|
/// The closest instance of this class that encloses the given context.
|
||||||
///
|
///
|
||||||
/// If there is no enclosing [ChannelListViewTheme] widget, then
|
/// If there is no enclosing [StreamChannelListViewTheme] widget, then
|
||||||
/// [StreamChatThemeData.channelListViewTheme] is used.
|
/// [StreamChatThemeData.channelListViewTheme] is used.
|
||||||
///
|
///
|
||||||
/// Typical usage is as follows:
|
/// Typical usage is as follows:
|
||||||
@@ -30,63 +36,69 @@ class ChannelListViewTheme extends InheritedTheme {
|
|||||||
/// ```dart
|
/// ```dart
|
||||||
/// ChannelListViewTheme theme = ChannelListViewTheme.of(context);
|
/// ChannelListViewTheme theme = ChannelListViewTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static ChannelListViewThemeData of(BuildContext context) {
|
static StreamChannelListViewThemeData of(BuildContext context) {
|
||||||
final channelListViewTheme =
|
final channelListViewTheme = context
|
||||||
context.dependOnInheritedWidgetOfExactType<ChannelListViewTheme>();
|
.dependOnInheritedWidgetOfExactType<StreamChannelListViewTheme>();
|
||||||
return channelListViewTheme?.data ??
|
return channelListViewTheme?.data ??
|
||||||
StreamChatTheme.of(context).channelListViewTheme;
|
StreamChatTheme.of(context).channelListViewTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget wrap(BuildContext context, Widget child) =>
|
Widget wrap(BuildContext context, Widget child) =>
|
||||||
ChannelListViewTheme(data: data, child: child);
|
StreamChannelListViewTheme(data: data, child: child);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool updateShouldNotify(ChannelListViewTheme oldWidget) =>
|
bool updateShouldNotify(StreamChannelListViewTheme oldWidget) =>
|
||||||
data != oldWidget.data;
|
data != oldWidget.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro channel_list_view_theme_data}
|
||||||
|
@Deprecated("Use 'StreamChannelListViewThemeData' instead")
|
||||||
|
typedef ChannelListViewThemeData = StreamChannelListViewThemeData;
|
||||||
|
|
||||||
|
/// {@template channel_list_view_theme_data}
|
||||||
/// A style that overrides the default appearance of [ChannelListView]s when
|
/// A style that overrides the default appearance of [ChannelListView]s when
|
||||||
/// used with [ChannelListViewTheme] or with the overall [StreamChatTheme]'s
|
/// used with [StreamChannelListViewTheme] or with the overall [StreamChatTheme]'s
|
||||||
/// [StreamChatThemeData.channelListViewTheme].
|
/// [StreamChatThemeData.channelListViewTheme].
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [ChannelListViewTheme], the theme which is configured with this class.
|
/// * [StreamChannelListViewTheme], the theme which is configured with this class.
|
||||||
/// * [StreamChatThemeData.channelListViewTheme], which can be used to override
|
/// * [StreamChatThemeData.channelListViewTheme], which can be used to override
|
||||||
/// the default style for [ChannelListView]s below the overall
|
/// the default style for [ChannelListView]s below the overall
|
||||||
/// [StreamChatTheme].
|
/// [StreamChatTheme].
|
||||||
class ChannelListViewThemeData with Diagnosticable {
|
/// {@endtemplate}
|
||||||
/// Creates a [ChannelListViewThemeData].
|
class StreamChannelListViewThemeData with Diagnosticable {
|
||||||
const ChannelListViewThemeData({
|
/// Creates a [StreamChannelListViewThemeData].
|
||||||
|
const StreamChannelListViewThemeData({
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The color of the [ChannelListView] background.
|
/// The color of the [ChannelListView] background.
|
||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
|
|
||||||
/// Copies this [ChannelListViewThemeData] to another.
|
/// Copies this [StreamChannelListViewThemeData] to another.
|
||||||
ChannelListViewThemeData copyWith({
|
StreamChannelListViewThemeData copyWith({
|
||||||
Color? backgroundColor,
|
Color? backgroundColor,
|
||||||
}) =>
|
}) =>
|
||||||
ChannelListViewThemeData(
|
StreamChannelListViewThemeData(
|
||||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Linearly interpolate between two [ChannelListViewThemeData] themes.
|
/// Linearly interpolate between two [StreamChannelListViewThemeData] themes.
|
||||||
///
|
///
|
||||||
/// All the properties must be non-null.
|
/// All the properties must be non-null.
|
||||||
ChannelListViewThemeData lerp(
|
StreamChannelListViewThemeData lerp(
|
||||||
ChannelListViewThemeData a,
|
StreamChannelListViewThemeData a,
|
||||||
ChannelListViewThemeData b,
|
StreamChannelListViewThemeData b,
|
||||||
double t,
|
double t,
|
||||||
) =>
|
) =>
|
||||||
ChannelListViewThemeData(
|
StreamChannelListViewThemeData(
|
||||||
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Merges one [ChannelListViewThemeData] with another.
|
/// Merges one [StreamChannelListViewThemeData] with another.
|
||||||
ChannelListViewThemeData merge(ChannelListViewThemeData? other) {
|
StreamChannelListViewThemeData merge(StreamChannelListViewThemeData? other) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
backgroundColor: other.backgroundColor,
|
backgroundColor: other.backgroundColor,
|
||||||
@@ -96,7 +108,7 @@ class ChannelListViewThemeData with Diagnosticable {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is ChannelListViewThemeData &&
|
other is StreamChannelListViewThemeData &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
backgroundColor == other.backgroundColor;
|
backgroundColor == other.backgroundColor;
|
||||||
|
|
||||||
|
|||||||
@@ -3,27 +3,33 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
|
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
|
||||||
|
|
||||||
|
/// {@macro channel_preview_theme}
|
||||||
|
@Deprecated("Use 'StreamChannelPreviewTheme' instead")
|
||||||
|
typedef ChannelPreviewTheme = StreamChannelPreviewTheme;
|
||||||
|
|
||||||
|
/// {@template channel_preview_theme}
|
||||||
/// Overrides the default style of [ChannelPreview] descendants.
|
/// Overrides the default style of [ChannelPreview] descendants.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [ChannelPreviewThemeData], which is used to configure this theme.
|
/// * [StreamChannelPreviewThemeData], which is used to configure this theme.
|
||||||
class ChannelPreviewTheme extends InheritedTheme {
|
/// {@endtemplate}
|
||||||
/// Creates a [ChannelPreviewTheme].
|
class StreamChannelPreviewTheme extends InheritedTheme {
|
||||||
|
/// Creates a [StreamChannelPreviewTheme].
|
||||||
///
|
///
|
||||||
/// The [data] parameter must not be null.
|
/// The [data] parameter must not be null.
|
||||||
const ChannelPreviewTheme({
|
const StreamChannelPreviewTheme({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.data,
|
required this.data,
|
||||||
required Widget child,
|
required Widget child,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
/// The configuration of this theme.
|
/// The configuration of this theme.
|
||||||
final ChannelPreviewThemeData data;
|
final StreamChannelPreviewThemeData data;
|
||||||
|
|
||||||
/// The closest instance of this class that encloses the given context.
|
/// The closest instance of this class that encloses the given context.
|
||||||
///
|
///
|
||||||
/// If there is no enclosing [ChannelPreviewTheme] widget, then
|
/// If there is no enclosing [StreamChannelPreviewTheme] widget, then
|
||||||
/// [StreamChatThemeData.channelPreviewTheme] is used.
|
/// [StreamChatThemeData.channelPreviewTheme] is used.
|
||||||
///
|
///
|
||||||
/// Typical usage is as follows:
|
/// Typical usage is as follows:
|
||||||
@@ -31,34 +37,40 @@ class ChannelPreviewTheme extends InheritedTheme {
|
|||||||
/// ```dart
|
/// ```dart
|
||||||
/// final theme = ChannelPreviewTheme.of(context);
|
/// final theme = ChannelPreviewTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static ChannelPreviewThemeData of(BuildContext context) {
|
static StreamChannelPreviewThemeData of(BuildContext context) {
|
||||||
final channelPreviewTheme =
|
final channelPreviewTheme =
|
||||||
context.dependOnInheritedWidgetOfExactType<ChannelPreviewTheme>();
|
context.dependOnInheritedWidgetOfExactType<StreamChannelPreviewTheme>();
|
||||||
return channelPreviewTheme?.data ??
|
return channelPreviewTheme?.data ??
|
||||||
StreamChatTheme.of(context).channelPreviewTheme;
|
StreamChatTheme.of(context).channelPreviewTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget wrap(BuildContext context, Widget child) =>
|
Widget wrap(BuildContext context, Widget child) =>
|
||||||
ChannelPreviewTheme(data: data, child: child);
|
StreamChannelPreviewTheme(data: data, child: child);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool updateShouldNotify(ChannelPreviewTheme oldWidget) =>
|
bool updateShouldNotify(StreamChannelPreviewTheme oldWidget) =>
|
||||||
data != oldWidget.data;
|
data != oldWidget.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro channel_preview_theme_data}
|
||||||
|
@Deprecated("Use 'StreamChannelPreviewThemeData' instead")
|
||||||
|
typedef ChannelPreviewThemeData = StreamChannelPreviewThemeData;
|
||||||
|
|
||||||
|
/// {@template channel_preview_theme_data}
|
||||||
/// A style that overrides the default appearance of [ChannelPreview]s when used
|
/// A style that overrides the default appearance of [ChannelPreview]s when used
|
||||||
/// with [ChannelPreviewTheme] or with the overall [StreamChatTheme]'s
|
/// with [StreamChannelPreviewTheme] or with the overall [StreamChatTheme]'s
|
||||||
/// [StreamChatThemeData.channelPreviewTheme].
|
/// [StreamChatThemeData.channelPreviewTheme].
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [ChannelPreviewTheme], the theme which is configured with this class.
|
/// * [StreamChannelPreviewTheme], the theme which is configured with this class.
|
||||||
/// * [StreamChatThemeData.channelPreviewTheme], which can be used to override
|
/// * [StreamChatThemeData.channelPreviewTheme], which can be used to override
|
||||||
/// the default style for [ChannelHeader]s below the overall [StreamChatTheme].
|
/// the default style for [ChannelHeader]s below the overall [StreamChatTheme].
|
||||||
class ChannelPreviewThemeData with Diagnosticable {
|
/// {@endtemplate}
|
||||||
/// Creates a [ChannelPreviewThemeData].
|
class StreamChannelPreviewThemeData with Diagnosticable {
|
||||||
const ChannelPreviewThemeData({
|
/// Creates a [StreamChannelPreviewThemeData].
|
||||||
|
const StreamChannelPreviewThemeData({
|
||||||
this.titleStyle,
|
this.titleStyle,
|
||||||
this.subtitleStyle,
|
this.subtitleStyle,
|
||||||
this.lastMessageAtStyle,
|
this.lastMessageAtStyle,
|
||||||
@@ -77,7 +89,7 @@ class ChannelPreviewThemeData with Diagnosticable {
|
|||||||
final TextStyle? lastMessageAtStyle;
|
final TextStyle? lastMessageAtStyle;
|
||||||
|
|
||||||
/// Avatar theme
|
/// Avatar theme
|
||||||
final AvatarThemeData? avatarTheme;
|
final StreamAvatarThemeData? avatarTheme;
|
||||||
|
|
||||||
/// Unread counter color
|
/// Unread counter color
|
||||||
final Color? unreadCounterColor;
|
final Color? unreadCounterColor;
|
||||||
@@ -86,15 +98,15 @@ class ChannelPreviewThemeData with Diagnosticable {
|
|||||||
final double? indicatorIconSize;
|
final double? indicatorIconSize;
|
||||||
|
|
||||||
/// Copy with theme
|
/// Copy with theme
|
||||||
ChannelPreviewThemeData copyWith({
|
StreamChannelPreviewThemeData copyWith({
|
||||||
TextStyle? titleStyle,
|
TextStyle? titleStyle,
|
||||||
TextStyle? subtitleStyle,
|
TextStyle? subtitleStyle,
|
||||||
TextStyle? lastMessageAtStyle,
|
TextStyle? lastMessageAtStyle,
|
||||||
AvatarThemeData? avatarTheme,
|
StreamAvatarThemeData? avatarTheme,
|
||||||
Color? unreadCounterColor,
|
Color? unreadCounterColor,
|
||||||
double? indicatorIconSize,
|
double? indicatorIconSize,
|
||||||
}) =>
|
}) =>
|
||||||
ChannelPreviewThemeData(
|
StreamChannelPreviewThemeData(
|
||||||
titleStyle: titleStyle ?? this.titleStyle,
|
titleStyle: titleStyle ?? this.titleStyle,
|
||||||
subtitleStyle: subtitleStyle ?? this.subtitleStyle,
|
subtitleStyle: subtitleStyle ?? this.subtitleStyle,
|
||||||
lastMessageAtStyle: lastMessageAtStyle ?? this.lastMessageAtStyle,
|
lastMessageAtStyle: lastMessageAtStyle ?? this.lastMessageAtStyle,
|
||||||
@@ -103,15 +115,15 @@ class ChannelPreviewThemeData with Diagnosticable {
|
|||||||
indicatorIconSize: indicatorIconSize ?? this.indicatorIconSize,
|
indicatorIconSize: indicatorIconSize ?? this.indicatorIconSize,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Linearly interpolate one [ChannelPreviewThemeData] to another.
|
/// Linearly interpolate one [StreamChannelPreviewThemeData] to another.
|
||||||
ChannelPreviewThemeData lerp(
|
StreamChannelPreviewThemeData lerp(
|
||||||
ChannelPreviewThemeData a,
|
StreamChannelPreviewThemeData a,
|
||||||
ChannelPreviewThemeData b,
|
StreamChannelPreviewThemeData b,
|
||||||
double t,
|
double t,
|
||||||
) =>
|
) =>
|
||||||
ChannelPreviewThemeData(
|
StreamChannelPreviewThemeData(
|
||||||
avatarTheme:
|
avatarTheme: const StreamAvatarThemeData()
|
||||||
const AvatarThemeData().lerp(a.avatarTheme!, b.avatarTheme!, t),
|
.lerp(a.avatarTheme!, b.avatarTheme!, t),
|
||||||
indicatorIconSize: a.indicatorIconSize,
|
indicatorIconSize: a.indicatorIconSize,
|
||||||
lastMessageAtStyle:
|
lastMessageAtStyle:
|
||||||
TextStyle.lerp(a.lastMessageAtStyle, b.lastMessageAtStyle, t),
|
TextStyle.lerp(a.lastMessageAtStyle, b.lastMessageAtStyle, t),
|
||||||
@@ -122,7 +134,7 @@ class ChannelPreviewThemeData with Diagnosticable {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/// Merge with theme
|
/// Merge with theme
|
||||||
ChannelPreviewThemeData merge(ChannelPreviewThemeData? other) {
|
StreamChannelPreviewThemeData merge(StreamChannelPreviewThemeData? other) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle,
|
titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle,
|
||||||
@@ -138,7 +150,7 @@ class ChannelPreviewThemeData with Diagnosticable {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is ChannelPreviewThemeData &&
|
other is StreamChannelPreviewThemeData &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
titleStyle == other.titleStyle &&
|
titleStyle == other.titleStyle &&
|
||||||
subtitleStyle == other.subtitleStyle &&
|
subtitleStyle == other.subtitleStyle &&
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// {@macro color_theme}
|
||||||
|
@Deprecated("Use 'StreamColorTheme' instead")
|
||||||
|
typedef ColorTheme = StreamColorTheme;
|
||||||
|
|
||||||
|
/// {@template color_theme}
|
||||||
/// Theme that holds colors
|
/// Theme that holds colors
|
||||||
class ColorTheme {
|
/// {@endtemplate}
|
||||||
|
class StreamColorTheme {
|
||||||
/// Initialise with light theme
|
/// Initialise with light theme
|
||||||
ColorTheme.light({
|
StreamColorTheme.light({
|
||||||
this.textHighEmphasis = const Color(0xff000000),
|
this.textHighEmphasis = const Color(0xff000000),
|
||||||
this.textLowEmphasis = const Color(0xff7a7a7a),
|
this.textLowEmphasis = const Color(0xff7a7a7a),
|
||||||
this.disabled = const Color(0xffdbdbdb),
|
this.disabled = const Color(0xffdbdbdb),
|
||||||
@@ -55,7 +61,7 @@ class ColorTheme {
|
|||||||
}) : brightness = Brightness.light;
|
}) : brightness = Brightness.light;
|
||||||
|
|
||||||
/// Initialise with dark theme
|
/// Initialise with dark theme
|
||||||
ColorTheme.dark({
|
StreamColorTheme.dark({
|
||||||
this.textHighEmphasis = const Color(0xffffffff),
|
this.textHighEmphasis = const Color(0xffffffff),
|
||||||
this.textLowEmphasis = const Color(0xff7a7a7a),
|
this.textLowEmphasis = const Color(0xff7a7a7a),
|
||||||
this.disabled = const Color(0xff2d2f2f),
|
this.disabled = const Color(0xff2d2f2f),
|
||||||
@@ -169,7 +175,7 @@ class ColorTheme {
|
|||||||
final Brightness brightness;
|
final Brightness brightness;
|
||||||
|
|
||||||
/// Copy with theme
|
/// Copy with theme
|
||||||
ColorTheme copyWith({
|
StreamColorTheme copyWith({
|
||||||
Brightness brightness = Brightness.light,
|
Brightness brightness = Brightness.light,
|
||||||
Color? textHighEmphasis,
|
Color? textHighEmphasis,
|
||||||
Color? textLowEmphasis,
|
Color? textLowEmphasis,
|
||||||
@@ -192,7 +198,7 @@ class ColorTheme {
|
|||||||
Gradient? bgGradient,
|
Gradient? bgGradient,
|
||||||
}) =>
|
}) =>
|
||||||
brightness == Brightness.light
|
brightness == Brightness.light
|
||||||
? ColorTheme.light(
|
? StreamColorTheme.light(
|
||||||
textHighEmphasis: textHighEmphasis ?? this.textHighEmphasis,
|
textHighEmphasis: textHighEmphasis ?? this.textHighEmphasis,
|
||||||
textLowEmphasis: textLowEmphasis ?? this.textLowEmphasis,
|
textLowEmphasis: textLowEmphasis ?? this.textLowEmphasis,
|
||||||
disabled: disabled ?? this.disabled,
|
disabled: disabled ?? this.disabled,
|
||||||
@@ -213,7 +219,7 @@ class ColorTheme {
|
|||||||
overlayDark: overlayDark ?? this.overlayDark,
|
overlayDark: overlayDark ?? this.overlayDark,
|
||||||
bgGradient: bgGradient ?? this.bgGradient,
|
bgGradient: bgGradient ?? this.bgGradient,
|
||||||
)
|
)
|
||||||
: ColorTheme.dark(
|
: StreamColorTheme.dark(
|
||||||
textHighEmphasis: textHighEmphasis ?? this.textHighEmphasis,
|
textHighEmphasis: textHighEmphasis ?? this.textHighEmphasis,
|
||||||
textLowEmphasis: textLowEmphasis ?? this.textLowEmphasis,
|
textLowEmphasis: textLowEmphasis ?? this.textLowEmphasis,
|
||||||
disabled: disabled ?? this.disabled,
|
disabled: disabled ?? this.disabled,
|
||||||
@@ -236,7 +242,7 @@ class ColorTheme {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/// Merge color theme
|
/// Merge color theme
|
||||||
ColorTheme merge(ColorTheme? other) {
|
StreamColorTheme merge(StreamColorTheme? other) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
textHighEmphasis: other.textHighEmphasis,
|
textHighEmphasis: other.textHighEmphasis,
|
||||||
|
|||||||
@@ -2,27 +2,33 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
|
/// {@macro gallery_footer_theme}
|
||||||
|
@Deprecated("Use 'StreamGalleryFooterTheme' instead")
|
||||||
|
typedef GalleryFooterTheme = StreamGalleryFooterTheme;
|
||||||
|
|
||||||
|
/// {@template gallery_footer_theme}
|
||||||
/// Overrides the default style of [GalleryFooter] descendants.
|
/// Overrides the default style of [GalleryFooter] descendants.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [GalleryFooterThemeData], which is used to configure this theme.
|
/// * [StreamGalleryFooterThemeData], which is used to configure this theme.
|
||||||
class GalleryFooterTheme extends InheritedTheme {
|
/// {@endtemplate}
|
||||||
/// Creates an [GalleryFooterTheme].
|
class StreamGalleryFooterTheme extends InheritedTheme {
|
||||||
|
/// Creates an [StreamGalleryFooterTheme].
|
||||||
///
|
///
|
||||||
/// The [data] parameter must not be null.
|
/// The [data] parameter must not be null.
|
||||||
const GalleryFooterTheme({
|
const StreamGalleryFooterTheme({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.data,
|
required this.data,
|
||||||
required Widget child,
|
required Widget child,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
/// The configuration of this theme.
|
/// The configuration of this theme.
|
||||||
final GalleryFooterThemeData data;
|
final StreamGalleryFooterThemeData data;
|
||||||
|
|
||||||
/// The closest instance of this class that encloses the given context.
|
/// The closest instance of this class that encloses the given context.
|
||||||
///
|
///
|
||||||
/// If there is no enclosing [GalleryFooterTheme] widget, then
|
/// If there is no enclosing [StreamGalleryFooterTheme] widget, then
|
||||||
/// [StreamChatThemeData.galleryFooterTheme] is used.
|
/// [StreamChatThemeData.galleryFooterTheme] is used.
|
||||||
///
|
///
|
||||||
/// Typical usage is as follows:
|
/// Typical usage is as follows:
|
||||||
@@ -30,34 +36,40 @@ class GalleryFooterTheme extends InheritedTheme {
|
|||||||
/// ```dart
|
/// ```dart
|
||||||
/// ImageFooterTheme theme = ImageFooterTheme.of(context);
|
/// ImageFooterTheme theme = ImageFooterTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static GalleryFooterThemeData of(BuildContext context) {
|
static StreamGalleryFooterThemeData of(BuildContext context) {
|
||||||
final imageFooterTheme =
|
final imageFooterTheme =
|
||||||
context.dependOnInheritedWidgetOfExactType<GalleryFooterTheme>();
|
context.dependOnInheritedWidgetOfExactType<StreamGalleryFooterTheme>();
|
||||||
return imageFooterTheme?.data ??
|
return imageFooterTheme?.data ??
|
||||||
StreamChatTheme.of(context).galleryFooterTheme;
|
StreamChatTheme.of(context).galleryFooterTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget wrap(BuildContext context, Widget child) =>
|
Widget wrap(BuildContext context, Widget child) =>
|
||||||
GalleryFooterTheme(data: data, child: child);
|
StreamGalleryFooterTheme(data: data, child: child);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool updateShouldNotify(GalleryFooterTheme oldWidget) =>
|
bool updateShouldNotify(StreamGalleryFooterTheme oldWidget) =>
|
||||||
data != oldWidget.data;
|
data != oldWidget.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro gallery_footer_theme_data}
|
||||||
|
@Deprecated("Use 'StreamGalleryFooterThemeData' instead")
|
||||||
|
typedef GalleryFooterThemeData = StreamGalleryFooterThemeData;
|
||||||
|
|
||||||
|
/// {@template gallery_footer_theme_data}
|
||||||
/// A style that overrides the default appearance of [GalleryFooter]s when used
|
/// A style that overrides the default appearance of [GalleryFooter]s when used
|
||||||
/// with [GalleryFooterTheme] or with the overall [StreamChatTheme]'s
|
/// with [StreamGalleryFooterTheme] or with the overall [StreamChatTheme]'s
|
||||||
/// [StreamChatThemeData.galleryFooterTheme].
|
/// [StreamChatThemeData.galleryFooterTheme].
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [GalleryFooterTheme], the theme which is configured with this class.
|
/// * [StreamGalleryFooterTheme], the theme which is configured with this class.
|
||||||
/// * [StreamChatThemeData.galleryFooterTheme], which can be used to override
|
/// * [StreamChatThemeData.galleryFooterTheme], which can be used to override
|
||||||
/// the default style for [GalleryFooter]s below the overall [StreamChatTheme].
|
/// the default style for [GalleryFooter]s below the overall [StreamChatTheme].
|
||||||
class GalleryFooterThemeData with Diagnosticable {
|
/// {@endtemplate}
|
||||||
/// Creates an [GalleryFooterThemeData].
|
class StreamGalleryFooterThemeData with Diagnosticable {
|
||||||
const GalleryFooterThemeData({
|
/// Creates an [StreamGalleryFooterThemeData].
|
||||||
|
const StreamGalleryFooterThemeData({
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.shareIconColor,
|
this.shareIconColor,
|
||||||
this.titleTextStyle,
|
this.titleTextStyle,
|
||||||
@@ -108,8 +120,8 @@ class GalleryFooterThemeData with Diagnosticable {
|
|||||||
/// Defaults to [ColorTheme.textHighEmphasis].
|
/// Defaults to [ColorTheme.textHighEmphasis].
|
||||||
final Color? bottomSheetCloseIconColor;
|
final Color? bottomSheetCloseIconColor;
|
||||||
|
|
||||||
/// Copies this [GalleryFooterThemeData] to another.
|
/// Copies this [StreamGalleryFooterThemeData] to another.
|
||||||
GalleryFooterThemeData copyWith({
|
StreamGalleryFooterThemeData copyWith({
|
||||||
Color? backgroundColor,
|
Color? backgroundColor,
|
||||||
Color? shareIconColor,
|
Color? shareIconColor,
|
||||||
TextStyle? titleTextStyle,
|
TextStyle? titleTextStyle,
|
||||||
@@ -119,7 +131,7 @@ class GalleryFooterThemeData with Diagnosticable {
|
|||||||
TextStyle? bottomSheetPhotosTextStyle,
|
TextStyle? bottomSheetPhotosTextStyle,
|
||||||
Color? bottomSheetCloseIconColor,
|
Color? bottomSheetCloseIconColor,
|
||||||
}) =>
|
}) =>
|
||||||
GalleryFooterThemeData(
|
StreamGalleryFooterThemeData(
|
||||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||||
shareIconColor: shareIconColor ?? this.shareIconColor,
|
shareIconColor: shareIconColor ?? this.shareIconColor,
|
||||||
titleTextStyle: titleTextStyle ?? this.titleTextStyle,
|
titleTextStyle: titleTextStyle ?? this.titleTextStyle,
|
||||||
@@ -137,12 +149,12 @@ class GalleryFooterThemeData with Diagnosticable {
|
|||||||
/// Linearly interpolate between two [GalleryFooter] themes.
|
/// Linearly interpolate between two [GalleryFooter] themes.
|
||||||
///
|
///
|
||||||
/// All the properties must be non-null.
|
/// All the properties must be non-null.
|
||||||
GalleryFooterThemeData lerp(
|
StreamGalleryFooterThemeData lerp(
|
||||||
GalleryFooterThemeData a,
|
StreamGalleryFooterThemeData a,
|
||||||
GalleryFooterThemeData b,
|
StreamGalleryFooterThemeData b,
|
||||||
double t,
|
double t,
|
||||||
) =>
|
) =>
|
||||||
GalleryFooterThemeData(
|
StreamGalleryFooterThemeData(
|
||||||
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
||||||
shareIconColor: Color.lerp(a.shareIconColor, b.shareIconColor, t),
|
shareIconColor: Color.lerp(a.shareIconColor, b.shareIconColor, t),
|
||||||
titleTextStyle: TextStyle.lerp(a.titleTextStyle, b.titleTextStyle, t),
|
titleTextStyle: TextStyle.lerp(a.titleTextStyle, b.titleTextStyle, t),
|
||||||
@@ -167,8 +179,8 @@ class GalleryFooterThemeData with Diagnosticable {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Merges one [GalleryFooterThemeData] with another.
|
/// Merges one [StreamGalleryFooterThemeData] with another.
|
||||||
GalleryFooterThemeData merge(GalleryFooterThemeData? other) {
|
StreamGalleryFooterThemeData merge(StreamGalleryFooterThemeData? other) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
backgroundColor: other.backgroundColor,
|
backgroundColor: other.backgroundColor,
|
||||||
@@ -185,7 +197,7 @@ class GalleryFooterThemeData with Diagnosticable {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is GalleryFooterThemeData &&
|
other is StreamGalleryFooterThemeData &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
backgroundColor == other.backgroundColor &&
|
backgroundColor == other.backgroundColor &&
|
||||||
shareIconColor == other.shareIconColor &&
|
shareIconColor == other.shareIconColor &&
|
||||||
|
|||||||
@@ -2,27 +2,33 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
|
/// {@macro gallery_header_them}
|
||||||
|
@Deprecated("Use 'StreamGalleryHeaderTheme' instead")
|
||||||
|
typedef GalleryHeaderTheme = StreamGalleryHeaderTheme;
|
||||||
|
|
||||||
|
/// {@template gallery_header_theme}
|
||||||
/// Overrides the default style of [GalleryHeader] descendants.
|
/// Overrides the default style of [GalleryHeader] descendants.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [GalleryHeaderThemeData], which is used to configure this theme.
|
/// * [StreamGalleryHeaderThemeData], which is used to configure this theme.
|
||||||
class GalleryHeaderTheme extends InheritedTheme {
|
/// {@endtemplate}
|
||||||
/// Creates a [GalleryHeaderTheme].
|
class StreamGalleryHeaderTheme extends InheritedTheme {
|
||||||
|
/// Creates a [StreamGalleryHeaderTheme].
|
||||||
///
|
///
|
||||||
/// The [data] parameter must not be null.
|
/// The [data] parameter must not be null.
|
||||||
const GalleryHeaderTheme({
|
const StreamGalleryHeaderTheme({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.data,
|
required this.data,
|
||||||
required Widget child,
|
required Widget child,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
/// The configuration of this theme.
|
/// The configuration of this theme.
|
||||||
final GalleryHeaderThemeData data;
|
final StreamGalleryHeaderThemeData data;
|
||||||
|
|
||||||
/// The closest instance of this class that encloses the given context.
|
/// The closest instance of this class that encloses the given context.
|
||||||
///
|
///
|
||||||
/// If there is no enclosing [GalleryHeaderTheme] widget, then
|
/// If there is no enclosing [StreamGalleryHeaderTheme] widget, then
|
||||||
/// [StreamChatThemeData.galleryHeaderTheme] is used.
|
/// [StreamChatThemeData.galleryHeaderTheme] is used.
|
||||||
///
|
///
|
||||||
/// Typical usage is as follows:
|
/// Typical usage is as follows:
|
||||||
@@ -30,34 +36,40 @@ class GalleryHeaderTheme extends InheritedTheme {
|
|||||||
/// ```dart
|
/// ```dart
|
||||||
/// ImageHeaderTheme theme = ImageHeaderTheme.of(context);
|
/// ImageHeaderTheme theme = ImageHeaderTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static GalleryHeaderThemeData of(BuildContext context) {
|
static StreamGalleryHeaderThemeData of(BuildContext context) {
|
||||||
final galleryHeaderTheme =
|
final galleryHeaderTheme =
|
||||||
context.dependOnInheritedWidgetOfExactType<GalleryHeaderTheme>();
|
context.dependOnInheritedWidgetOfExactType<StreamGalleryHeaderTheme>();
|
||||||
return galleryHeaderTheme?.data ??
|
return galleryHeaderTheme?.data ??
|
||||||
StreamChatTheme.of(context).galleryHeaderTheme;
|
StreamChatTheme.of(context).galleryHeaderTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget wrap(BuildContext context, Widget child) =>
|
Widget wrap(BuildContext context, Widget child) =>
|
||||||
GalleryHeaderTheme(data: data, child: child);
|
StreamGalleryHeaderTheme(data: data, child: child);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool updateShouldNotify(GalleryHeaderTheme oldWidget) =>
|
bool updateShouldNotify(StreamGalleryHeaderTheme oldWidget) =>
|
||||||
data != oldWidget.data;
|
data != oldWidget.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro gallery_header_theme_data}
|
||||||
|
@Deprecated("Use 'StreamGalleryHeaderThemeData' instead")
|
||||||
|
typedef GalleryHeaderThemeData = StreamGalleryHeaderThemeData;
|
||||||
|
|
||||||
|
/// {@template gallery_header_theme_data}
|
||||||
/// A style that overrides the default appearance of [GalleryHeader]s when used
|
/// A style that overrides the default appearance of [GalleryHeader]s when used
|
||||||
/// with [GalleryHeaderTheme] or with the overall [StreamChatTheme]'s
|
/// with [StreamGalleryHeaderTheme] or with the overall [StreamChatTheme]'s
|
||||||
/// [StreamChatThemeData.galleryHeaderTheme].
|
/// [StreamChatThemeData.galleryHeaderTheme].
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [GalleryHeaderTheme], the theme which is configured with this class.
|
/// * [StreamGalleryHeaderTheme], the theme which is configured with this class.
|
||||||
/// * [StreamChatThemeData.galleryHeaderTheme], which can be used to override
|
/// * [StreamChatThemeData.galleryHeaderTheme], which can be used to override
|
||||||
/// the default style for [GalleryHeader]s below the overall [StreamChatTheme].
|
/// the default style for [GalleryHeader]s below the overall [StreamChatTheme].
|
||||||
class GalleryHeaderThemeData with Diagnosticable {
|
/// {@endtemplate}
|
||||||
/// Creates an [GalleryHeaderThemeData].
|
class StreamGalleryHeaderThemeData with Diagnosticable {
|
||||||
const GalleryHeaderThemeData({
|
/// Creates an [StreamGalleryHeaderThemeData].
|
||||||
|
const StreamGalleryHeaderThemeData({
|
||||||
this.closeButtonColor,
|
this.closeButtonColor,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.iconMenuPointColor,
|
this.iconMenuPointColor,
|
||||||
@@ -92,8 +104,8 @@ class GalleryHeaderThemeData with Diagnosticable {
|
|||||||
///
|
///
|
||||||
final Color? bottomSheetBarrierColor;
|
final Color? bottomSheetBarrierColor;
|
||||||
|
|
||||||
/// Copies this [GalleryHeaderThemeData] to another.
|
/// Copies this [StreamGalleryHeaderThemeData] to another.
|
||||||
GalleryHeaderThemeData copyWith({
|
StreamGalleryHeaderThemeData copyWith({
|
||||||
Color? closeButtonColor,
|
Color? closeButtonColor,
|
||||||
Color? backgroundColor,
|
Color? backgroundColor,
|
||||||
Color? iconMenuPointColor,
|
Color? iconMenuPointColor,
|
||||||
@@ -101,7 +113,7 @@ class GalleryHeaderThemeData with Diagnosticable {
|
|||||||
TextStyle? subtitleTextStyle,
|
TextStyle? subtitleTextStyle,
|
||||||
Color? bottomSheetBarrierColor,
|
Color? bottomSheetBarrierColor,
|
||||||
}) =>
|
}) =>
|
||||||
GalleryHeaderThemeData(
|
StreamGalleryHeaderThemeData(
|
||||||
closeButtonColor: closeButtonColor ?? this.closeButtonColor,
|
closeButtonColor: closeButtonColor ?? this.closeButtonColor,
|
||||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||||
iconMenuPointColor: iconMenuPointColor ?? this.iconMenuPointColor,
|
iconMenuPointColor: iconMenuPointColor ?? this.iconMenuPointColor,
|
||||||
@@ -114,12 +126,12 @@ class GalleryHeaderThemeData with Diagnosticable {
|
|||||||
/// Linearly interpolate between two [GalleryHeader] themes.
|
/// Linearly interpolate between two [GalleryHeader] themes.
|
||||||
///
|
///
|
||||||
/// All the properties must be non-null.
|
/// All the properties must be non-null.
|
||||||
GalleryHeaderThemeData lerp(
|
StreamGalleryHeaderThemeData lerp(
|
||||||
GalleryHeaderThemeData a,
|
StreamGalleryHeaderThemeData a,
|
||||||
GalleryHeaderThemeData b,
|
StreamGalleryHeaderThemeData b,
|
||||||
double t,
|
double t,
|
||||||
) =>
|
) =>
|
||||||
GalleryHeaderThemeData(
|
StreamGalleryHeaderThemeData(
|
||||||
closeButtonColor: Color.lerp(a.closeButtonColor, b.closeButtonColor, t),
|
closeButtonColor: Color.lerp(a.closeButtonColor, b.closeButtonColor, t),
|
||||||
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
||||||
iconMenuPointColor:
|
iconMenuPointColor:
|
||||||
@@ -131,8 +143,8 @@ class GalleryHeaderThemeData with Diagnosticable {
|
|||||||
Color.lerp(a.bottomSheetBarrierColor, b.bottomSheetBarrierColor, t),
|
Color.lerp(a.bottomSheetBarrierColor, b.bottomSheetBarrierColor, t),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Merges one [GalleryHeaderThemeData] with the another
|
/// Merges one [StreamGalleryHeaderThemeData] with the another
|
||||||
GalleryHeaderThemeData merge(GalleryHeaderThemeData? other) {
|
StreamGalleryHeaderThemeData merge(StreamGalleryHeaderThemeData? other) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
closeButtonColor: other.closeButtonColor,
|
closeButtonColor: other.closeButtonColor,
|
||||||
@@ -147,7 +159,7 @@ class GalleryHeaderThemeData with Diagnosticable {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is GalleryHeaderThemeData &&
|
other is StreamGalleryHeaderThemeData &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
closeButtonColor == other.closeButtonColor &&
|
closeButtonColor == other.closeButtonColor &&
|
||||||
backgroundColor == other.backgroundColor &&
|
backgroundColor == other.backgroundColor &&
|
||||||
|
|||||||
@@ -5,27 +5,33 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
|
/// {@macro message_input_theme}
|
||||||
|
@Deprecated("Use 'StreamMessageInputTheme' instead")
|
||||||
|
typedef MessageInputTheme = StreamMessageInputTheme;
|
||||||
|
|
||||||
|
/// {@template message_input_theme}
|
||||||
/// Overrides the default style of [MessageInput] descendants.
|
/// Overrides the default style of [MessageInput] descendants.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [MessageInputThemeData], which is used to configure this theme.
|
/// * [StreamMessageInputThemeData], which is used to configure this theme.
|
||||||
class MessageInputTheme extends InheritedTheme {
|
/// {@endtemplate}
|
||||||
/// Creates a [MessageInputTheme].
|
class StreamMessageInputTheme extends InheritedTheme {
|
||||||
|
/// Creates a [StreamMessageInputTheme].
|
||||||
///
|
///
|
||||||
/// The [data] parameter must not be null.
|
/// The [data] parameter must not be null.
|
||||||
const MessageInputTheme({
|
const StreamMessageInputTheme({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.data,
|
required this.data,
|
||||||
required Widget child,
|
required Widget child,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
/// The configuration of this theme.
|
/// The configuration of this theme.
|
||||||
final MessageInputThemeData data;
|
final StreamMessageInputThemeData data;
|
||||||
|
|
||||||
/// The closest instance of this class that encloses the given context.
|
/// The closest instance of this class that encloses the given context.
|
||||||
///
|
///
|
||||||
/// If there is no enclosing [MessageInputTheme] widget, then
|
/// If there is no enclosing [StreamMessageInputTheme] widget, then
|
||||||
/// [StreamChatThemeData.messageInputTheme] is used.
|
/// [StreamChatThemeData.messageInputTheme] is used.
|
||||||
///
|
///
|
||||||
/// Typical usage is as follows:
|
/// Typical usage is as follows:
|
||||||
@@ -33,28 +39,34 @@ class MessageInputTheme extends InheritedTheme {
|
|||||||
/// ```dart
|
/// ```dart
|
||||||
/// final theme = MessageInputTheme.of(context);
|
/// final theme = MessageInputTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static MessageInputThemeData of(BuildContext context) {
|
static StreamMessageInputThemeData of(BuildContext context) {
|
||||||
final messageInputTheme =
|
final messageInputTheme =
|
||||||
context.dependOnInheritedWidgetOfExactType<MessageInputTheme>();
|
context.dependOnInheritedWidgetOfExactType<StreamMessageInputTheme>();
|
||||||
return messageInputTheme?.data ??
|
return messageInputTheme?.data ??
|
||||||
StreamChatTheme.of(context).messageInputTheme;
|
StreamChatTheme.of(context).messageInputTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget wrap(BuildContext context, Widget child) =>
|
Widget wrap(BuildContext context, Widget child) =>
|
||||||
MessageInputTheme(data: data, child: child);
|
StreamMessageInputTheme(data: data, child: child);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool updateShouldNotify(MessageInputTheme oldWidget) =>
|
bool updateShouldNotify(StreamMessageInputTheme oldWidget) =>
|
||||||
data != oldWidget.data;
|
data != oldWidget.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro message_input_theme_data}
|
||||||
|
@Deprecated("Use 'StreamMessageInputThemeData' instead")
|
||||||
|
typedef MessageInputThemeData = StreamMessageInputThemeData;
|
||||||
|
|
||||||
|
/// {@template message_input_theme_data}
|
||||||
/// A style that overrides the default appearance of [MessageInput] widgets
|
/// A style that overrides the default appearance of [MessageInput] widgets
|
||||||
/// when used with [MessageInputTheme] or with the overall [StreamChatTheme]'s
|
/// when used with [StreamMessageInputTheme] or with the overall [StreamChatTheme]'s
|
||||||
/// [StreamChatThemeData.messageInputTheme].
|
/// [StreamChatThemeData.messageInputTheme].
|
||||||
class MessageInputThemeData with Diagnosticable {
|
/// {@endtemplate}
|
||||||
/// Creates a [MessageInputThemeData].
|
class StreamMessageInputThemeData with Diagnosticable {
|
||||||
const MessageInputThemeData({
|
/// Creates a [StreamMessageInputThemeData].
|
||||||
|
const StreamMessageInputThemeData({
|
||||||
this.sendAnimationDuration,
|
this.sendAnimationDuration,
|
||||||
this.actionButtonColor,
|
this.actionButtonColor,
|
||||||
this.sendButtonColor,
|
this.sendButtonColor,
|
||||||
@@ -121,8 +133,8 @@ class MessageInputThemeData with Diagnosticable {
|
|||||||
/// Shadow for the [MessageInput] widget
|
/// Shadow for the [MessageInput] widget
|
||||||
final BoxShadow? shadow;
|
final BoxShadow? shadow;
|
||||||
|
|
||||||
/// Returns a new [MessageInputThemeData] replacing some of its properties
|
/// Returns a new [StreamMessageInputThemeData] replacing some of its properties
|
||||||
MessageInputThemeData copyWith({
|
StreamMessageInputThemeData copyWith({
|
||||||
Duration? sendAnimationDuration,
|
Duration? sendAnimationDuration,
|
||||||
Color? inputBackgroundColor,
|
Color? inputBackgroundColor,
|
||||||
Color? actionButtonColor,
|
Color? actionButtonColor,
|
||||||
@@ -140,7 +152,7 @@ class MessageInputThemeData with Diagnosticable {
|
|||||||
double? elevation,
|
double? elevation,
|
||||||
BoxShadow? shadow,
|
BoxShadow? shadow,
|
||||||
}) =>
|
}) =>
|
||||||
MessageInputThemeData(
|
StreamMessageInputThemeData(
|
||||||
sendAnimationDuration:
|
sendAnimationDuration:
|
||||||
sendAnimationDuration ?? this.sendAnimationDuration,
|
sendAnimationDuration ?? this.sendAnimationDuration,
|
||||||
inputBackgroundColor: inputBackgroundColor ?? this.inputBackgroundColor,
|
inputBackgroundColor: inputBackgroundColor ?? this.inputBackgroundColor,
|
||||||
@@ -161,13 +173,13 @@ class MessageInputThemeData with Diagnosticable {
|
|||||||
shadow: shadow ?? this.shadow,
|
shadow: shadow ?? this.shadow,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Linearly interpolate from one [MessageInputThemeData] to another.
|
/// Linearly interpolate from one [StreamMessageInputThemeData] to another.
|
||||||
MessageInputThemeData lerp(
|
StreamMessageInputThemeData lerp(
|
||||||
MessageInputThemeData a,
|
StreamMessageInputThemeData a,
|
||||||
MessageInputThemeData b,
|
StreamMessageInputThemeData b,
|
||||||
double t,
|
double t,
|
||||||
) =>
|
) =>
|
||||||
MessageInputThemeData(
|
StreamMessageInputThemeData(
|
||||||
actionButtonColor:
|
actionButtonColor:
|
||||||
Color.lerp(a.actionButtonColor, b.actionButtonColor, t),
|
Color.lerp(a.actionButtonColor, b.actionButtonColor, t),
|
||||||
actionButtonIdleColor:
|
actionButtonIdleColor:
|
||||||
@@ -194,8 +206,8 @@ class MessageInputThemeData with Diagnosticable {
|
|||||||
shadow: BoxShadow.lerp(a.shadow, b.shadow, t),
|
shadow: BoxShadow.lerp(a.shadow, b.shadow, t),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Merges [this] [MessageInputThemeData] with the [other]
|
/// Merges [this] [StreamMessageInputThemeData] with the [other]
|
||||||
MessageInputThemeData merge(MessageInputThemeData? other) {
|
StreamMessageInputThemeData merge(StreamMessageInputThemeData? other) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
sendAnimationDuration: other.sendAnimationDuration,
|
sendAnimationDuration: other.sendAnimationDuration,
|
||||||
@@ -222,7 +234,7 @@ class MessageInputThemeData with Diagnosticable {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is MessageInputThemeData &&
|
other is StreamMessageInputThemeData &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
sendAnimationDuration == other.sendAnimationDuration &&
|
sendAnimationDuration == other.sendAnimationDuration &&
|
||||||
sendButtonColor == other.sendButtonColor &&
|
sendButtonColor == other.sendButtonColor &&
|
||||||
|
|||||||
@@ -2,27 +2,33 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
|
/// {@macro message_list_view_theme}
|
||||||
|
@Deprecated("Use 'StreamMessageListViewTheme' instead")
|
||||||
|
typedef MessageListViewTheme = StreamMessageListViewTheme;
|
||||||
|
|
||||||
|
/// {@template message_list_view_theme}
|
||||||
/// Overrides the default style of [MessageListView] descendants.
|
/// Overrides the default style of [MessageListView] descendants.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [MessageListViewThemeData], which is used to configure this theme.
|
/// * [StreamMessageListViewThemeData], which is used to configure this theme.
|
||||||
class MessageListViewTheme extends InheritedTheme {
|
/// {@endtemplate}
|
||||||
/// Creates a [MessageListViewTheme].
|
class StreamMessageListViewTheme extends InheritedTheme {
|
||||||
|
/// Creates a [StreamMessageListViewTheme].
|
||||||
///
|
///
|
||||||
/// The [data] parameter must not be null.
|
/// The [data] parameter must not be null.
|
||||||
const MessageListViewTheme({
|
const StreamMessageListViewTheme({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.data,
|
required this.data,
|
||||||
required Widget child,
|
required Widget child,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
/// The configuration of this theme.
|
/// The configuration of this theme.
|
||||||
final MessageListViewThemeData data;
|
final StreamMessageListViewThemeData data;
|
||||||
|
|
||||||
/// The closest instance of this class that encloses the given context.
|
/// The closest instance of this class that encloses the given context.
|
||||||
///
|
///
|
||||||
/// If there is no enclosing [MessageListViewTheme] widget, then
|
/// If there is no enclosing [StreamMessageListViewTheme] widget, then
|
||||||
/// [StreamChatThemeData.messageListViewTheme] is used.
|
/// [StreamChatThemeData.messageListViewTheme] is used.
|
||||||
///
|
///
|
||||||
/// Typical usage is as follows:
|
/// Typical usage is as follows:
|
||||||
@@ -30,35 +36,41 @@ class MessageListViewTheme extends InheritedTheme {
|
|||||||
/// ```dart
|
/// ```dart
|
||||||
/// MessageListViewTheme theme = MessageListViewTheme.of(context);
|
/// MessageListViewTheme theme = MessageListViewTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static MessageListViewThemeData of(BuildContext context) {
|
static StreamMessageListViewThemeData of(BuildContext context) {
|
||||||
final messageListViewTheme =
|
final messageListViewTheme = context
|
||||||
context.dependOnInheritedWidgetOfExactType<MessageListViewTheme>();
|
.dependOnInheritedWidgetOfExactType<StreamMessageListViewTheme>();
|
||||||
return messageListViewTheme?.data ??
|
return messageListViewTheme?.data ??
|
||||||
StreamChatTheme.of(context).messageListViewTheme;
|
StreamChatTheme.of(context).messageListViewTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget wrap(BuildContext context, Widget child) =>
|
Widget wrap(BuildContext context, Widget child) =>
|
||||||
MessageListViewTheme(data: data, child: child);
|
StreamMessageListViewTheme(data: data, child: child);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool updateShouldNotify(MessageListViewTheme oldWidget) =>
|
bool updateShouldNotify(StreamMessageListViewTheme oldWidget) =>
|
||||||
data != oldWidget.data;
|
data != oldWidget.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro message_list_view_theme_data}
|
||||||
|
@Deprecated("Use 'StreamMessageListViewThemeData' instead")
|
||||||
|
typedef MessageListViewThemeData = StreamMessageListViewThemeData;
|
||||||
|
|
||||||
|
/// {@template message_list_view_theme_data}
|
||||||
/// A style that overrides the default appearance of [MessageListView]s when
|
/// A style that overrides the default appearance of [MessageListView]s when
|
||||||
/// used with [MessageListViewTheme] or with the overall [StreamChatTheme]'s
|
/// used with [StreamMessageListViewTheme] or with the overall [StreamChatTheme]'s
|
||||||
/// [StreamChatThemeData.messageListViewTheme].
|
/// [StreamChatThemeData.messageListViewTheme].
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [MessageListViewTheme], the theme which is configured with this class.
|
/// * [StreamMessageListViewTheme], the theme which is configured with this class.
|
||||||
/// * [StreamChatThemeData.messageListViewTheme], which can be used to override
|
/// * [StreamChatThemeData.messageListViewTheme], which can be used to override
|
||||||
/// the default style for [MessageListView]s below the overall
|
/// the default style for [MessageListView]s below the overall
|
||||||
/// [StreamChatTheme].
|
/// [StreamChatTheme].
|
||||||
class MessageListViewThemeData with Diagnosticable {
|
/// {@endtemplate}
|
||||||
/// Creates a [MessageListViewThemeData].
|
class StreamMessageListViewThemeData with Diagnosticable {
|
||||||
const MessageListViewThemeData({
|
/// Creates a [StreamMessageListViewThemeData].
|
||||||
|
const StreamMessageListViewThemeData({
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
this.backgroundImage,
|
this.backgroundImage,
|
||||||
});
|
});
|
||||||
@@ -69,12 +81,12 @@ class MessageListViewThemeData with Diagnosticable {
|
|||||||
/// The image of the [MessageListView] background.
|
/// The image of the [MessageListView] background.
|
||||||
final DecorationImage? backgroundImage;
|
final DecorationImage? backgroundImage;
|
||||||
|
|
||||||
/// Copies this [MessageListViewThemeData] to another.
|
/// Copies this [StreamMessageListViewThemeData] to another.
|
||||||
MessageListViewThemeData copyWith({
|
StreamMessageListViewThemeData copyWith({
|
||||||
Color? backgroundColor,
|
Color? backgroundColor,
|
||||||
DecorationImage? backgroundImage,
|
DecorationImage? backgroundImage,
|
||||||
}) =>
|
}) =>
|
||||||
MessageListViewThemeData(
|
StreamMessageListViewThemeData(
|
||||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||||
backgroundImage: backgroundImage ?? this.backgroundImage,
|
backgroundImage: backgroundImage ?? this.backgroundImage,
|
||||||
);
|
);
|
||||||
@@ -82,18 +94,18 @@ class MessageListViewThemeData with Diagnosticable {
|
|||||||
/// Linearly interpolate between two [MessageListView] themes.
|
/// Linearly interpolate between two [MessageListView] themes.
|
||||||
///
|
///
|
||||||
/// All the properties must be non-null.
|
/// All the properties must be non-null.
|
||||||
MessageListViewThemeData lerp(
|
StreamMessageListViewThemeData lerp(
|
||||||
MessageListViewThemeData a,
|
StreamMessageListViewThemeData a,
|
||||||
MessageListViewThemeData b,
|
StreamMessageListViewThemeData b,
|
||||||
double t,
|
double t,
|
||||||
) =>
|
) =>
|
||||||
MessageListViewThemeData(
|
StreamMessageListViewThemeData(
|
||||||
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
||||||
backgroundImage: t < 0.5 ? a.backgroundImage : b.backgroundImage,
|
backgroundImage: t < 0.5 ? a.backgroundImage : b.backgroundImage,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Merges one [MessageListViewThemeData] with another.
|
/// Merges one [StreamMessageListViewThemeData] with another.
|
||||||
MessageListViewThemeData merge(MessageListViewThemeData? other) {
|
StreamMessageListViewThemeData merge(StreamMessageListViewThemeData? other) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
backgroundColor: other.backgroundColor,
|
backgroundColor: other.backgroundColor,
|
||||||
@@ -104,7 +116,7 @@ class MessageListViewThemeData with Diagnosticable {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is MessageListViewThemeData &&
|
other is StreamMessageListViewThemeData &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
backgroundColor == other.backgroundColor &&
|
backgroundColor == other.backgroundColor &&
|
||||||
backgroundImage == other.backgroundImage;
|
backgroundImage == other.backgroundImage;
|
||||||
|
|||||||
@@ -2,23 +2,29 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
|
/// {@macro message_search_list_view_theme}
|
||||||
|
@Deprecated("Use 'StreamMessageSearchListViewTheme' instead")
|
||||||
|
typedef MessageSearchListViewTheme = StreamMessageSearchListViewTheme;
|
||||||
|
|
||||||
|
/// {@template message_search_list_view_theme}
|
||||||
/// Overrides the default style of [MessageSearchListView] descendants.
|
/// Overrides the default style of [MessageSearchListView] descendants.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [UserListViewThemeData], which is used to configure this theme.
|
/// * [UserListViewThemeData], which is used to configure this theme.
|
||||||
class MessageSearchListViewTheme extends InheritedTheme {
|
/// {@endtemplate}
|
||||||
|
class StreamMessageSearchListViewTheme extends InheritedTheme {
|
||||||
/// Creates a [UserListViewTheme].
|
/// Creates a [UserListViewTheme].
|
||||||
///
|
///
|
||||||
/// The [data] parameter must not be null.
|
/// The [data] parameter must not be null.
|
||||||
const MessageSearchListViewTheme({
|
const StreamMessageSearchListViewTheme({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.data,
|
required this.data,
|
||||||
required Widget child,
|
required Widget child,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
/// The configuration of this theme.
|
/// The configuration of this theme.
|
||||||
final MessageSearchListViewThemeData data;
|
final StreamMessageSearchListViewThemeData data;
|
||||||
|
|
||||||
/// The closest instance of this class that encloses the given context.
|
/// The closest instance of this class that encloses the given context.
|
||||||
///
|
///
|
||||||
@@ -30,64 +36,72 @@ class MessageSearchListViewTheme extends InheritedTheme {
|
|||||||
/// ```dart
|
/// ```dart
|
||||||
/// MessageSearchListViewTheme theme = MessageSearchListViewTheme.of(context);
|
/// MessageSearchListViewTheme theme = MessageSearchListViewTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static MessageSearchListViewThemeData of(BuildContext context) {
|
static StreamMessageSearchListViewThemeData of(BuildContext context) {
|
||||||
final messageSearchListViewTheme = context
|
final messageSearchListViewTheme = context
|
||||||
.dependOnInheritedWidgetOfExactType<MessageSearchListViewTheme>();
|
.dependOnInheritedWidgetOfExactType<StreamMessageSearchListViewTheme>();
|
||||||
return messageSearchListViewTheme?.data ??
|
return messageSearchListViewTheme?.data ??
|
||||||
StreamChatTheme.of(context).messageSearchListViewTheme;
|
StreamChatTheme.of(context).messageSearchListViewTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget wrap(BuildContext context, Widget child) =>
|
Widget wrap(BuildContext context, Widget child) =>
|
||||||
MessageSearchListViewTheme(data: data, child: child);
|
StreamMessageSearchListViewTheme(data: data, child: child);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool updateShouldNotify(MessageSearchListViewTheme oldWidget) =>
|
bool updateShouldNotify(StreamMessageSearchListViewTheme oldWidget) =>
|
||||||
data != oldWidget.data;
|
data != oldWidget.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro message_search_list_view_theme_data}
|
||||||
|
@Deprecated("Use 'StreamMessageSearchListViewThemeData' instead")
|
||||||
|
typedef MessageSearchListViewThemeData = StreamMessageSearchListViewThemeData;
|
||||||
|
|
||||||
|
/// {@macro message_search_list_view_theme_data}
|
||||||
/// A style that overrides the default appearance of [MessageSearchListView]s
|
/// A style that overrides the default appearance of [MessageSearchListView]s
|
||||||
/// when used with [MessageSearchListView] or with the overall
|
/// when used with [MessageSearchListView] or with the overall
|
||||||
/// [StreamChatTheme]'s [StreamChatThemeData.messageSearchListViewTheme].
|
/// [StreamChatTheme]'s [StreamChatThemeData.messageSearchListViewTheme].
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [MessageSearchListViewTheme], the theme which is configured with this
|
/// * [StreamMessageSearchListViewTheme], the theme which is configured with this
|
||||||
/// class.
|
/// class.
|
||||||
/// * [StreamChatThemeData.messageSearchListViewTheme], which can be used to
|
/// * [StreamChatThemeData.messageSearchListViewTheme], which can be used to
|
||||||
/// override the default style for [UserListView]s below the overall
|
/// override the default style for [UserListView]s below the overall
|
||||||
/// [StreamChatTheme].
|
/// [StreamChatTheme].
|
||||||
class MessageSearchListViewThemeData with Diagnosticable {
|
/// {@endtemplate}
|
||||||
/// Creates a [MessageSearchListViewThemeData].
|
class StreamMessageSearchListViewThemeData with Diagnosticable {
|
||||||
const MessageSearchListViewThemeData({
|
/// Creates a [StreamMessageSearchListViewThemeData].
|
||||||
|
const StreamMessageSearchListViewThemeData({
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The color of the [MessageSearchListView] background.
|
/// The color of the [MessageSearchListView] background.
|
||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
|
|
||||||
/// Copies this [MessageSearchListViewThemeData] to another.
|
/// Copies this [StreamMessageSearchListViewThemeData] to another.
|
||||||
MessageSearchListViewThemeData copyWith({
|
StreamMessageSearchListViewThemeData copyWith({
|
||||||
Color? backgroundColor,
|
Color? backgroundColor,
|
||||||
}) =>
|
}) =>
|
||||||
MessageSearchListViewThemeData(
|
StreamMessageSearchListViewThemeData(
|
||||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Linearly interpolate between two [UserListViewThemeData] themes.
|
/// Linearly interpolate between two [UserListViewThemeData] themes.
|
||||||
///
|
///
|
||||||
/// All the properties must be non-null.
|
/// All the properties must be non-null.
|
||||||
MessageSearchListViewThemeData lerp(
|
StreamMessageSearchListViewThemeData lerp(
|
||||||
MessageSearchListViewThemeData a,
|
StreamMessageSearchListViewThemeData a,
|
||||||
MessageSearchListViewThemeData b,
|
StreamMessageSearchListViewThemeData b,
|
||||||
double t,
|
double t,
|
||||||
) =>
|
) =>
|
||||||
MessageSearchListViewThemeData(
|
StreamMessageSearchListViewThemeData(
|
||||||
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Merges one [MessageSearchListViewThemeData] with another.
|
/// Merges one [StreamMessageSearchListViewThemeData] with another.
|
||||||
MessageSearchListViewThemeData merge(MessageSearchListViewThemeData? other) {
|
StreamMessageSearchListViewThemeData merge(
|
||||||
|
StreamMessageSearchListViewThemeData? other,
|
||||||
|
) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
backgroundColor: other.backgroundColor,
|
backgroundColor: other.backgroundColor,
|
||||||
@@ -97,7 +111,7 @@ class MessageSearchListViewThemeData with Diagnosticable {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is MessageSearchListViewThemeData &&
|
other is StreamMessageSearchListViewThemeData &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
backgroundColor == other.backgroundColor;
|
backgroundColor == other.backgroundColor;
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,17 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
|
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
|
||||||
|
|
||||||
|
/// {@macro message_theme_data}
|
||||||
|
@Deprecated("Use 'StreamMessageThemeData' instead")
|
||||||
|
typedef MessageThemeData = StreamMessageThemeData;
|
||||||
|
|
||||||
|
/// {@template message_theme_data}
|
||||||
/// Class for getting message theme
|
/// Class for getting message theme
|
||||||
|
/// {@endtemplate}
|
||||||
// ignore: prefer-match-file-name
|
// ignore: prefer-match-file-name
|
||||||
class MessageThemeData with Diagnosticable {
|
class StreamMessageThemeData with Diagnosticable {
|
||||||
/// Creates a [MessageThemeData].
|
/// Creates a [StreamMessageThemeData].
|
||||||
const MessageThemeData({
|
const StreamMessageThemeData({
|
||||||
this.repliesStyle,
|
this.repliesStyle,
|
||||||
this.messageTextStyle,
|
this.messageTextStyle,
|
||||||
this.messageAuthorStyle,
|
this.messageAuthorStyle,
|
||||||
@@ -52,13 +58,13 @@ class MessageThemeData with Diagnosticable {
|
|||||||
final Color? reactionsMaskColor;
|
final Color? reactionsMaskColor;
|
||||||
|
|
||||||
/// Theme of the avatar
|
/// Theme of the avatar
|
||||||
final AvatarThemeData? avatarTheme;
|
final StreamAvatarThemeData? avatarTheme;
|
||||||
|
|
||||||
/// Background color for messages with url attachments.
|
/// Background color for messages with url attachments.
|
||||||
final Color? linkBackgroundColor;
|
final Color? linkBackgroundColor;
|
||||||
|
|
||||||
/// Copy with a theme
|
/// Copy with a theme
|
||||||
MessageThemeData copyWith({
|
StreamMessageThemeData copyWith({
|
||||||
TextStyle? messageTextStyle,
|
TextStyle? messageTextStyle,
|
||||||
TextStyle? messageAuthorStyle,
|
TextStyle? messageAuthorStyle,
|
||||||
TextStyle? messageLinksStyle,
|
TextStyle? messageLinksStyle,
|
||||||
@@ -66,13 +72,13 @@ class MessageThemeData with Diagnosticable {
|
|||||||
TextStyle? repliesStyle,
|
TextStyle? repliesStyle,
|
||||||
Color? messageBackgroundColor,
|
Color? messageBackgroundColor,
|
||||||
Color? messageBorderColor,
|
Color? messageBorderColor,
|
||||||
AvatarThemeData? avatarTheme,
|
StreamAvatarThemeData? avatarTheme,
|
||||||
Color? reactionsBackgroundColor,
|
Color? reactionsBackgroundColor,
|
||||||
Color? reactionsBorderColor,
|
Color? reactionsBorderColor,
|
||||||
Color? reactionsMaskColor,
|
Color? reactionsMaskColor,
|
||||||
Color? linkBackgroundColor,
|
Color? linkBackgroundColor,
|
||||||
}) =>
|
}) =>
|
||||||
MessageThemeData(
|
StreamMessageThemeData(
|
||||||
messageTextStyle: messageTextStyle ?? this.messageTextStyle,
|
messageTextStyle: messageTextStyle ?? this.messageTextStyle,
|
||||||
messageAuthorStyle: messageAuthorStyle ?? this.messageAuthorStyle,
|
messageAuthorStyle: messageAuthorStyle ?? this.messageAuthorStyle,
|
||||||
messageLinksStyle: messageLinksStyle ?? this.messageLinksStyle,
|
messageLinksStyle: messageLinksStyle ?? this.messageLinksStyle,
|
||||||
@@ -89,11 +95,15 @@ class MessageThemeData with Diagnosticable {
|
|||||||
linkBackgroundColor: linkBackgroundColor ?? this.linkBackgroundColor,
|
linkBackgroundColor: linkBackgroundColor ?? this.linkBackgroundColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Linearly interpolate from one [MessageThemeData] to another.
|
/// Linearly interpolate from one [StreamMessageThemeData] to another.
|
||||||
MessageThemeData lerp(MessageThemeData a, MessageThemeData b, double t) =>
|
StreamMessageThemeData lerp(
|
||||||
MessageThemeData(
|
StreamMessageThemeData a,
|
||||||
avatarTheme:
|
StreamMessageThemeData b,
|
||||||
const AvatarThemeData().lerp(a.avatarTheme!, b.avatarTheme!, t),
|
double t,
|
||||||
|
) =>
|
||||||
|
StreamMessageThemeData(
|
||||||
|
avatarTheme: const StreamAvatarThemeData()
|
||||||
|
.lerp(a.avatarTheme!, b.avatarTheme!, t),
|
||||||
createdAtStyle: TextStyle.lerp(a.createdAtStyle, b.createdAtStyle, t),
|
createdAtStyle: TextStyle.lerp(a.createdAtStyle, b.createdAtStyle, t),
|
||||||
messageAuthorStyle:
|
messageAuthorStyle:
|
||||||
TextStyle.lerp(a.messageAuthorStyle, b.messageAuthorStyle, t),
|
TextStyle.lerp(a.messageAuthorStyle, b.messageAuthorStyle, t),
|
||||||
@@ -120,7 +130,7 @@ class MessageThemeData with Diagnosticable {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/// Merge with a theme
|
/// Merge with a theme
|
||||||
MessageThemeData merge(MessageThemeData? other) {
|
StreamMessageThemeData merge(StreamMessageThemeData? other) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
messageTextStyle: messageTextStyle?.merge(other.messageTextStyle) ??
|
messageTextStyle: messageTextStyle?.merge(other.messageTextStyle) ??
|
||||||
@@ -146,7 +156,7 @@ class MessageThemeData with Diagnosticable {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is MessageThemeData &&
|
other is StreamMessageThemeData &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
messageTextStyle == other.messageTextStyle &&
|
messageTextStyle == other.messageTextStyle &&
|
||||||
messageAuthorStyle == other.messageAuthorStyle &&
|
messageAuthorStyle == other.messageAuthorStyle &&
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// {@macro text_theme}
|
||||||
|
@Deprecated("Use 'StreamTextTheme' instead")
|
||||||
|
typedef TextTheme = StreamTextTheme;
|
||||||
|
|
||||||
|
/// {@template text_theme}
|
||||||
/// Class for holding text theme
|
/// Class for holding text theme
|
||||||
class TextTheme {
|
/// {@endtemplate}
|
||||||
|
class StreamTextTheme {
|
||||||
/// Initialise light text theme
|
/// Initialise light text theme
|
||||||
TextTheme.light({
|
StreamTextTheme.light({
|
||||||
this.title = const TextStyle(
|
this.title = const TextStyle(
|
||||||
fontSize: 22,
|
fontSize: 22,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@@ -46,7 +52,7 @@ class TextTheme {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/// Initialise with dark theme
|
/// Initialise with dark theme
|
||||||
TextTheme.dark({
|
StreamTextTheme.dark({
|
||||||
this.title = const TextStyle(
|
this.title = const TextStyle(
|
||||||
fontSize: 22,
|
fontSize: 22,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
@@ -113,7 +119,7 @@ class TextTheme {
|
|||||||
final TextStyle captionBold;
|
final TextStyle captionBold;
|
||||||
|
|
||||||
/// Copy with theme
|
/// Copy with theme
|
||||||
TextTheme copyWith({
|
StreamTextTheme copyWith({
|
||||||
Brightness brightness = Brightness.light,
|
Brightness brightness = Brightness.light,
|
||||||
TextStyle? body,
|
TextStyle? body,
|
||||||
TextStyle? title,
|
TextStyle? title,
|
||||||
@@ -125,7 +131,7 @@ class TextTheme {
|
|||||||
TextStyle? captionBold,
|
TextStyle? captionBold,
|
||||||
}) =>
|
}) =>
|
||||||
brightness == Brightness.light
|
brightness == Brightness.light
|
||||||
? TextTheme.light(
|
? StreamTextTheme.light(
|
||||||
body: body ?? this.body,
|
body: body ?? this.body,
|
||||||
title: title ?? this.title,
|
title: title ?? this.title,
|
||||||
headlineBold: headlineBold ?? this.headlineBold,
|
headlineBold: headlineBold ?? this.headlineBold,
|
||||||
@@ -135,7 +141,7 @@ class TextTheme {
|
|||||||
footnote: footnote ?? this.footnote,
|
footnote: footnote ?? this.footnote,
|
||||||
captionBold: captionBold ?? this.captionBold,
|
captionBold: captionBold ?? this.captionBold,
|
||||||
)
|
)
|
||||||
: TextTheme.dark(
|
: StreamTextTheme.dark(
|
||||||
body: body ?? this.body,
|
body: body ?? this.body,
|
||||||
title: title ?? this.title,
|
title: title ?? this.title,
|
||||||
headlineBold: headlineBold ?? this.headlineBold,
|
headlineBold: headlineBold ?? this.headlineBold,
|
||||||
@@ -147,7 +153,7 @@ class TextTheme {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/// Merge text theme
|
/// Merge text theme
|
||||||
TextTheme merge(TextTheme? other) {
|
StreamTextTheme merge(StreamTextTheme? other) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
body: body.merge(other.body),
|
body: body.merge(other.body),
|
||||||
|
|||||||
@@ -2,27 +2,33 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||||
|
|
||||||
|
/// {@macro user_list_view_theme}
|
||||||
|
@Deprecated("Use 'StreamUserListViewTheme' instead")
|
||||||
|
typedef UserListViewTheme = StreamUserListViewTheme;
|
||||||
|
|
||||||
|
/// {@template user_list_view_theme}
|
||||||
/// Overrides the default style of [UserListView] descendants.
|
/// Overrides the default style of [UserListView] descendants.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [UserListViewThemeData], which is used to configure this theme.
|
/// * [StreamUserListViewThemeData], which is used to configure this theme.
|
||||||
class UserListViewTheme extends InheritedTheme {
|
/// {@endtemplate}
|
||||||
/// Creates a [UserListViewTheme].
|
class StreamUserListViewTheme extends InheritedTheme {
|
||||||
|
/// Creates a [StreamUserListViewTheme].
|
||||||
///
|
///
|
||||||
/// The [data] parameter must not be null.
|
/// The [data] parameter must not be null.
|
||||||
const UserListViewTheme({
|
const StreamUserListViewTheme({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.data,
|
required this.data,
|
||||||
required Widget child,
|
required Widget child,
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
/// The configuration of this theme.
|
/// The configuration of this theme.
|
||||||
final UserListViewThemeData data;
|
final StreamUserListViewThemeData data;
|
||||||
|
|
||||||
/// The closest instance of this class that encloses the given context.
|
/// The closest instance of this class that encloses the given context.
|
||||||
///
|
///
|
||||||
/// If there is no enclosing [UserListViewTheme] widget, then
|
/// If there is no enclosing [StreamUserListViewTheme] widget, then
|
||||||
/// [StreamChatThemeData.userListViewTheme] is used.
|
/// [StreamChatThemeData.userListViewTheme] is used.
|
||||||
///
|
///
|
||||||
/// Typical usage is as follows:
|
/// Typical usage is as follows:
|
||||||
@@ -30,35 +36,41 @@ class UserListViewTheme extends InheritedTheme {
|
|||||||
/// ```dart
|
/// ```dart
|
||||||
/// UserListViewTheme theme = UserListViewTheme.of(context);
|
/// UserListViewTheme theme = UserListViewTheme.of(context);
|
||||||
/// ```
|
/// ```
|
||||||
static UserListViewThemeData of(BuildContext context) {
|
static StreamUserListViewThemeData of(BuildContext context) {
|
||||||
final userListViewTheme =
|
final userListViewTheme =
|
||||||
context.dependOnInheritedWidgetOfExactType<UserListViewTheme>();
|
context.dependOnInheritedWidgetOfExactType<StreamUserListViewTheme>();
|
||||||
return userListViewTheme?.data ??
|
return userListViewTheme?.data ??
|
||||||
StreamChatTheme.of(context).userListViewTheme;
|
StreamChatTheme.of(context).userListViewTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget wrap(BuildContext context, Widget child) =>
|
Widget wrap(BuildContext context, Widget child) =>
|
||||||
UserListViewTheme(data: data, child: child);
|
StreamUserListViewTheme(data: data, child: child);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool updateShouldNotify(UserListViewTheme oldWidget) =>
|
bool updateShouldNotify(StreamUserListViewTheme oldWidget) =>
|
||||||
data != oldWidget.data;
|
data != oldWidget.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// {@macro user_list_view_theme_data}
|
||||||
|
@Deprecated("Use 'StreamUserListViewThemeData' instead")
|
||||||
|
typedef UserListViewThemeData = StreamUserListViewThemeData;
|
||||||
|
|
||||||
|
/// {@template user_list_view_theme_data}
|
||||||
/// A style that overrides the default appearance of [UserListView]s when
|
/// A style that overrides the default appearance of [UserListView]s when
|
||||||
/// used with [UserListViewTheme] or with the overall [StreamChatTheme]'s
|
/// used with [StreamUserListViewTheme] or with the overall [StreamChatTheme]'s
|
||||||
/// [StreamChatThemeData.userListViewTheme].
|
/// [StreamChatThemeData.userListViewTheme].
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [UserListViewTheme], the theme which is configured with this class.
|
/// * [StreamUserListViewTheme], the theme which is configured with this class.
|
||||||
/// * [StreamChatThemeData.userListViewTheme], which can be used to override
|
/// * [StreamChatThemeData.userListViewTheme], which can be used to override
|
||||||
/// the default style for [UserListView]s below the overall
|
/// the default style for [UserListView]s below the overall
|
||||||
/// [StreamChatTheme].
|
/// [StreamChatTheme].
|
||||||
class UserListViewThemeData with Diagnosticable {
|
/// {@endtemplate}
|
||||||
/// Creates a [UserListViewThemeData].
|
class StreamUserListViewThemeData with Diagnosticable {
|
||||||
const UserListViewThemeData({
|
/// Creates a [StreamUserListViewThemeData].
|
||||||
|
const StreamUserListViewThemeData({
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -66,27 +78,27 @@ class UserListViewThemeData with Diagnosticable {
|
|||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
|
|
||||||
/// Copies this [ChannelListViewThemeData] to another.
|
/// Copies this [ChannelListViewThemeData] to another.
|
||||||
UserListViewThemeData copyWith({
|
StreamUserListViewThemeData copyWith({
|
||||||
Color? backgroundColor,
|
Color? backgroundColor,
|
||||||
}) =>
|
}) =>
|
||||||
UserListViewThemeData(
|
StreamUserListViewThemeData(
|
||||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Linearly interpolate between two [UserListViewThemeData] themes.
|
/// Linearly interpolate between two [StreamUserListViewThemeData] themes.
|
||||||
///
|
///
|
||||||
/// All the properties must be non-null.
|
/// All the properties must be non-null.
|
||||||
UserListViewThemeData lerp(
|
StreamUserListViewThemeData lerp(
|
||||||
UserListViewThemeData a,
|
StreamUserListViewThemeData a,
|
||||||
UserListViewThemeData b,
|
StreamUserListViewThemeData b,
|
||||||
double t,
|
double t,
|
||||||
) =>
|
) =>
|
||||||
UserListViewThemeData(
|
StreamUserListViewThemeData(
|
||||||
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Merges one [UserListViewThemeData] with another.
|
/// Merges one [StreamUserListViewThemeData] with another.
|
||||||
UserListViewThemeData merge(UserListViewThemeData? other) {
|
StreamUserListViewThemeData merge(StreamUserListViewThemeData? other) {
|
||||||
if (other == null) return this;
|
if (other == null) return this;
|
||||||
return copyWith(
|
return copyWith(
|
||||||
backgroundColor: other.backgroundColor,
|
backgroundColor: other.backgroundColor,
|
||||||
@@ -96,7 +108,7 @@ class UserListViewThemeData with Diagnosticable {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is UserListViewThemeData &&
|
other is StreamUserListViewThemeData &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
backgroundColor == other.backgroundColor;
|
backgroundColor == other.backgroundColor;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,11 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro thread_header}
|
||||||
|
@Deprecated("Use 'StreamThreadHeader' instead")
|
||||||
|
typedef ThreadHeader = StreamThreadHeader;
|
||||||
|
|
||||||
|
/// {@template thread_header}
|
||||||
/// 
|
/// 
|
||||||
/// 
|
/// 
|
||||||
///
|
///
|
||||||
@@ -56,9 +61,11 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
/// The widget components render the ui based on the first ancestor of type
|
/// The widget components render the ui based on the first ancestor of type
|
||||||
/// [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property.
|
/// [StreamChatTheme] and on its [ChannelTheme.channelHeaderTheme] property.
|
||||||
/// Modify it to change the widget appearance.
|
/// Modify it to change the widget appearance.
|
||||||
class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamThreadHeader extends StatelessWidget
|
||||||
|
implements PreferredSizeWidget {
|
||||||
/// Instantiate a new ThreadHeader
|
/// Instantiate a new ThreadHeader
|
||||||
const ThreadHeader({
|
const StreamThreadHeader({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.parent,
|
required this.parent,
|
||||||
this.showBackButton = true,
|
this.showBackButton = true,
|
||||||
@@ -102,12 +109,12 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
/// if a user is typing in this thread
|
/// if a user is typing in this thread
|
||||||
final bool showTypingIndicator;
|
final bool showTypingIndicator;
|
||||||
|
|
||||||
/// The background color of this [ThreadHeader].
|
/// The background color of this [StreamThreadHeader].
|
||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final channelHeaderTheme = ChannelHeaderTheme.of(context);
|
final channelHeaderTheme = StreamChannelHeaderTheme.of(context);
|
||||||
|
|
||||||
final defaultSubtitle = subtitle ??
|
final defaultSubtitle = subtitle ??
|
||||||
Row(
|
Row(
|
||||||
@@ -162,7 +169,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
if (showTypingIndicator)
|
if (showTypingIndicator)
|
||||||
Align(
|
Align(
|
||||||
child: TypingIndicator(
|
child: StreamTypingIndicator(
|
||||||
channel: StreamChannel.of(context).channel,
|
channel: StreamChannel.of(context).channel,
|
||||||
style: channelHeaderTheme.subtitleStyle,
|
style: channelHeaderTheme.subtitleStyle,
|
||||||
parentId: parent.id,
|
parentId: parent.id,
|
||||||
|
|||||||
@@ -3,10 +3,16 @@ import 'package:lottie/lottie.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
|
||||||
|
/// {@macro typing_indicator}
|
||||||
|
@Deprecated("Use 'StreamTypingIndicator' instead")
|
||||||
|
typedef TypingIndicator = StreamTypingIndicator;
|
||||||
|
|
||||||
|
/// {@template typing_indicator}
|
||||||
/// Widget to show the current list of typing users
|
/// Widget to show the current list of typing users
|
||||||
class TypingIndicator extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamTypingIndicator extends StatelessWidget {
|
||||||
/// Instantiate a new TypingIndicator
|
/// Instantiate a new TypingIndicator
|
||||||
const TypingIndicator({
|
const StreamTypingIndicator({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.channel,
|
this.channel,
|
||||||
this.alternativeWidget,
|
this.alternativeWidget,
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro unread_indicator}
|
||||||
|
@Deprecated("Use 'StreamUnreadIndicator' instead")
|
||||||
|
typedef UnreadIndicator = StreamUnreadIndicator;
|
||||||
|
|
||||||
|
/// {@template unread_indicator}
|
||||||
/// Widget for showing an unread indicator
|
/// Widget for showing an unread indicator
|
||||||
class UnreadIndicator extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating an [UnreadIndicator]
|
class StreamUnreadIndicator extends StatelessWidget {
|
||||||
const UnreadIndicator({
|
/// Constructor for creating an [StreamUnreadIndicator]
|
||||||
|
const StreamUnreadIndicator({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.cid,
|
this.cid,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro upload_progress_indicator}
|
||||||
|
@Deprecated("Use 'StreamUploadProgressIndicator' instead")
|
||||||
|
typedef UploadProgressIndicator = StreamUploadProgressIndicator;
|
||||||
|
|
||||||
|
/// {@template upload_progress_indicator}
|
||||||
/// Widget for showing upload progress
|
/// Widget for showing upload progress
|
||||||
class UploadProgressIndicator extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating an [UploadProgressIndicator]
|
class StreamUploadProgressIndicator extends StatelessWidget {
|
||||||
const UploadProgressIndicator({
|
/// Constructor for creating an [StreamUploadProgressIndicator]
|
||||||
|
const StreamUploadProgressIndicator({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.uploaded,
|
required this.uploaded,
|
||||||
required this.total,
|
required this.total,
|
||||||
|
|||||||
@@ -2,10 +2,16 @@ import 'package:cached_network_image/cached_network_image.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro user_avatar}
|
||||||
|
@Deprecated("Use 'StreamUserAvatar' instead")
|
||||||
|
typedef UserAvatar = StreamUserAvatar;
|
||||||
|
|
||||||
|
/// {@template user_avatar}
|
||||||
/// Widget that displays a user avatar
|
/// Widget that displays a user avatar
|
||||||
class UserAvatar extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor to create a [UserAvatar]
|
class StreamUserAvatar extends StatelessWidget {
|
||||||
const UserAvatar({
|
/// Constructor to create a [StreamUserAvatar]
|
||||||
|
const StreamUserAvatar({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.user,
|
required this.user,
|
||||||
this.constraints,
|
this.constraints,
|
||||||
|
|||||||
@@ -2,21 +2,26 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
///
|
/// {@macro user_item}
|
||||||
|
@Deprecated("Use 'StreamUserItem' instead")
|
||||||
|
typedef UserItem = StreamUserItem;
|
||||||
|
|
||||||
|
/// {@template user_item}
|
||||||
/// It shows the current [User] preview.
|
/// It shows the current [User] preview.
|
||||||
///
|
///
|
||||||
/// The widget uses a [StreamBuilder] to render the user information
|
/// The widget uses a [StreamBuilder] to render the user information
|
||||||
/// image as soon as it updates.
|
/// image as soon as it updates.
|
||||||
///
|
///
|
||||||
/// Usually you don't use this widget as it's the default user preview used
|
/// Usually you don't use this widget as it's the default user preview used
|
||||||
/// by [UserListView].
|
/// by [StreamUserListView].
|
||||||
///
|
///
|
||||||
/// The widget renders the ui based on the first ancestor of type
|
/// The widget renders the ui based on the first ancestor of type
|
||||||
/// [StreamChatTheme].
|
/// [StreamChatTheme].
|
||||||
/// Modify it to change the widget appearance.
|
/// Modify it to change the widget appearance.
|
||||||
class UserItem extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamUserItem extends StatelessWidget {
|
||||||
/// Instantiate a new UserItem
|
/// Instantiate a new UserItem
|
||||||
const UserItem({
|
const StreamUserItem({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.user,
|
required this.user,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
@@ -38,10 +43,10 @@ class UserItem extends StatelessWidget {
|
|||||||
/// The function called when the image is tapped
|
/// The function called when the image is tapped
|
||||||
final void Function(User)? onImageTap;
|
final void Function(User)? onImageTap;
|
||||||
|
|
||||||
/// If true the [UserItem] will show a trailing checkmark
|
/// If true the [StreamUserItem] will show a trailing checkmark
|
||||||
final bool selected;
|
final bool selected;
|
||||||
|
|
||||||
/// If true the [UserItem] will show the last seen
|
/// If true the [StreamUserItem] will show the last seen
|
||||||
final bool showLastOnline;
|
final bool showLastOnline;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -58,7 +63,7 @@ class UserItem extends StatelessWidget {
|
|||||||
onLongPress!(user);
|
onLongPress!(user);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
leading: UserAvatar(
|
leading: StreamUserAvatar(
|
||||||
user: user,
|
user: user,
|
||||||
onTap: (user) {
|
onTap: (user) {
|
||||||
if (onImageTap != null) {
|
if (onImageTap != null) {
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ typedef UserTapCallback = void Function(User, Widget?);
|
|||||||
/// Builder used to create a custom [ListUserItem] from a [User]
|
/// Builder used to create a custom [ListUserItem] from a [User]
|
||||||
typedef UserItemBuilder = Widget Function(BuildContext, User, bool);
|
typedef UserItemBuilder = Widget Function(BuildContext, User, bool);
|
||||||
|
|
||||||
///
|
/// {@macro user_list_view}
|
||||||
|
@Deprecated("Use 'StreamUserListView' instead")
|
||||||
|
typedef UserListView = StreamUserListView;
|
||||||
|
|
||||||
|
/// {@template user_list_view}
|
||||||
/// It shows the list of current users.
|
/// It shows the list of current users.
|
||||||
///
|
///
|
||||||
/// ```dart
|
/// ```dart
|
||||||
@@ -42,9 +46,10 @@ typedef UserItemBuilder = Widget Function(BuildContext, User, bool);
|
|||||||
/// The widget components render the ui based on the first ancestor of
|
/// The widget components render the ui based on the first ancestor of
|
||||||
/// type [StreamChatTheme].
|
/// type [StreamChatTheme].
|
||||||
/// Modify it to change the widget appearance.
|
/// Modify it to change the widget appearance.
|
||||||
class UserListView extends StatefulWidget {
|
/// {@endtemplate}
|
||||||
|
class StreamUserListView extends StatefulWidget {
|
||||||
/// Instantiate a new UserListView
|
/// Instantiate a new UserListView
|
||||||
UserListView({
|
StreamUserListView({
|
||||||
Key? key,
|
Key? key,
|
||||||
this.filter = const Filter.empty(),
|
this.filter = const Filter.empty(),
|
||||||
this.sort,
|
this.sort,
|
||||||
@@ -160,10 +165,10 @@ class UserListView extends StatefulWidget {
|
|||||||
final UserListController? userListController;
|
final UserListController? userListController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_UserListViewState createState() => _UserListViewState();
|
_StreamUserListViewState createState() => _StreamUserListViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _UserListViewState extends State<UserListView>
|
class _StreamUserListViewState extends State<StreamUserListView>
|
||||||
with WidgetsBindingObserver {
|
with WidgetsBindingObserver {
|
||||||
bool get _isListView => widget.crossAxisCount == 1;
|
bool get _isListView => widget.crossAxisCount == 1;
|
||||||
|
|
||||||
@@ -203,7 +208,7 @@ class _UserListViewState extends State<UserListView>
|
|||||||
userListController: _userListController,
|
userListController: _userListController,
|
||||||
);
|
);
|
||||||
|
|
||||||
final backgroundColor = UserListViewTheme.of(context).backgroundColor;
|
final backgroundColor = StreamUserListViewTheme.of(context).backgroundColor;
|
||||||
|
|
||||||
Widget child;
|
Widget child;
|
||||||
|
|
||||||
@@ -332,7 +337,7 @@ class _UserListViewState extends State<UserListView>
|
|||||||
key: ValueKey<String>('USER-${user.id}'),
|
key: ValueKey<String>('USER-${user.id}'),
|
||||||
child: widget.userItemBuilder != null
|
child: widget.userItemBuilder != null
|
||||||
? widget.userItemBuilder!(context, user, selected)
|
? widget.userItemBuilder!(context, user, selected)
|
||||||
: UserItem(
|
: StreamUserItem(
|
||||||
user: user,
|
user: user,
|
||||||
onTap: (user) => widget.onUserTap!(user, widget.userWidget),
|
onTap: (user) => widget.onUserTap!(user, widget.userWidget),
|
||||||
onLongPress: widget.onUserLongPress,
|
onLongPress: widget.onUserLongPress,
|
||||||
@@ -362,7 +367,7 @@ class _UserListViewState extends State<UserListView>
|
|||||||
: Column(
|
: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
UserAvatar(
|
StreamUserAvatar(
|
||||||
user: user,
|
user: user,
|
||||||
borderRadius: BorderRadius.circular(32),
|
borderRadius: BorderRadius.circular(32),
|
||||||
selected: selected,
|
selected: selected,
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro user_mention_tile}
|
||||||
|
@Deprecated("Use 'StreamUserMentionTile' instead")
|
||||||
|
typedef UserMentionTile = StreamUserMentionTile;
|
||||||
|
|
||||||
|
/// {@template user_mention_tile}
|
||||||
/// This widget is used for showing user tiles for mentions
|
/// This widget is used for showing user tiles for mentions
|
||||||
/// Use [title], [subtitle], [leading], [trailing] for
|
/// Use [title], [subtitle], [leading], [trailing] for
|
||||||
/// substituting widgets in respective positions
|
/// substituting widgets in respective positions
|
||||||
class UserMentionTile extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [UserMentionTile] widget
|
class StreamUserMentionTile extends StatelessWidget {
|
||||||
const UserMentionTile(
|
/// Constructor for creating a [StreamUserMentionTile] widget
|
||||||
|
const StreamUserMentionTile(
|
||||||
this.user, {
|
this.user, {
|
||||||
Key? key,
|
Key? key,
|
||||||
this.title,
|
this.title,
|
||||||
@@ -41,7 +47,7 @@ class UserMentionTile extends StatelessWidget {
|
|||||||
width: 16,
|
width: 16,
|
||||||
),
|
),
|
||||||
leading ??
|
leading ??
|
||||||
UserAvatar(
|
StreamUserAvatar(
|
||||||
user: user,
|
user: user,
|
||||||
constraints: BoxConstraints.tight(const Size(40, 40)),
|
constraints: BoxConstraints.tight(const Size(40, 40)),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -6,16 +6,22 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
|||||||
|
|
||||||
/// Builder function for building a mention tile.
|
/// Builder function for building a mention tile.
|
||||||
///
|
///
|
||||||
/// Use [UserMentionTile] for the default implementation.
|
/// Use [StreamUserMentionTile] for the default implementation.
|
||||||
typedef MentionTileBuilder = Widget Function(
|
typedef MentionTileBuilder = Widget Function(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
User user,
|
User user,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// {@macro user_mention_tile}
|
||||||
|
@Deprecated("Use 'StreamUserMentionsOverlay' instead")
|
||||||
|
typedef UserMentionsOverlay = StreamUserMentionsOverlay;
|
||||||
|
|
||||||
|
/// {@template user_mentions_overlay}
|
||||||
/// Overlay for displaying users that can be mentioned.
|
/// Overlay for displaying users that can be mentioned.
|
||||||
class UserMentionsOverlay extends StatefulWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [UserMentionsOverlay].
|
class StreamUserMentionsOverlay extends StatefulWidget {
|
||||||
UserMentionsOverlay({
|
/// Constructor for creating a [StreamUserMentionsOverlay].
|
||||||
|
StreamUserMentionsOverlay({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.query,
|
required this.query,
|
||||||
required this.channel,
|
required this.channel,
|
||||||
@@ -62,10 +68,11 @@ class UserMentionsOverlay extends StatefulWidget {
|
|||||||
final void Function(User user)? onMentionUserTap;
|
final void Function(User user)? onMentionUserTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_UserMentionsOverlayState createState() => _UserMentionsOverlayState();
|
_StreamUserMentionsOverlayState createState() =>
|
||||||
|
_StreamUserMentionsOverlayState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _UserMentionsOverlayState extends State<UserMentionsOverlay> {
|
class _StreamUserMentionsOverlayState extends State<StreamUserMentionsOverlay> {
|
||||||
late Future<List<User>> userMentionsFuture;
|
late Future<List<User>> userMentionsFuture;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -75,7 +82,7 @@ class _UserMentionsOverlayState extends State<UserMentionsOverlay> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(covariant UserMentionsOverlay oldWidget) {
|
void didUpdateWidget(covariant StreamUserMentionsOverlay oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
if (widget.channel != oldWidget.channel ||
|
if (widget.channel != oldWidget.channel ||
|
||||||
widget.query != oldWidget.query ||
|
widget.query != oldWidget.query ||
|
||||||
@@ -116,7 +123,7 @@ class _UserMentionsOverlayState extends State<UserMentionsOverlay> {
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => widget.onMentionUserTap?.call(user),
|
onTap: () => widget.onMentionUserTap?.call(user),
|
||||||
child: widget.mentionsTileBuilder?.call(context, user) ??
|
child: widget.mentionsTileBuilder?.call(context, user) ??
|
||||||
UserMentionTile(user),
|
StreamUserMentionTile(user),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
+40
-10
@@ -9,6 +9,7 @@ import 'package:stream_chat_flutter/src/typing_indicator.dart';
|
|||||||
import 'package:stream_chat_flutter/src/unread_indicator.dart';
|
import 'package:stream_chat_flutter/src/unread_indicator.dart';
|
||||||
import 'package:stream_chat_flutter/src/v4/stream_channel_avatar.dart';
|
import 'package:stream_chat_flutter/src/v4/stream_channel_avatar.dart';
|
||||||
import 'package:stream_chat_flutter/src/v4/stream_channel_name.dart';
|
import 'package:stream_chat_flutter/src/v4/stream_channel_name.dart';
|
||||||
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
|
||||||
/// A widget that displays a channel preview.
|
/// A widget that displays a channel preview.
|
||||||
@@ -131,7 +132,7 @@ class StreamChannelListTile extends StatelessWidget {
|
|||||||
final channelState = channel.state!;
|
final channelState = channel.state!;
|
||||||
final currentUser = channel.client.state.currentUser!;
|
final currentUser = channel.client.state.currentUser!;
|
||||||
|
|
||||||
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
final channelPreviewTheme = StreamChannelPreviewTheme.of(context);
|
||||||
|
|
||||||
final leading = this.leading ??
|
final leading = this.leading ??
|
||||||
StreamChannelAvatar(
|
StreamChannelAvatar(
|
||||||
@@ -182,7 +183,7 @@ class StreamChannelListTile extends StatelessWidget {
|
|||||||
return const Offstage();
|
return const Offstage();
|
||||||
}
|
}
|
||||||
return unreadIndicatorBuilder?.call(context) ??
|
return unreadIndicatorBuilder?.call(context) ??
|
||||||
UnreadIndicator(cid: channel.cid);
|
StreamUnreadIndicator(cid: channel.cid);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -213,7 +214,7 @@ class StreamChannelListTile extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.only(right: 4),
|
padding: const EdgeInsets.only(right: 4),
|
||||||
child:
|
child:
|
||||||
sendingIndicatorBuilder?.call(context, lastMessage) ??
|
sendingIndicatorBuilder?.call(context, lastMessage) ??
|
||||||
SendingIndicator(
|
StreamSendingIndicator(
|
||||||
message: lastMessage,
|
message: lastMessage,
|
||||||
size: channelPreviewTheme.indicatorIconSize,
|
size: channelPreviewTheme.indicatorIconSize,
|
||||||
isMessageRead: channelState
|
isMessageRead: channelState
|
||||||
@@ -318,7 +319,7 @@ class ChannelListTileSubtitle extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return TypingIndicator(
|
return StreamTypingIndicator(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
style: textStyle,
|
style: textStyle,
|
||||||
alternativeWidget: ChannelLastMessageText(
|
alternativeWidget: ChannelLastMessageText(
|
||||||
@@ -359,10 +360,18 @@ class ChannelLastMessageText extends StatelessWidget {
|
|||||||
|
|
||||||
if (lastMessage == null) return const Offstage();
|
if (lastMessage == null) return const Offstage();
|
||||||
|
|
||||||
final lastMessageText = lastMessage.text;
|
final lastMessageText = lastMessage
|
||||||
|
.translate(channel.client.state.currentUser?.language ?? 'en')
|
||||||
|
.replaceMentions(linkify: false)
|
||||||
|
.text;
|
||||||
final lastMessageAttachments = lastMessage.attachments;
|
final lastMessageAttachments = lastMessage.attachments;
|
||||||
final lastMessageMentionedUsers = lastMessage.mentionedUsers;
|
final lastMessageMentionedUsers = lastMessage.mentionedUsers;
|
||||||
|
|
||||||
|
final mentionedUsersRegex = RegExp(
|
||||||
|
lastMessageMentionedUsers.map((it) => '@${it.name}').join('|'),
|
||||||
|
caseSensitive: false,
|
||||||
|
);
|
||||||
|
|
||||||
final messageTextParts = [
|
final messageTextParts = [
|
||||||
...lastMessageAttachments.map((it) {
|
...lastMessageAttachments.map((it) {
|
||||||
if (it.type == 'image') {
|
if (it.type == 'image') {
|
||||||
@@ -376,7 +385,11 @@ class ChannelLastMessageText extends StatelessWidget {
|
|||||||
? (it.title ?? 'File')
|
? (it.title ?? 'File')
|
||||||
: '${it.title ?? 'File'} , ';
|
: '${it.title ?? 'File'} , ';
|
||||||
}),
|
}),
|
||||||
if (lastMessageText != null) lastMessageText,
|
if (lastMessageText != null)
|
||||||
|
if (lastMessageMentionedUsers.isNotEmpty)
|
||||||
|
...mentionedUsersRegex.allMatchesWithSep(lastMessageText)
|
||||||
|
else
|
||||||
|
lastMessageText,
|
||||||
];
|
];
|
||||||
|
|
||||||
final fontStyle = (lastMessage.isSystem || lastMessage.isDeleted)
|
final fontStyle = (lastMessage.isSystem || lastMessage.isDeleted)
|
||||||
@@ -395,7 +408,7 @@ class ChannelLastMessageText extends StatelessWidget {
|
|||||||
if (lastMessageMentionedUsers.isNotEmpty &&
|
if (lastMessageMentionedUsers.isNotEmpty &&
|
||||||
lastMessageMentionedUsers.any((it) => '@${it.name}' == part))
|
lastMessageMentionedUsers.any((it) => '@${it.name}' == part))
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: '$part ',
|
text: part,
|
||||||
style: mentionsTextStyle,
|
style: mentionsTextStyle,
|
||||||
)
|
)
|
||||||
else if (lastMessageAttachments.isNotEmpty &&
|
else if (lastMessageAttachments.isNotEmpty &&
|
||||||
@@ -403,12 +416,14 @@ class ChannelLastMessageText extends StatelessWidget {
|
|||||||
.where((it) => it.title != null)
|
.where((it) => it.title != null)
|
||||||
.any((it) => it.title == part))
|
.any((it) => it.title == part))
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: '$part ',
|
text: part,
|
||||||
style: regularTextStyle,
|
style: regularTextStyle?.copyWith(
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: part == messageTextParts.last ? part : '$part ',
|
text: part,
|
||||||
style: regularTextStyle,
|
style: regularTextStyle,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
@@ -422,3 +437,18 @@ class ChannelLastMessageText extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension _RegExpX on RegExp {
|
||||||
|
List<String> allMatchesWithSep(String input, [int start = 0]) {
|
||||||
|
final result = <String>[];
|
||||||
|
for (final match in allMatches(input, start)) {
|
||||||
|
result.add(input.substring(start, match.start));
|
||||||
|
// ignore: cascade_invocations
|
||||||
|
result.add(match[0]!);
|
||||||
|
// ignore: parameter_assignments
|
||||||
|
start = match.end;
|
||||||
|
}
|
||||||
|
result.add(input.substring(start));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ class StreamChannelAvatar extends StatelessWidget {
|
|||||||
return BetterStreamBuilder<User>(
|
return BetterStreamBuilder<User>(
|
||||||
stream: client.currentUserStream.map((it) => it!),
|
stream: client.currentUserStream.map((it) => it!),
|
||||||
initialData: currentUser,
|
initialData: currentUser,
|
||||||
builder: (context, user) => UserAvatar(
|
builder: (context, user) => StreamUserAvatar(
|
||||||
borderRadius: borderRadius ?? previewTheme?.borderRadius,
|
borderRadius: borderRadius ?? previewTheme?.borderRadius,
|
||||||
user: user,
|
user: user,
|
||||||
constraints: constraints ?? previewTheme?.constraints,
|
constraints: constraints ?? previewTheme?.constraints,
|
||||||
@@ -171,7 +171,7 @@ class StreamChannelAvatar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
initialData: member,
|
initialData: member,
|
||||||
builder: (context, member) => UserAvatar(
|
builder: (context, member) => StreamUserAvatar(
|
||||||
borderRadius: borderRadius ?? previewTheme?.borderRadius,
|
borderRadius: borderRadius ?? previewTheme?.borderRadius,
|
||||||
user: member.user!,
|
user: member.user!,
|
||||||
constraints: constraints ?? previewTheme?.constraints,
|
constraints: constraints ?? previewTheme?.constraints,
|
||||||
@@ -184,7 +184,7 @@ class StreamChannelAvatar extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Group conversation
|
// Group conversation
|
||||||
return GroupAvatar(
|
return StreamGroupAvatar(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
members: otherMembers,
|
members: otherMembers,
|
||||||
borderRadius: borderRadius ?? previewTheme?.borderRadius,
|
borderRadius: borderRadius ?? previewTheme?.borderRadius,
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final themeData = StreamChatTheme.of(context);
|
final themeData = StreamChatTheme.of(context);
|
||||||
final colorTheme = themeData.colorTheme;
|
final colorTheme = themeData.colorTheme;
|
||||||
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
final channelPreviewTheme = StreamChannelPreviewTheme.of(context);
|
||||||
|
|
||||||
final currentUser = channel.client.state.currentUser;
|
final currentUser = channel.client.state.currentUser;
|
||||||
final isOneToOneChannel = channel.isDistinct && channel.memberCount == 2;
|
final isOneToOneChannel = channel.isDistinct && channel.memberCount == 2;
|
||||||
@@ -84,7 +84,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
|
|||||||
const SizedBox(height: 5),
|
const SizedBox(height: 5),
|
||||||
Center(
|
Center(
|
||||||
// TODO: Refactor ChannelInfo
|
// TODO: Refactor ChannelInfo
|
||||||
child: ChannelInfo(
|
child: StreamChannelInfo(
|
||||||
showTypingIndicator: false,
|
showTypingIndicator: false,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
textStyle: channelPreviewTheme.subtitleStyle,
|
textStyle: channelPreviewTheme.subtitleStyle,
|
||||||
@@ -105,7 +105,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
|
|||||||
final user = member.user!;
|
final user = member.user!;
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
UserAvatar(
|
StreamUserAvatar(
|
||||||
user: user,
|
user: user,
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
maxHeight: 64,
|
maxHeight: 64,
|
||||||
@@ -132,7 +132,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
OptionListTile(
|
StreamOptionListTile(
|
||||||
leading: Padding(
|
leading: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: StreamSvgIcon.user(
|
child: StreamSvgIcon.user(
|
||||||
@@ -143,7 +143,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
|
|||||||
onTap: onViewInfoTap,
|
onTap: onViewInfoTap,
|
||||||
),
|
),
|
||||||
if (!isOneToOneChannel)
|
if (!isOneToOneChannel)
|
||||||
OptionListTile(
|
StreamOptionListTile(
|
||||||
title: context.translations.leaveGroupLabel,
|
title: context.translations.leaveGroupLabel,
|
||||||
leading: Padding(
|
leading: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
@@ -154,7 +154,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
|
|||||||
onTap: onLeaveChannelTap,
|
onTap: onLeaveChannelTap,
|
||||||
),
|
),
|
||||||
if (isOwner)
|
if (isOwner)
|
||||||
OptionListTile(
|
StreamOptionListTile(
|
||||||
leading: Padding(
|
leading: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: StreamSvgIcon.delete(
|
child: StreamSvgIcon.delete(
|
||||||
@@ -165,7 +165,7 @@ class StreamChannelInfoBottomSheet extends StatelessWidget {
|
|||||||
titleColor: colorTheme.accentError,
|
titleColor: colorTheme.accentError,
|
||||||
onTap: onDeleteConversationTap,
|
onTap: onDeleteConversationTap,
|
||||||
),
|
),
|
||||||
OptionListTile(
|
StreamOptionListTile(
|
||||||
leading: Padding(
|
leading: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: StreamSvgIcon.closeSmall(
|
child: StreamSvgIcon.closeSmall(
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:synchronized/synchronized.dart';
|
|
||||||
import 'package:video_compress/video_compress.dart';
|
|
||||||
import 'package:video_thumbnail/video_thumbnail.dart';
|
import 'package:video_thumbnail/video_thumbnail.dart';
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -12,32 +10,6 @@ class _IVideoService {
|
|||||||
|
|
||||||
/// Singleton instance of [_IVideoService]
|
/// Singleton instance of [_IVideoService]
|
||||||
static final _IVideoService instance = _IVideoService._();
|
static final _IVideoService instance = _IVideoService._();
|
||||||
final _lock = Lock();
|
|
||||||
|
|
||||||
/// compress video from [path]
|
|
||||||
/// compress video from [path] return [Future<MediaInfo>]
|
|
||||||
///
|
|
||||||
/// you can choose its [quality] and [frameRate]
|
|
||||||
///
|
|
||||||
/// ## example
|
|
||||||
/// ```dart
|
|
||||||
/// final info = await _flutterVideoCompress.compressVideo(
|
|
||||||
/// file.path,
|
|
||||||
/// );
|
|
||||||
/// debugPrint(info.toJson());
|
|
||||||
/// ```
|
|
||||||
Future<MediaInfo?> compressVideo(
|
|
||||||
String path, {
|
|
||||||
int frameRate = 30,
|
|
||||||
VideoQuality quality = VideoQuality.DefaultQuality,
|
|
||||||
}) async =>
|
|
||||||
_lock.synchronized(
|
|
||||||
() => VideoCompress.compressVideo(
|
|
||||||
path,
|
|
||||||
frameRate: frameRate,
|
|
||||||
quality: quality,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Generates a thumbnail image data in memory as UInt8List,
|
/// Generates a thumbnail image data in memory as UInt8List,
|
||||||
/// it can be easily used by Image.memory(...).
|
/// it can be easily used by Image.memory(...).
|
||||||
@@ -66,5 +38,10 @@ class _IVideoService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get instance of [_IVideoService]
|
/// Get instance of [_IVideoService]
|
||||||
|
@Deprecated("Use 'StreamVideoService' instead")
|
||||||
// ignore: non_constant_identifier_names
|
// ignore: non_constant_identifier_names
|
||||||
_IVideoService get VideoService => _IVideoService.instance;
|
_IVideoService get VideoService => _IVideoService.instance;
|
||||||
|
|
||||||
|
/// Get instance of [_IVideoService]
|
||||||
|
// ignore: non_constant_identifier_names
|
||||||
|
_IVideoService get StreamVideoService => _IVideoService.instance;
|
||||||
|
|||||||
@@ -6,10 +6,16 @@ import 'package:stream_chat_flutter/src/video_service.dart';
|
|||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:video_thumbnail/video_thumbnail.dart';
|
import 'package:video_thumbnail/video_thumbnail.dart';
|
||||||
|
|
||||||
|
/// {@macro video_thumbnail_image}
|
||||||
|
@Deprecated("Use 'StreamVideoThumbnailImage' instead")
|
||||||
|
typedef VideoThumbnailImage = StreamVideoThumbnailImage;
|
||||||
|
|
||||||
|
/// {@template video_thumbnail_image}
|
||||||
/// Widget for creating video thumbnail image
|
/// Widget for creating video thumbnail image
|
||||||
class VideoThumbnailImage extends StatefulWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating [VideoThumbnailImage]
|
class StreamVideoThumbnailImage extends StatefulWidget {
|
||||||
const VideoThumbnailImage({
|
/// Constructor for creating [StreamVideoThumbnailImage]
|
||||||
|
const StreamVideoThumbnailImage({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.video,
|
required this.video,
|
||||||
this.width,
|
this.width,
|
||||||
@@ -42,16 +48,17 @@ class VideoThumbnailImage extends StatefulWidget {
|
|||||||
final WidgetBuilder? placeholderBuilder;
|
final WidgetBuilder? placeholderBuilder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_VideoThumbnailImageState createState() => _VideoThumbnailImageState();
|
_StreamVideoThumbnailImageState createState() =>
|
||||||
|
_StreamVideoThumbnailImageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _VideoThumbnailImageState extends State<VideoThumbnailImage> {
|
class _StreamVideoThumbnailImageState extends State<StreamVideoThumbnailImage> {
|
||||||
late Future<Uint8List?> thumbnailFuture;
|
late Future<Uint8List?> thumbnailFuture;
|
||||||
late StreamChatThemeData _streamChatTheme;
|
late StreamChatThemeData _streamChatTheme;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
thumbnailFuture = VideoService.generateVideoThumbnail(
|
thumbnailFuture = StreamVideoService.generateVideoThumbnail(
|
||||||
video: widget.video,
|
video: widget.video,
|
||||||
imageFormat: widget.format,
|
imageFormat: widget.format,
|
||||||
);
|
);
|
||||||
@@ -65,9 +72,9 @@ class _VideoThumbnailImageState extends State<VideoThumbnailImage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(covariant VideoThumbnailImage oldWidget) {
|
void didUpdateWidget(covariant StreamVideoThumbnailImage oldWidget) {
|
||||||
if (oldWidget.video != widget.video || oldWidget.format != widget.format) {
|
if (oldWidget.video != widget.video || oldWidget.format != widget.format) {
|
||||||
thumbnailFuture = VideoService.generateVideoThumbnail(
|
thumbnailFuture = StreamVideoService.generateVideoThumbnail(
|
||||||
video: widget.video,
|
video: widget.video,
|
||||||
imageFormat: widget.format,
|
imageFormat: widget.format,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,10 +2,16 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
|
/// {@macro visible_footnote}
|
||||||
|
@Deprecated("Use 'StreamVisibleFootnote' instead")
|
||||||
|
typedef VisibleFootnote = StreamVisibleFootnote;
|
||||||
|
|
||||||
|
/// {@template visible_footnote}
|
||||||
/// Widget for displaying a footnote
|
/// Widget for displaying a footnote
|
||||||
class VisibleFootnote extends StatelessWidget {
|
/// {@endtemplate}
|
||||||
/// Constructor for creating a [VisibleFootnote]
|
class StreamVisibleFootnote extends StatelessWidget {
|
||||||
const VisibleFootnote({Key? key}) : super(key: key);
|
/// Constructor for creating a [StreamVisibleFootnote]
|
||||||
|
const StreamVisibleFootnote({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user