Skip to content

Add Message Reminders #3623

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 44 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
0830c0a
Add new reminder endpoint paths
nuno-vieira Mar 14, 2025
3f8991a
Add new Message Reminder Endpoints
nuno-vieira Mar 14, 2025
ad6f17d
Add MessageReminderListQuery
nuno-vieira Mar 14, 2025
1608d89
Change the default baseURL of Frankfurt C2 to staging env
nuno-vieira Mar 14, 2025
29c2b1b
Remove user_id from request payloads since this is server side only
nuno-vieira Mar 14, 2025
b130b12
Add MessageReminder and MessageReminderDTO
nuno-vieira Mar 17, 2025
51b4976
Add createReminder, updateReminder and deleteReminder actions
nuno-vieira Mar 17, 2025
abfb764
Add `Message.reminder` and update it or delete it when needed
nuno-vieira Mar 18, 2025
2eff1f7
Add demo app example to create, update and delete reminders
nuno-vieira Mar 18, 2025
804e012
Add highlighted message view when saved for later in the demo app
nuno-vieira Mar 18, 2025
d2e3e7b
Add test coverage to Message Controller
nuno-vieira Mar 18, 2025
bfd833d
Add test coverage to MessagUpdater
nuno-vieira Mar 18, 2025
3063d9e
Add test coverage to ReminderPayload parsing
nuno-vieira Mar 19, 2025
12c3a08
Expose `Filter.isNil` that wraps the`.exists` filter
nuno-vieira Mar 19, 2025
6396538
Rename `Filter+ChatChannel` to `Filter+predicate` so that it can be u…
nuno-vieira Mar 19, 2025
3ecfff3
Implementation of the Message Reminder Query
nuno-vieira Mar 19, 2025
061a821
Add Reminder List Demo App UI Component
nuno-vieira Mar 19, 2025
795da15
Move reminder MessageUpdater functions to RemindersRepository
nuno-vieira Mar 19, 2025
aa19fb7
Handle Reminder Events
nuno-vieira Mar 20, 2025
7950334
Fix forgotten hardcoded test in reminder list query
nuno-vieira Mar 20, 2025
470c0a3
Fix reminder list query tests
nuno-vieira Mar 20, 2025
0f44197
Add local push notification when reminder is expired
nuno-vieira Mar 20, 2025
501d4ca
Fix reminder with empty text in the Reminder List Demo App UI
nuno-vieira Mar 21, 2025
5ced891
Add Demo App reminders feature flag
nuno-vieira Mar 21, 2025
3af5f57
Improve the Filter+predicate documentation
nuno-vieira Mar 21, 2025
4ea6208
Fix removeAllData tests
nuno-vieira Mar 21, 2025
f3cc074
Add reminders enabled by default on the demo app
nuno-vieira Mar 27, 2025
482f986
Remove local notification of reminders since it should come from the …
nuno-vieira Mar 28, 2025
6bfa0a9
Refactor reminders to have their own controller
nuno-vieira Mar 28, 2025
f0d95b7
Move reminder endpoints to a separate file
nuno-vieira Mar 29, 2025
61161db
Create Reminder Payloads file
nuno-vieira Mar 29, 2025
daf382f
Move reminder payloads to classes to reduce SDK size
nuno-vieira Mar 29, 2025
5e54db1
Update CHANGELOG.md
nuno-vieira Mar 29, 2025
a7186b3
Remove unnecessary notifications import
nuno-vieira Mar 29, 2025
1a3ef47
Fix unit tests by missing inits of payloads
nuno-vieira Mar 31, 2025
273e5d3
Merge branch 'develop' into add/snooze-messages
nuno-vieira Mar 31, 2025
ba98cd8
Remove `messageId` from FilterKey since it is not really useful at th…
nuno-vieira Apr 1, 2025
b4940e3
Merge branch 'add/snooze-messages' of github.com:GetStream/stream-cha…
nuno-vieira Apr 1, 2025
8c7062d
Fix reminder lists not updating when due date is reached by the fact …
nuno-vieira Apr 2, 2025
95072ac
Fix forgotten setting of a delegate
nuno-vieira Apr 2, 2025
e7ef1d3
Remove unnecessary available iOS 13 macros
nuno-vieira Apr 2, 2025
9e12edb
Add "Message" prefix to Reminder Events
nuno-vieira Apr 2, 2025
6d5a78d
Use new "converting" helper function to simply reminders repository
nuno-vieira Apr 2, 2025
59f7fca
Remove some unnecessary warnings
nuno-vieira Apr 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

# Upcoming

### 🔄 Changed
## StreamChat
### ✅ Added
- Add new `Filter.isNil` to make it easier to query by nil values [#3623](https://github.com/GetStream/stream-chat-swift/pull/3623)
- Add Message Reminders [#3623](https://github.com/GetStream/stream-chat-swift/pull/3623)
- Add `ChatMessageController.createReminder()`
- Add `ChatMessageController.updateReminder()`
- Add `ChatMessageController.deleteReminder()`
- Add `MessageReminderListController` and `MessageReminderListQuery`

# [4.76.0](https://github.com/GetStream/stream-chat-swift/releases/tag/4.76.0)
_March 31, 2025_
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ struct DemoAppConfig {
var shouldShowConnectionBanner: Bool
/// A Boolean value to define if the premium member feature is enabled. This is to test custom member data.
var isPremiumMemberFeatureEnabled: Bool
/// A Boolean value to define if the reminders feature is enabled.
var isRemindersEnabled: Bool

/// The details to generate expirable tokens in the demo app.
struct TokenRefreshDetails {
Expand Down Expand Up @@ -50,7 +52,8 @@ class AppConfig {
isLocationAttachmentsEnabled: false,
tokenRefreshDetails: nil,
shouldShowConnectionBanner: false,
isPremiumMemberFeatureEnabled: false
isPremiumMemberFeatureEnabled: false,
isRemindersEnabled: true
)

if StreamRuntimeCheck.isStreamInternalConfiguration {
Expand All @@ -61,6 +64,7 @@ class AppConfig {
demoAppConfig.isHardDeleteEnabled = true
demoAppConfig.shouldShowConnectionBanner = true
demoAppConfig.isPremiumMemberFeatureEnabled = true
demoAppConfig.isRemindersEnabled = true
StreamRuntimeCheck.assertionsEnabled = true
}
}
Expand Down Expand Up @@ -173,6 +177,7 @@ class AppConfigViewController: UITableViewController {
case tokenRefreshDetails
case shouldShowConnectionBanner
case isPremiumMemberFeatureEnabled
case isRemindersEnabled
}

enum ComponentsConfigOption: String, CaseIterable {
Expand Down Expand Up @@ -338,6 +343,10 @@ class AppConfigViewController: UITableViewController {
cell.accessoryView = makeSwitchButton(demoAppConfig.isPremiumMemberFeatureEnabled) { [weak self] newValue in
self?.demoAppConfig.isPremiumMemberFeatureEnabled = newValue
}
case .isRemindersEnabled:
cell.accessoryView = makeSwitchButton(demoAppConfig.isRemindersEnabled) { [weak self] newValue in
self?.demoAppConfig.isRemindersEnabled = newValue
}
}
}

Expand Down Expand Up @@ -735,6 +744,9 @@ class AppConfigViewController: UITableViewController {
guard let selectedOption = options.first else { return }
apiKeyString = selectedOption.rawValue
StreamChatWrapper.replaceSharedInstance(apiKeyString: apiKeyString)
if let baseURL = selectedOption.customBaseURL {
self?.chatClientConfig.baseURL = .init(url: baseURL)
}
self?.tableView.reloadData()
}

Expand Down
43 changes: 39 additions & 4 deletions DemoApp/Screens/DemoAppTabBarController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,31 @@ import StreamChat
import StreamChatUI
import UIKit

class DemoAppTabBarController: UITabBarController, CurrentChatUserControllerDelegate {
class DemoAppTabBarController: UITabBarController, CurrentChatUserControllerDelegate, MessageReminderListControllerDelegate {
let channelListVC: UIViewController
let threadListVC: UIViewController
let draftListVC: UIViewController
let reminderListVC: UIViewController
let currentUserController: CurrentChatUserController
let allRemindersListController: MessageReminderListController

// Events controller for listening to chat events
private var eventsController: EventsController!

init(
channelListVC: UIViewController,
threadListVC: UIViewController,
draftListVC: UIViewController,
currentUserController: CurrentChatUserController
reminderListVC: UIViewController,
currentUserController: CurrentChatUserController,
allRemindersListController: MessageReminderListController
) {
self.channelListVC = channelListVC
self.threadListVC = threadListVC
self.draftListVC = draftListVC
self.reminderListVC = reminderListVC
self.currentUserController = currentUserController
self.allRemindersListController = allRemindersListController
super.init(nibName: nil, bundle: nil)
}

Expand Down Expand Up @@ -52,6 +61,12 @@ class DemoAppTabBarController: UITabBarController, CurrentChatUserControllerDele
currentUserController.delegate = self
unreadCount = currentUserController.unreadCount

// Update reminders badge if the feature is enabled.
if AppConfig.shared.demoAppConfig.isRemindersEnabled {
allRemindersListController.delegate = self
updateRemindersBadge()
}

tabBar.backgroundColor = Appearance.default.colorPalette.background
tabBar.isTranslucent = true

Expand All @@ -65,14 +80,34 @@ class DemoAppTabBarController: UITabBarController, CurrentChatUserControllerDele

draftListVC.tabBarItem.title = "Drafts"
draftListVC.tabBarItem.image = UIImage(systemName: "bubble.and.pencil")

reminderListVC.tabBarItem.title = "Reminders"
reminderListVC.tabBarItem.image = UIImage(systemName: "bell")

viewControllers = [channelListVC, threadListVC, draftListVC]
// Only show reminders tab if the feature is enabled
if AppConfig.shared.demoAppConfig.isRemindersEnabled {
viewControllers = [channelListVC, threadListVC, draftListVC, reminderListVC]
} else {
viewControllers = [channelListVC, threadListVC, draftListVC]
}
}

func currentUserController(_ controller: CurrentChatUserController, didChangeCurrentUserUnreadCount: UnreadCount) {
let unreadCount = didChangeCurrentUserUnreadCount
self.unreadCount = unreadCount
let totalUnreadBadge = unreadCount.channels + unreadCount.threads
UIApplication.shared.applicationIconBadgeNumber = totalUnreadBadge
}

func controller(
_ controller: MessageReminderListController,
didChangeReminders changes: [ListChange<MessageReminder>]
) {
updateRemindersBadge()
}

private func updateRemindersBadge() {
let reminders = allRemindersListController.reminders
reminderListVC.tabBarItem.badgeValue = reminders.isEmpty ? nil : "\(reminders.count)"
}
}
Loading
Loading