diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index c623039b..5607b193 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -582,7 +582,7 @@ class Channel { // Eg. Updating the message while the previous call is in progress. _messageAttachmentsUploadCompleter .remove(message.id) - ?.completeError('Message Cancelled'); + ?.completeError(const StreamChatError('Message deleted')); final quotedMessage = state!.messages.firstWhereOrNull( (m) => m.id == message.quotedMessageId, @@ -592,7 +592,7 @@ class Channel { localCreatedAt: DateTime.now(), user: _client.state.currentUser, quotedMessage: quotedMessage, - status: MessageSendingStatus.sending, + state: MessageState.sending, attachments: message.attachments.map( (it) { if (it.uploadState.isSuccess) return it; @@ -630,15 +630,24 @@ class Channel { ), ); - final sentMessage = response.message.syncWith(message); + final sentMessage = response.message.syncWith(message).copyWith( + // Update the message state to updated. + state: MessageState.sent, + ); state!.updateMessage(sentMessage); if (cooldown > 0) cooldownStartedAt = DateTime.now(); return response; } catch (e) { if (e is StreamChatNetworkError && e.isRetriable) { - state!._retryQueue.add([message]); + state!._retryQueue.add([ + message.copyWith( + // Update the message state to failed. + state: MessageState.sendingFailed, + ), + ]); } + rethrow; } } @@ -653,17 +662,18 @@ class Channel { Message message, { bool skipEnrichUrl = false, }) async { + _checkInitialized(); final originalMessage = message; // Cancelling previous completer in case it's called again in the process // Eg. Updating the message while the previous call is in progress. _messageAttachmentsUploadCompleter .remove(message.id) - ?.completeError('Message Cancelled'); + ?.completeError(const StreamChatError('Message deleted')); // ignore: parameter_assignments message = message.copyWith( - status: MessageSendingStatus.updating, + state: MessageState.updating, localUpdatedAt: DateTime.now(), attachments: message.attachments.map( (it) { @@ -699,19 +709,30 @@ class Channel { ), ); - final updatedMessage = response.message - .syncWith(message) - .copyWith(ownReactions: message.ownReactions); + final updateMessage = response.message.syncWith(message).copyWith( + // Update the message state to updated. + state: MessageState.updated, + ownReactions: message.ownReactions, + ); - state?.updateMessage(updatedMessage); + state?.updateMessage(updateMessage); return response; } catch (e) { if (e is StreamChatNetworkError) { if (e.isRetriable) { - state!._retryQueue.add([message]); + state!._retryQueue.add([ + message.copyWith( + // Update the message state to failed. + state: MessageState.updatingFailed, + ), + ]); } else { - state?.updateMessage(originalMessage); + // Reset the message to original state if the update fails and is not + // retriable. + state?.updateMessage(originalMessage.copyWith( + state: MessageState.updatingFailed, + )); } } rethrow; @@ -729,6 +750,23 @@ class Channel { List? unset, bool skipEnrichUrl = false, }) async { + _checkInitialized(); + final originalMessage = message; + + // Cancelling previous completer in case it's called again in the process + // Eg. Updating the message while the previous call is in progress. + _messageAttachmentsUploadCompleter + .remove(message.id) + ?.completeError(const StreamChatError('Message deleted')); + + // ignore: parameter_assignments + message = message.copyWith( + state: MessageState.updating, + localUpdatedAt: DateTime.now(), + ); + + state?.updateMessage(message); + try { // Wait for the previous update call to finish. Otherwise, the order of // messages will not be maintained. @@ -741,17 +779,33 @@ class Channel { ), ); - final updatedMessage = response.message - .syncWith(message) - .copyWith(ownReactions: message.ownReactions); + final updatedMessage = response.message.syncWith(message).copyWith( + // Update the message state to updated. + state: MessageState.updated, + ownReactions: message.ownReactions, + ); state?.updateMessage(updatedMessage); return response; } catch (e) { - if (e is StreamChatNetworkError && e.isRetriable) { - state!._retryQueue.add([message]); + if (e is StreamChatNetworkError) { + if (e.isRetriable) { + state!._retryQueue.add([ + message.copyWith( + // Update the message state to failed. + state: MessageState.updatingFailed, + ), + ]); + } else { + // Reset the message to original state if the update fails and is not + // retriable. + state?.updateMessage(originalMessage.copyWith( + state: MessageState.updatingFailed, + )); + } } + rethrow; } } @@ -759,39 +813,49 @@ class Channel { final _deleteMessageLock = Lock(); /// Deletes the [message] from the channel. - Future deleteMessage(Message message, {bool? hard}) async { - final hardDelete = hard ?? false; + Future deleteMessage( + Message message, { + bool hard = false, + }) async { + _checkInitialized(); - // Directly deleting the local messages which are not yet sent to server - if (message.status == MessageSendingStatus.sending || - message.status == MessageSendingStatus.failed) { + // Directly deleting the local messages which are not yet sent to server. + final isSynced = message.state.isCompleted || + message.state.isUpdating || + message.state.isDeleting || + message.state.isUpdatingFailed || + message.state.isDeletingFailed; + + if (!isSynced) { state!.deleteMessage( message.copyWith( type: 'deleted', localDeletedAt: DateTime.now(), - status: MessageSendingStatus.sent, + state: MessageState.deleted(hard: hard), ), - hardDelete: hardDelete, + hardDelete: hard, ); // Removing the attachments upload completer to stop the `sendMessage` // waiting for attachments to complete. _messageAttachmentsUploadCompleter .remove(message.id) - ?.completeError(Exception('Message deleted')); + ?.completeError(const StreamChatError('Message deleted')); + + // Returning empty response to mark the api call as success. return EmptyResponse(); } + // ignore: parameter_assignments + message = message.copyWith( + type: 'deleted', + deletedAt: DateTime.now(), + state: MessageState.deleting(hard: hard), + ); + + state?.deleteMessage(message, hardDelete: hard); + try { - // ignore: parameter_assignments - message = message.copyWith( - type: 'deleted', - status: MessageSendingStatus.deleting, - deletedAt: message.deletedAt ?? DateTime.now(), - ); - - state?.deleteMessage(message, hardDelete: hardDelete); - // Wait for the previous delete call to finish. Otherwise, the order of // messages will not be maintained. final response = await _deleteMessageLock.synchronized( @@ -799,15 +863,20 @@ class Channel { ); final deletedMessage = message.copyWith( - status: MessageSendingStatus.sent, + state: MessageState.deleted(hard: hard), ); - state?.deleteMessage(deletedMessage, hardDelete: hardDelete); + state?.deleteMessage(deletedMessage, hardDelete: hard); return response; } catch (e) { if (e is StreamChatNetworkError && e.isRetriable) { - state!._retryQueue.add([message]); + state!._retryQueue.add([ + message.copyWith( + // Update the message state to failed. + state: MessageState.deletingFailed(hard: hard), + ), + ]); } rethrow; } @@ -1877,15 +1946,7 @@ class ChannelClientState { /// Retry failed message. Future retryFailedMessages() async { final failedMessages = [...messages, ...threads.values.expand((v) => v)] - .where( - (message) => - message.status != MessageSendingStatus.sent && - message.createdAt.isBefore( - DateTime.now().subtract(const Duration(seconds: 5)), - ), - ) - .toList(); - + .where((it) => it.state.isFailed); _retryQueue.add(failedMessages); } diff --git a/packages/stream_chat/lib/src/client/client.dart b/packages/stream_chat/lib/src/client/client.dart index ec6443e9..9fc99531 100644 --- a/packages/stream_chat/lib/src/client/client.dart +++ b/packages/stream_chat/lib/src/client/client.dart @@ -109,8 +109,9 @@ class StreamChatClient { _retryPolicy = retryPolicy ?? RetryPolicy( - shouldRetry: (_, attempt, __) => attempt < 5, - retryTimeout: (_, attempt, __) => Duration(seconds: attempt), + shouldRetry: (_, __, error) { + return error is StreamChatNetworkError && error.isRetriable; + }, ); state = ClientState(this); @@ -1397,12 +1398,19 @@ class StreamChatClient { ); /// Deletes the given message - Future deleteMessage(String messageId, {bool? hard}) async { - final response = - await _chatApi.message.deleteMessage(messageId, hard: hard); - if (hard == true) { + Future deleteMessage( + String messageId, { + bool hard = false, + }) async { + final response = await _chatApi.message.deleteMessage( + messageId, + hard: hard, + ); + + if (hard) { await chatPersistenceClient?.deleteMessageById(messageId); } + return response; } diff --git a/packages/stream_chat/lib/src/client/retry_policy.dart b/packages/stream_chat/lib/src/client/retry_policy.dart index 5b7812ab..f086d44b 100644 --- a/packages/stream_chat/lib/src/client/retry_policy.dart +++ b/packages/stream_chat/lib/src/client/retry_policy.dart @@ -1,27 +1,54 @@ +import 'dart:async'; + import 'package:stream_chat/src/client/client.dart'; import 'package:stream_chat/src/core/error/error.dart'; -/// The retry options -/// When sending/updating/deleting a message any temporary error will trigger the retry policy -/// The retry policy exposes 2 methods -/// - shouldRetry: returns a boolean if the request should be retried -/// - retryTimeout: How many milliseconds to wait till the next attempt +/// The retry policy associated to a client. /// -/// maxRetryAttempts is a hard limit on maximum retry attempts before giving up +/// This policy is used to determine if a request should be retried and when. +/// +/// also see: +/// - [RetryQueue] class RetryPolicy { /// Instantiate a new RetryPolicy RetryPolicy({ required this.shouldRetry, - required this.retryTimeout, + @Deprecated("Use 'delayFactor' instead.") this.retryTimeout, this.maxRetryAttempts = 6, + this.delayFactor = const Duration(milliseconds: 200), + this.randomizationFactor = 0.25, + this.maxDelay = const Duration(seconds: 30), }); - /// Hard limit on maximum retry attempts before giving up, defaults to 6 - /// Resets once connection recovers. + /// Delay factor to double after every attempt. + /// + /// Defaults to 200 ms, which results in the following delays: + /// + /// 1. 400 ms + /// 2. 800 ms + /// 3. 1600 ms + /// 4. 3200 ms + /// 5. 6400 ms + /// 6. 12800 ms + /// + /// Before application of [randomizationFactor]. + final Duration delayFactor; + + /// Percentage the delay should be randomized, given as fraction between + /// 0 and 1. + /// + /// If [randomizationFactor] is `0.25` (default) this indicates 25 % of the + /// delay should be increased or decreased by 25 %. + final double randomizationFactor; + + /// Maximum delay between retries, defaults to 30 seconds. + final Duration maxDelay; + + /// Maximum number of attempts before giving up, defaults to 6. final int maxRetryAttempts; - /// This function evaluates if we should retry the failure - final bool Function( + /// Function to determine if a retry should be attempted. + final FutureOr Function( StreamChatClient client, int attempt, StreamChatError? error, @@ -29,9 +56,10 @@ class RetryPolicy { /// 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; + )? retryTimeout; } diff --git a/packages/stream_chat/lib/src/client/retry_queue.dart b/packages/stream_chat/lib/src/client/retry_queue.dart index 388dda57..786c4c8f 100644 --- a/packages/stream_chat/lib/src/client/retry_queue.dart +++ b/packages/stream_chat/lib/src/client/retry_queue.dart @@ -14,7 +14,7 @@ class RetryQueue { }) : client = channel.client { _retryPolicy = client.retryPolicy; _listenConnectionRecovered(); - _listenFailedEvents(); + _listenMessageEvents(); } /// The channel of this queue. @@ -31,153 +31,105 @@ class RetryQueue { final _compositeSubscription = CompositeSubscription(); final _messageQueue = HeapPriorityQueue(_byDate); - bool _isRetrying = false; void _listenConnectionRecovered() { - client.on(EventType.connectionRecovered).listen((event) { + client.on(EventType.connectionRecovered).distinct().listen((event) { if (event.online == true) { - _startRetrying(); + logger?.info('Connection recovered, retrying failed messages'); + channel.state?.retryFailedMessages(); } }).addTo(_compositeSubscription); } - void _listenFailedEvents() { + void _listenMessageEvents() { channel.on().where((event) => event.message != null).listen((event) { final message = event.message!; final containsMessage = _messageQueue.containsMessage(message); if (!containsMessage) return; - if (message.status == MessageSendingStatus.sent) { + + if (message.state.isCompleted) { logger?.info('Removing sent message from queue : ${message.id}'); - _messageQueue.removeMessage(message); - return; - } else { - if ([ - MessageSendingStatus.failed_update, - MessageSendingStatus.failed, - MessageSendingStatus.failed_delete, - ].contains(message.status)) { - logger?.info('Adding failed message from event : ${event.type}'); - add([message]); - } + return _messageQueue.removeMessage(message); } }).addTo(_compositeSubscription); } /// Add a list of messages. - void add(List messages) { - if (messages.isEmpty) return; - if (!_messageQueue.containsAllMessage(messages)) { - logger?.info('Adding ${messages.length} messages'); - final messageList = _messageQueue.toList(); - // we should not add message if already available in the queue - _messageQueue.addAll(messages.where( - (it) => !messageList.any((m) => m.id == it.id), - )); - } + void add(Iterable messages) { + assert( + messages.every((it) => it.state.isFailed), + 'Only failed messages can be added to the queue', + ); - _startRetrying(); + // Filter out messages that are already in the queue. + final messagesToAdd = messages.where((it) { + return !_messageQueue.containsMessage(it); + }); + + // If there are no messages to add, return. + if (messagesToAdd.isEmpty) return; + + logger?.info('Adding ${messagesToAdd.length} messages to the queue'); + _messageQueue.addAll(messagesToAdd); + + _processQueue(); } - Future _startRetrying() async { - if (_isRetrying) return; - _isRetrying = true; + bool _isProcessing = false; + + Future _processQueue() async { + if (_isProcessing) return; + _isProcessing = true; logger?.info('Started retrying failed messages'); while (_messageQueue.isNotEmpty) { logger?.info('${_messageQueue.length} messages remaining in the queue'); + final message = _messageQueue.first; - final succeeded = await _runAndRetry(message); - if (!succeeded) { - _messageQueue.toList().forEach(_sendFailedEvent); - break; - } - } - _isRetrying = false; - } - - Future _runAndRetry(Message message) async { - var attempt = 1; - - final maxAttempt = _retryPolicy.maxRetryAttempts; - // early return in case maxAttempt is less than 0 - if (attempt > maxAttempt) return false; - - // ignore: literal_only_boolean_expressions - while (true) { + final retryPolicy = _retryPolicy; try { - logger?.info('Message (${message.id}) retry attempt $attempt'); - await _retryMessage(message); - logger?.info('Message (${message.id}) sent successfully'); - _messageQueue.removeMessage(message); - return true; - } catch (e) { - if (e is! StreamChatNetworkError || !e.isRetriable) { - _messageQueue.removeMessage(message); - _sendFailedEvent(message); - return true; - } - // retry logic - final maxAttempt = _retryPolicy.maxRetryAttempts; - if (attempt < maxAttempt) { - final shouldRetry = _retryPolicy.shouldRetry(client, attempt, e); - if (shouldRetry) { - final timeout = _retryPolicy.retryTimeout(client, attempt, e); - // temporary failure, continue - logger?.info( - 'API call failed (attempt $attempt), ' - 'retrying in ${timeout.inSeconds} seconds. Error was $e', - ); - await Future.delayed(timeout); - attempt += 1; - } else { - logger?.info( - 'API call failed (attempt $attempt). ' - 'Giving up for now, will retry when connection recovers. ' - 'Error was $e', - ); - _sendFailedEvent(message); - break; - } - } else { - logger?.info( - 'API call failed (attempt $attempt). ' - 'Exceeds maxRetryAttempt : $maxAttempt ' - 'Giving up for now, will retry when connection recovers. ' - 'Error was $e', - ); - _sendFailedEvent(message); - break; - } + await backOff( + () => _retryMessage(message), + delayFactor: retryPolicy.delayFactor, + randomizationFactor: retryPolicy.randomizationFactor, + maxDelay: retryPolicy.maxDelay, + maxAttempts: retryPolicy.maxRetryAttempts, + retryIf: (error, attempt) { + if (error is! StreamChatError) return false; + return retryPolicy.shouldRetry(client, attempt, error); + }, + ); + } catch (error) { + logger?.severe('Error while retrying message ${message.id}', error); + // If we are unable to successfully retry the message, update the state + // with the failed state. + channel.state?.updateMessage(message); + } finally { + // remove the message from the queue after it's handled. + _messageQueue.removeFirst(); } } - return false; + + _isProcessing = false; } - void _sendFailedEvent(Message message) { - final newStatus = message.status == MessageSendingStatus.sending - ? MessageSendingStatus.failed - : message.status == MessageSendingStatus.updating - ? MessageSendingStatus.failed_update - : MessageSendingStatus.failed_delete; - channel.state?.updateMessage(message.copyWith(status: newStatus)); - } - - Future _retryMessage(Message message) async { - if (message.status == MessageSendingStatus.failed_update || - message.status == MessageSendingStatus.updating) { - await channel.updateMessage(message); - } else if (message.status == MessageSendingStatus.failed || - message.status == MessageSendingStatus.sending) { - await channel.sendMessage(message); - } else if (message.status == MessageSendingStatus.failed_delete || - message.status == MessageSendingStatus.deleting) { - await channel.deleteMessage(message); - } + Future _retryMessage(Message message) async { + return message.state.maybeWhen( + failed: (state, _) => state.when( + sendingFailed: () => channel.sendMessage(message), + updatingFailed: () => channel.updateMessage(message), + deletingFailed: (hard) => channel.deleteMessage(message, hard: hard), + ), + orElse: () => throw StateError('Message state is not failed'), + ); } /// Whether our [_messageQueue] has messages or not. bool get hasMessages => _messageQueue.isNotEmpty; + /// Returns true if the queue contains the given [message]. + bool contains(Message message) => _messageQueue.containsMessage(message); + /// Call this method to dispose this object. void dispose() { _messageQueue.clear(); @@ -188,33 +140,25 @@ class RetryQueue { final date1 = _getMessageDate(m1); final date2 = _getMessageDate(m2); - if (date1 == null || date2 == null) { - return 0; - } - + if (date1 == null && date2 == null) return 0; + if (date1 == null) return -1; + if (date2 == null) return 1; return date1.compareTo(date2); } - static DateTime? _getMessageDate(Message m1) { - switch (m1.status) { - case MessageSendingStatus.failed_delete: - case MessageSendingStatus.deleting: - return m1.deletedAt; - - case MessageSendingStatus.failed: - case MessageSendingStatus.sending: - return m1.createdAt; - - case MessageSendingStatus.failed_update: - case MessageSendingStatus.updating: - return m1.updatedAt; - default: - return null; - } + static DateTime? _getMessageDate(Message message) { + return message.state.maybeWhen( + failed: (state, _) => state.when( + sendingFailed: () => message.createdAt, + updatingFailed: () => message.updatedAt, + deletingFailed: (_) => message.deletedAt, + ), + orElse: () => null, + ); } } -extension _MessageHeapPriorityQueue on HeapPriorityQueue { +extension on HeapPriorityQueue { void removeMessage(Message message) { final list = toUnorderedList(); final index = list.indexWhere((it) => it.id == message.id); @@ -229,11 +173,4 @@ extension _MessageHeapPriorityQueue on HeapPriorityQueue { if (index == -1) return false; return true; } - - bool containsAllMessage(List messages) { - if (isEmpty) return false; - final list = toUnorderedList(); - final messageIds = messages.map((it) => it.id); - return list.every((it) => messageIds.contains(it.id)); - } } diff --git a/packages/stream_chat/lib/src/core/models/message.dart b/packages/stream_chat/lib/src/core/models/message.dart index 59491c5c..40f0ad62 100644 --- a/packages/stream_chat/lib/src/core/models/message.dart +++ b/packages/stream_chat/lib/src/core/models/message.dart @@ -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 json) => _$MessageFromJson( - Serializer.moveToExtraDataFromRoot(json, topLevelFields), - ).copyWith( - status: MessageSendingStatus.sent, - ); + factory Message.fromJson(Map 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? extraData, - MessageSendingStatus? status, + @Deprecated('Use `state` instead') MessageSendingStatus? status, + MessageState? state, Map? 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, ]; } diff --git a/packages/stream_chat/lib/src/core/models/message_state.dart b/packages/stream_chat/lib/src/core/models/message_state.dart new file mode 100644 index 00000000..64292451 --- /dev/null +++ b/packages/stream_chat/lib/src/core/models/message_state.dart @@ -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 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 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 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 json) => + _$FailedStateFromJson(json); +} diff --git a/packages/stream_chat/lib/src/core/models/message_state.freezed.dart b/packages/stream_chat/lib/src/core/models/message_state.freezed.dart new file mode 100644 index 00000000..5096839d --- /dev/null +++ b/packages/stream_chat/lib/src/core/models/message_state.freezed.dart @@ -0,0 +1,2221 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'message_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +MessageState _$MessageStateFromJson(Map json) { + switch (json['runtimeType']) { + case 'initial': + return MessageInitial.fromJson(json); + case 'outgoing': + return MessageOutgoing.fromJson(json); + case 'completed': + return MessageCompleted.fromJson(json); + case 'failed': + return MessageFailed.fromJson(json); + + default: + throw CheckedFromJsonException(json, 'runtimeType', 'MessageState', + 'Invalid union type "${json['runtimeType']}"!'); + } +} + +/// @nodoc +mixin _$MessageState { + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function(OutgoingState state) outgoing, + required TResult Function(CompletedState state) completed, + required TResult Function(FailedState state, Object? reason) failed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function(OutgoingState state)? outgoing, + TResult? Function(CompletedState state)? completed, + TResult? Function(FailedState state, Object? reason)? failed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function(OutgoingState state)? outgoing, + TResult Function(CompletedState state)? completed, + TResult Function(FailedState state, Object? reason)? failed, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(MessageInitial value) initial, + required TResult Function(MessageOutgoing value) outgoing, + required TResult Function(MessageCompleted value) completed, + required TResult Function(MessageFailed value) failed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(MessageInitial value)? initial, + TResult? Function(MessageOutgoing value)? outgoing, + TResult? Function(MessageCompleted value)? completed, + TResult? Function(MessageFailed value)? failed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(MessageInitial value)? initial, + TResult Function(MessageOutgoing value)? outgoing, + TResult Function(MessageCompleted value)? completed, + TResult Function(MessageFailed value)? failed, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + Map toJson() => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $MessageStateCopyWith<$Res> { + factory $MessageStateCopyWith( + MessageState value, $Res Function(MessageState) then) = + _$MessageStateCopyWithImpl<$Res, MessageState>; +} + +/// @nodoc +class _$MessageStateCopyWithImpl<$Res, $Val extends MessageState> + implements $MessageStateCopyWith<$Res> { + _$MessageStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$MessageInitialCopyWith<$Res> { + factory _$$MessageInitialCopyWith( + _$MessageInitial value, $Res Function(_$MessageInitial) then) = + __$$MessageInitialCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$MessageInitialCopyWithImpl<$Res> + extends _$MessageStateCopyWithImpl<$Res, _$MessageInitial> + implements _$$MessageInitialCopyWith<$Res> { + __$$MessageInitialCopyWithImpl( + _$MessageInitial _value, $Res Function(_$MessageInitial) _then) + : super(_value, _then); +} + +/// @nodoc +@JsonSerializable() +class _$MessageInitial implements MessageInitial { + const _$MessageInitial({final String? $type}) : $type = $type ?? 'initial'; + + factory _$MessageInitial.fromJson(Map json) => + _$$MessageInitialFromJson(json); + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'MessageState.initial()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$MessageInitial); + } + + @JsonKey(ignore: true) + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function(OutgoingState state) outgoing, + required TResult Function(CompletedState state) completed, + required TResult Function(FailedState state, Object? reason) failed, + }) { + return initial(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function(OutgoingState state)? outgoing, + TResult? Function(CompletedState state)? completed, + TResult? Function(FailedState state, Object? reason)? failed, + }) { + return initial?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function(OutgoingState state)? outgoing, + TResult Function(CompletedState state)? completed, + TResult Function(FailedState state, Object? reason)? failed, + required TResult orElse(), + }) { + if (initial != null) { + return initial(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(MessageInitial value) initial, + required TResult Function(MessageOutgoing value) outgoing, + required TResult Function(MessageCompleted value) completed, + required TResult Function(MessageFailed value) failed, + }) { + return initial(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(MessageInitial value)? initial, + TResult? Function(MessageOutgoing value)? outgoing, + TResult? Function(MessageCompleted value)? completed, + TResult? Function(MessageFailed value)? failed, + }) { + return initial?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(MessageInitial value)? initial, + TResult Function(MessageOutgoing value)? outgoing, + TResult Function(MessageCompleted value)? completed, + TResult Function(MessageFailed value)? failed, + required TResult orElse(), + }) { + if (initial != null) { + return initial(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$MessageInitialToJson( + this, + ); + } +} + +abstract class MessageInitial implements MessageState { + const factory MessageInitial() = _$MessageInitial; + + factory MessageInitial.fromJson(Map json) = + _$MessageInitial.fromJson; +} + +/// @nodoc +abstract class _$$MessageOutgoingCopyWith<$Res> { + factory _$$MessageOutgoingCopyWith( + _$MessageOutgoing value, $Res Function(_$MessageOutgoing) then) = + __$$MessageOutgoingCopyWithImpl<$Res>; + @useResult + $Res call({OutgoingState state}); + + $OutgoingStateCopyWith<$Res> get state; +} + +/// @nodoc +class __$$MessageOutgoingCopyWithImpl<$Res> + extends _$MessageStateCopyWithImpl<$Res, _$MessageOutgoing> + implements _$$MessageOutgoingCopyWith<$Res> { + __$$MessageOutgoingCopyWithImpl( + _$MessageOutgoing _value, $Res Function(_$MessageOutgoing) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? state = null, + }) { + return _then(_$MessageOutgoing( + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as OutgoingState, + )); + } + + @override + @pragma('vm:prefer-inline') + $OutgoingStateCopyWith<$Res> get state { + return $OutgoingStateCopyWith<$Res>(_value.state, (value) { + return _then(_value.copyWith(state: value)); + }); + } +} + +/// @nodoc +@JsonSerializable() +class _$MessageOutgoing implements MessageOutgoing { + const _$MessageOutgoing({required this.state, final String? $type}) + : $type = $type ?? 'outgoing'; + + factory _$MessageOutgoing.fromJson(Map json) => + _$$MessageOutgoingFromJson(json); + + @override + final OutgoingState state; + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'MessageState.outgoing(state: $state)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$MessageOutgoing && + (identical(other.state, state) || other.state == state)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, state); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$MessageOutgoingCopyWith<_$MessageOutgoing> get copyWith => + __$$MessageOutgoingCopyWithImpl<_$MessageOutgoing>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function(OutgoingState state) outgoing, + required TResult Function(CompletedState state) completed, + required TResult Function(FailedState state, Object? reason) failed, + }) { + return outgoing(state); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function(OutgoingState state)? outgoing, + TResult? Function(CompletedState state)? completed, + TResult? Function(FailedState state, Object? reason)? failed, + }) { + return outgoing?.call(state); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function(OutgoingState state)? outgoing, + TResult Function(CompletedState state)? completed, + TResult Function(FailedState state, Object? reason)? failed, + required TResult orElse(), + }) { + if (outgoing != null) { + return outgoing(state); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(MessageInitial value) initial, + required TResult Function(MessageOutgoing value) outgoing, + required TResult Function(MessageCompleted value) completed, + required TResult Function(MessageFailed value) failed, + }) { + return outgoing(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(MessageInitial value)? initial, + TResult? Function(MessageOutgoing value)? outgoing, + TResult? Function(MessageCompleted value)? completed, + TResult? Function(MessageFailed value)? failed, + }) { + return outgoing?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(MessageInitial value)? initial, + TResult Function(MessageOutgoing value)? outgoing, + TResult Function(MessageCompleted value)? completed, + TResult Function(MessageFailed value)? failed, + required TResult orElse(), + }) { + if (outgoing != null) { + return outgoing(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$MessageOutgoingToJson( + this, + ); + } +} + +abstract class MessageOutgoing implements MessageState { + const factory MessageOutgoing({required final OutgoingState state}) = + _$MessageOutgoing; + + factory MessageOutgoing.fromJson(Map json) = + _$MessageOutgoing.fromJson; + + OutgoingState get state; + @JsonKey(ignore: true) + _$$MessageOutgoingCopyWith<_$MessageOutgoing> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$MessageCompletedCopyWith<$Res> { + factory _$$MessageCompletedCopyWith( + _$MessageCompleted value, $Res Function(_$MessageCompleted) then) = + __$$MessageCompletedCopyWithImpl<$Res>; + @useResult + $Res call({CompletedState state}); + + $CompletedStateCopyWith<$Res> get state; +} + +/// @nodoc +class __$$MessageCompletedCopyWithImpl<$Res> + extends _$MessageStateCopyWithImpl<$Res, _$MessageCompleted> + implements _$$MessageCompletedCopyWith<$Res> { + __$$MessageCompletedCopyWithImpl( + _$MessageCompleted _value, $Res Function(_$MessageCompleted) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? state = null, + }) { + return _then(_$MessageCompleted( + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as CompletedState, + )); + } + + @override + @pragma('vm:prefer-inline') + $CompletedStateCopyWith<$Res> get state { + return $CompletedStateCopyWith<$Res>(_value.state, (value) { + return _then(_value.copyWith(state: value)); + }); + } +} + +/// @nodoc +@JsonSerializable() +class _$MessageCompleted implements MessageCompleted { + const _$MessageCompleted({required this.state, final String? $type}) + : $type = $type ?? 'completed'; + + factory _$MessageCompleted.fromJson(Map json) => + _$$MessageCompletedFromJson(json); + + @override + final CompletedState state; + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'MessageState.completed(state: $state)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$MessageCompleted && + (identical(other.state, state) || other.state == state)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, state); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$MessageCompletedCopyWith<_$MessageCompleted> get copyWith => + __$$MessageCompletedCopyWithImpl<_$MessageCompleted>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function(OutgoingState state) outgoing, + required TResult Function(CompletedState state) completed, + required TResult Function(FailedState state, Object? reason) failed, + }) { + return completed(state); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function(OutgoingState state)? outgoing, + TResult? Function(CompletedState state)? completed, + TResult? Function(FailedState state, Object? reason)? failed, + }) { + return completed?.call(state); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function(OutgoingState state)? outgoing, + TResult Function(CompletedState state)? completed, + TResult Function(FailedState state, Object? reason)? failed, + required TResult orElse(), + }) { + if (completed != null) { + return completed(state); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(MessageInitial value) initial, + required TResult Function(MessageOutgoing value) outgoing, + required TResult Function(MessageCompleted value) completed, + required TResult Function(MessageFailed value) failed, + }) { + return completed(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(MessageInitial value)? initial, + TResult? Function(MessageOutgoing value)? outgoing, + TResult? Function(MessageCompleted value)? completed, + TResult? Function(MessageFailed value)? failed, + }) { + return completed?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(MessageInitial value)? initial, + TResult Function(MessageOutgoing value)? outgoing, + TResult Function(MessageCompleted value)? completed, + TResult Function(MessageFailed value)? failed, + required TResult orElse(), + }) { + if (completed != null) { + return completed(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$MessageCompletedToJson( + this, + ); + } +} + +abstract class MessageCompleted implements MessageState { + const factory MessageCompleted({required final CompletedState state}) = + _$MessageCompleted; + + factory MessageCompleted.fromJson(Map json) = + _$MessageCompleted.fromJson; + + CompletedState get state; + @JsonKey(ignore: true) + _$$MessageCompletedCopyWith<_$MessageCompleted> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$MessageFailedCopyWith<$Res> { + factory _$$MessageFailedCopyWith( + _$MessageFailed value, $Res Function(_$MessageFailed) then) = + __$$MessageFailedCopyWithImpl<$Res>; + @useResult + $Res call({FailedState state, Object? reason}); + + $FailedStateCopyWith<$Res> get state; +} + +/// @nodoc +class __$$MessageFailedCopyWithImpl<$Res> + extends _$MessageStateCopyWithImpl<$Res, _$MessageFailed> + implements _$$MessageFailedCopyWith<$Res> { + __$$MessageFailedCopyWithImpl( + _$MessageFailed _value, $Res Function(_$MessageFailed) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? state = null, + Object? reason = freezed, + }) { + return _then(_$MessageFailed( + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as FailedState, + reason: freezed == reason ? _value.reason : reason, + )); + } + + @override + @pragma('vm:prefer-inline') + $FailedStateCopyWith<$Res> get state { + return $FailedStateCopyWith<$Res>(_value.state, (value) { + return _then(_value.copyWith(state: value)); + }); + } +} + +/// @nodoc +@JsonSerializable() +class _$MessageFailed implements MessageFailed { + const _$MessageFailed({required this.state, this.reason, final String? $type}) + : $type = $type ?? 'failed'; + + factory _$MessageFailed.fromJson(Map json) => + _$$MessageFailedFromJson(json); + + @override + final FailedState state; + @override + final Object? reason; + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'MessageState.failed(state: $state, reason: $reason)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$MessageFailed && + (identical(other.state, state) || other.state == state) && + const DeepCollectionEquality().equals(other.reason, reason)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash( + runtimeType, state, const DeepCollectionEquality().hash(reason)); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$MessageFailedCopyWith<_$MessageFailed> get copyWith => + __$$MessageFailedCopyWithImpl<_$MessageFailed>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() initial, + required TResult Function(OutgoingState state) outgoing, + required TResult Function(CompletedState state) completed, + required TResult Function(FailedState state, Object? reason) failed, + }) { + return failed(state, reason); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? initial, + TResult? Function(OutgoingState state)? outgoing, + TResult? Function(CompletedState state)? completed, + TResult? Function(FailedState state, Object? reason)? failed, + }) { + return failed?.call(state, reason); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? initial, + TResult Function(OutgoingState state)? outgoing, + TResult Function(CompletedState state)? completed, + TResult Function(FailedState state, Object? reason)? failed, + required TResult orElse(), + }) { + if (failed != null) { + return failed(state, reason); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(MessageInitial value) initial, + required TResult Function(MessageOutgoing value) outgoing, + required TResult Function(MessageCompleted value) completed, + required TResult Function(MessageFailed value) failed, + }) { + return failed(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(MessageInitial value)? initial, + TResult? Function(MessageOutgoing value)? outgoing, + TResult? Function(MessageCompleted value)? completed, + TResult? Function(MessageFailed value)? failed, + }) { + return failed?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(MessageInitial value)? initial, + TResult Function(MessageOutgoing value)? outgoing, + TResult Function(MessageCompleted value)? completed, + TResult Function(MessageFailed value)? failed, + required TResult orElse(), + }) { + if (failed != null) { + return failed(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$MessageFailedToJson( + this, + ); + } +} + +abstract class MessageFailed implements MessageState { + const factory MessageFailed( + {required final FailedState state, + final Object? reason}) = _$MessageFailed; + + factory MessageFailed.fromJson(Map json) = + _$MessageFailed.fromJson; + + FailedState get state; + Object? get reason; + @JsonKey(ignore: true) + _$$MessageFailedCopyWith<_$MessageFailed> get copyWith => + throw _privateConstructorUsedError; +} + +OutgoingState _$OutgoingStateFromJson(Map json) { + switch (json['runtimeType']) { + case 'sending': + return Sending.fromJson(json); + case 'updating': + return Updating.fromJson(json); + case 'deleting': + return Deleting.fromJson(json); + + default: + throw CheckedFromJsonException(json, 'runtimeType', 'OutgoingState', + 'Invalid union type "${json['runtimeType']}"!'); + } +} + +/// @nodoc +mixin _$OutgoingState { + @optionalTypeArgs + TResult when({ + required TResult Function() sending, + required TResult Function() updating, + required TResult Function(bool hard) deleting, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? sending, + TResult? Function()? updating, + TResult? Function(bool hard)? deleting, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? sending, + TResult Function()? updating, + TResult Function(bool hard)? deleting, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(Sending value) sending, + required TResult Function(Updating value) updating, + required TResult Function(Deleting value) deleting, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Sending value)? sending, + TResult? Function(Updating value)? updating, + TResult? Function(Deleting value)? deleting, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Sending value)? sending, + TResult Function(Updating value)? updating, + TResult Function(Deleting value)? deleting, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + Map toJson() => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $OutgoingStateCopyWith<$Res> { + factory $OutgoingStateCopyWith( + OutgoingState value, $Res Function(OutgoingState) then) = + _$OutgoingStateCopyWithImpl<$Res, OutgoingState>; +} + +/// @nodoc +class _$OutgoingStateCopyWithImpl<$Res, $Val extends OutgoingState> + implements $OutgoingStateCopyWith<$Res> { + _$OutgoingStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$SendingCopyWith<$Res> { + factory _$$SendingCopyWith(_$Sending value, $Res Function(_$Sending) then) = + __$$SendingCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$SendingCopyWithImpl<$Res> + extends _$OutgoingStateCopyWithImpl<$Res, _$Sending> + implements _$$SendingCopyWith<$Res> { + __$$SendingCopyWithImpl(_$Sending _value, $Res Function(_$Sending) _then) + : super(_value, _then); +} + +/// @nodoc +@JsonSerializable() +class _$Sending implements Sending { + const _$Sending({final String? $type}) : $type = $type ?? 'sending'; + + factory _$Sending.fromJson(Map json) => + _$$SendingFromJson(json); + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'OutgoingState.sending()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$Sending); + } + + @JsonKey(ignore: true) + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() sending, + required TResult Function() updating, + required TResult Function(bool hard) deleting, + }) { + return sending(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? sending, + TResult? Function()? updating, + TResult? Function(bool hard)? deleting, + }) { + return sending?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? sending, + TResult Function()? updating, + TResult Function(bool hard)? deleting, + required TResult orElse(), + }) { + if (sending != null) { + return sending(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Sending value) sending, + required TResult Function(Updating value) updating, + required TResult Function(Deleting value) deleting, + }) { + return sending(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Sending value)? sending, + TResult? Function(Updating value)? updating, + TResult? Function(Deleting value)? deleting, + }) { + return sending?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Sending value)? sending, + TResult Function(Updating value)? updating, + TResult Function(Deleting value)? deleting, + required TResult orElse(), + }) { + if (sending != null) { + return sending(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$SendingToJson( + this, + ); + } +} + +abstract class Sending implements OutgoingState { + const factory Sending() = _$Sending; + + factory Sending.fromJson(Map json) = _$Sending.fromJson; +} + +/// @nodoc +abstract class _$$UpdatingCopyWith<$Res> { + factory _$$UpdatingCopyWith( + _$Updating value, $Res Function(_$Updating) then) = + __$$UpdatingCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$UpdatingCopyWithImpl<$Res> + extends _$OutgoingStateCopyWithImpl<$Res, _$Updating> + implements _$$UpdatingCopyWith<$Res> { + __$$UpdatingCopyWithImpl(_$Updating _value, $Res Function(_$Updating) _then) + : super(_value, _then); +} + +/// @nodoc +@JsonSerializable() +class _$Updating implements Updating { + const _$Updating({final String? $type}) : $type = $type ?? 'updating'; + + factory _$Updating.fromJson(Map json) => + _$$UpdatingFromJson(json); + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'OutgoingState.updating()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$Updating); + } + + @JsonKey(ignore: true) + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() sending, + required TResult Function() updating, + required TResult Function(bool hard) deleting, + }) { + return updating(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? sending, + TResult? Function()? updating, + TResult? Function(bool hard)? deleting, + }) { + return updating?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? sending, + TResult Function()? updating, + TResult Function(bool hard)? deleting, + required TResult orElse(), + }) { + if (updating != null) { + return updating(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Sending value) sending, + required TResult Function(Updating value) updating, + required TResult Function(Deleting value) deleting, + }) { + return updating(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Sending value)? sending, + TResult? Function(Updating value)? updating, + TResult? Function(Deleting value)? deleting, + }) { + return updating?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Sending value)? sending, + TResult Function(Updating value)? updating, + TResult Function(Deleting value)? deleting, + required TResult orElse(), + }) { + if (updating != null) { + return updating(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$UpdatingToJson( + this, + ); + } +} + +abstract class Updating implements OutgoingState { + const factory Updating() = _$Updating; + + factory Updating.fromJson(Map json) = _$Updating.fromJson; +} + +/// @nodoc +abstract class _$$DeletingCopyWith<$Res> { + factory _$$DeletingCopyWith( + _$Deleting value, $Res Function(_$Deleting) then) = + __$$DeletingCopyWithImpl<$Res>; + @useResult + $Res call({bool hard}); +} + +/// @nodoc +class __$$DeletingCopyWithImpl<$Res> + extends _$OutgoingStateCopyWithImpl<$Res, _$Deleting> + implements _$$DeletingCopyWith<$Res> { + __$$DeletingCopyWithImpl(_$Deleting _value, $Res Function(_$Deleting) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? hard = null, + }) { + return _then(_$Deleting( + hard: null == hard + ? _value.hard + : hard // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$Deleting implements Deleting { + const _$Deleting({this.hard = false, final String? $type}) + : $type = $type ?? 'deleting'; + + factory _$Deleting.fromJson(Map json) => + _$$DeletingFromJson(json); + + @override + @JsonKey() + final bool hard; + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'OutgoingState.deleting(hard: $hard)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$Deleting && + (identical(other.hard, hard) || other.hard == hard)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, hard); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$DeletingCopyWith<_$Deleting> get copyWith => + __$$DeletingCopyWithImpl<_$Deleting>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() sending, + required TResult Function() updating, + required TResult Function(bool hard) deleting, + }) { + return deleting(hard); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? sending, + TResult? Function()? updating, + TResult? Function(bool hard)? deleting, + }) { + return deleting?.call(hard); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? sending, + TResult Function()? updating, + TResult Function(bool hard)? deleting, + required TResult orElse(), + }) { + if (deleting != null) { + return deleting(hard); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Sending value) sending, + required TResult Function(Updating value) updating, + required TResult Function(Deleting value) deleting, + }) { + return deleting(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Sending value)? sending, + TResult? Function(Updating value)? updating, + TResult? Function(Deleting value)? deleting, + }) { + return deleting?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Sending value)? sending, + TResult Function(Updating value)? updating, + TResult Function(Deleting value)? deleting, + required TResult orElse(), + }) { + if (deleting != null) { + return deleting(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$DeletingToJson( + this, + ); + } +} + +abstract class Deleting implements OutgoingState { + const factory Deleting({final bool hard}) = _$Deleting; + + factory Deleting.fromJson(Map json) = _$Deleting.fromJson; + + bool get hard; + @JsonKey(ignore: true) + _$$DeletingCopyWith<_$Deleting> get copyWith => + throw _privateConstructorUsedError; +} + +CompletedState _$CompletedStateFromJson(Map json) { + switch (json['runtimeType']) { + case 'sent': + return Sent.fromJson(json); + case 'updated': + return Updated.fromJson(json); + case 'deleted': + return Deleted.fromJson(json); + + default: + throw CheckedFromJsonException(json, 'runtimeType', 'CompletedState', + 'Invalid union type "${json['runtimeType']}"!'); + } +} + +/// @nodoc +mixin _$CompletedState { + @optionalTypeArgs + TResult when({ + required TResult Function() sent, + required TResult Function() updated, + required TResult Function(bool hard) deleted, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? sent, + TResult? Function()? updated, + TResult? Function(bool hard)? deleted, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? sent, + TResult Function()? updated, + TResult Function(bool hard)? deleted, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(Sent value) sent, + required TResult Function(Updated value) updated, + required TResult Function(Deleted value) deleted, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Sent value)? sent, + TResult? Function(Updated value)? updated, + TResult? Function(Deleted value)? deleted, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Sent value)? sent, + TResult Function(Updated value)? updated, + TResult Function(Deleted value)? deleted, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + Map toJson() => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $CompletedStateCopyWith<$Res> { + factory $CompletedStateCopyWith( + CompletedState value, $Res Function(CompletedState) then) = + _$CompletedStateCopyWithImpl<$Res, CompletedState>; +} + +/// @nodoc +class _$CompletedStateCopyWithImpl<$Res, $Val extends CompletedState> + implements $CompletedStateCopyWith<$Res> { + _$CompletedStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$SentCopyWith<$Res> { + factory _$$SentCopyWith(_$Sent value, $Res Function(_$Sent) then) = + __$$SentCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$SentCopyWithImpl<$Res> + extends _$CompletedStateCopyWithImpl<$Res, _$Sent> + implements _$$SentCopyWith<$Res> { + __$$SentCopyWithImpl(_$Sent _value, $Res Function(_$Sent) _then) + : super(_value, _then); +} + +/// @nodoc +@JsonSerializable() +class _$Sent implements Sent { + const _$Sent({final String? $type}) : $type = $type ?? 'sent'; + + factory _$Sent.fromJson(Map json) => _$$SentFromJson(json); + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'CompletedState.sent()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$Sent); + } + + @JsonKey(ignore: true) + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() sent, + required TResult Function() updated, + required TResult Function(bool hard) deleted, + }) { + return sent(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? sent, + TResult? Function()? updated, + TResult? Function(bool hard)? deleted, + }) { + return sent?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? sent, + TResult Function()? updated, + TResult Function(bool hard)? deleted, + required TResult orElse(), + }) { + if (sent != null) { + return sent(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Sent value) sent, + required TResult Function(Updated value) updated, + required TResult Function(Deleted value) deleted, + }) { + return sent(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Sent value)? sent, + TResult? Function(Updated value)? updated, + TResult? Function(Deleted value)? deleted, + }) { + return sent?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Sent value)? sent, + TResult Function(Updated value)? updated, + TResult Function(Deleted value)? deleted, + required TResult orElse(), + }) { + if (sent != null) { + return sent(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$SentToJson( + this, + ); + } +} + +abstract class Sent implements CompletedState { + const factory Sent() = _$Sent; + + factory Sent.fromJson(Map json) = _$Sent.fromJson; +} + +/// @nodoc +abstract class _$$UpdatedCopyWith<$Res> { + factory _$$UpdatedCopyWith(_$Updated value, $Res Function(_$Updated) then) = + __$$UpdatedCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$UpdatedCopyWithImpl<$Res> + extends _$CompletedStateCopyWithImpl<$Res, _$Updated> + implements _$$UpdatedCopyWith<$Res> { + __$$UpdatedCopyWithImpl(_$Updated _value, $Res Function(_$Updated) _then) + : super(_value, _then); +} + +/// @nodoc +@JsonSerializable() +class _$Updated implements Updated { + const _$Updated({final String? $type}) : $type = $type ?? 'updated'; + + factory _$Updated.fromJson(Map json) => + _$$UpdatedFromJson(json); + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'CompletedState.updated()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$Updated); + } + + @JsonKey(ignore: true) + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() sent, + required TResult Function() updated, + required TResult Function(bool hard) deleted, + }) { + return updated(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? sent, + TResult? Function()? updated, + TResult? Function(bool hard)? deleted, + }) { + return updated?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? sent, + TResult Function()? updated, + TResult Function(bool hard)? deleted, + required TResult orElse(), + }) { + if (updated != null) { + return updated(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Sent value) sent, + required TResult Function(Updated value) updated, + required TResult Function(Deleted value) deleted, + }) { + return updated(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Sent value)? sent, + TResult? Function(Updated value)? updated, + TResult? Function(Deleted value)? deleted, + }) { + return updated?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Sent value)? sent, + TResult Function(Updated value)? updated, + TResult Function(Deleted value)? deleted, + required TResult orElse(), + }) { + if (updated != null) { + return updated(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$UpdatedToJson( + this, + ); + } +} + +abstract class Updated implements CompletedState { + const factory Updated() = _$Updated; + + factory Updated.fromJson(Map json) = _$Updated.fromJson; +} + +/// @nodoc +abstract class _$$DeletedCopyWith<$Res> { + factory _$$DeletedCopyWith(_$Deleted value, $Res Function(_$Deleted) then) = + __$$DeletedCopyWithImpl<$Res>; + @useResult + $Res call({bool hard}); +} + +/// @nodoc +class __$$DeletedCopyWithImpl<$Res> + extends _$CompletedStateCopyWithImpl<$Res, _$Deleted> + implements _$$DeletedCopyWith<$Res> { + __$$DeletedCopyWithImpl(_$Deleted _value, $Res Function(_$Deleted) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? hard = null, + }) { + return _then(_$Deleted( + hard: null == hard + ? _value.hard + : hard // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$Deleted implements Deleted { + const _$Deleted({this.hard = false, final String? $type}) + : $type = $type ?? 'deleted'; + + factory _$Deleted.fromJson(Map json) => + _$$DeletedFromJson(json); + + @override + @JsonKey() + final bool hard; + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'CompletedState.deleted(hard: $hard)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$Deleted && + (identical(other.hard, hard) || other.hard == hard)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, hard); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$DeletedCopyWith<_$Deleted> get copyWith => + __$$DeletedCopyWithImpl<_$Deleted>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() sent, + required TResult Function() updated, + required TResult Function(bool hard) deleted, + }) { + return deleted(hard); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? sent, + TResult? Function()? updated, + TResult? Function(bool hard)? deleted, + }) { + return deleted?.call(hard); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? sent, + TResult Function()? updated, + TResult Function(bool hard)? deleted, + required TResult orElse(), + }) { + if (deleted != null) { + return deleted(hard); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Sent value) sent, + required TResult Function(Updated value) updated, + required TResult Function(Deleted value) deleted, + }) { + return deleted(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(Sent value)? sent, + TResult? Function(Updated value)? updated, + TResult? Function(Deleted value)? deleted, + }) { + return deleted?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Sent value)? sent, + TResult Function(Updated value)? updated, + TResult Function(Deleted value)? deleted, + required TResult orElse(), + }) { + if (deleted != null) { + return deleted(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$DeletedToJson( + this, + ); + } +} + +abstract class Deleted implements CompletedState { + const factory Deleted({final bool hard}) = _$Deleted; + + factory Deleted.fromJson(Map json) = _$Deleted.fromJson; + + bool get hard; + @JsonKey(ignore: true) + _$$DeletedCopyWith<_$Deleted> get copyWith => + throw _privateConstructorUsedError; +} + +FailedState _$FailedStateFromJson(Map json) { + switch (json['runtimeType']) { + case 'sendingFailed': + return SendingFailed.fromJson(json); + case 'updatingFailed': + return UpdatingFailed.fromJson(json); + case 'deletingFailed': + return DeletingFailed.fromJson(json); + + default: + throw CheckedFromJsonException(json, 'runtimeType', 'FailedState', + 'Invalid union type "${json['runtimeType']}"!'); + } +} + +/// @nodoc +mixin _$FailedState { + @optionalTypeArgs + TResult when({ + required TResult Function() sendingFailed, + required TResult Function() updatingFailed, + required TResult Function(bool hard) deletingFailed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? sendingFailed, + TResult? Function()? updatingFailed, + TResult? Function(bool hard)? deletingFailed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? sendingFailed, + TResult Function()? updatingFailed, + TResult Function(bool hard)? deletingFailed, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(SendingFailed value) sendingFailed, + required TResult Function(UpdatingFailed value) updatingFailed, + required TResult Function(DeletingFailed value) deletingFailed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(SendingFailed value)? sendingFailed, + TResult? Function(UpdatingFailed value)? updatingFailed, + TResult? Function(DeletingFailed value)? deletingFailed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(SendingFailed value)? sendingFailed, + TResult Function(UpdatingFailed value)? updatingFailed, + TResult Function(DeletingFailed value)? deletingFailed, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + Map toJson() => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $FailedStateCopyWith<$Res> { + factory $FailedStateCopyWith( + FailedState value, $Res Function(FailedState) then) = + _$FailedStateCopyWithImpl<$Res, FailedState>; +} + +/// @nodoc +class _$FailedStateCopyWithImpl<$Res, $Val extends FailedState> + implements $FailedStateCopyWith<$Res> { + _$FailedStateCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; +} + +/// @nodoc +abstract class _$$SendingFailedCopyWith<$Res> { + factory _$$SendingFailedCopyWith( + _$SendingFailed value, $Res Function(_$SendingFailed) then) = + __$$SendingFailedCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$SendingFailedCopyWithImpl<$Res> + extends _$FailedStateCopyWithImpl<$Res, _$SendingFailed> + implements _$$SendingFailedCopyWith<$Res> { + __$$SendingFailedCopyWithImpl( + _$SendingFailed _value, $Res Function(_$SendingFailed) _then) + : super(_value, _then); +} + +/// @nodoc +@JsonSerializable() +class _$SendingFailed implements SendingFailed { + const _$SendingFailed({final String? $type}) + : $type = $type ?? 'sendingFailed'; + + factory _$SendingFailed.fromJson(Map json) => + _$$SendingFailedFromJson(json); + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'FailedState.sendingFailed()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$SendingFailed); + } + + @JsonKey(ignore: true) + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() sendingFailed, + required TResult Function() updatingFailed, + required TResult Function(bool hard) deletingFailed, + }) { + return sendingFailed(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? sendingFailed, + TResult? Function()? updatingFailed, + TResult? Function(bool hard)? deletingFailed, + }) { + return sendingFailed?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? sendingFailed, + TResult Function()? updatingFailed, + TResult Function(bool hard)? deletingFailed, + required TResult orElse(), + }) { + if (sendingFailed != null) { + return sendingFailed(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(SendingFailed value) sendingFailed, + required TResult Function(UpdatingFailed value) updatingFailed, + required TResult Function(DeletingFailed value) deletingFailed, + }) { + return sendingFailed(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(SendingFailed value)? sendingFailed, + TResult? Function(UpdatingFailed value)? updatingFailed, + TResult? Function(DeletingFailed value)? deletingFailed, + }) { + return sendingFailed?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(SendingFailed value)? sendingFailed, + TResult Function(UpdatingFailed value)? updatingFailed, + TResult Function(DeletingFailed value)? deletingFailed, + required TResult orElse(), + }) { + if (sendingFailed != null) { + return sendingFailed(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$SendingFailedToJson( + this, + ); + } +} + +abstract class SendingFailed implements FailedState { + const factory SendingFailed() = _$SendingFailed; + + factory SendingFailed.fromJson(Map json) = + _$SendingFailed.fromJson; +} + +/// @nodoc +abstract class _$$UpdatingFailedCopyWith<$Res> { + factory _$$UpdatingFailedCopyWith( + _$UpdatingFailed value, $Res Function(_$UpdatingFailed) then) = + __$$UpdatingFailedCopyWithImpl<$Res>; +} + +/// @nodoc +class __$$UpdatingFailedCopyWithImpl<$Res> + extends _$FailedStateCopyWithImpl<$Res, _$UpdatingFailed> + implements _$$UpdatingFailedCopyWith<$Res> { + __$$UpdatingFailedCopyWithImpl( + _$UpdatingFailed _value, $Res Function(_$UpdatingFailed) _then) + : super(_value, _then); +} + +/// @nodoc +@JsonSerializable() +class _$UpdatingFailed implements UpdatingFailed { + const _$UpdatingFailed({final String? $type}) + : $type = $type ?? 'updatingFailed'; + + factory _$UpdatingFailed.fromJson(Map json) => + _$$UpdatingFailedFromJson(json); + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'FailedState.updatingFailed()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && other is _$UpdatingFailed); + } + + @JsonKey(ignore: true) + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() sendingFailed, + required TResult Function() updatingFailed, + required TResult Function(bool hard) deletingFailed, + }) { + return updatingFailed(); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? sendingFailed, + TResult? Function()? updatingFailed, + TResult? Function(bool hard)? deletingFailed, + }) { + return updatingFailed?.call(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? sendingFailed, + TResult Function()? updatingFailed, + TResult Function(bool hard)? deletingFailed, + required TResult orElse(), + }) { + if (updatingFailed != null) { + return updatingFailed(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(SendingFailed value) sendingFailed, + required TResult Function(UpdatingFailed value) updatingFailed, + required TResult Function(DeletingFailed value) deletingFailed, + }) { + return updatingFailed(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(SendingFailed value)? sendingFailed, + TResult? Function(UpdatingFailed value)? updatingFailed, + TResult? Function(DeletingFailed value)? deletingFailed, + }) { + return updatingFailed?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(SendingFailed value)? sendingFailed, + TResult Function(UpdatingFailed value)? updatingFailed, + TResult Function(DeletingFailed value)? deletingFailed, + required TResult orElse(), + }) { + if (updatingFailed != null) { + return updatingFailed(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$UpdatingFailedToJson( + this, + ); + } +} + +abstract class UpdatingFailed implements FailedState { + const factory UpdatingFailed() = _$UpdatingFailed; + + factory UpdatingFailed.fromJson(Map json) = + _$UpdatingFailed.fromJson; +} + +/// @nodoc +abstract class _$$DeletingFailedCopyWith<$Res> { + factory _$$DeletingFailedCopyWith( + _$DeletingFailed value, $Res Function(_$DeletingFailed) then) = + __$$DeletingFailedCopyWithImpl<$Res>; + @useResult + $Res call({bool hard}); +} + +/// @nodoc +class __$$DeletingFailedCopyWithImpl<$Res> + extends _$FailedStateCopyWithImpl<$Res, _$DeletingFailed> + implements _$$DeletingFailedCopyWith<$Res> { + __$$DeletingFailedCopyWithImpl( + _$DeletingFailed _value, $Res Function(_$DeletingFailed) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? hard = null, + }) { + return _then(_$DeletingFailed( + hard: null == hard + ? _value.hard + : hard // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$DeletingFailed implements DeletingFailed { + const _$DeletingFailed({this.hard = false, final String? $type}) + : $type = $type ?? 'deletingFailed'; + + factory _$DeletingFailed.fromJson(Map json) => + _$$DeletingFailedFromJson(json); + + @override + @JsonKey() + final bool hard; + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'FailedState.deletingFailed(hard: $hard)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$DeletingFailed && + (identical(other.hard, hard) || other.hard == hard)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, hard); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$DeletingFailedCopyWith<_$DeletingFailed> get copyWith => + __$$DeletingFailedCopyWithImpl<_$DeletingFailed>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() sendingFailed, + required TResult Function() updatingFailed, + required TResult Function(bool hard) deletingFailed, + }) { + return deletingFailed(hard); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function()? sendingFailed, + TResult? Function()? updatingFailed, + TResult? Function(bool hard)? deletingFailed, + }) { + return deletingFailed?.call(hard); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? sendingFailed, + TResult Function()? updatingFailed, + TResult Function(bool hard)? deletingFailed, + required TResult orElse(), + }) { + if (deletingFailed != null) { + return deletingFailed(hard); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(SendingFailed value) sendingFailed, + required TResult Function(UpdatingFailed value) updatingFailed, + required TResult Function(DeletingFailed value) deletingFailed, + }) { + return deletingFailed(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(SendingFailed value)? sendingFailed, + TResult? Function(UpdatingFailed value)? updatingFailed, + TResult? Function(DeletingFailed value)? deletingFailed, + }) { + return deletingFailed?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(SendingFailed value)? sendingFailed, + TResult Function(UpdatingFailed value)? updatingFailed, + TResult Function(DeletingFailed value)? deletingFailed, + required TResult orElse(), + }) { + if (deletingFailed != null) { + return deletingFailed(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$DeletingFailedToJson( + this, + ); + } +} + +abstract class DeletingFailed implements FailedState { + const factory DeletingFailed({final bool hard}) = _$DeletingFailed; + + factory DeletingFailed.fromJson(Map json) = + _$DeletingFailed.fromJson; + + bool get hard; + @JsonKey(ignore: true) + _$$DeletingFailedCopyWith<_$DeletingFailed> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/packages/stream_chat/lib/src/core/models/message_state.g.dart b/packages/stream_chat/lib/src/core/models/message_state.g.dart new file mode 100644 index 00000000..708222bf --- /dev/null +++ b/packages/stream_chat/lib/src/core/models/message_state.g.dart @@ -0,0 +1,141 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'message_state.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$MessageInitial _$$MessageInitialFromJson(Map json) => + _$MessageInitial( + $type: json['runtimeType'] as String?, + ); + +Map _$$MessageInitialToJson(_$MessageInitial instance) => + { + 'runtimeType': instance.$type, + }; + +_$MessageOutgoing _$$MessageOutgoingFromJson(Map json) => + _$MessageOutgoing( + state: OutgoingState.fromJson(json['state'] as Map), + $type: json['runtimeType'] as String?, + ); + +Map _$$MessageOutgoingToJson(_$MessageOutgoing instance) => + { + 'state': instance.state.toJson(), + 'runtimeType': instance.$type, + }; + +_$MessageCompleted _$$MessageCompletedFromJson(Map json) => + _$MessageCompleted( + state: CompletedState.fromJson(json['state'] as Map), + $type: json['runtimeType'] as String?, + ); + +Map _$$MessageCompletedToJson(_$MessageCompleted instance) => + { + 'state': instance.state.toJson(), + 'runtimeType': instance.$type, + }; + +_$MessageFailed _$$MessageFailedFromJson(Map json) => + _$MessageFailed( + state: FailedState.fromJson(json['state'] as Map), + reason: json['reason'], + $type: json['runtimeType'] as String?, + ); + +Map _$$MessageFailedToJson(_$MessageFailed instance) => + { + 'state': instance.state.toJson(), + 'reason': instance.reason, + 'runtimeType': instance.$type, + }; + +_$Sending _$$SendingFromJson(Map json) => _$Sending( + $type: json['runtimeType'] as String?, + ); + +Map _$$SendingToJson(_$Sending instance) => { + 'runtimeType': instance.$type, + }; + +_$Updating _$$UpdatingFromJson(Map json) => _$Updating( + $type: json['runtimeType'] as String?, + ); + +Map _$$UpdatingToJson(_$Updating instance) => + { + 'runtimeType': instance.$type, + }; + +_$Deleting _$$DeletingFromJson(Map json) => _$Deleting( + hard: json['hard'] as bool? ?? false, + $type: json['runtimeType'] as String?, + ); + +Map _$$DeletingToJson(_$Deleting instance) => + { + 'hard': instance.hard, + 'runtimeType': instance.$type, + }; + +_$Sent _$$SentFromJson(Map json) => _$Sent( + $type: json['runtimeType'] as String?, + ); + +Map _$$SentToJson(_$Sent instance) => { + 'runtimeType': instance.$type, + }; + +_$Updated _$$UpdatedFromJson(Map json) => _$Updated( + $type: json['runtimeType'] as String?, + ); + +Map _$$UpdatedToJson(_$Updated instance) => { + 'runtimeType': instance.$type, + }; + +_$Deleted _$$DeletedFromJson(Map json) => _$Deleted( + hard: json['hard'] as bool? ?? false, + $type: json['runtimeType'] as String?, + ); + +Map _$$DeletedToJson(_$Deleted instance) => { + 'hard': instance.hard, + 'runtimeType': instance.$type, + }; + +_$SendingFailed _$$SendingFailedFromJson(Map json) => + _$SendingFailed( + $type: json['runtimeType'] as String?, + ); + +Map _$$SendingFailedToJson(_$SendingFailed instance) => + { + 'runtimeType': instance.$type, + }; + +_$UpdatingFailed _$$UpdatingFailedFromJson(Map json) => + _$UpdatingFailed( + $type: json['runtimeType'] as String?, + ); + +Map _$$UpdatingFailedToJson(_$UpdatingFailed instance) => + { + 'runtimeType': instance.$type, + }; + +_$DeletingFailed _$$DeletingFailedFromJson(Map json) => + _$DeletingFailed( + hard: json['hard'] as bool? ?? false, + $type: json['runtimeType'] as String?, + ); + +Map _$$DeletingFailedToJson(_$DeletingFailed instance) => + { + 'hard': instance.hard, + 'runtimeType': instance.$type, + }; diff --git a/packages/stream_chat/lib/stream_chat.dart b/packages/stream_chat/lib/stream_chat.dart index 2dbf1afd..71a217dc 100644 --- a/packages/stream_chat/lib/stream_chat.dart +++ b/packages/stream_chat/lib/stream_chat.dart @@ -38,6 +38,7 @@ export 'src/core/models/event.dart'; export 'src/core/models/filter.dart' show Filter; export 'src/core/models/member.dart'; export 'src/core/models/message.dart'; +export 'src/core/models/message_state.dart'; export 'src/core/models/mute.dart'; export 'src/core/models/own_user.dart'; export 'src/core/models/reaction.dart';