Skip to content
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

Handle push notifications for DMs #3895

Merged
merged 23 commits into from
May 9, 2024
Merged

Handle push notifications for DMs #3895

merged 23 commits into from
May 9, 2024

Conversation

haileyok
Copy link
Contributor

@haileyok haileyok commented May 7, 2024

Why

Edit

For now, let's merge this in with only the DM notification logic, since that is the primary thing we need right now. We should investigate other platforms and determine how we want to handle each individual case here. I.e. where do we want to push for a certain type of notification.


This needed a good bit of thinking to get right, but I think it is mostly there. We're tackling a few birds with one stone here!

  1. Pressing a mention or reply notification takes you to that post rather than the notifications tab
  2. Pressing a follow notification takes you to that profile
  3. DM notifications will (currently) alway show up in the app. Unless...
  4. Notifications will not be displayed for the current conversation you are viewing
  5. When the app is foregrounded, you will not see notifications for messages on accounts other than the one you're currently actively signed in to.
  6. When in the background, you will see notifications for all accounts. If you tap on a notification for an account that is not your currently signed-in account, you'll be automatically switched to the other account and then pushed to the conversation.

Note about points 3 and 4

We need to consider one thing when it comes to points one and two here. When you open the app through one of these notifications, we won't actually "remove" these items from your "unread" notifications. This is a tricky thing to do, because we are currently making notifications as read with a "last seen" time. If we updated that time when you pressed a notification for a mention, we'd be wiping all your unreads up to that point - not just the one you're tapping.

With that said, we can comment out those handlers for now. It sort of comes down to "which is the better experience" I think right now. We'll talk about how to improve this as well, but it was a super easy thing to add in here where I needed to rework the handler anyway.

Test Plan

Testing this is not fun. There isn't any way to receive notifications on the simulator, and even if you build for a device, you still cannot receive the notifications as the push notification token is a development token rather than a production one. With that said, you can send "fake" notifications.

  1. Figure out the device name - xcrun simctl list devices | grep Booted
  2. Save a payload to testnotif.json. An example payload would be
{
    "aps": {
        "alert": {
            "title": "Mention Notification",
            "body": "A test Mention notification"
        }
    },
    "reason": "mention",
    "uri": "at://did:plc:2p25gewthftad2wefe7yyzhr/app.bsky.feed.post/3krxmsj45iw2x",
    "subject": ""
}
  1. Send the notification - xcrun simctl push "iPhone 15 Pro" xyz.blueskyweb.app testMention.json

Pressing a mention or reply notification takes you to the post

RocketSim_Recording_iPhone_15_Pro_6 1_2024-05-08_12 19 14

Those types of notifications still do not show up when the app is foregrounded

Screen.Recording.2024-05-08.at.12.20.22.PM.mov

Pressing a follow notification takes you to the profile

RocketSim_Recording_iPhone_15_Pro_6 1_2024-05-08_12 45 55

Pressing a message notification takes you to the convo

RocketSim_Recording_iPhone_15_Pro_6 1_2024-05-08_12 47 48

Pressing a notification for an account that isn't the current one switches your account

RocketSim_Recording_iPhone_15_Pro_6 1_2024-05-08_12 49 00

Copy link

render bot commented May 7, 2024

Copy link

github-actions bot commented May 7, 2024

Old size New size Diff
6.89 MB 6.89 MB 196 B (0.00%)

prep merge

move `useNotificationsListener` into shell

progress

better structure

only show messages notifications while using app if it is the current account

progress

only emit on native

current chat emitter

only show alerts for the current chat

type

add logs

setup handlers
@haileyok haileyok force-pushed the hailey/dm-push-notifs branch from ead83b0 to 417de2b Compare May 8, 2024 05:31
@haileyok haileyok marked this pull request as ready for review May 8, 2024 17:58
Comment on lines 76 to 84
setTimeout(() => {
// @ts-expect-error types are weird here
navigation.navigate('MessagesTab', {
screen: 'MessagesConversation',
params: {
conversation: payload.convoId,
},
})
}, 500)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The setTimeouts for .navigate in this code are not "necessary", but they have a better feel then the very immediate navigation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another thing that I'd like to look at here is handling adding the Messages screen onto this stack if it doesn't exist already. The react nav documentation is a bit unclear on how to do this, so maybe I can find an example elsewhere in the codebase.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah having Messages as the immediate screen when pressing "back" would be awesome

Comment on lines 122 to 149
Notifications.setNotificationHandler({
handleNotification: async e => {
if (e.request.trigger.type !== 'push') return DEFAULT_HANDLER_OPTIONS

logger.debug(
'Notifications: received',
{e},
logger.DebugContext.notifications,
)

const payload = e.request.trigger.payload as NotificationRecord
if (
payload.reason === 'chat-message' &&
payload.recipientDid === currentAccount?.did &&
currentConvoId !== payload.convoId
) {
return {
shouldShowAlert: true,
shouldPlaySound: false,
shouldSetBadge: false,
}
}

// Any notification other than a chat message should invalidate the unread page
invalidateCachedUnreadPage()
return DEFAULT_HANDLER_OPTIONS
},
})
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This replaces the old addNotificationReceivedListener, because it lets us also control visibility of the push notification.

Comment on lines +185 to +191
if (
storedPayload?.reason === 'chat-message' &&
currentAccount?.did === storedPayload.recipientDid
) {
handleNotification(storedPayload)
storedPayload = undefined
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

When we encounter a case where you open a notification that doesn't belong to the currently signed in account, we switch the account above and store the payload. Once currentAccount changes, we will re-handle the notification.

This only applies to chat-message right now because we don't have a recipientDid yet on other notification payloads.

Copy link
Member

Choose a reason for hiding this comment

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

Nice one

Comment on lines 112 to 115
navigation.reset({
index: 0,
routes: [{name: 'Messages'}],
})
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For now, in cases where we got to this screen from a notification, adding the Messages route to the start of this creates the "pop" animation that we are looking for.

Copy link
Member

@estrattonbailey estrattonbailey left a comment

Choose a reason for hiding this comment

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

Code LGTM, pending discussion of behaviors

Comment on lines 21 to 41
type NotificationReason =
| 'like'
| 'repost'
| 'follow'
| 'mention'
| 'reply'
| 'quote'
| 'chat-message'

type NotificationRecord =
| {
reason: Exclude<NotificationReason, 'chat-message'>
uri: string
subject: string
}
| {
reason: 'chat-message'
convoId: string
messageId: string
recipientDid: string
}
Copy link
Member

Choose a reason for hiding this comment

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

sickos-yes.png

Comment on lines 76 to 84
setTimeout(() => {
// @ts-expect-error types are weird here
navigation.navigate('MessagesTab', {
screen: 'MessagesConversation',
params: {
conversation: payload.convoId,
},
})
}, 500)
Copy link
Member

Choose a reason for hiding this comment

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

Yeah having Messages as the immediate screen when pressing "back" would be awesome

Comment on lines +185 to +191
if (
storedPayload?.reason === 'chat-message' &&
currentAccount?.did === storedPayload.recipientDid
) {
handleNotification(storedPayload)
storedPayload = undefined
}
Copy link
Member

Choose a reason for hiding this comment

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

Nice one

@haileyok haileyok requested a review from estrattonbailey May 9, 2024 16:20
@haileyok haileyok changed the title Better push notification handling Handle push notifications for DMs May 9, 2024
@haileyok haileyok merged commit 17e3b94 into main May 9, 2024
6 checks passed
@haileyok haileyok deleted the hailey/dm-push-notifs branch May 9, 2024 17:04
estrattonbailey added a commit that referenced this pull request May 9, 2024
* origin/main:
  Handle push notifications for DMs (#3895)
  Add gate, a:a swap onboarding state (#3930)
  [🐴] Add hover context menu for convo list on web (#3923)
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.

2 participants