chore(repo): remove deprecated code.
Signed-off-by: xsahil03x <[email protected]>
This commit is contained in:
@@ -17,7 +17,6 @@ import 'package:stream_chat/src/core/http/stream_http_client.dart';
|
|||||||
import 'package:stream_chat/src/core/http/token.dart';
|
import 'package:stream_chat/src/core/http/token.dart';
|
||||||
import 'package:stream_chat/src/core/http/token_manager.dart';
|
import 'package:stream_chat/src/core/http/token_manager.dart';
|
||||||
import 'package:stream_chat/src/core/models/attachment_file.dart';
|
import 'package:stream_chat/src/core/models/attachment_file.dart';
|
||||||
import 'package:stream_chat/src/core/models/channel_model.dart';
|
|
||||||
import 'package:stream_chat/src/core/models/channel_state.dart';
|
import 'package:stream_chat/src/core/models/channel_state.dart';
|
||||||
import 'package:stream_chat/src/core/models/event.dart';
|
import 'package:stream_chat/src/core/models/event.dart';
|
||||||
import 'package:stream_chat/src/core/models/filter.dart';
|
import 'package:stream_chat/src/core/models/filter.dart';
|
||||||
@@ -572,8 +571,6 @@ class StreamChatClient {
|
|||||||
/// Requests channels with a given query.
|
/// Requests channels with a given query.
|
||||||
Stream<List<Channel>> queryChannels({
|
Stream<List<Channel>> queryChannels({
|
||||||
Filter? filter,
|
Filter? filter,
|
||||||
@Deprecated('Use channelStateSort instead.')
|
|
||||||
List<SortOption<ChannelModel>>? sort,
|
|
||||||
List<SortOption<ChannelState>>? channelStateSort,
|
List<SortOption<ChannelState>>? channelStateSort,
|
||||||
bool state = true,
|
bool state = true,
|
||||||
bool watch = true,
|
bool watch = true,
|
||||||
@@ -590,7 +587,7 @@ class StreamChatClient {
|
|||||||
|
|
||||||
final hash = generateHash([
|
final hash = generateHash([
|
||||||
filter,
|
filter,
|
||||||
sort,
|
channelStateSort,
|
||||||
state,
|
state,
|
||||||
watch,
|
watch,
|
||||||
presence,
|
presence,
|
||||||
@@ -604,8 +601,6 @@ class StreamChatClient {
|
|||||||
} else {
|
} else {
|
||||||
final channels = await queryChannelsOffline(
|
final channels = await queryChannelsOffline(
|
||||||
filter: filter,
|
filter: filter,
|
||||||
// ignore: deprecated_member_use_from_same_package
|
|
||||||
sort: sort,
|
|
||||||
channelStateSort: channelStateSort,
|
channelStateSort: channelStateSort,
|
||||||
paginationParams: paginationParams,
|
paginationParams: paginationParams,
|
||||||
);
|
);
|
||||||
@@ -614,7 +609,7 @@ class StreamChatClient {
|
|||||||
try {
|
try {
|
||||||
final newQueryChannelsFuture = queryChannelsOnline(
|
final newQueryChannelsFuture = queryChannelsOnline(
|
||||||
filter: filter,
|
filter: filter,
|
||||||
sort: channelStateSort ?? sort,
|
sort: channelStateSort,
|
||||||
state: state,
|
state: state,
|
||||||
watch: watch,
|
watch: watch,
|
||||||
presence: presence,
|
presence: presence,
|
||||||
@@ -731,17 +726,11 @@ class StreamChatClient {
|
|||||||
/// Requests channels with a given query from the Persistence client.
|
/// Requests channels with a given query from the Persistence client.
|
||||||
Future<List<Channel>> queryChannelsOffline({
|
Future<List<Channel>> queryChannelsOffline({
|
||||||
Filter? filter,
|
Filter? filter,
|
||||||
@Deprecated('''
|
|
||||||
sort has been deprecated.
|
|
||||||
Please use channelStateSort instead.''')
|
|
||||||
List<SortOption<ChannelModel>>? sort,
|
|
||||||
List<SortOption<ChannelState>>? channelStateSort,
|
List<SortOption<ChannelState>>? channelStateSort,
|
||||||
PaginationParams paginationParams = const PaginationParams(),
|
PaginationParams paginationParams = const PaginationParams(),
|
||||||
}) async {
|
}) async {
|
||||||
final offlineChannels = (await chatPersistenceClient?.getChannelStates(
|
final offlineChannels = (await chatPersistenceClient?.getChannelStates(
|
||||||
filter: filter,
|
filter: filter,
|
||||||
// ignore: deprecated_member_use_from_same_package
|
|
||||||
sort: sort,
|
|
||||||
channelStateSort: channelStateSort,
|
channelStateSort: channelStateSort,
|
||||||
paginationParams: paginationParams,
|
paginationParams: paginationParams,
|
||||||
)) ??
|
)) ??
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ class RetryPolicy {
|
|||||||
/// Instantiate a new RetryPolicy
|
/// Instantiate a new RetryPolicy
|
||||||
RetryPolicy({
|
RetryPolicy({
|
||||||
required this.shouldRetry,
|
required this.shouldRetry,
|
||||||
@Deprecated("Use 'delayFactor' instead.") this.retryTimeout,
|
|
||||||
this.maxRetryAttempts = 6,
|
this.maxRetryAttempts = 6,
|
||||||
this.delayFactor = const Duration(milliseconds: 200),
|
this.delayFactor = const Duration(milliseconds: 200),
|
||||||
this.randomizationFactor = 0.25,
|
this.randomizationFactor = 0.25,
|
||||||
@@ -53,13 +52,4 @@ class RetryPolicy {
|
|||||||
int attempt,
|
int attempt,
|
||||||
StreamChatError? error,
|
StreamChatError? error,
|
||||||
) shouldRetry;
|
) shouldRetry;
|
||||||
|
|
||||||
/// In the case that we want to retry a failed request the retryTimeout
|
|
||||||
/// method is called to determine the timeout
|
|
||||||
@Deprecated("Use 'delayFactor' instead.")
|
|
||||||
final Duration Function(
|
|
||||||
StreamChatClient client,
|
|
||||||
int attempt,
|
|
||||||
StreamChatError? error,
|
|
||||||
)? retryTimeout;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// ignore_for_file: deprecated_member_use_from_same_package
|
|
||||||
|
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -88,11 +88,6 @@ class StreamChatNetworkError extends StreamChatError {
|
|||||||
this.isRequestCancelledError = false,
|
this.isRequestCancelledError = false,
|
||||||
}) : super(message);
|
}) : super(message);
|
||||||
|
|
||||||
///
|
|
||||||
@Deprecated('Use `StreamChatNetworkError.fromDioException` instead')
|
|
||||||
factory StreamChatNetworkError.fromDioError(DioException error) =
|
|
||||||
StreamChatNetworkError.fromDioException;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
factory StreamChatNetworkError.fromDioException(DioException exception) {
|
factory StreamChatNetworkError.fromDioException(DioException exception) {
|
||||||
final response = exception.response;
|
final response = exception.response;
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// ignore_for_file: deprecated_member_use_from_same_package
|
|
||||||
|
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:stream_chat/src/core/models/user.dart';
|
import 'package:stream_chat/src/core/models/user.dart';
|
||||||
|
|||||||
@@ -15,70 +15,6 @@ class _NullConst {
|
|||||||
|
|
||||||
const _nullConst = _NullConst();
|
const _nullConst = _NullConst();
|
||||||
|
|
||||||
/// Enum defining the status of a sending message.
|
|
||||||
enum MessageSendingStatus {
|
|
||||||
/// Message is being sent
|
|
||||||
sending,
|
|
||||||
|
|
||||||
/// Message is being updated
|
|
||||||
updating,
|
|
||||||
|
|
||||||
/// Message is being deleted
|
|
||||||
deleting,
|
|
||||||
|
|
||||||
/// Message failed to send
|
|
||||||
failed,
|
|
||||||
|
|
||||||
/// Message failed to updated
|
|
||||||
// ignore: constant_identifier_names
|
|
||||||
failed_update,
|
|
||||||
|
|
||||||
/// Message failed to delete
|
|
||||||
// ignore: constant_identifier_names
|
|
||||||
failed_delete,
|
|
||||||
|
|
||||||
/// Message correctly sent
|
|
||||||
sent;
|
|
||||||
|
|
||||||
/// Returns a [MessageState] from a [MessageSendingStatus]
|
|
||||||
MessageState toMessageState() {
|
|
||||||
switch (this) {
|
|
||||||
case MessageSendingStatus.sending:
|
|
||||||
return MessageState.sending;
|
|
||||||
case MessageSendingStatus.updating:
|
|
||||||
return MessageState.updating;
|
|
||||||
case MessageSendingStatus.deleting:
|
|
||||||
return MessageState.softDeleting;
|
|
||||||
case MessageSendingStatus.failed:
|
|
||||||
return MessageState.sendingFailed;
|
|
||||||
case MessageSendingStatus.failed_update:
|
|
||||||
return MessageState.updatingFailed;
|
|
||||||
case MessageSendingStatus.failed_delete:
|
|
||||||
return MessageState.softDeletingFailed;
|
|
||||||
case MessageSendingStatus.sent:
|
|
||||||
return MessageState.sent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a [MessageSendingStatus] from a [MessageState].
|
|
||||||
static MessageSendingStatus fromMessageState(MessageState state) {
|
|
||||||
return state.when(
|
|
||||||
initial: () => MessageSendingStatus.sending,
|
|
||||||
outgoing: (it) => it.when(
|
|
||||||
sending: () => MessageSendingStatus.sending,
|
|
||||||
updating: () => MessageSendingStatus.updating,
|
|
||||||
deleting: (_) => MessageSendingStatus.deleting,
|
|
||||||
),
|
|
||||||
completed: (_) => MessageSendingStatus.sent,
|
|
||||||
failed: (it, __) => it.when(
|
|
||||||
sendingFailed: () => MessageSendingStatus.failed,
|
|
||||||
updatingFailed: () => MessageSendingStatus.failed_update,
|
|
||||||
deletingFailed: (_) => MessageSendingStatus.failed_delete,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The class that contains the information about a message.
|
/// The class that contains the information about a message.
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class Message extends Equatable {
|
class Message extends Equatable {
|
||||||
@@ -114,23 +50,14 @@ class Message extends Equatable {
|
|||||||
DateTime? pinExpires,
|
DateTime? pinExpires,
|
||||||
this.pinnedBy,
|
this.pinnedBy,
|
||||||
this.extraData = const {},
|
this.extraData = const {},
|
||||||
@Deprecated('Use `state` instead') MessageSendingStatus? status,
|
this.state = const MessageState.initial(),
|
||||||
MessageState? state,
|
|
||||||
this.i18n,
|
this.i18n,
|
||||||
}) : id = id ?? const Uuid().v4(),
|
}) : id = id ?? const Uuid().v4(),
|
||||||
pinExpires = pinExpires?.toUtc(),
|
pinExpires = pinExpires?.toUtc(),
|
||||||
remoteCreatedAt = createdAt,
|
remoteCreatedAt = createdAt,
|
||||||
remoteUpdatedAt = updatedAt,
|
remoteUpdatedAt = updatedAt,
|
||||||
remoteDeletedAt = deletedAt,
|
remoteDeletedAt = deletedAt,
|
||||||
_quotedMessageId = quotedMessageId {
|
_quotedMessageId = quotedMessageId;
|
||||||
var messageState = state ?? const MessageState.initial();
|
|
||||||
// Backward compatibility. TODO: Remove in the next major version
|
|
||||||
if (status != null) {
|
|
||||||
messageState = status.toMessageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.state = messageState;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new instance from JSON.
|
/// Create a new instance from JSON.
|
||||||
factory Message.fromJson(Map<String, dynamic> json) {
|
factory Message.fromJson(Map<String, dynamic> json) {
|
||||||
@@ -155,17 +82,9 @@ class Message extends Equatable {
|
|||||||
/// The text of this message.
|
/// The text of this message.
|
||||||
final String? text;
|
final String? text;
|
||||||
|
|
||||||
/// The status of a sending message.
|
|
||||||
@Deprecated('Use `state` instead')
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
MessageSendingStatus get status {
|
|
||||||
return MessageSendingStatus.fromMessageState(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove late modifier in the next major version.
|
|
||||||
/// The current state of the message.
|
/// The current state of the message.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
late final MessageState state;
|
final MessageState state;
|
||||||
|
|
||||||
/// The message type.
|
/// The message type.
|
||||||
@JsonKey(includeToJson: false)
|
@JsonKey(includeToJson: false)
|
||||||
@@ -381,7 +300,6 @@ class Message extends Equatable {
|
|||||||
Object? pinExpires = _nullConst,
|
Object? pinExpires = _nullConst,
|
||||||
User? pinnedBy,
|
User? pinnedBy,
|
||||||
Map<String, Object?>? extraData,
|
Map<String, Object?>? extraData,
|
||||||
@Deprecated('Use `state` instead') MessageSendingStatus? status,
|
|
||||||
MessageState? state,
|
MessageState? state,
|
||||||
Map<String, String>? i18n,
|
Map<String, String>? i18n,
|
||||||
}) {
|
}) {
|
||||||
@@ -416,8 +334,6 @@ class Message extends Equatable {
|
|||||||
return true;
|
return true;
|
||||||
}(), 'Validate type for quotedMessage');
|
}(), 'Validate type for quotedMessage');
|
||||||
|
|
||||||
final messageState = state ?? status?.toMessageState();
|
|
||||||
|
|
||||||
return Message(
|
return Message(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
text: text ?? this.text,
|
text: text ?? this.text,
|
||||||
@@ -454,7 +370,7 @@ class Message extends Equatable {
|
|||||||
pinExpires == _nullConst ? this.pinExpires : pinExpires as DateTime?,
|
pinExpires == _nullConst ? this.pinExpires : pinExpires as DateTime?,
|
||||||
pinnedBy: pinnedBy ?? this.pinnedBy,
|
pinnedBy: pinnedBy ?? this.pinnedBy,
|
||||||
extraData: extraData ?? this.extraData,
|
extraData: extraData ?? this.extraData,
|
||||||
state: messageState ?? this.state,
|
state: state ?? this.state,
|
||||||
i18n: i18n ?? this.i18n,
|
i18n: i18n ?? this.i18n,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,8 +102,6 @@ abstract class ChatPersistenceClient {
|
|||||||
/// for filtering out states.
|
/// for filtering out states.
|
||||||
Future<List<ChannelState>> getChannelStates({
|
Future<List<ChannelState>> getChannelStates({
|
||||||
Filter? filter,
|
Filter? filter,
|
||||||
@Deprecated('Use channelStateSort instead.')
|
|
||||||
List<SortOption<ChannelModel>>? sort,
|
|
||||||
List<SortOption<ChannelState>>? channelStateSort,
|
List<SortOption<ChannelState>>? channelStateSort,
|
||||||
PaginationParams? paginationParams,
|
PaginationParams? paginationParams,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -62,8 +62,6 @@ class TestPersistenceClient extends ChatPersistenceClient {
|
|||||||
@override
|
@override
|
||||||
Future<List<ChannelState>> getChannelStates(
|
Future<List<ChannelState>> getChannelStates(
|
||||||
{Filter? filter,
|
{Filter? filter,
|
||||||
@Deprecated('Use channelStateSort instead.')
|
|
||||||
List<SortOption<ChannelModel>>? sort,
|
|
||||||
List<SortOption<ChannelState>>? channelStateSort,
|
List<SortOption<ChannelState>>? channelStateSort,
|
||||||
PaginationParams? paginationParams}) =>
|
PaginationParams? paginationParams}) =>
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
|
|||||||
@@ -1,510 +0,0 @@
|
|||||||
// ignore_for_file: deprecated_member_use_from_same_package
|
|
||||||
|
|
||||||
import 'package:collection/collection.dart'
|
|
||||||
show IterableExtension, ListEquality;
|
|
||||||
import 'package:contextmenu/contextmenu.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stream_chat_flutter/src/context_menu_items/stream_chat_context_menu_item.dart';
|
|
||||||
import 'package:stream_chat_flutter/src/dialogs/dialogs.dart';
|
|
||||||
import 'package:stream_chat_flutter/src/message_widget/sending_indicator_builder.dart';
|
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|
||||||
|
|
||||||
/// {@template channelPreview}
|
|
||||||
/// 
|
|
||||||
/// 
|
|
||||||
///
|
|
||||||
/// Shows a preview for the current [Channel].
|
|
||||||
///
|
|
||||||
/// Uses a [StreamBuilder] to render the channel information image as soon as
|
|
||||||
/// it updates.
|
|
||||||
///
|
|
||||||
/// It is not recommended to use this widget directly as it is the
|
|
||||||
/// default channel preview widget used by [ChannelListView].
|
|
||||||
///
|
|
||||||
/// The UI is rendered based on the first ancestor of type [StreamChatTheme].
|
|
||||||
/// Modify it to change the widget's appearance.
|
|
||||||
/// {@endtemplate}
|
|
||||||
@Deprecated('Use StreamChannelListTile instead.')
|
|
||||||
class ChannelPreview extends StatelessWidget {
|
|
||||||
/// {@macro channelPreview}
|
|
||||||
const ChannelPreview({
|
|
||||||
required this.channel,
|
|
||||||
super.key,
|
|
||||||
this.onTap,
|
|
||||||
this.onLongPress,
|
|
||||||
this.onViewInfoTap,
|
|
||||||
this.onImageTap,
|
|
||||||
this.title,
|
|
||||||
this.subtitle,
|
|
||||||
this.leading,
|
|
||||||
this.sendingIndicator,
|
|
||||||
this.trailing,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// The action to perform when this widget is tapped or clicked.
|
|
||||||
final void Function(Channel)? onTap;
|
|
||||||
|
|
||||||
/// The action to perform when this widget is long pressed.
|
|
||||||
final void Function(Channel)? onLongPress;
|
|
||||||
|
|
||||||
/// The action to perform when 'View Info' is tapped or clicked.
|
|
||||||
final ViewInfoCallback? onViewInfoTap;
|
|
||||||
|
|
||||||
/// The [Channel] being previewed.
|
|
||||||
final Channel channel;
|
|
||||||
|
|
||||||
/// The action to perform when the image is tapped
|
|
||||||
final VoidCallback? onImageTap;
|
|
||||||
|
|
||||||
/// Widget rendering the title
|
|
||||||
final Widget? title;
|
|
||||||
|
|
||||||
/// Widget rendering the subtitle
|
|
||||||
final Widget? subtitle;
|
|
||||||
|
|
||||||
/// Widget rendering the leading element. By default it shows the
|
|
||||||
/// [StreamChannelAvatar].
|
|
||||||
final Widget? leading;
|
|
||||||
|
|
||||||
/// Widget rendering the trailing element. By default it shows the date of
|
|
||||||
/// the last message.
|
|
||||||
final Widget? trailing;
|
|
||||||
|
|
||||||
/// Widget rendering the sending indicator. By default it uses the
|
|
||||||
/// [StreamSendingIndicator] widget.
|
|
||||||
final Widget? sendingIndicator;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final channelPreviewTheme = StreamChannelPreviewTheme.of(context);
|
|
||||||
final streamChatState = StreamChat.of(context);
|
|
||||||
final streamChatTheme = StreamChatTheme.of(context);
|
|
||||||
return BetterStreamBuilder<bool>(
|
|
||||||
stream: channel.isMutedStream,
|
|
||||||
initialData: channel.isMuted,
|
|
||||||
builder: (context, data) => AnimatedOpacity(
|
|
||||||
opacity: data ? 0.5 : 1,
|
|
||||||
duration: const Duration(milliseconds: 300),
|
|
||||||
child: ContextMenuArea(
|
|
||||||
verticalPadding: 0,
|
|
||||||
builder: (context) => [
|
|
||||||
StreamChatContextMenuItem(
|
|
||||||
leading: StreamSvgIcon.user(
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
|
||||||
title: Text(context.translations.viewInfoLabel),
|
|
||||||
onClick: () {
|
|
||||||
Navigator.of(context, rootNavigator: true).pop();
|
|
||||||
if (onViewInfoTap != null) {
|
|
||||||
onViewInfoTap?.call(channel);
|
|
||||||
} else {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => ChannelInfoDialog(
|
|
||||||
channel: channel,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
StreamChatContextMenuItem(
|
|
||||||
leading: StreamSvgIcon.mute(
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
|
||||||
title: channel.isGroup
|
|
||||||
? Text(
|
|
||||||
context.translations
|
|
||||||
.toggleMuteUnmuteGroupText(isMuted: channel.isMuted),
|
|
||||||
)
|
|
||||||
: Text(
|
|
||||||
context.translations
|
|
||||||
.toggleMuteUnmuteUserText(isMuted: channel.isMuted),
|
|
||||||
),
|
|
||||||
onClick: () async {
|
|
||||||
Navigator.of(context, rootNavigator: true).pop();
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => ConfirmationDialog(
|
|
||||||
titleText: channel.isGroup
|
|
||||||
? context.translations
|
|
||||||
.toggleMuteUnmuteGroupText(isMuted: channel.isMuted)
|
|
||||||
: context.translations
|
|
||||||
.toggleMuteUnmuteUserText(isMuted: channel.isMuted),
|
|
||||||
promptText: channel.isGroup
|
|
||||||
? context.translations.toggleMuteUnmuteGroupQuestion(
|
|
||||||
isMuted: channel.isMuted,
|
|
||||||
)
|
|
||||||
: context.translations.toggleMuteUnmuteUserQuestion(
|
|
||||||
isMuted: channel.isMuted,
|
|
||||||
),
|
|
||||||
affirmativeText: context.translations
|
|
||||||
.toggleMuteUnmuteAction(isMuted: channel.isMuted),
|
|
||||||
onConfirmation: () async {
|
|
||||||
try {
|
|
||||||
if (channel.isMuted) {
|
|
||||||
await channel.unmute();
|
|
||||||
} else {
|
|
||||||
await channel.mute();
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => MessageDialog(
|
|
||||||
messageText: e.toString(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (channel.isGroup)
|
|
||||||
StreamChatContextMenuItem(
|
|
||||||
leading: StreamSvgIcon.userRemove(
|
|
||||||
color: Colors.red,
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
context.translations.leaveGroupLabel,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.red,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onClick: () {
|
|
||||||
Navigator.of(context, rootNavigator: true).pop();
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => ConfirmationDialog(
|
|
||||||
titleText: context.translations.leaveGroupLabel,
|
|
||||||
promptText:
|
|
||||||
context.translations.leaveConversationQuestion,
|
|
||||||
affirmativeText: context.translations.leaveLabel,
|
|
||||||
onConfirmation: () async {
|
|
||||||
final userAsMember = channel.state?.members.firstWhere(
|
|
||||||
(e) =>
|
|
||||||
e.user?.id ==
|
|
||||||
StreamChat.of(context).currentUser?.id,
|
|
||||||
);
|
|
||||||
try {
|
|
||||||
await channel.removeMembers([userAsMember!.user!.id]);
|
|
||||||
} catch (e) {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => MessageDialog(
|
|
||||||
messageText: e.toString(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (!channel.isGroup)
|
|
||||||
StreamChatContextMenuItem(
|
|
||||||
leading: StreamSvgIcon.delete(
|
|
||||||
color: Colors.red,
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
context.translations.deleteConversationLabel,
|
|
||||||
style: const TextStyle(
|
|
||||||
color: Colors.red,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onClick: () {
|
|
||||||
Navigator.of(context, rootNavigator: true).pop();
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => ConfirmationDialog(
|
|
||||||
titleText: context.translations.deleteConversationLabel,
|
|
||||||
promptText:
|
|
||||||
context.translations.deleteConversationQuestion,
|
|
||||||
affirmativeText: context.translations.deleteLabel,
|
|
||||||
onConfirmation: () async {
|
|
||||||
try {
|
|
||||||
await channel.delete();
|
|
||||||
} catch (e) {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => MessageDialog(
|
|
||||||
messageText: e.toString(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
child: ListTile(
|
|
||||||
visualDensity: VisualDensity.compact,
|
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 8,
|
|
||||||
),
|
|
||||||
onTap: () => onTap?.call(channel),
|
|
||||||
onLongPress: () => onLongPress?.call(channel),
|
|
||||||
leading: leading ??
|
|
||||||
StreamChannelAvatar(
|
|
||||||
onTap: onImageTap,
|
|
||||||
channel: channel,
|
|
||||||
),
|
|
||||||
title: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: <Widget>[
|
|
||||||
Flexible(
|
|
||||||
child: title ??
|
|
||||||
ChannelName(
|
|
||||||
textStyle: channelPreviewTheme.titleStyle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
BetterStreamBuilder<List<Member>>(
|
|
||||||
stream: channel.state?.membersStream,
|
|
||||||
initialData: channel.state?.members,
|
|
||||||
comparator: const ListEquality().equals,
|
|
||||||
builder: (context, members) {
|
|
||||||
if (members.isEmpty ||
|
|
||||||
!members.any((Member e) =>
|
|
||||||
e.user!.id ==
|
|
||||||
channel.client.state.currentUser?.id)) {
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
|
||||||
return StreamUnreadIndicator(
|
|
||||||
cid: channel.cid,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
subtitle: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: <Widget>[
|
|
||||||
Flexible(child: subtitle ?? _Subtitle(channel: channel)),
|
|
||||||
sendingIndicator ??
|
|
||||||
Builder(
|
|
||||||
builder: (context) {
|
|
||||||
final lastMessage =
|
|
||||||
channel.state?.messages.lastWhereOrNull(
|
|
||||||
(m) => !m.isDeleted && !m.shadowed,
|
|
||||||
);
|
|
||||||
if (lastMessage?.user?.id ==
|
|
||||||
streamChatState.currentUser?.id) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 4),
|
|
||||||
child: BetterStreamBuilder<List<Read>>(
|
|
||||||
stream: channel.state?.readStream,
|
|
||||||
initialData: channel.state?.read,
|
|
||||||
builder: (context, data) {
|
|
||||||
final hasNonUrlAttachments = lastMessage!
|
|
||||||
.attachments
|
|
||||||
.where((it) =>
|
|
||||||
it.titleLink == null ||
|
|
||||||
it.type == 'giphy')
|
|
||||||
.isNotEmpty;
|
|
||||||
|
|
||||||
return SendingIndicatorBuilder(
|
|
||||||
messageTheme: streamChatTheme.ownMessageTheme,
|
|
||||||
message: lastMessage,
|
|
||||||
hasNonUrlAttachments: hasNonUrlAttachments,
|
|
||||||
streamChat: streamChatState,
|
|
||||||
streamChatTheme: streamChatTheme,
|
|
||||||
channel: channel,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return const SizedBox();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
trailing ?? _Date(channel: channel),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _Date extends StatelessWidget {
|
|
||||||
const _Date({
|
|
||||||
required this.channel,
|
|
||||||
});
|
|
||||||
|
|
||||||
final Channel channel;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return BetterStreamBuilder<DateTime>(
|
|
||||||
stream: channel.lastMessageAtStream,
|
|
||||||
initialData: channel.lastMessageAt,
|
|
||||||
builder: (context, data) {
|
|
||||||
final lastMessageAt = data.toLocal();
|
|
||||||
|
|
||||||
String stringDate;
|
|
||||||
final now = DateTime.now();
|
|
||||||
|
|
||||||
final startOfDay = DateTime(now.year, now.month, now.day);
|
|
||||||
|
|
||||||
if (lastMessageAt.millisecondsSinceEpoch >=
|
|
||||||
startOfDay.millisecondsSinceEpoch) {
|
|
||||||
stringDate = Jiffy.parseFromDateTime(lastMessageAt.toLocal()).jm;
|
|
||||||
} else if (lastMessageAt.millisecondsSinceEpoch >=
|
|
||||||
startOfDay
|
|
||||||
.subtract(const Duration(days: 1))
|
|
||||||
.millisecondsSinceEpoch) {
|
|
||||||
stringDate = context.translations.yesterdayLabel;
|
|
||||||
} else if (startOfDay.difference(lastMessageAt).inDays < 7) {
|
|
||||||
stringDate = Jiffy.parseFromDateTime(lastMessageAt.toLocal()).EEEE;
|
|
||||||
} else {
|
|
||||||
stringDate = Jiffy.parseFromDateTime(lastMessageAt.toLocal()).yMd;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Text(
|
|
||||||
stringDate,
|
|
||||||
style: StreamChannelPreviewTheme.of(context).lastMessageAtStyle,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _Subtitle extends StatelessWidget {
|
|
||||||
const _Subtitle({
|
|
||||||
required this.channel,
|
|
||||||
});
|
|
||||||
|
|
||||||
final Channel channel;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final channelPreviewTheme = StreamChannelPreviewTheme.of(context);
|
|
||||||
if (channel.isMuted) {
|
|
||||||
return Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
children: <Widget>[
|
|
||||||
StreamSvgIcon.mute(
|
|
||||||
size: 16,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
' ${context.translations.channelIsMutedText}',
|
|
||||||
style: channelPreviewTheme.subtitleStyle,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return StreamTypingIndicator(
|
|
||||||
channel: channel,
|
|
||||||
alternativeWidget: _LastMessage(
|
|
||||||
channel: channel,
|
|
||||||
),
|
|
||||||
style: channelPreviewTheme.subtitleStyle,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _LastMessage extends StatelessWidget {
|
|
||||||
const _LastMessage({
|
|
||||||
required this.channel,
|
|
||||||
});
|
|
||||||
|
|
||||||
final Channel channel;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Align(
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: BetterStreamBuilder<List<Message>>(
|
|
||||||
stream: channel.state!.messagesStream,
|
|
||||||
initialData: channel.state!.messages,
|
|
||||||
builder: (context, data) {
|
|
||||||
final lastMessage =
|
|
||||||
data.lastWhereOrNull((m) => !m.shadowed && !m.isDeleted);
|
|
||||||
if (lastMessage == null) {
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
var text = lastMessage.text;
|
|
||||||
final parts = <String>[
|
|
||||||
...lastMessage.attachments.map((e) {
|
|
||||||
if (e.type == 'image') {
|
|
||||||
return '📷';
|
|
||||||
} else if (e.type == 'video') {
|
|
||||||
return '🎬';
|
|
||||||
} else if (e.type == 'giphy') {
|
|
||||||
return '[GIF]';
|
|
||||||
}
|
|
||||||
return e == lastMessage.attachments.last
|
|
||||||
? (e.title ?? 'File')
|
|
||||||
: '${e.title ?? 'File'} , ';
|
|
||||||
}),
|
|
||||||
lastMessage.text ?? '',
|
|
||||||
];
|
|
||||||
|
|
||||||
text = parts.join(' ');
|
|
||||||
|
|
||||||
final channelPreviewTheme = StreamChannelPreviewTheme.of(context);
|
|
||||||
return Text.rich(
|
|
||||||
_getDisplayText(
|
|
||||||
text,
|
|
||||||
lastMessage.mentionedUsers,
|
|
||||||
lastMessage.attachments,
|
|
||||||
channelPreviewTheme.subtitleStyle?.copyWith(
|
|
||||||
color: channelPreviewTheme.subtitleStyle?.color,
|
|
||||||
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
|
|
||||||
? FontStyle.italic
|
|
||||||
: FontStyle.normal,
|
|
||||||
),
|
|
||||||
channelPreviewTheme.subtitleStyle?.copyWith(
|
|
||||||
color: channelPreviewTheme.subtitleStyle?.color,
|
|
||||||
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
|
|
||||||
? FontStyle.italic
|
|
||||||
: FontStyle.normal,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextSpan _getDisplayText(
|
|
||||||
String text,
|
|
||||||
List<User> mentions,
|
|
||||||
List<Attachment> attachments,
|
|
||||||
TextStyle? normalTextStyle,
|
|
||||||
TextStyle? mentionsTextStyle,
|
|
||||||
) {
|
|
||||||
final textList = text.split(' ');
|
|
||||||
final resList = <TextSpan>[];
|
|
||||||
for (final e in textList) {
|
|
||||||
if (mentions.isNotEmpty &&
|
|
||||||
mentions.any((element) => '@${element.name}' == e)) {
|
|
||||||
resList.add(TextSpan(
|
|
||||||
text: '$e ',
|
|
||||||
style: mentionsTextStyle,
|
|
||||||
));
|
|
||||||
} else if (attachments.isNotEmpty &&
|
|
||||||
attachments
|
|
||||||
.where((e) => e.title != null)
|
|
||||||
.any((element) => element.title == e)) {
|
|
||||||
resList.add(TextSpan(
|
|
||||||
text: '$e ',
|
|
||||||
style: normalTextStyle?.copyWith(fontStyle: FontStyle.italic),
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
resList.add(TextSpan(
|
|
||||||
text: e == textList.last ? e : '$e ',
|
|
||||||
style: normalTextStyle,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TextSpan(children: resList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
// TODO: remove in v6 as this is no longer used. Currently exported.
|
|
||||||
|
|
||||||
/// Return action for coming back from pages
|
|
||||||
@Deprecated('''
|
|
||||||
ReturnActionType has been deprecated and is no longer used.''')
|
|
||||||
enum ReturnActionType {
|
|
||||||
/// No return action
|
|
||||||
none,
|
|
||||||
|
|
||||||
/// Go to reply message action
|
|
||||||
reply,
|
|
||||||
}
|
|
||||||
@@ -81,10 +81,7 @@ abstract class Translations {
|
|||||||
|
|
||||||
/// The text for showing the unread messages count
|
/// The text for showing the unread messages count
|
||||||
/// in the [StreamMessageListView]
|
/// in the [StreamMessageListView]
|
||||||
String unreadMessagesSeparatorText(
|
String unreadMessagesSeparatorText();
|
||||||
@Deprecated('unreadCount is not used anymore and will be removed ')
|
|
||||||
int unreadCount,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// The label for "connected" in [StreamConnectionStatusBuilder]
|
/// The label for "connected" in [StreamConnectionStatusBuilder]
|
||||||
String get connectedLabel;
|
String get connectedLabel;
|
||||||
@@ -802,7 +799,7 @@ Attachment limit exceeded: it's not possible to add more than $limit attachments
|
|||||||
String get linkDisabledError => 'Links are disabled';
|
String get linkDisabledError => 'Links are disabled';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String unreadMessagesSeparatorText(int unreadCount) => 'New messages';
|
String unreadMessagesSeparatorText() => 'New messages';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enableFileAccessMessage => 'Please enable access to files'
|
String get enableFileAccessMessage => 'Please enable access to files'
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// ignore_for_file: deprecated_member_use_from_same_package
|
|
||||||
|
|
||||||
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';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// ignore_for_file: deprecated_member_use_from_same_package
|
|
||||||
|
|
||||||
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';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
// ignore_for_file: deprecated_member_use_from_same_package
|
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
@@ -110,8 +108,6 @@ class StreamMessageInput extends StatefulWidget {
|
|||||||
this.mediaAttachmentListBuilder,
|
this.mediaAttachmentListBuilder,
|
||||||
this.fileAttachmentBuilder,
|
this.fileAttachmentBuilder,
|
||||||
this.mediaAttachmentBuilder,
|
this.mediaAttachmentBuilder,
|
||||||
@Deprecated('Use `mediaAttachmentBuilder` instead.')
|
|
||||||
this.attachmentThumbnailBuilders,
|
|
||||||
this.focusNode,
|
this.focusNode,
|
||||||
this.sendButtonLocation = SendButtonLocation.outside,
|
this.sendButtonLocation = SendButtonLocation.outside,
|
||||||
this.autofocus = false,
|
this.autofocus = false,
|
||||||
@@ -235,10 +231,6 @@ class StreamMessageInput extends StatefulWidget {
|
|||||||
/// Builder used to build the media attachment item.
|
/// Builder used to build the media attachment item.
|
||||||
final AttachmentItemBuilder? mediaAttachmentBuilder;
|
final AttachmentItemBuilder? mediaAttachmentBuilder;
|
||||||
|
|
||||||
/// Map that defines a thumbnail builder for an attachment type.
|
|
||||||
@Deprecated('Use `mediaAttachmentBuilder` instead.')
|
|
||||||
final Map<String, AttachmentThumbnailBuilder>? attachmentThumbnailBuilders;
|
|
||||||
|
|
||||||
/// Map that defines a thumbnail builder for an attachment type.
|
/// Map that defines a thumbnail builder for an attachment type.
|
||||||
///
|
///
|
||||||
/// This is used to build the thumbnail for the attachment in the quoted
|
/// This is used to build the thumbnail for the attachment in the quoted
|
||||||
@@ -1220,44 +1212,7 @@ class StreamMessageInputState extends State<StreamMessageInput>
|
|||||||
fileAttachmentListBuilder: widget.fileAttachmentListBuilder,
|
fileAttachmentListBuilder: widget.fileAttachmentListBuilder,
|
||||||
mediaAttachmentListBuilder: widget.mediaAttachmentListBuilder,
|
mediaAttachmentListBuilder: widget.mediaAttachmentListBuilder,
|
||||||
fileAttachmentBuilder: widget.fileAttachmentBuilder,
|
fileAttachmentBuilder: widget.fileAttachmentBuilder,
|
||||||
mediaAttachmentBuilder: widget.mediaAttachmentBuilder ??
|
mediaAttachmentBuilder: widget.mediaAttachmentBuilder,
|
||||||
// For backward compatibility.
|
|
||||||
// TODO: Remove in the next major release.
|
|
||||||
(context, attachment, onRemovePressed) {
|
|
||||||
final Widget mediaAttachmentThumbnail;
|
|
||||||
|
|
||||||
final builder =
|
|
||||||
widget.attachmentThumbnailBuilders?[attachment.type];
|
|
||||||
if (builder != null) {
|
|
||||||
mediaAttachmentThumbnail = builder(context, attachment);
|
|
||||||
} else {
|
|
||||||
mediaAttachmentThumbnail = MessageInputMediaAttachmentThumbnail(
|
|
||||||
attachment: attachment,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ClipRRect(
|
|
||||||
key: Key(attachment.id),
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
child: Stack(
|
|
||||||
children: <Widget>[
|
|
||||||
AspectRatio(
|
|
||||||
aspectRatio: 1,
|
|
||||||
child: mediaAttachmentThumbnail,
|
|
||||||
),
|
|
||||||
Positioned(
|
|
||||||
top: 8,
|
|
||||||
right: 8,
|
|
||||||
child: RemoveAttachmentButton(
|
|
||||||
onPressed: onRemovePressed != null
|
|
||||||
? () => onRemovePressed(attachment)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
// ignore_for_file: lines_longer_than_80_chars
|
// ignore_for_file: lines_longer_than_80_chars
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:math' as math;
|
|
||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -97,11 +95,6 @@ class StreamMessageListView extends StatefulWidget {
|
|||||||
this.initialAlignment,
|
this.initialAlignment,
|
||||||
this.scrollController,
|
this.scrollController,
|
||||||
this.itemPositionListener,
|
this.itemPositionListener,
|
||||||
@Deprecated(
|
|
||||||
'Try wrapping the `MessageWidget` with a `Swipeable`, `Dismissible` or a '
|
|
||||||
'custom widget to achieve the swipe to reply behaviour.',
|
|
||||||
)
|
|
||||||
this.onMessageSwiped,
|
|
||||||
this.highlightInitialMessage = false,
|
this.highlightInitialMessage = false,
|
||||||
this.messageHighlightColor,
|
this.messageHighlightColor,
|
||||||
this.showConnectionStateTile = false,
|
this.showConnectionStateTile = false,
|
||||||
@@ -215,9 +208,6 @@ class StreamMessageListView extends StatefulWidget {
|
|||||||
/// The ScrollPhysics used by the ListView
|
/// The ScrollPhysics used by the ListView
|
||||||
final ScrollPhysics? scrollPhysics;
|
final ScrollPhysics? scrollPhysics;
|
||||||
|
|
||||||
/// {@macro onMessageSwiped}
|
|
||||||
final OnMessageSwiped? onMessageSwiped;
|
|
||||||
|
|
||||||
/// If true the list will highlight the initialMessage if there is any.
|
/// If true the list will highlight the initialMessage if there is any.
|
||||||
///
|
///
|
||||||
/// Also See [StreamChannel]
|
/// Also See [StreamChannel]
|
||||||
@@ -1263,76 +1253,6 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add swipeable if the callback is provided and the message is not deleted,
|
|
||||||
// system or ephemeral.
|
|
||||||
final onMessageSwiped = widget.onMessageSwiped;
|
|
||||||
if (onMessageSwiped != null &&
|
|
||||||
!message.isDeleted &&
|
|
||||||
!message.isSystem &&
|
|
||||||
!message.isEphemeral) {
|
|
||||||
// The threshold after which the message is considered swiped.
|
|
||||||
const threshold = 0.2;
|
|
||||||
|
|
||||||
// The direction in which the message can be swiped.
|
|
||||||
final swipeDirection = isMyMessage
|
|
||||||
? SwipeDirection.endToStart //
|
|
||||||
: SwipeDirection.startToEnd;
|
|
||||||
|
|
||||||
child = Swipeable(
|
|
||||||
key: ValueKey(message.id),
|
|
||||||
direction: swipeDirection,
|
|
||||||
swipeThreshold: threshold,
|
|
||||||
onSwiped: (_) => onMessageSwiped(message),
|
|
||||||
backgroundBuilder: (context, details) {
|
|
||||||
// The alignment of the swipe action.
|
|
||||||
final alignment = isMyMessage
|
|
||||||
? Alignment.centerRight //
|
|
||||||
: Alignment.centerLeft;
|
|
||||||
|
|
||||||
// The progress of the swipe action.
|
|
||||||
final progress = math.min(details.progress, threshold) / threshold;
|
|
||||||
|
|
||||||
// The offset for the reply icon.
|
|
||||||
var offset = Offset.lerp(
|
|
||||||
const Offset(-24, 0),
|
|
||||||
const Offset(12, 0),
|
|
||||||
progress,
|
|
||||||
)!;
|
|
||||||
|
|
||||||
// If the message is mine, we need to flip the offset.
|
|
||||||
if (isMyMessage) {
|
|
||||||
offset = Offset(-offset.dx, -offset.dy);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Align(
|
|
||||||
alignment: alignment,
|
|
||||||
child: Transform.translate(
|
|
||||||
offset: offset,
|
|
||||||
child: Opacity(
|
|
||||||
opacity: progress,
|
|
||||||
child: SizedBox.square(
|
|
||||||
dimension: 30,
|
|
||||||
child: CustomPaint(
|
|
||||||
painter: AnimatedCircleBorderPainter(
|
|
||||||
progress: progress,
|
|
||||||
color: _streamTheme.colorTheme.borders,
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: StreamSvgIcon.reply(
|
|
||||||
size: lerpDouble(0, 18, progress),
|
|
||||||
color: _streamTheme.colorTheme.accentPrimary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ class UnreadMessagesSeparator extends StatelessWidget {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Text(
|
child: Text(
|
||||||
context.translations.unreadMessagesSeparatorText(unreadCount),
|
context.translations.unreadMessagesSeparatorText(),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: StreamChannelHeaderTheme.of(context).subtitleStyle,
|
style: StreamChannelHeaderTheme.of(context).subtitleStyle,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -55,9 +55,7 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
this.attachmentBorderRadiusGeometry,
|
this.attachmentBorderRadiusGeometry,
|
||||||
this.onMentionTap,
|
this.onMentionTap,
|
||||||
this.onMessageTap,
|
this.onMessageTap,
|
||||||
bool? showReactionPicker,
|
this.showReactionPicker = true,
|
||||||
@Deprecated('Use `showReactionPicker` instead')
|
|
||||||
bool showReactionPickerIndicator = true,
|
|
||||||
@internal this.showReactionPickerTail = false,
|
@internal this.showReactionPickerTail = false,
|
||||||
this.showUserAvatar = DisplayWidget.show,
|
this.showUserAvatar = DisplayWidget.show,
|
||||||
this.showSendingIndicator = true,
|
this.showSendingIndicator = true,
|
||||||
@@ -86,15 +84,7 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
this.quotedMessageBuilder,
|
this.quotedMessageBuilder,
|
||||||
this.editMessageInputBuilder,
|
this.editMessageInputBuilder,
|
||||||
this.textBuilder,
|
this.textBuilder,
|
||||||
@Deprecated('''
|
|
||||||
Use [bottomRowBuilderWithDefaultWidget] instead.
|
|
||||||
Will be removed in the next major version.
|
|
||||||
''') this.bottomRowBuilder,
|
|
||||||
this.bottomRowBuilderWithDefaultWidget,
|
this.bottomRowBuilderWithDefaultWidget,
|
||||||
@Deprecated('''
|
|
||||||
Use [bottomRowBuilderWithDefaultWidget] instead.
|
|
||||||
Will be removed in the next major version.
|
|
||||||
''') this.deletedBottomRowBuilder,
|
|
||||||
this.customAttachmentBuilders,
|
this.customAttachmentBuilders,
|
||||||
this.padding,
|
this.padding,
|
||||||
this.textPadding = const EdgeInsets.symmetric(
|
this.textPadding = const EdgeInsets.symmetric(
|
||||||
@@ -106,20 +96,11 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
this.onQuotedMessageTap,
|
this.onQuotedMessageTap,
|
||||||
this.customActions = const [],
|
this.customActions = const [],
|
||||||
this.onAttachmentTap,
|
this.onAttachmentTap,
|
||||||
@Deprecated('''
|
|
||||||
Use [bottomRowBuilderWithDefaultWidget] instead.
|
|
||||||
Will be removed in the next major version.
|
|
||||||
''') this.usernameBuilder,
|
|
||||||
this.imageAttachmentThumbnailSize = const Size(400, 400),
|
this.imageAttachmentThumbnailSize = const Size(400, 400),
|
||||||
this.imageAttachmentThumbnailResizeType = 'clip',
|
this.imageAttachmentThumbnailResizeType = 'clip',
|
||||||
this.imageAttachmentThumbnailCropType = 'center',
|
this.imageAttachmentThumbnailCropType = 'center',
|
||||||
this.attachmentActionsModalBuilder,
|
this.attachmentActionsModalBuilder,
|
||||||
}) : assert(
|
}) : attachmentBuilders = {
|
||||||
bottomRowBuilder == null || bottomRowBuilderWithDefaultWidget == null,
|
|
||||||
'You can only use one of the two bottom row builders',
|
|
||||||
),
|
|
||||||
showReactionPicker = showReactionPicker ?? showReactionPickerIndicator,
|
|
||||||
attachmentBuilders = {
|
|
||||||
'image': (context, message, attachments) {
|
'image': (context, message, attachments) {
|
||||||
final border = RoundedRectangleBorder(
|
final border = RoundedRectangleBorder(
|
||||||
side: attachmentBorderSide ??
|
side: attachmentBorderSide ??
|
||||||
@@ -329,32 +310,17 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
final Widget Function(BuildContext, Message)? textBuilder;
|
final Widget Function(BuildContext, Message)? textBuilder;
|
||||||
|
|
||||||
/// {@template usernameBuilder}
|
|
||||||
/// Widget builder for building username
|
|
||||||
/// {@endtemplate}
|
|
||||||
final Widget Function(BuildContext, Message)? usernameBuilder;
|
|
||||||
|
|
||||||
/// {@template onMessageActions}
|
/// {@template onMessageActions}
|
||||||
/// Function called on long press
|
/// Function called on long press
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
final void Function(BuildContext, Message)? onMessageActions;
|
final void Function(BuildContext, Message)? onMessageActions;
|
||||||
|
|
||||||
/// {@template bottomRowBuilder}
|
|
||||||
/// Widget builder for building a bottom row below the message
|
|
||||||
/// {@endtemplate}
|
|
||||||
final BottomRowBuilder? bottomRowBuilder;
|
|
||||||
|
|
||||||
/// {@template bottomRowBuilderWithDefaultWidget}
|
/// {@template bottomRowBuilderWithDefaultWidget}
|
||||||
/// Widget builder for building a bottom row below the message.
|
/// Widget builder for building a bottom row below the message.
|
||||||
/// Also contains the default bottom row widget.
|
/// Also contains the default bottom row widget.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
final BottomRowBuilderWithDefaultWidget? bottomRowBuilderWithDefaultWidget;
|
final BottomRowBuilderWithDefaultWidget? bottomRowBuilderWithDefaultWidget;
|
||||||
|
|
||||||
/// {@template deletedBottomRowBuilder}
|
|
||||||
/// Widget builder for building a bottom row below a deleted message
|
|
||||||
/// {@endtemplate}
|
|
||||||
final Widget Function(BuildContext, Message)? deletedBottomRowBuilder;
|
|
||||||
|
|
||||||
/// {@template userAvatarBuilder}
|
/// {@template userAvatarBuilder}
|
||||||
/// Widget builder for building user avatar
|
/// Widget builder for building user avatar
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
@@ -471,11 +437,6 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
final bool showReactionPicker;
|
final bool showReactionPicker;
|
||||||
|
|
||||||
/// {@template showReactionPickerIndicator}
|
|
||||||
/// Used in [StreamMessageReactionsModal] and [MessageActionsModal]
|
|
||||||
/// {@endtemplate} @Deprecated('Use `showReactionPicker` instead')
|
|
||||||
bool get showReactionPickerIndicator => showReactionPicker;
|
|
||||||
|
|
||||||
/// {@template showReactionPickerTail}
|
/// {@template showReactionPickerTail}
|
||||||
/// Whether or not to show the reaction picker tail
|
/// Whether or not to show the reaction picker tail
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
@@ -601,19 +562,7 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
Widget Function(BuildContext, Message)? editMessageInputBuilder,
|
Widget Function(BuildContext, Message)? editMessageInputBuilder,
|
||||||
Widget Function(BuildContext, Message)? textBuilder,
|
Widget Function(BuildContext, Message)? textBuilder,
|
||||||
Widget Function(BuildContext, Message)? quotedMessageBuilder,
|
Widget Function(BuildContext, Message)? quotedMessageBuilder,
|
||||||
@Deprecated('''
|
|
||||||
Use [bottomRowBuilderWithDefaultWidget] instead.
|
|
||||||
Will be removed in the next major version.
|
|
||||||
''') Widget Function(BuildContext, Message)? usernameBuilder,
|
|
||||||
@Deprecated('''
|
|
||||||
Use [bottomRowBuilderWithDefaultWidget] instead.
|
|
||||||
Will be removed in the next major version.
|
|
||||||
''') BottomRowBuilder? bottomRowBuilder,
|
|
||||||
BottomRowBuilderWithDefaultWidget? bottomRowBuilderWithDefaultWidget,
|
BottomRowBuilderWithDefaultWidget? bottomRowBuilderWithDefaultWidget,
|
||||||
@Deprecated('''
|
|
||||||
Use [bottomRowBuilderWithDefaultWidget] instead.
|
|
||||||
Will be removed in the next major version.
|
|
||||||
''') Widget Function(BuildContext, Message)? deletedBottomRowBuilder,
|
|
||||||
void Function(BuildContext, Message)? onMessageActions,
|
void Function(BuildContext, Message)? onMessageActions,
|
||||||
Message? message,
|
Message? message,
|
||||||
StreamMessageThemeData? messageTheme,
|
StreamMessageThemeData? messageTheme,
|
||||||
@@ -637,8 +586,6 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
void Function(User)? onUserAvatarTap,
|
void Function(User)? onUserAvatarTap,
|
||||||
void Function(String)? onLinkTap,
|
void Function(String)? onLinkTap,
|
||||||
bool? showReactionPicker,
|
bool? showReactionPicker,
|
||||||
@Deprecated('Use `showReactionPicker` instead')
|
|
||||||
bool? showReactionPickerIndicator,
|
|
||||||
@internal bool? showReactionPickerTail,
|
@internal bool? showReactionPickerTail,
|
||||||
List<Read>? readList,
|
List<Read>? readList,
|
||||||
ShowMessageCallback? onShowMessage,
|
ShowMessageCallback? onShowMessage,
|
||||||
@@ -665,29 +612,6 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
String? imageAttachmentThumbnailCropType,
|
String? imageAttachmentThumbnailCropType,
|
||||||
AttachmentActionsBuilder? attachmentActionsModalBuilder,
|
AttachmentActionsBuilder? attachmentActionsModalBuilder,
|
||||||
}) {
|
}) {
|
||||||
assert(
|
|
||||||
bottomRowBuilder == null || bottomRowBuilderWithDefaultWidget == null,
|
|
||||||
'You can only use one of the two bottom row builders',
|
|
||||||
);
|
|
||||||
|
|
||||||
var _bottomRowBuilderWithDefaultWidget =
|
|
||||||
bottomRowBuilderWithDefaultWidget ??
|
|
||||||
this.bottomRowBuilderWithDefaultWidget;
|
|
||||||
|
|
||||||
_bottomRowBuilderWithDefaultWidget ??= (context, message, defaultWidget) {
|
|
||||||
final _bottomRowBuilder = bottomRowBuilder ?? this.bottomRowBuilder;
|
|
||||||
if (_bottomRowBuilder != null) {
|
|
||||||
return _bottomRowBuilder(context, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultWidget.copyWith(
|
|
||||||
onThreadTap: onThreadTap ?? this.onThreadTap,
|
|
||||||
usernameBuilder: usernameBuilder ?? this.usernameBuilder,
|
|
||||||
deletedBottomRowBuilder:
|
|
||||||
deletedBottomRowBuilder ?? this.deletedBottomRowBuilder,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return StreamMessageWidget(
|
return StreamMessageWidget(
|
||||||
key: key ?? this.key,
|
key: key ?? this.key,
|
||||||
onMentionTap: onMentionTap ?? this.onMentionTap,
|
onMentionTap: onMentionTap ?? this.onMentionTap,
|
||||||
@@ -698,7 +622,8 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
editMessageInputBuilder ?? this.editMessageInputBuilder,
|
editMessageInputBuilder ?? this.editMessageInputBuilder,
|
||||||
textBuilder: textBuilder ?? this.textBuilder,
|
textBuilder: textBuilder ?? this.textBuilder,
|
||||||
quotedMessageBuilder: quotedMessageBuilder ?? this.quotedMessageBuilder,
|
quotedMessageBuilder: quotedMessageBuilder ?? this.quotedMessageBuilder,
|
||||||
bottomRowBuilderWithDefaultWidget: _bottomRowBuilderWithDefaultWidget,
|
bottomRowBuilderWithDefaultWidget: bottomRowBuilderWithDefaultWidget ??
|
||||||
|
this.bottomRowBuilderWithDefaultWidget,
|
||||||
onMessageActions: onMessageActions ?? this.onMessageActions,
|
onMessageActions: onMessageActions ?? this.onMessageActions,
|
||||||
message: message ?? this.message,
|
message: message ?? this.message,
|
||||||
messageTheme: messageTheme ?? this.messageTheme,
|
messageTheme: messageTheme ?? this.messageTheme,
|
||||||
@@ -723,9 +648,7 @@ class StreamMessageWidget extends StatefulWidget {
|
|||||||
showInChannelIndicator ?? this.showInChannelIndicator,
|
showInChannelIndicator ?? this.showInChannelIndicator,
|
||||||
onUserAvatarTap: onUserAvatarTap ?? this.onUserAvatarTap,
|
onUserAvatarTap: onUserAvatarTap ?? this.onUserAvatarTap,
|
||||||
onLinkTap: onLinkTap ?? this.onLinkTap,
|
onLinkTap: onLinkTap ?? this.onLinkTap,
|
||||||
showReactionPicker: showReactionPicker ??
|
showReactionPicker: showReactionPicker ?? this.showReactionPicker,
|
||||||
showReactionPickerIndicator ??
|
|
||||||
this.showReactionPicker,
|
|
||||||
showReactionPickerTail:
|
showReactionPickerTail:
|
||||||
showReactionPickerTail ?? this.showReactionPickerTail,
|
showReactionPickerTail ?? this.showReactionPickerTail,
|
||||||
onShowMessage: onShowMessage ?? this.onShowMessage,
|
onShowMessage: onShowMessage ?? this.onShowMessage,
|
||||||
@@ -941,23 +864,6 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
: Alignment.centerLeft,
|
: Alignment.centerLeft,
|
||||||
widthFactor: widget.widthFactor,
|
widthFactor: widget.widthFactor,
|
||||||
child: Builder(builder: (context) {
|
child: Builder(builder: (context) {
|
||||||
var _bottomRowBuilderWithDefaultWidget =
|
|
||||||
widget.bottomRowBuilderWithDefaultWidget;
|
|
||||||
|
|
||||||
_bottomRowBuilderWithDefaultWidget ??=
|
|
||||||
(context, message, defaultWidget) {
|
|
||||||
final _bottomRowBuilder = widget.bottomRowBuilder;
|
|
||||||
if (_bottomRowBuilder != null) {
|
|
||||||
return _bottomRowBuilder(context, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultWidget.copyWith(
|
|
||||||
onThreadTap: widget.onThreadTap,
|
|
||||||
usernameBuilder: widget.usernameBuilder,
|
|
||||||
deletedBottomRowBuilder: widget.deletedBottomRowBuilder,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return MessageWidgetContent(
|
return MessageWidgetContent(
|
||||||
streamChatTheme: _streamChatTheme,
|
streamChatTheme: _streamChatTheme,
|
||||||
showUsername: showUsername,
|
showUsername: showUsername,
|
||||||
@@ -999,7 +905,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
onMentionTap: widget.onMentionTap,
|
onMentionTap: widget.onMentionTap,
|
||||||
onQuotedMessageTap: widget.onQuotedMessageTap,
|
onQuotedMessageTap: widget.onQuotedMessageTap,
|
||||||
bottomRowBuilderWithDefaultWidget:
|
bottomRowBuilderWithDefaultWidget:
|
||||||
_bottomRowBuilderWithDefaultWidget,
|
widget.bottomRowBuilderWithDefaultWidget,
|
||||||
onUserAvatarTap: widget.onUserAvatarTap,
|
onUserAvatarTap: widget.onUserAvatarTap,
|
||||||
userAvatarBuilder: widget.userAvatarBuilder,
|
userAvatarBuilder: widget.userAvatarBuilder,
|
||||||
);
|
);
|
||||||
@@ -1249,7 +1155,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
showSendingIndicator: false,
|
showSendingIndicator: false,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
// Show both the tail and indicator if the indicator is shown.
|
// Show both the tail and indicator if the indicator is shown.
|
||||||
showReactionPickerTail: widget.showReactionPickerIndicator,
|
showReactionPickerTail: widget.showReactionPicker,
|
||||||
showPinHighlight: false,
|
showPinHighlight: false,
|
||||||
showUserAvatar: widget.message.user!.id ==
|
showUserAvatar: widget.message.user!.id ==
|
||||||
channel.client.state.currentUser!.id
|
channel.client.state.currentUser!.id
|
||||||
@@ -1271,7 +1177,7 @@ class _StreamMessageWidgetState extends State<StreamMessageWidget>
|
|||||||
showResendMessage: shouldShowResendAction,
|
showResendMessage: shouldShowResendAction,
|
||||||
showCopyMessage: shouldShowCopyAction,
|
showCopyMessage: shouldShowCopyAction,
|
||||||
showEditMessage: shouldShowEditAction,
|
showEditMessage: shouldShowEditAction,
|
||||||
showReactionPicker: widget.showReactionPickerIndicator,
|
showReactionPicker: widget.showReactionPicker,
|
||||||
showReplyMessage: shouldShowReplyAction,
|
showReplyMessage: shouldShowReplyAction,
|
||||||
showThreadReplyMessage: shouldShowThreadReplyAction,
|
showThreadReplyMessage: shouldShowThreadReplyAction,
|
||||||
showFlagButton: widget.showFlagButton,
|
showFlagButton: widget.showFlagButton,
|
||||||
|
|||||||
@@ -67,28 +67,9 @@ class MessageWidgetContent extends StatelessWidget {
|
|||||||
this.onLinkTap,
|
this.onLinkTap,
|
||||||
this.textBuilder,
|
this.textBuilder,
|
||||||
this.quotedMessageBuilder,
|
this.quotedMessageBuilder,
|
||||||
@Deprecated('''
|
|
||||||
Use [bottomRowBuilderWithDefaultWidget] instead.
|
|
||||||
Will be removed in the next major version.
|
|
||||||
''') this.bottomRowBuilder,
|
|
||||||
this.bottomRowBuilderWithDefaultWidget,
|
this.bottomRowBuilderWithDefaultWidget,
|
||||||
@Deprecated('''
|
|
||||||
Use [bottomRowBuilderWithDefaultWidget] instead.
|
|
||||||
Will be removed in the next major version.
|
|
||||||
''') this.onThreadTap,
|
|
||||||
@Deprecated('''
|
|
||||||
Use [bottomRowBuilderWithDefaultWidget] instead.
|
|
||||||
Will be removed in the next major version.
|
|
||||||
''') this.deletedBottomRowBuilder,
|
|
||||||
this.userAvatarBuilder,
|
this.userAvatarBuilder,
|
||||||
@Deprecated('''
|
});
|
||||||
Use [bottomRowBuilderWithDefaultWidget] instead.
|
|
||||||
Will be removed in the next major version.
|
|
||||||
''') this.usernameBuilder,
|
|
||||||
}) : assert(
|
|
||||||
bottomRowBuilder == null || bottomRowBuilderWithDefaultWidget == null,
|
|
||||||
'You can only use one of the two bottom row builders',
|
|
||||||
);
|
|
||||||
|
|
||||||
/// {@macro reverse}
|
/// {@macro reverse}
|
||||||
final bool reverse;
|
final bool reverse;
|
||||||
@@ -191,9 +172,6 @@ class MessageWidgetContent extends StatelessWidget {
|
|||||||
/// The padding to use for this widget.
|
/// The padding to use for this widget.
|
||||||
final double bottomRowPadding;
|
final double bottomRowPadding;
|
||||||
|
|
||||||
/// {@macro bottomRowBuilder}
|
|
||||||
final BottomRowBuilder? bottomRowBuilder;
|
|
||||||
|
|
||||||
/// {@macro bottomRowBuilderWithDefaultWidget}
|
/// {@macro bottomRowBuilderWithDefaultWidget}
|
||||||
final BottomRowBuilderWithDefaultWidget? bottomRowBuilderWithDefaultWidget;
|
final BottomRowBuilderWithDefaultWidget? bottomRowBuilderWithDefaultWidget;
|
||||||
|
|
||||||
@@ -215,21 +193,12 @@ class MessageWidgetContent extends StatelessWidget {
|
|||||||
/// {@macro showUsername}
|
/// {@macro showUsername}
|
||||||
final bool showUsername;
|
final bool showUsername;
|
||||||
|
|
||||||
/// {@macro onThreadTap}
|
|
||||||
final void Function(Message)? onThreadTap;
|
|
||||||
|
|
||||||
/// {@macro deletedBottomRowBuilder}
|
|
||||||
final Widget Function(BuildContext, Message)? deletedBottomRowBuilder;
|
|
||||||
|
|
||||||
/// {@macro messageWidget}
|
/// {@macro messageWidget}
|
||||||
final StreamMessageWidget messageWidget;
|
final StreamMessageWidget messageWidget;
|
||||||
|
|
||||||
/// {@macro userAvatarBuilder}
|
/// {@macro userAvatarBuilder}
|
||||||
final Widget Function(BuildContext, User)? userAvatarBuilder;
|
final Widget Function(BuildContext, User)? userAvatarBuilder;
|
||||||
|
|
||||||
/// {@macro usernameBuilder}
|
|
||||||
final Widget Function(BuildContext, Message)? usernameBuilder;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
@@ -457,16 +426,11 @@ class MessageWidgetContent extends StatelessWidget {
|
|||||||
showTimeStamp: showTimeStamp,
|
showTimeStamp: showTimeStamp,
|
||||||
showUsername: showUsername,
|
showUsername: showUsername,
|
||||||
streamChatTheme: streamChatTheme,
|
streamChatTheme: streamChatTheme,
|
||||||
onThreadTap: onThreadTap,
|
|
||||||
deletedBottomRowBuilder: deletedBottomRowBuilder,
|
|
||||||
streamChat: streamChat,
|
streamChat: streamChat,
|
||||||
hasNonUrlAttachments: hasNonUrlAttachments,
|
hasNonUrlAttachments: hasNonUrlAttachments,
|
||||||
usernameBuilder: usernameBuilder,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (bottomRowBuilder != null) {
|
if (bottomRowBuilderWithDefaultWidget != null) {
|
||||||
return bottomRowBuilder!(context, message);
|
|
||||||
} else if (bottomRowBuilderWithDefaultWidget != null) {
|
|
||||||
return bottomRowBuilderWithDefaultWidget!(
|
return bottomRowBuilderWithDefaultWidget!(
|
||||||
context,
|
context,
|
||||||
message,
|
message,
|
||||||
|
|||||||
-2
@@ -1,5 +1,3 @@
|
|||||||
// ignore_for_file: deprecated_member_use_from_same_package
|
|
||||||
|
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/src/scroll_view/stream_scroll_view_error_widget.dart';
|
import 'package:stream_chat_flutter/src/scroll_view/stream_scroll_view_error_widget.dart';
|
||||||
|
|||||||
-2
@@ -1,5 +1,3 @@
|
|||||||
// ignore_for_file: deprecated_member_use_from_same_package
|
|
||||||
|
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/src/scroll_view/stream_scroll_view_error_widget.dart';
|
import 'package:stream_chat_flutter/src/scroll_view/stream_scroll_view_error_widget.dart';
|
||||||
|
|||||||
-2
@@ -1,5 +1,3 @@
|
|||||||
// ignore_for_file: deprecated_member_use_from_same_package
|
|
||||||
|
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/src/scroll_view/stream_scroll_view_error_widget.dart';
|
import 'package:stream_chat_flutter/src/scroll_view/stream_scroll_view_error_widget.dart';
|
||||||
|
|||||||
@@ -22,16 +22,13 @@ class StreamMessageThemeData with Diagnosticable {
|
|||||||
this.reactionsMaskColor,
|
this.reactionsMaskColor,
|
||||||
this.avatarTheme,
|
this.avatarTheme,
|
||||||
this.createdAtStyle,
|
this.createdAtStyle,
|
||||||
@Deprecated('Use urlAttachmentBackgroundColor instead')
|
this.urlAttachmentBackgroundColor,
|
||||||
Color? linkBackgroundColor,
|
|
||||||
Color? urlAttachmentBackgroundColor,
|
|
||||||
this.urlAttachmentHostStyle,
|
this.urlAttachmentHostStyle,
|
||||||
this.urlAttachmentTitleStyle,
|
this.urlAttachmentTitleStyle,
|
||||||
this.urlAttachmentTextStyle,
|
this.urlAttachmentTextStyle,
|
||||||
this.urlAttachmentTitleMaxLine,
|
this.urlAttachmentTitleMaxLine,
|
||||||
this.urlAttachmentTextMaxLine,
|
this.urlAttachmentTextMaxLine,
|
||||||
}) : urlAttachmentBackgroundColor =
|
});
|
||||||
urlAttachmentBackgroundColor ?? linkBackgroundColor;
|
|
||||||
|
|
||||||
/// Text style for message text
|
/// Text style for message text
|
||||||
final TextStyle? messageTextStyle;
|
final TextStyle? messageTextStyle;
|
||||||
@@ -66,10 +63,6 @@ class StreamMessageThemeData with Diagnosticable {
|
|||||||
/// Theme of the avatar
|
/// Theme of the avatar
|
||||||
final StreamAvatarThemeData? avatarTheme;
|
final StreamAvatarThemeData? avatarTheme;
|
||||||
|
|
||||||
/// Background color for messages with url attachments.
|
|
||||||
@Deprecated('Use urlAttachmentBackgroundColor instead')
|
|
||||||
Color? get linkBackgroundColor => urlAttachmentBackgroundColor;
|
|
||||||
|
|
||||||
/// Background color for messages with url attachments.
|
/// Background color for messages with url attachments.
|
||||||
final Color? urlAttachmentBackgroundColor;
|
final Color? urlAttachmentBackgroundColor;
|
||||||
|
|
||||||
@@ -101,8 +94,6 @@ class StreamMessageThemeData with Diagnosticable {
|
|||||||
Color? reactionsBackgroundColor,
|
Color? reactionsBackgroundColor,
|
||||||
Color? reactionsBorderColor,
|
Color? reactionsBorderColor,
|
||||||
Color? reactionsMaskColor,
|
Color? reactionsMaskColor,
|
||||||
@Deprecated('Use urlAttachmentBackgroundColor instead')
|
|
||||||
Color? linkBackgroundColor,
|
|
||||||
Color? urlAttachmentBackgroundColor,
|
Color? urlAttachmentBackgroundColor,
|
||||||
TextStyle? urlAttachmentHostStyle,
|
TextStyle? urlAttachmentHostStyle,
|
||||||
TextStyle? urlAttachmentTitleStyle,
|
TextStyle? urlAttachmentTitleStyle,
|
||||||
@@ -124,9 +115,8 @@ class StreamMessageThemeData with Diagnosticable {
|
|||||||
reactionsBackgroundColor ?? this.reactionsBackgroundColor,
|
reactionsBackgroundColor ?? this.reactionsBackgroundColor,
|
||||||
reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor,
|
reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor,
|
||||||
reactionsMaskColor: reactionsMaskColor ?? this.reactionsMaskColor,
|
reactionsMaskColor: reactionsMaskColor ?? this.reactionsMaskColor,
|
||||||
urlAttachmentBackgroundColor: urlAttachmentBackgroundColor ??
|
urlAttachmentBackgroundColor:
|
||||||
linkBackgroundColor ??
|
urlAttachmentBackgroundColor ?? this.urlAttachmentBackgroundColor,
|
||||||
this.urlAttachmentBackgroundColor,
|
|
||||||
urlAttachmentHostStyle:
|
urlAttachmentHostStyle:
|
||||||
urlAttachmentHostStyle ?? this.urlAttachmentHostStyle,
|
urlAttachmentHostStyle ?? this.urlAttachmentHostStyle,
|
||||||
urlAttachmentTitleStyle:
|
urlAttachmentTitleStyle:
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|
||||||
|
|
||||||
/// {@template streamUserItem}
|
|
||||||
/// Shows a preview of the current [User].
|
|
||||||
///
|
|
||||||
/// This widget uses a [StreamBuilder] to render the user information
|
|
||||||
/// image as soon as it updates.
|
|
||||||
///
|
|
||||||
/// It is not recommended to use this widget as it's the default user preview
|
|
||||||
/// used by [StreamUserListView].
|
|
||||||
///
|
|
||||||
/// The widget renders the ui based on the first ancestor of type
|
|
||||||
/// [StreamChatTheme].
|
|
||||||
/// Modify it to change the widget's appearance.
|
|
||||||
/// {@endtemplate}
|
|
||||||
@Deprecated('Use `StreamUserListTile` instead.')
|
|
||||||
class StreamUserItem extends StatelessWidget {
|
|
||||||
/// {@macro streamUserItem}
|
|
||||||
const StreamUserItem({
|
|
||||||
super.key,
|
|
||||||
required this.user,
|
|
||||||
this.onTap,
|
|
||||||
this.onLongPress,
|
|
||||||
this.onImageTap,
|
|
||||||
this.selected = false,
|
|
||||||
this.showLastOnline = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// Function called when tapping or clicking on this widget
|
|
||||||
final void Function(User)? onTap;
|
|
||||||
|
|
||||||
/// Function called when long pressing this widget
|
|
||||||
final void Function(User)? onLongPress;
|
|
||||||
|
|
||||||
/// The user to display
|
|
||||||
final User user;
|
|
||||||
|
|
||||||
/// The function called when the image is tapped or clicked
|
|
||||||
final void Function(User)? onImageTap;
|
|
||||||
|
|
||||||
/// If true the [StreamUserItem] will show a trailing checkmark
|
|
||||||
final bool selected;
|
|
||||||
|
|
||||||
/// If true the [StreamUserItem] will show the last seen
|
|
||||||
final bool showLastOnline;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
|
||||||
return ListTile(
|
|
||||||
onTap: onTap == null ? null : () => onTap!(user),
|
|
||||||
onLongPress: onLongPress == null ? null : () => onLongPress!(user),
|
|
||||||
leading: StreamUserAvatar(
|
|
||||||
user: user,
|
|
||||||
onTap: onImageTap,
|
|
||||||
constraints: const BoxConstraints.tightFor(
|
|
||||||
height: 40,
|
|
||||||
width: 40,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
trailing: selected
|
|
||||||
? StreamSvgIcon.checkSend(
|
|
||||||
color: chatThemeData.colorTheme.accentPrimary,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
title: Text(
|
|
||||||
user.name,
|
|
||||||
style: chatThemeData.textTheme.bodyBold,
|
|
||||||
),
|
|
||||||
subtitle: showLastOnline ? _buildLastActive(context) : null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildLastActive(BuildContext context) {
|
|
||||||
final chatTheme = StreamChatTheme.of(context);
|
|
||||||
final lastActive = user.lastActive ?? DateTime.now();
|
|
||||||
return Text(
|
|
||||||
user.online
|
|
||||||
? context.translations.userOnlineText
|
|
||||||
: '${context.translations.userLastOnlineText} '
|
|
||||||
'${Jiffy.parseFromDateTime(lastActive).fromNow()}',
|
|
||||||
style: chatTheme.textTheme.footnote.copyWith(
|
|
||||||
color: chatTheme.colorTheme.textHighEmphasis.withOpacity(0.5),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -59,29 +59,6 @@ bool getEffectiveCenterTitle(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shows confirmation dialog
|
|
||||||
@Deprecated(
|
|
||||||
'''
|
|
||||||
showConfirmationDialog is deprecated.
|
|
||||||
Use showConfirmationBottomSheet instead.''',
|
|
||||||
)
|
|
||||||
Future<bool?> showConfirmationDialog(
|
|
||||||
BuildContext context, {
|
|
||||||
required String title,
|
|
||||||
required String okText,
|
|
||||||
Widget? icon,
|
|
||||||
String? question,
|
|
||||||
String? cancelText,
|
|
||||||
}) =>
|
|
||||||
showConfirmationBottomSheet(
|
|
||||||
context,
|
|
||||||
title: title,
|
|
||||||
okText: okText,
|
|
||||||
icon: icon,
|
|
||||||
question: question,
|
|
||||||
cancelText: cancelText,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Shows confirmation bottom sheet
|
/// Shows confirmation bottom sheet
|
||||||
Future<bool?> showConfirmationBottomSheet(
|
Future<bool?> showConfirmationBottomSheet(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
@@ -169,29 +146,6 @@ Future<bool?> showConfirmationBottomSheet(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shows info dialog
|
|
||||||
@Deprecated(
|
|
||||||
'''
|
|
||||||
showInfoDialog is deprecated.
|
|
||||||
Use showInfoBottomSheet instead.''',
|
|
||||||
)
|
|
||||||
Future<bool?> showInfoDialog(
|
|
||||||
BuildContext context, {
|
|
||||||
required String title,
|
|
||||||
required String okText,
|
|
||||||
Widget? icon,
|
|
||||||
String? details,
|
|
||||||
StreamChatThemeData? theme,
|
|
||||||
}) =>
|
|
||||||
showInfoBottomSheet(
|
|
||||||
context,
|
|
||||||
title: title,
|
|
||||||
okText: okText,
|
|
||||||
icon: icon,
|
|
||||||
details: details,
|
|
||||||
theme: theme,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Shows info bottom sheet
|
/// Shows info bottom sheet
|
||||||
Future<bool?> showInfoBottomSheet(
|
Future<bool?> showInfoBottomSheet(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
@@ -418,25 +372,6 @@ StreamSvgIcon getFileTypeImage(String? mimeType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps attachment widget with custom shape
|
|
||||||
@Deprecated(
|
|
||||||
'''
|
|
||||||
wrapAttachmentWidget is deprecated.
|
|
||||||
Use WrapAttachmentWidget instead
|
|
||||||
''',
|
|
||||||
)
|
|
||||||
Widget wrapAttachmentWidget(
|
|
||||||
BuildContext context,
|
|
||||||
Widget attachmentWidget,
|
|
||||||
ShapeBorder attachmentShape,
|
|
||||||
// ignore: avoid_positional_boolean_parameters
|
|
||||||
bool reverse,
|
|
||||||
) =>
|
|
||||||
WrapAttachmentWidget(
|
|
||||||
attachmentWidget: attachmentWidget,
|
|
||||||
attachmentShape: attachmentShape,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Wraps attachment widget with custom shape
|
/// Wraps attachment widget with custom shape
|
||||||
class WrapAttachmentWidget extends StatelessWidget {
|
class WrapAttachmentWidget extends StatelessWidget {
|
||||||
/// Builds a [WrapAttachmentWidget].
|
/// Builds a [WrapAttachmentWidget].
|
||||||
|
|||||||
@@ -60,14 +60,12 @@ typedef OnUserAvatarPress = void Function(User);
|
|||||||
typedef PlaceholderUserImage = Widget Function(BuildContext, User);
|
typedef PlaceholderUserImage = Widget Function(BuildContext, User);
|
||||||
|
|
||||||
/// {@template editMessageInputBuilder}
|
/// {@template editMessageInputBuilder}
|
||||||
// ignore: deprecated_member_use_from_same_package
|
|
||||||
/// A widget builder for building a pre-populated [MessageInput] for use in
|
/// A widget builder for building a pre-populated [MessageInput] for use in
|
||||||
/// editing messages.
|
/// editing messages.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
typedef EditMessageInputBuilder = Widget Function(BuildContext, Message);
|
typedef EditMessageInputBuilder = Widget Function(BuildContext, Message);
|
||||||
|
|
||||||
/// {@template channelListHeaderTitleBuilder}
|
/// {@template channelListHeaderTitleBuilder}
|
||||||
// ignore: deprecated_member_use_from_same_package
|
|
||||||
/// A widget builder for custom [ChannelListHeader] title widgets.
|
/// A widget builder for custom [ChannelListHeader] title widgets.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
typedef ChannelListHeaderTitleBuilder = Widget Function(
|
typedef ChannelListHeaderTitleBuilder = Widget Function(
|
||||||
@@ -87,12 +85,6 @@ typedef ChannelTapCallback = void Function(Channel, Widget?);
|
|||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
typedef ChannelInfoCallback = void Function(Channel);
|
typedef ChannelInfoCallback = void Function(Channel);
|
||||||
|
|
||||||
/// {@template channelPreviewBuilder}
|
|
||||||
/// Builder used to create a custom ChannelPreview for a [Channel]
|
|
||||||
/// {@endtemplate}
|
|
||||||
@Deprecated('Use StreamChannelListViewIndexedWidgetBuilder instead')
|
|
||||||
typedef ChannelPreviewBuilder = Widget Function(BuildContext, Channel);
|
|
||||||
|
|
||||||
/// {@template viewInfoCallback}
|
/// {@template viewInfoCallback}
|
||||||
/// Callback for when 'View Info' is tapped
|
/// Callback for when 'View Info' is tapped
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
@@ -164,7 +156,6 @@ typedef MentionTileOverlayBuilder = Widget Function(
|
|||||||
/// {@template userMentionTileBuilder}
|
/// {@template userMentionTileBuilder}
|
||||||
/// A builder function for representing a custom user mention tile.
|
/// A builder function for representing a custom user mention tile.
|
||||||
///
|
///
|
||||||
// ignore: deprecated_member_use_from_same_package
|
|
||||||
/// Use [UserMentionTile] for the default implementation.
|
/// Use [UserMentionTile] for the default implementation.
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
typedef UserMentionTileBuilder = Widget Function(
|
typedef UserMentionTileBuilder = Widget Function(
|
||||||
@@ -232,7 +223,6 @@ typedef OnMessageTap = void Function(Message);
|
|||||||
|
|
||||||
/// {@template messageSearchItemTapCallback}
|
/// {@template messageSearchItemTapCallback}
|
||||||
/// The action to perform when tapping or clicking on a user in a
|
/// The action to perform when tapping or clicking on a user in a
|
||||||
// ignore: deprecated_member_use_from_same_package
|
|
||||||
/// [MessageSearchListView].
|
/// [MessageSearchListView].
|
||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
typedef MessageSearchItemTapCallback = void Function(GetMessageResponse);
|
typedef MessageSearchItemTapCallback = void Function(GetMessageResponse);
|
||||||
|
|||||||
@@ -26,11 +26,9 @@ export 'src/channel/channel_header.dart';
|
|||||||
export 'src/channel/channel_info.dart';
|
export 'src/channel/channel_info.dart';
|
||||||
export 'src/channel/channel_list_header.dart';
|
export 'src/channel/channel_list_header.dart';
|
||||||
export 'src/channel/channel_name.dart';
|
export 'src/channel/channel_name.dart';
|
||||||
export 'src/channel/channel_preview.dart';
|
|
||||||
export 'src/channel/stream_channel_avatar.dart';
|
export 'src/channel/stream_channel_avatar.dart';
|
||||||
export 'src/channel/stream_channel_name.dart';
|
export 'src/channel/stream_channel_name.dart';
|
||||||
export 'src/channel/stream_message_preview_text.dart';
|
export 'src/channel/stream_message_preview_text.dart';
|
||||||
export 'src/fullscreen_media/fsm_enums.dart';
|
|
||||||
export 'src/fullscreen_media/full_screen_media.dart';
|
export 'src/fullscreen_media/full_screen_media.dart';
|
||||||
export 'src/fullscreen_media/full_screen_media_builder.dart';
|
export 'src/fullscreen_media/full_screen_media_builder.dart';
|
||||||
export 'src/gallery/gallery_footer.dart';
|
export 'src/gallery/gallery_footer.dart';
|
||||||
@@ -93,7 +91,6 @@ export 'src/stream_chat.dart';
|
|||||||
export 'src/stream_chat_configuration.dart';
|
export 'src/stream_chat_configuration.dart';
|
||||||
export 'src/theme/stream_chat_theme.dart';
|
export 'src/theme/stream_chat_theme.dart';
|
||||||
export 'src/theme/themes.dart';
|
export 'src/theme/themes.dart';
|
||||||
export 'src/user/user_item.dart';
|
|
||||||
export 'src/user/user_mention_tile.dart';
|
export 'src/user/user_mention_tile.dart';
|
||||||
export 'src/utils/device_segmentation.dart';
|
export 'src/utils/device_segmentation.dart';
|
||||||
export 'src/utils/extensions.dart';
|
export 'src/utils/extensions.dart';
|
||||||
|
|||||||
@@ -1,97 +0,0 @@
|
|||||||
// ignore_for_file: deprecated_member_use_from_same_package
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:mocktail/mocktail.dart';
|
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|
||||||
|
|
||||||
import '../mocks.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets(
|
|
||||||
'it should show basic channel information',
|
|
||||||
(WidgetTester tester) async {
|
|
||||||
final client = MockClient();
|
|
||||||
final clientState = MockClientState();
|
|
||||||
final channel = MockChannel();
|
|
||||||
final channelState = MockChannelState();
|
|
||||||
final user = OwnUser(id: 'user-id');
|
|
||||||
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');
|
|
||||||
|
|
||||||
when(() => channel.cid).thenReturn('cid');
|
|
||||||
when(() => client.state).thenReturn(clientState);
|
|
||||||
when(() => clientState.currentUser).thenReturn(user);
|
|
||||||
when(() => clientState.currentUserStream)
|
|
||||||
.thenAnswer((_) => Stream.value(user));
|
|
||||||
when(() => channel.lastMessageAtStream)
|
|
||||||
.thenAnswer((_) => Stream.value(lastMessageAt));
|
|
||||||
when(() => channel.lastMessageAt).thenReturn(lastMessageAt);
|
|
||||||
when(() => channel.state).thenReturn(channelState);
|
|
||||||
when(() => channel.client).thenReturn(client);
|
|
||||||
when(() => channel.isMuted).thenReturn(false);
|
|
||||||
when(() => channel.isMutedStream).thenAnswer((i) => Stream.value(false));
|
|
||||||
when(() => channel.nameStream)
|
|
||||||
.thenAnswer((i) => Stream.value('test name'));
|
|
||||||
when(() => channel.name).thenReturn('test name');
|
|
||||||
when(() => channel.imageStream)
|
|
||||||
.thenAnswer((i) => Stream.value('https://bit.ly/321RmWb'));
|
|
||||||
when(() => channel.image).thenReturn('https://bit.ly/321RmWb');
|
|
||||||
when(() => clientState.channels).thenReturn({
|
|
||||||
channel.cid!: channel,
|
|
||||||
});
|
|
||||||
when(() => channelState.unreadCount).thenReturn(1);
|
|
||||||
when(() => channelState.unreadCountStream)
|
|
||||||
.thenAnswer((i) => Stream.value(1));
|
|
||||||
when(() => channelState.membersStream).thenAnswer(
|
|
||||||
(i) => Stream.value([
|
|
||||||
Member(
|
|
||||||
userId: 'user-id',
|
|
||||||
user: User(id: 'user-id'),
|
|
||||||
)
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
when(() => channelState.members).thenReturn([
|
|
||||||
Member(
|
|
||||||
userId: 'user-id',
|
|
||||||
user: User(id: 'user-id'),
|
|
||||||
),
|
|
||||||
]);
|
|
||||||
when(() => channelState.messages).thenReturn([
|
|
||||||
Message(
|
|
||||||
text: 'hello',
|
|
||||||
user: User(id: 'other-user'),
|
|
||||||
)
|
|
||||||
]);
|
|
||||||
when(() => channelState.messagesStream).thenAnswer(
|
|
||||||
(i) => Stream.value([
|
|
||||||
Message(
|
|
||||||
text: 'hello',
|
|
||||||
user: User(id: 'other-user'),
|
|
||||||
)
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
|
|
||||||
await tester.pumpWidget(
|
|
||||||
MaterialApp(
|
|
||||||
home: StreamChat(
|
|
||||||
client: client,
|
|
||||||
child: StreamChannel(
|
|
||||||
channel: channel,
|
|
||||||
child: Scaffold(
|
|
||||||
body: ChannelPreview(
|
|
||||||
channel: channel,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(find.text('6/22/2020'), findsOneWidget);
|
|
||||||
expect(find.text('test name'), findsOneWidget);
|
|
||||||
expect(find.text('1'), findsOneWidget);
|
|
||||||
expect(find.text('hello'), findsOneWidget);
|
|
||||||
expect(find.byType(StreamChannelAvatar), findsOneWidget);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
// ignore_for_file: deprecated_member_use_from_same_package
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:mocktail/mocktail.dart';
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
|||||||
@@ -44,9 +44,6 @@ class StreamChannelListController extends PagedValueNotifier<int, Channel> {
|
|||||||
required this.client,
|
required this.client,
|
||||||
StreamChannelListEventHandler? eventHandler,
|
StreamChannelListEventHandler? eventHandler,
|
||||||
this.filter,
|
this.filter,
|
||||||
@Deprecated('''
|
|
||||||
sort has been deprecated.
|
|
||||||
Please use channelStateSort instead.''') this.sort,
|
|
||||||
this.channelStateSort,
|
this.channelStateSort,
|
||||||
this.presence = true,
|
this.presence = true,
|
||||||
this.limit = defaultChannelPagedLimit,
|
this.limit = defaultChannelPagedLimit,
|
||||||
@@ -62,9 +59,6 @@ class StreamChannelListController extends PagedValueNotifier<int, Channel> {
|
|||||||
StreamChannelListEventHandler? eventHandler,
|
StreamChannelListEventHandler? eventHandler,
|
||||||
this.filter,
|
this.filter,
|
||||||
this.channelStateSort,
|
this.channelStateSort,
|
||||||
@Deprecated('''
|
|
||||||
sort has been deprecated.
|
|
||||||
Please use channelStateSort instead.''') this.sort,
|
|
||||||
this.presence = true,
|
this.presence = true,
|
||||||
this.limit = defaultChannelPagedLimit,
|
this.limit = defaultChannelPagedLimit,
|
||||||
this.messageLimit,
|
this.messageLimit,
|
||||||
@@ -84,20 +78,6 @@ class StreamChannelListController extends PagedValueNotifier<int, Channel> {
|
|||||||
/// You can also filter other built-in channel fields.
|
/// You can also filter other built-in channel fields.
|
||||||
final Filter? filter;
|
final Filter? filter;
|
||||||
|
|
||||||
/// The sorting used for the channels matching the filters.
|
|
||||||
///
|
|
||||||
/// Sorting is based on field and direction, multiple sorting options
|
|
||||||
/// can be provided.
|
|
||||||
///
|
|
||||||
/// You can sort based on last_updated, last_message_at, updated_at,
|
|
||||||
/// created_at or member_count.
|
|
||||||
///
|
|
||||||
/// Direction can be ascending or descending.
|
|
||||||
@Deprecated('''
|
|
||||||
sort has been deprecated.
|
|
||||||
Please use channelStateSort instead.''')
|
|
||||||
final List<SortOption<ChannelModel>>? sort;
|
|
||||||
|
|
||||||
/// The sorting used for the channels matching the filters.
|
/// The sorting used for the channels matching the filters.
|
||||||
///
|
///
|
||||||
/// Sorting is based on field and direction, multiple sorting options
|
/// Sorting is based on field and direction, multiple sorting options
|
||||||
@@ -132,8 +112,6 @@ class StreamChannelListController extends PagedValueNotifier<int, Channel> {
|
|||||||
await for (final channels in client.queryChannels(
|
await for (final channels in client.queryChannels(
|
||||||
filter: filter,
|
filter: filter,
|
||||||
channelStateSort: channelStateSort,
|
channelStateSort: channelStateSort,
|
||||||
// ignore: deprecated_member_use, deprecated_member_use_from_same_package
|
|
||||||
sort: sort,
|
|
||||||
memberLimit: memberLimit,
|
memberLimit: memberLimit,
|
||||||
messageLimit: messageLimit,
|
messageLimit: messageLimit,
|
||||||
presence: presence,
|
presence: presence,
|
||||||
@@ -162,8 +140,6 @@ class StreamChannelListController extends PagedValueNotifier<int, Channel> {
|
|||||||
try {
|
try {
|
||||||
await for (final channels in client.queryChannels(
|
await for (final channels in client.queryChannels(
|
||||||
filter: filter,
|
filter: filter,
|
||||||
// ignore: deprecated_member_use, deprecated_member_use_from_same_package
|
|
||||||
sort: sort,
|
|
||||||
channelStateSort: channelStateSort,
|
channelStateSort: channelStateSort,
|
||||||
memberLimit: memberLimit,
|
memberLimit: memberLimit,
|
||||||
messageLimit: messageLimit,
|
messageLimit: messageLimit,
|
||||||
|
|||||||
@@ -461,7 +461,7 @@ class NnStreamChatLocalizations extends GlobalStreamChatLocalizations {
|
|||||||
String get viewLibrary => 'View library';
|
String get viewLibrary => 'View library';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String unreadMessagesSeparatorText(int unreadCount) => 'New messages';
|
String unreadMessagesSeparatorText() => 'New messages';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enableFileAccessMessage => 'Enable file access to continue';
|
String get enableFileAccessMessage => 'Enable file access to continue';
|
||||||
|
|||||||
@@ -440,7 +440,7 @@ class StreamChatLocalizationsCa extends GlobalStreamChatLocalizations {
|
|||||||
String get linkDisabledError => 'Els enllaços estan deshabilitats';
|
String get linkDisabledError => 'Els enllaços estan deshabilitats';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String unreadMessagesSeparatorText(int unreadCount) => 'Missatges nous';
|
String unreadMessagesSeparatorText() => 'Missatges nous';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enableFileAccessMessage => "Habilita l'accés als fitxers"
|
String get enableFileAccessMessage => "Habilita l'accés als fitxers"
|
||||||
|
|||||||
@@ -433,7 +433,7 @@ class StreamChatLocalizationsDe extends GlobalStreamChatLocalizations {
|
|||||||
String get viewLibrary => 'Bibliothek öffnen';
|
String get viewLibrary => 'Bibliothek öffnen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String unreadMessagesSeparatorText(int unreadCount) => 'Neue Nachrichten';
|
String unreadMessagesSeparatorText() => 'Neue Nachrichten';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enableFileAccessMessage =>
|
String get enableFileAccessMessage =>
|
||||||
|
|||||||
@@ -437,7 +437,7 @@ class StreamChatLocalizationsEn extends GlobalStreamChatLocalizations {
|
|||||||
String get viewLibrary => 'View library';
|
String get viewLibrary => 'View library';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String unreadMessagesSeparatorText(int unreadCount) => 'New messages';
|
String unreadMessagesSeparatorText() => 'New messages';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enableFileAccessMessage => 'Please enable access to files'
|
String get enableFileAccessMessage => 'Please enable access to files'
|
||||||
|
|||||||
@@ -442,7 +442,7 @@ No es posible añadir más de $limit archivos adjuntos
|
|||||||
String get linkDisabledError => 'Los enlaces están deshabilitados';
|
String get linkDisabledError => 'Los enlaces están deshabilitados';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String unreadMessagesSeparatorText(int unreadCount) => 'Nuevos mensajes';
|
String unreadMessagesSeparatorText() => 'Nuevos mensajes';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enableFileAccessMessage => 'Habilite el acceso a los archivos'
|
String get enableFileAccessMessage => 'Habilite el acceso a los archivos'
|
||||||
|
|||||||
@@ -441,7 +441,7 @@ Limite de pièces jointes dépassée : il n'est pas possible d'ajouter plus de $
|
|||||||
String get linkDisabledError => 'Les liens sont désactivés';
|
String get linkDisabledError => 'Les liens sont désactivés';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String unreadMessagesSeparatorText(int unreadCount) => 'Nouveaux messages';
|
String unreadMessagesSeparatorText() => 'Nouveaux messages';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enableFileAccessMessage =>
|
String get enableFileAccessMessage =>
|
||||||
|
|||||||
@@ -435,7 +435,7 @@ class StreamChatLocalizationsHi extends GlobalStreamChatLocalizations {
|
|||||||
String get linkDisabledError => 'लिंक भेजना प्रतिबंधित';
|
String get linkDisabledError => 'लिंक भेजना प्रतिबंधित';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String unreadMessagesSeparatorText(int unreadCount) => 'नए संदेश।';
|
String unreadMessagesSeparatorText() => 'नए संदेश।';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enableFileAccessMessage => 'कृपया फ़ाइलों तक पहुंच सक्षम करें ताकि'
|
String get enableFileAccessMessage => 'कृपया फ़ाइलों तक पहुंच सक्षम करें ताकि'
|
||||||
|
|||||||
@@ -444,7 +444,7 @@ Attenzione: il limite massimo di $limit file è stato superato.
|
|||||||
String get linkDisabledError => 'I links sono disattivati';
|
String get linkDisabledError => 'I links sono disattivati';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String unreadMessagesSeparatorText(int unreadCount) => 'Nouveaux messages';
|
String unreadMessagesSeparatorText() => 'Nouveaux messages';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enableFileAccessMessage => "Per favore attiva l'accesso ai file"
|
String get enableFileAccessMessage => "Per favore attiva l'accesso ai file"
|
||||||
|
|||||||
@@ -420,7 +420,7 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations {
|
|||||||
String get linkDisabledError => 'リンクが無効になっています';
|
String get linkDisabledError => 'リンクが無効になっています';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String unreadMessagesSeparatorText(int unreadCount) => '新しいメッセージ。';
|
String unreadMessagesSeparatorText() => '新しいメッセージ。';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enableFileAccessMessage =>
|
String get enableFileAccessMessage =>
|
||||||
|
|||||||
@@ -421,7 +421,7 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations {
|
|||||||
String get linkDisabledError => '링크가 비활성화되었습니다.';
|
String get linkDisabledError => '링크가 비활성화되었습니다.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String unreadMessagesSeparatorText(int unreadCount) => '새 메시지.';
|
String unreadMessagesSeparatorText() => '새 메시지.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enableFileAccessMessage => '친구와 공유할 수 있도록 파일에 대한 액세스를 허용하세요.';
|
String get enableFileAccessMessage => '친구와 공유할 수 있도록 파일에 대한 액세스를 허용하세요.';
|
||||||
|
|||||||
@@ -385,7 +385,7 @@ class StreamChatLocalizationsNo extends GlobalStreamChatLocalizations {
|
|||||||
String get viewLibrary => 'Se bibliotek';
|
String get viewLibrary => 'Se bibliotek';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String unreadMessagesSeparatorText(int unreadCount) => 'Nye meldinger.';
|
String unreadMessagesSeparatorText() => 'Nye meldinger.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get couldNotReadBytesFromFileError =>
|
String get couldNotReadBytesFromFileError =>
|
||||||
|
|||||||
@@ -440,7 +440,7 @@ Não é possível adicionar mais de $limit arquivos de uma vez
|
|||||||
String get viewLibrary => 'Ver biblioteca';
|
String get viewLibrary => 'Ver biblioteca';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String unreadMessagesSeparatorText(int unreadCount) => 'Novas mensagens';
|
String unreadMessagesSeparatorText() => 'Novas mensagens';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get enableFileAccessMessage =>
|
String get enableFileAccessMessage =>
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ void main() {
|
|||||||
localizations.toggleMuteUnmuteUserQuestion(isMuted: true), isNotNull);
|
localizations.toggleMuteUnmuteUserQuestion(isMuted: true), isNotNull);
|
||||||
expect(localizations.toggleMuteUnmuteUserText(isMuted: true), isNotNull);
|
expect(localizations.toggleMuteUnmuteUserText(isMuted: true), isNotNull);
|
||||||
expect(localizations.viewLibrary, isNotNull);
|
expect(localizations.viewLibrary, isNotNull);
|
||||||
expect(localizations.unreadMessagesSeparatorText(2), isNotNull);
|
expect(localizations.unreadMessagesSeparatorText(), isNotNull);
|
||||||
expect(localizations.enableFileAccessMessage, isNotNull);
|
expect(localizations.enableFileAccessMessage, isNotNull);
|
||||||
expect(localizations.allowFileAccessMessage, isNotNull);
|
expect(localizations.allowFileAccessMessage, isNotNull);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -251,39 +251,18 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
|
|||||||
@override
|
@override
|
||||||
Future<List<ChannelState>> getChannelStates({
|
Future<List<ChannelState>> getChannelStates({
|
||||||
Filter? filter,
|
Filter? filter,
|
||||||
@Deprecated('Use channelStateSort instead.')
|
|
||||||
List<SortOption<ChannelModel>>? sort,
|
|
||||||
List<SortOption<ChannelState>>? channelStateSort,
|
List<SortOption<ChannelState>>? channelStateSort,
|
||||||
PaginationParams? paginationParams,
|
PaginationParams? paginationParams,
|
||||||
}) async {
|
}) async {
|
||||||
assert(_debugIsConnected, '');
|
assert(_debugIsConnected, '');
|
||||||
assert(
|
|
||||||
sort == null || channelStateSort == null,
|
|
||||||
'sort and channelStateSort cannot be used together',
|
|
||||||
);
|
|
||||||
_logger.info('getChannelStates');
|
_logger.info('getChannelStates');
|
||||||
|
|
||||||
final channels = await db!.channelQueryDao.getChannels(
|
final channels = await db!.channelQueryDao.getChannels(filter: filter);
|
||||||
filter: filter,
|
|
||||||
sort: sort,
|
|
||||||
);
|
|
||||||
|
|
||||||
final channelStates = await Future.wait(
|
final channelStates = await Future.wait(
|
||||||
channels.map((e) => getChannelStateByCid(e.cid)),
|
channels.map((e) => getChannelStateByCid(e.cid)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Only sort the channel states if the channels are not already sorted.
|
|
||||||
if (sort == null) {
|
|
||||||
var comparator = _defaultChannelStateComparator;
|
|
||||||
if (channelStateSort != null && channelStateSort.isNotEmpty) {
|
|
||||||
comparator = _combineComparators(
|
|
||||||
channelStateSort.map((it) => it.comparator).withNullifyer,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
channelStates.sort(comparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
final offset = paginationParams?.offset;
|
final offset = paginationParams?.offset;
|
||||||
if (offset != null && offset > 0 && channelStates.isNotEmpty) {
|
if (offset != null && offset > 0 && channelStates.isNotEmpty) {
|
||||||
channelStates.removeRange(0, offset);
|
channelStates.removeRange(0, offset);
|
||||||
@@ -421,35 +400,3 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new combined [Comparator] which sorts items
|
|
||||||
// by the given [comparators].
|
|
||||||
Comparator<T> _combineComparators<T>(Iterable<Comparator<T>> comparators) {
|
|
||||||
return (T a, T b) {
|
|
||||||
for (final comparator in comparators) {
|
|
||||||
try {
|
|
||||||
final result = comparator(a, b);
|
|
||||||
if (result != 0) return result;
|
|
||||||
} catch (e) {
|
|
||||||
// If the comparator throws an exception, we ignore it and
|
|
||||||
// continue with the next comparator.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// The default [Comparator] used to sort [ChannelState]s.
|
|
||||||
int _defaultChannelStateComparator(ChannelState a, ChannelState b) {
|
|
||||||
final dateA = a.channel?.lastMessageAt ?? a.channel?.createdAt;
|
|
||||||
final dateB = b.channel?.lastMessageAt ?? b.channel?.createdAt;
|
|
||||||
|
|
||||||
if (dateA == null && dateB == null) return 0;
|
|
||||||
if (dateA == null) return 1;
|
|
||||||
if (dateB == null) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return dateB.compareTo(dateA);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -148,7 +148,6 @@ void main() {
|
|||||||
// Should match with the inserted channels
|
// Should match with the inserted channels
|
||||||
final updatedChannels = await channelQueryDao.getChannels(
|
final updatedChannels = await channelQueryDao.getChannels(
|
||||||
filter: filter,
|
filter: filter,
|
||||||
// ignore: deprecated_member_use_from_same_package
|
|
||||||
sort: [
|
sort: [
|
||||||
SortOption(
|
SortOption(
|
||||||
'member_count',
|
'member_count',
|
||||||
@@ -196,7 +195,6 @@ void main() {
|
|||||||
// Should match with the inserted channels
|
// Should match with the inserted channels
|
||||||
final updatedChannels = await channelQueryDao.getChannels(
|
final updatedChannels = await channelQueryDao.getChannels(
|
||||||
filter: filter,
|
filter: filter,
|
||||||
// ignore: deprecated_member_use_from_same_package
|
|
||||||
sort: [SortOption('test_custom_field', comparator: sortComparator)],
|
sort: [SortOption('test_custom_field', comparator: sortComparator)],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user