Skip to content

Scheduled messages (4/4): Scheduled Messages Demo App - #4365

Merged
nuno-vieira merged 51 commits into
developfrom
add/scheduled-messages-demo-app
Oct 28, 2026
Merged

nuno-vieira merged 51 commits into
developfrom
add/scheduled-messages-demo-app

Conversation

@nuno-vieira

@nuno-vieira nuno-vieira commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

🔗 Issue Links

Stacked PRs (review and merge in order):

  1. Scheduled messages (1/4): OpenAPI models and endpoints #4360 OpenAPI models and endpoints
  2. Scheduled messages (2/4): Controllers public API and events #4357 Controllers public API and events
  3. Scheduled messages (3/4): State Layer API #4358 State Layer API
  4. Scheduled messages (4/4): Scheduled Messages Demo App #4365 Scheduled Messages Demo App 👈 this PR

🎯 Goal

Show how to schedule messages from the composer, like in Slack, and how to list them with ScheduledMessageListController.

📝 Summary

  • Long press the send button to schedule a message, with presets and a custom date picker.
  • A banner above the composer shows how many messages are scheduled in the channel or thread, and opens the Scheduled tab.
  • A Scheduled tab lists the scheduled messages of every channel, pending ones first and failed ones after, with a badge of the pending ones.
  • Swipe a row to send it now, reschedule it, retry it or delete it, and tap it to edit it in the composer of its channel: send saves the changes, and a long press on send reschedules it.
  • The feature is enabled on the US East staging app only, which the configuration screen and the login screen offer.

🛠 Implementation

  • The composer subclass schedules with ChatChannelController and ChatMessageController, and edits a scheduled message in place.
  • The channel list and the channel queries set includeScheduledMessages, so the banner reads ChatChannel.scheduledMessages.
  • DemoScheduledMessageListVC is a SwiftUI list hosted in a UIHostingController, driven by a ScheduledMessageListController. Each row shows the status and the failure of the scheduled message, and only offers the actions that apply.

🧪 Manual Testing Notes

  1. In the demo app, log out, open Configuration and pick vfa6gxospjf0 (US East Staging), then log in as Alice.
  2. In a channel, type a message, long press the send button and pick a time. The banner above the composer shows the scheduled message.
  3. Repeat with an image or a video attached: it is uploaded first, then scheduled.
  4. Open the Scheduled tab: the messages of every channel are listed, and the badge counts the pending ones.
  5. Swipe a row to send it now, reschedule it or delete it. Tap it to edit it in its channel.
  6. Schedule more messages than the app allows in one channel (2 on this app): the row shows the server's error and no Retry.
  7. Turn on Airplane mode, schedule a message, turn it off: it is sent once connected.

☑️ Contributor Checklist

  • I have signed the Stream CLA (required)
  • This change should be manually QAed
  • Changelog is updated with client-facing changes
  • Changelog is updated with new localization keys
  • New code is covered by unit tests
  • Documentation has been updated in the docs-content repo

🤖 Generated with Claude Code

@nuno-vieira
nuno-vieira requested a review from a team as a code owner October 26, 2026 16:25
@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Caution

Review failed

The pull request is closed.

Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
1 Warning
⚠️ Big PR

Generated by 🚫 Danger

@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-demo-app branch from 8e46563 to c0a956c Compare October 26, 2026 17:29
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-state-layer branch from be1bb81 to 3c3237a Compare October 26, 2026 17:29
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-demo-app branch from c0a956c to 70901a7 Compare October 26, 2026 17:50
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-state-layer branch 2 times, most recently from 93cf328 to 6d5d8a3 Compare October 26, 2026 18:05
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-demo-app branch 2 times, most recently from d7f2189 to 7ccbd09 Compare October 26, 2026 18:41
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-state-layer branch 2 times, most recently from 3c46fb4 to 2b638a0 Compare October 26, 2026 18:49
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-demo-app branch 2 times, most recently from d210bf1 to 3d2e9d6 Compare October 26, 2026 19:29
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-state-layer branch 2 times, most recently from 8625ad5 to bdc4285 Compare October 26, 2026 19:49
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-demo-app branch from 3d2e9d6 to 8708d5e Compare October 26, 2026 19:49
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-state-layer branch from bdc4285 to fecbfba Compare October 26, 2026 20:17
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-demo-app branch from 8708d5e to f403eda Compare October 26, 2026 20:18
@nuno-vieira nuno-vieira mentioned this pull request Oct 26, 2026
3 of 6 tasks
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-demo-app branch from f403eda to b50305a Compare October 26, 2026 20:28
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-state-layer branch from fecbfba to 2681d40 Compare October 26, 2026 20:28
"\(dayString(from: date, now: now, calendar: calendar)) at \(timeString(from: date))"
}

static func separatorString(from date: Date, now: Date = Date(), calendar: Calendar = .current) -> String {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks unused

@nuno-vieira nuno-vieira Oct 28, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, separatorString was left over from an earlier version of the scheduled list. Removed it and made timeString private, since only the formatter uses it: 29ccbcde9

@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-demo-app branch from b50305a to faa8d50 Compare October 27, 2026 15:18
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-state-layer branch from 2681d40 to 214d9df Compare October 27, 2026 15:18
Add ScheduledMessageList and ScheduledMessageListState, created with ChatClient.makeScheduledMessageList(with:), and async methods on Chat to schedule, update, reschedule, delete and send now scheduled messages and replies.
Without a next cursor, loadMoreScheduledMessages() requested the first page again. It now returns an empty array.
Like the controllers, scheduling, editing, rescheduling and resending save
the changes locally and return. The server answers later on the scheduled
message, unlike sendMessage, which waits for it.
…e sent

Like the controllers, sending now marks the message locally and does not
wait for the server.
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-state-layer branch from 39234c8 to 400a2f7 Compare October 28, 2026 18:58
Long press the send button to schedule a message, like in Slack. A banner above the composer shows how many messages are scheduled in the channel or thread, and a scheduled message can be edited in the composer. The Scheduled tab lists the scheduled messages of every channel, pending ones first, with swipe actions to send now, reschedule, retry or delete them. The feature is enabled on the US East staging app.
Use ScheduledMessageFailure and the failure of a scheduled message, receive the updated scheduled messages in the list controller delegate, and pass extraData last when scheduling.
- Show the scheduling confirmation once the server accepts the message, and
  a red error toast with the reason when it rejects it
- Create the composer's scheduled message list controller on set up
- Describe each rejection reason, with a generic text for unknown ones
- Offer scheduling for commands, so the SDK's local validation is shown
- Remove only the quote when closing it while editing a scheduled message
…o app

The SDK refuses locally what the server would reject, so the confirmation
shows as soon as the message is saved. A later failure of the server shows
in the Scheduled list.
@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-demo-app branch from 5ee16b5 to 0948d96 Compare October 28, 2026 19:00
@Stream-SDK-Bot

Copy link
Copy Markdown
Collaborator

SDK Size

title develop branch diff status
StreamChat 7.17 MB 7.43 MB +270 KB 🟡
StreamChatUI 3.38 MB 3.38 MB 0 KB 🟢
StreamChatCommonUI 1.03 MB 1.03 MB 0 KB 🟢
StreamChatAI 2.59 MB 2.59 MB 0 KB 🟢

@Stream-SDK-Bot

Copy link
Copy Markdown
Collaborator

StreamChat XCSize

Object Diff (bytes)
ScheduledMessagesRepository.o +39245
ScheduledMessageDTO.o +26506
ScheduledMessageFailure.o +11084
ScheduledMessageListController.o +10495
ScheduledMessage.o +9532
Show 71 more objects
Object Diff (bytes)
RequestEncoder.o +9260
ChannelDTO.o +8489
ScheduledMessageListQuery.o +8281
StreamCDNStorage.o +7760
ScheduledMessageEvents.o +6494
MessageScheduler.o +5186
ScheduledMessageList.o +5116
APIClient.o +4864
ScheduledMessageListState.o +4459
Chat.o +3412
ChannelController.o +3306
MessageSender.o +3160
GroupedChannelListLinker.o +2812
ScheduledMessageStatus.o +2640
ScheduledMessageSentEventDTO.o +2611
SyncOperations.o -2468
ScheduledMessageCreatedEventDTO.o +2418
ScheduledMessageUpdatedEventDTO.o +2410
ScheduledMessageDeletedEventDTO.o +2410
ScheduledMessageFailedEventDTO.o +2409
ScheduledMessageChannel.o +2312
ChannelListPayload.o +2115
ScheduledMessageListController+Combine.o +1742
ChannelListController.o +1530
ScheduledMessageFailureReason.o +1413
MessageReactionDTO.o +1364
ScheduledMessageListState+Observer.o +1261
WSEvent.o +1242
ScheduledMessageUpdaterMiddleware.o +1242
MessageController.o +1236
ChannelSearch.o -1200
ChatClient.o +1182
AttachmentDownloader.o +1164
ChannelConfigDTO.o +1127
MessageSearchController.o +1116
AudioAnalysisEngine.o +847
LivestreamChannelController.o +816
ChannelListQuery.o +764
AttachmentQueueUploader.o +760
ChannelSearchController.o -640
RoleSearchController.o +620
ChannelUpdater.o -616
OfflineRequestsRepository.o +400
ChannelController+Combine.o +382
MessageDTO.o +369
Sequence+CompactMapLoggingError.o +356
ChannelQuery.o +336
Channel.o +319
MessageUpdater.o -308
MessageRepository.o -264
Filter.o -244
ChannelSearchState+Observer.o +242
DatabaseSession.o +186
AnyAttachmentPayload.o +172
ChatClient+Factory.o +164
ActiveLiveLocationsEndTimeTracker.o +148
UserUpdater.o -104
Event.o +96
ChannelListUpdater.o -92
StreamCore.o -86
BannedUser.o -68
SyncRepository.o -58
ChatRemoteNotificationHandler.o +56
MulticastDelegate.o +52
CurrentUserDTO.o +52
ChannelPayload+asModel.o -52
ChannelMemberListUpdater.o +48
LivestreamChat.o +48
ChatClient+ChannelController.o +44
AppSettings+Extensions.o +44
UserGroupSearchController.o +44

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@github-actions

Copy link
Copy Markdown

Public Interface

🚀 No changes affecting the public interface.

@nuno-vieira
nuno-vieira force-pushed the add/scheduled-messages-state-layer branch from 400a2f7 to f5b9e52 Compare October 28, 2026 22:09
Base automatically changed from add/scheduled-messages-state-layer to develop October 28, 2026 23:26
@nuno-vieira
nuno-vieira merged commit 3aa8b31 into develop Oct 28, 2026
5 of 6 checks passed
@nuno-vieira
nuno-vieira deleted the add/scheduled-messages-demo-app branch October 28, 2026 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants