refactor: deprecate MessageSendingStatus in favor of MessageState.

Signed-off-by: xsahil03x <[email protected]>
This commit is contained in:
Sahil Kumar
2023-06-17 03:57:16 +05:30
committed by xsahil03x
parent d1862e9671
commit 810957c516
9 changed files with 3018 additions and 251 deletions
@@ -1,6 +1,7 @@
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/core/models/attachment.dart';
import 'package:stream_chat/src/core/models/message_state.dart';
import 'package:stream_chat/src/core/models/reaction.dart';
import 'package:stream_chat/src/core/models/user.dart';
import 'package:stream_chat/src/core/util/serializer.dart';
@@ -15,6 +16,7 @@ class _NullConst {
const _nullConst = _NullConst();
/// Enum defining the status of a sending message.
@Deprecated('Use MessageState instead')
enum MessageSendingStatus {
/// Message is being sent
sending,
@@ -37,7 +39,45 @@ enum MessageSendingStatus {
failed_delete,
/// Message correctly sent
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.
@@ -75,21 +115,39 @@ class Message extends Equatable {
DateTime? pinExpires,
this.pinnedBy,
this.extraData = const {},
this.status = MessageSendingStatus.sending,
@Deprecated('Use `state` instead') MessageSendingStatus? status,
MessageState? state,
this.i18n,
}) : id = id ?? const Uuid().v4(),
pinExpires = pinExpires?.toUtc(),
remoteCreatedAt = createdAt,
remoteUpdatedAt = updatedAt,
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.
factory Message.fromJson(Map<String, dynamic> json) => _$MessageFromJson(
Serializer.moveToExtraDataFromRoot(json, topLevelFields),
).copyWith(
status: MessageSendingStatus.sent,
);
factory Message.fromJson(Map<String, dynamic> json) {
final message = _$MessageFromJson(
Serializer.moveToExtraDataFromRoot(json, topLevelFields),
);
var state = MessageState.sent;
if (message.deletedAt != null) {
state = MessageState.softDeleted;
} else if (message.updatedAt.isAfter(message.createdAt)) {
state = MessageState.updated;
}
return message.copyWith(state: state);
}
/// The message ID. This is either created by Stream or set client side when
/// the message is added.
@@ -99,8 +157,16 @@ class Message extends Equatable {
final String? text;
/// The status of a sending message.
@Deprecated('Use `state` instead')
@JsonKey(includeFromJson: false, includeToJson: false)
final MessageSendingStatus status;
MessageSendingStatus get status {
return MessageSendingStatus.fromMessageState(state);
}
// TODO: Remove late modifier in the next major version.
/// The current state of the message.
@JsonKey(includeFromJson: false, includeToJson: false)
late final MessageState state;
/// The message type.
@JsonKey(includeToJson: false)
@@ -316,7 +382,8 @@ class Message extends Equatable {
Object? pinExpires = _nullConst,
User? pinnedBy,
Map<String, Object?>? extraData,
MessageSendingStatus? status,
@Deprecated('Use `state` instead') MessageSendingStatus? status,
MessageState? state,
Map<String, String>? i18n,
}) {
assert(() {
@@ -350,6 +417,8 @@ class Message extends Equatable {
return true;
}(), 'Validate type for quotedMessage');
final messageState = state ?? status?.toMessageState();
return Message(
id: id ?? this.id,
text: text ?? this.text,
@@ -386,47 +455,49 @@ class Message extends Equatable {
pinExpires == _nullConst ? this.pinExpires : pinExpires as DateTime?,
pinnedBy: pinnedBy ?? this.pinnedBy,
extraData: extraData ?? this.extraData,
status: status ?? this.status,
state: messageState ?? this.state,
i18n: i18n ?? this.i18n,
);
}
/// Returns a new [Message] that is a combination of this message and the
/// given [other] message.
Message merge(Message other) => copyWith(
id: other.id,
text: other.text,
type: other.type,
attachments: other.attachments,
mentionedUsers: other.mentionedUsers,
silent: other.silent,
shadowed: other.shadowed,
reactionCounts: other.reactionCounts,
reactionScores: other.reactionScores,
latestReactions: other.latestReactions,
ownReactions: other.ownReactions,
parentId: other.parentId,
quotedMessage: other.quotedMessage,
quotedMessageId: other.quotedMessageId,
replyCount: other.replyCount,
threadParticipants: other.threadParticipants,
showInChannel: other.showInChannel,
command: other.command,
createdAt: other.remoteCreatedAt,
localCreatedAt: other.localCreatedAt,
updatedAt: other.remoteUpdatedAt,
localUpdatedAt: other.localUpdatedAt,
deletedAt: other.remoteDeletedAt,
localDeletedAt: other.localDeletedAt,
user: other.user,
pinned: other.pinned,
pinnedAt: other.pinnedAt,
pinExpires: other.pinExpires,
pinnedBy: other.pinnedBy,
extraData: other.extraData,
status: other.status,
i18n: other.i18n,
);
Message merge(Message other) {
return copyWith(
id: other.id,
text: other.text,
type: other.type,
attachments: other.attachments,
mentionedUsers: other.mentionedUsers,
silent: other.silent,
shadowed: other.shadowed,
reactionCounts: other.reactionCounts,
reactionScores: other.reactionScores,
latestReactions: other.latestReactions,
ownReactions: other.ownReactions,
parentId: other.parentId,
quotedMessage: other.quotedMessage,
quotedMessageId: other.quotedMessageId,
replyCount: other.replyCount,
threadParticipants: other.threadParticipants,
showInChannel: other.showInChannel,
command: other.command,
createdAt: other.remoteCreatedAt,
localCreatedAt: other.localCreatedAt,
updatedAt: other.remoteUpdatedAt,
localUpdatedAt: other.localUpdatedAt,
deletedAt: other.remoteDeletedAt,
localDeletedAt: other.localDeletedAt,
user: other.user,
pinned: other.pinned,
pinnedAt: other.pinnedAt,
pinExpires: other.pinExpires,
pinnedBy: other.pinnedBy,
extraData: other.extraData,
state: other.state,
i18n: other.i18n,
);
}
/// Returns a new [Message] that is [other] with local changes applied to it.
///
@@ -482,7 +553,7 @@ class Message extends Equatable {
pinExpires,
pinnedBy,
extraData,
status,
state,
i18n,
];
}
@@ -0,0 +1,299 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'message_state.freezed.dart';
part 'message_state.g.dart';
/// Helper extension for [MessageState].
extension MessageStateX on MessageState {
/// Returns true if the message is in initial state.
bool get isInitial => this is MessageInitial;
/// Returns true if the message is in outgoing state.
bool get isOutgoing => this is MessageOutgoing;
/// Returns true if the message is in completed state.
bool get isCompleted => this is MessageCompleted;
/// Returns true if the message is in failed state.
bool get isFailed => this is MessageFailed;
/// Returns true if the message is in outgoing sending state.
bool get isSending {
final messageState = this;
return messageState is MessageOutgoing && messageState.state is Sending;
}
/// Returns true if the message is in outgoing updating state.
bool get isUpdating {
final messageState = this;
return messageState is MessageOutgoing && messageState.state is Updating;
}
/// Returns true if the message is in outgoing deleting state.
bool get isDeleting => isSoftDeleting || isHardDeleting;
/// Returns true if the message is in outgoing soft deleting state.
bool get isSoftDeleting {
final messageState = this;
if (messageState is! MessageOutgoing) return false;
final outgoingState = messageState.state;
if (outgoingState is! Deleting) return false;
return !outgoingState.hard;
}
/// Returns true if the message is in outgoing hard deleting state.
bool get isHardDeleting {
final messageState = this;
if (messageState is! MessageOutgoing) return false;
final outgoingState = messageState.state;
if (outgoingState is! Deleting) return false;
return outgoingState.hard;
}
/// Returns true if the message is in completed sent state.
bool get isSent {
final messageState = this;
return messageState is MessageCompleted && messageState.state is Sent;
}
/// Returns true if the message is in completed updated state.
bool get isUpdated {
final messageState = this;
return messageState is MessageCompleted && messageState.state is Updated;
}
/// Returns true if the message is in completed deleted state.
bool get isDeleted => isSoftDeleted || isHardDeleted;
/// Returns true if the message is in completed soft deleted state.
bool get isSoftDeleted {
final messageState = this;
if (messageState is! MessageCompleted) return false;
final completedState = messageState.state;
if (completedState is! Deleted) return false;
return !completedState.hard;
}
/// Returns true if the message is in completed hard deleted state.
bool get isHardDeleted {
final messageState = this;
if (messageState is! MessageCompleted) return false;
final completedState = messageState.state;
if (completedState is! Deleted) return false;
return completedState.hard;
}
/// Returns true if the message is in failed sending state.
bool get isSendingFailed {
final messageState = this;
if (messageState is! MessageFailed) return false;
return messageState.state is SendingFailed;
}
/// Returns true if the message is in failed updating state.
bool get isUpdatingFailed {
final messageState = this;
if (messageState is! MessageFailed) return false;
return messageState.state is UpdatingFailed;
}
/// Returns true if the message is in failed deleting state.
bool get isDeletingFailed => isSoftDeletingFailed || isHardDeletingFailed;
/// Returns true if the message is in failed soft deleting state.
bool get isSoftDeletingFailed {
final messageState = this;
if (messageState is! MessageFailed) return false;
final failedState = messageState.state;
if (failedState is! DeletingFailed) return false;
return !failedState.hard;
}
/// Returns true if the message is in failed hard deleting state.
bool get isHardDeletingFailed {
final messageState = this;
if (messageState is! MessageFailed) return false;
final failedState = messageState.state;
if (failedState is! DeletingFailed) return false;
return failedState.hard;
}
}
/// Represents the various states a message can be in.
@freezed
class MessageState with _$MessageState {
/// Initial state when the message is created.
const factory MessageState.initial() = MessageInitial;
/// Outgoing state when the message is being sent, updated, or deleted.
const factory MessageState.outgoing({
required OutgoingState state,
}) = MessageOutgoing;
/// Completed state when the message has been successfully sent, updated, or
/// deleted.
const factory MessageState.completed({
required CompletedState state,
}) = MessageCompleted;
/// Failed state when the message fails to be sent, updated, or deleted.
const factory MessageState.failed({
required FailedState state,
Object? reason,
}) = MessageFailed;
/// Creates a new instance from a json
factory MessageState.fromJson(Map<String, dynamic> json) =>
_$MessageStateFromJson(json);
/// Deleting state when the message is being deleted.
factory MessageState.deleting({required bool hard}) {
return MessageState.outgoing(
state: OutgoingState.deleting(hard: hard),
);
}
/// Deleting state when the message has been successfully deleted.
factory MessageState.deleted({required bool hard}) {
return MessageState.completed(
state: CompletedState.deleted(hard: hard),
);
}
/// Deleting failed state when the message fails to be deleted.
factory MessageState.deletingFailed({required bool hard}) {
return MessageState.failed(
state: FailedState.deletingFailed(hard: hard),
);
}
/// Sending state when the message is being sent.
static const sending = MessageState.outgoing(
state: OutgoingState.sending(),
);
/// Updating state when the message is being updated.
static const updating = MessageState.outgoing(
state: OutgoingState.updating(),
);
/// Deleting state when the message is being soft deleted.
static const softDeleting = MessageState.outgoing(
state: OutgoingState.deleting(),
);
/// Hard deleting state when the message is being hard deleted.
static const hardDeleting = MessageState.outgoing(
state: OutgoingState.deleting(hard: true),
);
/// Sent state when the message has been successfully sent.
static const sent = MessageState.completed(
state: CompletedState.sent(),
);
/// Updated state when the message has been successfully updated.
static const updated = MessageState.completed(
state: CompletedState.updated(),
);
/// Deleted state when the message has been successfully soft deleted.
static const softDeleted = MessageState.completed(
state: CompletedState.deleted(),
);
/// Hard deleted state when the message has been successfully hard deleted.
static const hardDeleted = MessageState.completed(
state: CompletedState.deleted(hard: true),
);
/// Sending failed state when the message fails to be sent.
static const sendingFailed = MessageState.failed(
state: FailedState.sendingFailed(),
);
/// Updating failed state when the message fails to be updated.
static const updatingFailed = MessageState.failed(
state: FailedState.updatingFailed(),
);
/// Deleting failed state when the message fails to be soft deleted.
static const softDeletingFailed = MessageState.failed(
state: FailedState.deletingFailed(),
);
/// Hard deleting failed state when the message fails to be hard deleted.
static const hardDeletingFailed = MessageState.failed(
state: FailedState.deletingFailed(hard: true),
);
}
/// Represents the state of an outgoing message.
@freezed
class OutgoingState with _$OutgoingState {
/// Sending state when the message is being sent.
const factory OutgoingState.sending() = Sending;
/// Updating state when the message is being updated.
const factory OutgoingState.updating() = Updating;
/// Deleting state when the message is being deleted.
const factory OutgoingState.deleting({
@Default(false) bool hard,
}) = Deleting;
/// Creates a new instance from a json
factory OutgoingState.fromJson(Map<String, dynamic> json) =>
_$OutgoingStateFromJson(json);
}
/// Represents the completed state of a message.
@freezed
class CompletedState with _$CompletedState {
/// Sent state when the message has been successfully sent.
const factory CompletedState.sent() = Sent;
/// Updated state when the message has been successfully updated.
const factory CompletedState.updated() = Updated;
/// Deleted state when the message has been successfully deleted.
const factory CompletedState.deleted({
@Default(false) bool hard,
}) = Deleted;
/// Creates a new instance from a json
factory CompletedState.fromJson(Map<String, dynamic> json) =>
_$CompletedStateFromJson(json);
}
/// Represents the failed state of a message.
@freezed
class FailedState with _$FailedState {
/// Sending failed state when the message fails to be sent.
const factory FailedState.sendingFailed() = SendingFailed;
/// Updating failed state when the message fails to be updated.
const factory FailedState.updatingFailed() = UpdatingFailed;
/// Deleting failed state when the message fails to be deleted.
const factory FailedState.deletingFailed({
@Default(false) bool hard,
}) = DeletingFailed;
/// Creates a new instance from a json
factory FailedState.fromJson(Map<String, dynamic> json) =>
_$FailedStateFromJson(json);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,141 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'message_state.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$MessageInitial _$$MessageInitialFromJson(Map<String, dynamic> json) =>
_$MessageInitial(
$type: json['runtimeType'] as String?,
);
Map<String, dynamic> _$$MessageInitialToJson(_$MessageInitial instance) =>
<String, dynamic>{
'runtimeType': instance.$type,
};
_$MessageOutgoing _$$MessageOutgoingFromJson(Map<String, dynamic> json) =>
_$MessageOutgoing(
state: OutgoingState.fromJson(json['state'] as Map<String, dynamic>),
$type: json['runtimeType'] as String?,
);
Map<String, dynamic> _$$MessageOutgoingToJson(_$MessageOutgoing instance) =>
<String, dynamic>{
'state': instance.state.toJson(),
'runtimeType': instance.$type,
};
_$MessageCompleted _$$MessageCompletedFromJson(Map<String, dynamic> json) =>
_$MessageCompleted(
state: CompletedState.fromJson(json['state'] as Map<String, dynamic>),
$type: json['runtimeType'] as String?,
);
Map<String, dynamic> _$$MessageCompletedToJson(_$MessageCompleted instance) =>
<String, dynamic>{
'state': instance.state.toJson(),
'runtimeType': instance.$type,
};
_$MessageFailed _$$MessageFailedFromJson(Map<String, dynamic> json) =>
_$MessageFailed(
state: FailedState.fromJson(json['state'] as Map<String, dynamic>),
reason: json['reason'],
$type: json['runtimeType'] as String?,
);
Map<String, dynamic> _$$MessageFailedToJson(_$MessageFailed instance) =>
<String, dynamic>{
'state': instance.state.toJson(),
'reason': instance.reason,
'runtimeType': instance.$type,
};
_$Sending _$$SendingFromJson(Map<String, dynamic> json) => _$Sending(
$type: json['runtimeType'] as String?,
);
Map<String, dynamic> _$$SendingToJson(_$Sending instance) => <String, dynamic>{
'runtimeType': instance.$type,
};
_$Updating _$$UpdatingFromJson(Map<String, dynamic> json) => _$Updating(
$type: json['runtimeType'] as String?,
);
Map<String, dynamic> _$$UpdatingToJson(_$Updating instance) =>
<String, dynamic>{
'runtimeType': instance.$type,
};
_$Deleting _$$DeletingFromJson(Map<String, dynamic> json) => _$Deleting(
hard: json['hard'] as bool? ?? false,
$type: json['runtimeType'] as String?,
);
Map<String, dynamic> _$$DeletingToJson(_$Deleting instance) =>
<String, dynamic>{
'hard': instance.hard,
'runtimeType': instance.$type,
};
_$Sent _$$SentFromJson(Map<String, dynamic> json) => _$Sent(
$type: json['runtimeType'] as String?,
);
Map<String, dynamic> _$$SentToJson(_$Sent instance) => <String, dynamic>{
'runtimeType': instance.$type,
};
_$Updated _$$UpdatedFromJson(Map<String, dynamic> json) => _$Updated(
$type: json['runtimeType'] as String?,
);
Map<String, dynamic> _$$UpdatedToJson(_$Updated instance) => <String, dynamic>{
'runtimeType': instance.$type,
};
_$Deleted _$$DeletedFromJson(Map<String, dynamic> json) => _$Deleted(
hard: json['hard'] as bool? ?? false,
$type: json['runtimeType'] as String?,
);
Map<String, dynamic> _$$DeletedToJson(_$Deleted instance) => <String, dynamic>{
'hard': instance.hard,
'runtimeType': instance.$type,
};
_$SendingFailed _$$SendingFailedFromJson(Map<String, dynamic> json) =>
_$SendingFailed(
$type: json['runtimeType'] as String?,
);
Map<String, dynamic> _$$SendingFailedToJson(_$SendingFailed instance) =>
<String, dynamic>{
'runtimeType': instance.$type,
};
_$UpdatingFailed _$$UpdatingFailedFromJson(Map<String, dynamic> json) =>
_$UpdatingFailed(
$type: json['runtimeType'] as String?,
);
Map<String, dynamic> _$$UpdatingFailedToJson(_$UpdatingFailed instance) =>
<String, dynamic>{
'runtimeType': instance.$type,
};
_$DeletingFailed _$$DeletingFailedFromJson(Map<String, dynamic> json) =>
_$DeletingFailed(
hard: json['hard'] as bool? ?? false,
$type: json['runtimeType'] as String?,
);
Map<String, dynamic> _$$DeletingFailedToJson(_$DeletingFailed instance) =>
<String, dynamic>{
'hard': instance.hard,
'runtimeType': instance.$type,
};