Skip to content

Commit 162d42b

Browse files
authored
Merge pull request #1674 from GetStream/release/6.7.0
2 parents 3b957ee + a920b58 commit 162d42b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+3701
-681
lines changed

packages/stream_chat/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 6.6.0
2+
3+
🔄 Changed
4+
5+
- Deprecated `Message.status` in favor of `Message.state`.
6+
- Deprecated `RetryPolicy.retryTimeout` in favor of `RetryPolicy.delayFactor`.
7+
18
## 6.5.0
29

310
🔄 Changed

packages/stream_chat/lib/src/client/channel.dart

Lines changed: 117 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ class Channel {
582582
// Eg. Updating the message while the previous call is in progress.
583583
_messageAttachmentsUploadCompleter
584584
.remove(message.id)
585-
?.completeError('Message Cancelled');
585+
?.completeError(const StreamChatError('Message cancelled'));
586586

587587
final quotedMessage = state!.messages.firstWhereOrNull(
588588
(m) => m.id == message.quotedMessageId,
@@ -592,7 +592,7 @@ class Channel {
592592
localCreatedAt: DateTime.now(),
593593
user: _client.state.currentUser,
594594
quotedMessage: quotedMessage,
595-
status: MessageSendingStatus.sending,
595+
state: MessageState.sending,
596596
attachments: message.attachments.map(
597597
(it) {
598598
if (it.uploadState.isSuccess) return it;
@@ -630,15 +630,24 @@ class Channel {
630630
),
631631
);
632632

633-
final sentMessage = response.message.syncWith(message);
633+
final sentMessage = response.message.syncWith(message).copyWith(
634+
// Update the message state to sent.
635+
state: MessageState.sent,
636+
);
634637

635638
state!.updateMessage(sentMessage);
636639
if (cooldown > 0) cooldownStartedAt = DateTime.now();
637640
return response;
638641
} catch (e) {
639642
if (e is StreamChatNetworkError && e.isRetriable) {
640-
state!._retryQueue.add([message]);
643+
state!._retryQueue.add([
644+
message.copyWith(
645+
// Update the message state to failed.
646+
state: MessageState.sendingFailed,
647+
),
648+
]);
641649
}
650+
642651
rethrow;
643652
}
644653
}
@@ -653,17 +662,18 @@ class Channel {
653662
Message message, {
654663
bool skipEnrichUrl = false,
655664
}) async {
665+
_checkInitialized();
656666
final originalMessage = message;
657667

658668
// Cancelling previous completer in case it's called again in the process
659669
// Eg. Updating the message while the previous call is in progress.
660670
_messageAttachmentsUploadCompleter
661671
.remove(message.id)
662-
?.completeError('Message Cancelled');
672+
?.completeError(const StreamChatError('Message cancelled'));
663673

664674
// ignore: parameter_assignments
665675
message = message.copyWith(
666-
status: MessageSendingStatus.updating,
676+
state: MessageState.updating,
667677
localUpdatedAt: DateTime.now(),
668678
attachments: message.attachments.map(
669679
(it) {
@@ -699,19 +709,30 @@ class Channel {
699709
),
700710
);
701711

702-
final updatedMessage = response.message
703-
.syncWith(message)
704-
.copyWith(ownReactions: message.ownReactions);
712+
final updateMessage = response.message.syncWith(message).copyWith(
713+
// Update the message state to updated.
714+
state: MessageState.updated,
715+
ownReactions: message.ownReactions,
716+
);
705717

706-
state?.updateMessage(updatedMessage);
718+
state?.updateMessage(updateMessage);
707719

708720
return response;
709721
} catch (e) {
710722
if (e is StreamChatNetworkError) {
711723
if (e.isRetriable) {
712-
state!._retryQueue.add([message]);
724+
state!._retryQueue.add([
725+
message.copyWith(
726+
// Update the message state to failed.
727+
state: MessageState.updatingFailed,
728+
),
729+
]);
713730
} else {
714-
state?.updateMessage(originalMessage);
731+
// Reset the message to original state if the update fails and is not
732+
// retriable.
733+
state?.updateMessage(originalMessage.copyWith(
734+
state: MessageState.updatingFailed,
735+
));
715736
}
716737
}
717738
rethrow;
@@ -729,6 +750,23 @@ class Channel {
729750
List<String>? unset,
730751
bool skipEnrichUrl = false,
731752
}) async {
753+
_checkInitialized();
754+
final originalMessage = message;
755+
756+
// Cancelling previous completer in case it's called again in the process
757+
// Eg. Updating the message while the previous call is in progress.
758+
_messageAttachmentsUploadCompleter
759+
.remove(message.id)
760+
?.completeError(const StreamChatError('Message cancelled'));
761+
762+
// ignore: parameter_assignments
763+
message = message.copyWith(
764+
state: MessageState.updating,
765+
localUpdatedAt: DateTime.now(),
766+
);
767+
768+
state?.updateMessage(message);
769+
732770
try {
733771
// Wait for the previous update call to finish. Otherwise, the order of
734772
// messages will not be maintained.
@@ -741,78 +779,120 @@ class Channel {
741779
),
742780
);
743781

744-
final updatedMessage = response.message
745-
.syncWith(message)
746-
.copyWith(ownReactions: message.ownReactions);
782+
final updatedMessage = response.message.syncWith(message).copyWith(
783+
// Update the message state to updated.
784+
state: MessageState.updated,
785+
ownReactions: message.ownReactions,
786+
);
747787

748788
state?.updateMessage(updatedMessage);
749789

750790
return response;
751791
} catch (e) {
752-
if (e is StreamChatNetworkError && e.isRetriable) {
753-
state!._retryQueue.add([message]);
792+
if (e is StreamChatNetworkError) {
793+
if (e.isRetriable) {
794+
state!._retryQueue.add([
795+
message.copyWith(
796+
// Update the message state to failed.
797+
state: MessageState.updatingFailed,
798+
),
799+
]);
800+
} else {
801+
// Reset the message to original state if the update fails and is not
802+
// retriable.
803+
state?.updateMessage(originalMessage.copyWith(
804+
state: MessageState.updatingFailed,
805+
));
806+
}
754807
}
808+
755809
rethrow;
756810
}
757811
}
758812

759813
final _deleteMessageLock = Lock();
760814

761815
/// Deletes the [message] from the channel.
762-
Future<EmptyResponse> deleteMessage(Message message, {bool? hard}) async {
763-
final hardDelete = hard ?? false;
816+
Future<EmptyResponse> deleteMessage(
817+
Message message, {
818+
bool hard = false,
819+
}) async {
820+
_checkInitialized();
764821

765-
// Directly deleting the local messages which are not yet sent to server
766-
if (message.status == MessageSendingStatus.sending ||
767-
message.status == MessageSendingStatus.failed) {
822+
// Directly deleting the local messages which are not yet sent to server.
823+
if (message.remoteCreatedAt == null) {
768824
state!.deleteMessage(
769825
message.copyWith(
770826
type: 'deleted',
771827
localDeletedAt: DateTime.now(),
772-
status: MessageSendingStatus.sent,
828+
state: MessageState.deleted(hard: hard),
773829
),
774-
hardDelete: hardDelete,
830+
hardDelete: hard,
775831
);
776832

777833
// Removing the attachments upload completer to stop the `sendMessage`
778834
// waiting for attachments to complete.
779835
_messageAttachmentsUploadCompleter
780836
.remove(message.id)
781-
?.completeError(Exception('Message deleted'));
837+
?.completeError(const StreamChatError('Message deleted'));
838+
839+
// Returning empty response to mark the api call as success.
782840
return EmptyResponse();
783841
}
784842

785-
try {
786-
// ignore: parameter_assignments
787-
message = message.copyWith(
788-
type: 'deleted',
789-
status: MessageSendingStatus.deleting,
790-
deletedAt: message.deletedAt ?? DateTime.now(),
791-
);
843+
// ignore: parameter_assignments
844+
message = message.copyWith(
845+
type: 'deleted',
846+
deletedAt: DateTime.now(),
847+
state: MessageState.deleting(hard: hard),
848+
);
792849

793-
state?.deleteMessage(message, hardDelete: hardDelete);
850+
state?.deleteMessage(message, hardDelete: hard);
794851

852+
try {
795853
// Wait for the previous delete call to finish. Otherwise, the order of
796854
// messages will not be maintained.
797855
final response = await _deleteMessageLock.synchronized(
798856
() => _client.deleteMessage(message.id, hard: hard),
799857
);
800858

801859
final deletedMessage = message.copyWith(
802-
status: MessageSendingStatus.sent,
860+
state: MessageState.deleted(hard: hard),
803861
);
804862

805-
state?.deleteMessage(deletedMessage, hardDelete: hardDelete);
863+
state?.deleteMessage(deletedMessage, hardDelete: hard);
806864

807865
return response;
808866
} catch (e) {
809867
if (e is StreamChatNetworkError && e.isRetriable) {
810-
state!._retryQueue.add([message]);
868+
state!._retryQueue.add([
869+
message.copyWith(
870+
// Update the message state to failed.
871+
state: MessageState.deletingFailed(hard: hard),
872+
),
873+
]);
811874
}
812875
rethrow;
813876
}
814877
}
815878

879+
/// Retry the operation on the message based on the failed state.
880+
///
881+
/// For example, if the message failed to send, it will retry sending the
882+
/// message and vice-versa.
883+
Future<Object> retryMessage(Message message) async {
884+
assert(message.state.isFailed, 'Message state is not failed');
885+
886+
return message.state.maybeWhen(
887+
failed: (state, _) => state.when(
888+
sendingFailed: () => sendMessage(message),
889+
updatingFailed: () => updateMessage(message),
890+
deletingFailed: (hard) => deleteMessage(message, hard: hard),
891+
),
892+
orElse: () => throw StateError('Message state is not failed'),
893+
);
894+
}
895+
816896
/// Pins provided message
817897
Future<UpdateMessageResponse> pinMessage(
818898
Message message, {
@@ -1895,15 +1975,7 @@ class ChannelClientState {
18951975
/// Retry failed message.
18961976
Future<void> retryFailedMessages() async {
18971977
final failedMessages = [...messages, ...threads.values.expand((v) => v)]
1898-
.where(
1899-
(message) =>
1900-
message.status != MessageSendingStatus.sent &&
1901-
message.createdAt.isBefore(
1902-
DateTime.now().subtract(const Duration(seconds: 5)),
1903-
),
1904-
)
1905-
.toList();
1906-
1978+
.where((it) => it.state.isFailed);
19071979
_retryQueue.add(failedMessages);
19081980
}
19091981

packages/stream_chat/lib/src/client/client.dart

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,9 @@ class StreamChatClient {
109109

110110
_retryPolicy = retryPolicy ??
111111
RetryPolicy(
112-
shouldRetry: (_, attempt, __) => attempt < 5,
113-
retryTimeout: (_, attempt, __) => Duration(seconds: attempt),
112+
shouldRetry: (_, __, error) {
113+
return error is StreamChatNetworkError && error.isRetriable;
114+
},
114115
);
115116

116117
state = ClientState(this);
@@ -1397,12 +1398,19 @@ class StreamChatClient {
13971398
);
13981399

13991400
/// Deletes the given message
1400-
Future<EmptyResponse> deleteMessage(String messageId, {bool? hard}) async {
1401-
final response =
1402-
await _chatApi.message.deleteMessage(messageId, hard: hard);
1403-
if (hard == true) {
1401+
Future<EmptyResponse> deleteMessage(
1402+
String messageId, {
1403+
bool hard = false,
1404+
}) async {
1405+
final response = await _chatApi.message.deleteMessage(
1406+
messageId,
1407+
hard: hard,
1408+
);
1409+
1410+
if (hard) {
14041411
await chatPersistenceClient?.deleteMessageById(messageId);
14051412
}
1413+
14061414
return response;
14071415
}
14081416

0 commit comments

Comments
 (0)