Multiple notifications fixes (#2154)

* Dont reset notifications feed on push notification event

* Dont separate notifications by read state to avoid jank

* On notifications screen focus, check latest and only rerender if not scrolled down

* Reuse the cached notifs page when its not stale

* Bump ios build number

* Improve comments

* Change the 'mark all read' condition to avoid firing too early
zio/stable
Paul Frazee 2023-12-09 15:09:31 -08:00 committed by GitHub
parent d854e88218
commit 6b3eb401b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 162 additions and 146 deletions

View File

@ -9,7 +9,7 @@ module.exports = function () {
/** /**
* iOS build number. Must be incremented for each TestFlight version. * iOS build number. Must be incremented for each TestFlight version.
*/ */
const IOS_BUILD_NUMBER = '12' const IOS_BUILD_NUMBER = '13'
/** /**
* Android build number. Must be incremented for each release. * Android build number. Must be incremented for each release.

View File

@ -81,6 +81,7 @@ export function registerTokenChangeHandler(
export function init(queryClient: QueryClient) { export function init(queryClient: QueryClient) {
// handle notifications that are received, both in the foreground or background // handle notifications that are received, both in the foreground or background
// NOTE: currently just here for debug logging
Notifications.addNotificationReceivedListener(event => { Notifications.addNotificationReceivedListener(event => {
logger.debug( logger.debug(
'Notifications: received', 'Notifications: received',
@ -88,8 +89,6 @@ export function init(queryClient: QueryClient) {
logger.DebugContext.notifications, logger.DebugContext.notifications,
) )
if (event.request.trigger.type === 'push') { if (event.request.trigger.type === 'push') {
// refresh notifications in the background
truncateAndInvalidate(queryClient, RQKEY_NOTIFS())
// handle payload-based deeplinks // handle payload-based deeplinks
let payload let payload
if (isIOS) { if (isIOS) {

View File

@ -38,12 +38,12 @@ msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite
msgstr "" msgstr ""
#: src/view/screens/Settings.tsx:407 #: src/view/screens/Settings.tsx:407
#: src/view/shell/Drawer.tsx:648 #: src/view/shell/Drawer.tsx:640
msgid "{invitesAvailable} invite code available" msgid "{invitesAvailable} invite code available"
msgstr "" msgstr ""
#: src/view/screens/Settings.tsx:409 #: src/view/screens/Settings.tsx:409
#: src/view/shell/Drawer.tsx:650 #: src/view/shell/Drawer.tsx:642
msgid "{invitesAvailable} invite codes available" msgid "{invitesAvailable} invite codes available"
msgstr "" msgstr ""
@ -830,16 +830,16 @@ msgid "Feed Preferences"
msgstr "" msgstr ""
#: src/view/shell/desktop/RightNav.tsx:64 #: src/view/shell/desktop/RightNav.tsx:64
#: src/view/shell/Drawer.tsx:300 #: src/view/shell/Drawer.tsx:292
msgid "Feedback" msgid "Feedback"
msgstr "" msgstr ""
#: src/view/screens/Feeds.tsx:475 #: src/view/screens/Feeds.tsx:475
#: src/view/screens/Profile.tsx:164 #: src/view/screens/Profile.tsx:164
#: src/view/shell/bottom-bar/BottomBar.tsx:168 #: src/view/shell/bottom-bar/BottomBar.tsx:160
#: src/view/shell/desktop/LeftNav.tsx:341 #: src/view/shell/desktop/LeftNav.tsx:333
#: src/view/shell/Drawer.tsx:463 #: src/view/shell/Drawer.tsx:455
#: src/view/shell/Drawer.tsx:464 #: src/view/shell/Drawer.tsx:456
msgid "Feeds" msgid "Feeds"
msgstr "" msgstr ""
@ -928,7 +928,7 @@ msgstr ""
#: src/view/com/auth/LoggedOut.tsx:68 #: src/view/com/auth/LoggedOut.tsx:68
#: src/view/com/auth/LoggedOut.tsx:69 #: src/view/com/auth/LoggedOut.tsx:69
#: src/view/com/util/moderation/ScreenHider.tsx:105 #: src/view/com/util/moderation/ScreenHider.tsx:105
#: src/view/shell/desktop/LeftNav.tsx:106 #: src/view/shell/desktop/LeftNav.tsx:103
msgid "Go back" msgid "Go back"
msgstr "" msgstr ""
@ -950,7 +950,7 @@ msgid "Handle"
msgstr "" msgstr ""
#: src/view/shell/desktop/RightNav.tsx:93 #: src/view/shell/desktop/RightNav.tsx:93
#: src/view/shell/Drawer.tsx:310 #: src/view/shell/Drawer.tsx:302
msgid "Help" msgid "Help"
msgstr "" msgstr ""
@ -994,10 +994,10 @@ msgstr ""
#~ msgid "Hmmm, we're having trouble finding this feed. It may have been deleted." #~ msgid "Hmmm, we're having trouble finding this feed. It may have been deleted."
#~ msgstr "" #~ msgstr ""
#: src/view/shell/bottom-bar/BottomBar.tsx:124 #: src/view/shell/bottom-bar/BottomBar.tsx:116
#: src/view/shell/desktop/LeftNav.tsx:305 #: src/view/shell/desktop/LeftNav.tsx:297
#: src/view/shell/Drawer.tsx:387 #: src/view/shell/Drawer.tsx:379
#: src/view/shell/Drawer.tsx:388 #: src/view/shell/Drawer.tsx:380
msgid "Home" msgid "Home"
msgstr "" msgstr ""
@ -1063,7 +1063,7 @@ msgstr ""
msgid "Invite code not accepted. Check that you input it correctly and try again." msgid "Invite code not accepted. Check that you input it correctly and try again."
msgstr "" msgstr ""
#: src/view/shell/Drawer.tsx:629 #: src/view/shell/Drawer.tsx:621
msgid "Invite codes: {invitesAvailable} available" msgid "Invite codes: {invitesAvailable} available"
msgstr "" msgstr ""
@ -1162,9 +1162,9 @@ msgid "List Name"
msgstr "" msgstr ""
#: src/view/screens/Profile.tsx:165 #: src/view/screens/Profile.tsx:165
#: src/view/shell/desktop/LeftNav.tsx:381 #: src/view/shell/desktop/LeftNav.tsx:373
#: src/view/shell/Drawer.tsx:479 #: src/view/shell/Drawer.tsx:471
#: src/view/shell/Drawer.tsx:480 #: src/view/shell/Drawer.tsx:472
msgid "Lists" msgid "Lists"
msgstr "" msgstr ""
@ -1173,7 +1173,7 @@ msgstr ""
msgid "Load more posts" msgid "Load more posts"
msgstr "" msgstr ""
#: src/view/screens/Notifications.tsx:130 #: src/view/screens/Notifications.tsx:141
msgid "Load new notifications" msgid "Load new notifications"
msgstr "" msgstr ""
@ -1224,9 +1224,9 @@ msgstr ""
#: src/view/screens/Moderation.tsx:63 #: src/view/screens/Moderation.tsx:63
#: src/view/screens/Settings.tsx:563 #: src/view/screens/Settings.tsx:563
#: src/view/shell/desktop/LeftNav.tsx:399 #: src/view/shell/desktop/LeftNav.tsx:391
#: src/view/shell/Drawer.tsx:498 #: src/view/shell/Drawer.tsx:490
#: src/view/shell/Drawer.tsx:499 #: src/view/shell/Drawer.tsx:491
msgid "Moderation" msgid "Moderation"
msgstr "" msgstr ""
@ -1300,7 +1300,7 @@ msgstr ""
msgid "My Feeds" msgid "My Feeds"
msgstr "" msgstr ""
#: src/view/shell/desktop/LeftNav.tsx:67 #: src/view/shell/desktop/LeftNav.tsx:64
msgid "My Profile" msgid "My Profile"
msgstr "" msgstr ""
@ -1328,11 +1328,11 @@ msgstr ""
#: src/view/screens/ProfileFeed.tsx:451 #: src/view/screens/ProfileFeed.tsx:451
#: src/view/screens/ProfileList.tsx:212 #: src/view/screens/ProfileList.tsx:212
#: src/view/screens/ProfileList.tsx:244 #: src/view/screens/ProfileList.tsx:244
#: src/view/shell/desktop/LeftNav.tsx:254 #: src/view/shell/desktop/LeftNav.tsx:246
msgid "New post" msgid "New post"
msgstr "" msgstr ""
#: src/view/shell/desktop/LeftNav.tsx:264 #: src/view/shell/desktop/LeftNav.tsx:256
msgid "New Post" msgid "New Post"
msgstr "" msgstr ""
@ -1402,12 +1402,12 @@ msgstr ""
#~ msgid "Note: Third-party apps that display Bluesky content may not respect this setting." #~ msgid "Note: Third-party apps that display Bluesky content may not respect this setting."
#~ msgstr "" #~ msgstr ""
#: src/view/screens/Notifications.tsx:97 #: src/view/screens/Notifications.tsx:108
#: src/view/screens/Notifications.tsx:121 #: src/view/screens/Notifications.tsx:132
#: src/view/shell/bottom-bar/BottomBar.tsx:195 #: src/view/shell/bottom-bar/BottomBar.tsx:187
#: src/view/shell/desktop/LeftNav.tsx:363 #: src/view/shell/desktop/LeftNav.tsx:355
#: src/view/shell/Drawer.tsx:424 #: src/view/shell/Drawer.tsx:416
#: src/view/shell/Drawer.tsx:425 #: src/view/shell/Drawer.tsx:417
msgid "Notifications" msgid "Notifications"
msgstr "" msgstr ""
@ -1432,7 +1432,7 @@ msgid "Opens configurable language settings"
msgstr "" msgstr ""
#: src/view/shell/desktop/RightNav.tsx:146 #: src/view/shell/desktop/RightNav.tsx:146
#: src/view/shell/Drawer.tsx:630 #: src/view/shell/Drawer.tsx:622
msgid "Opens list of invite codes" msgid "Opens list of invite codes"
msgstr "" msgstr ""
@ -1592,10 +1592,10 @@ msgstr ""
msgid "Processing..." msgid "Processing..."
msgstr "" msgstr ""
#: src/view/shell/bottom-bar/BottomBar.tsx:237 #: src/view/shell/bottom-bar/BottomBar.tsx:229
#: src/view/shell/Drawer.tsx:72 #: src/view/shell/Drawer.tsx:69
#: src/view/shell/Drawer.tsx:533 #: src/view/shell/Drawer.tsx:525
#: src/view/shell/Drawer.tsx:534 #: src/view/shell/Drawer.tsx:526
msgid "Profile" msgid "Profile"
msgstr "" msgstr ""
@ -1813,12 +1813,12 @@ msgstr ""
#: src/view/com/util/forms/SearchInput.tsx:64 #: src/view/com/util/forms/SearchInput.tsx:64
#: src/view/screens/Search/Search.tsx:381 #: src/view/screens/Search/Search.tsx:381
#: src/view/screens/Search/Search.tsx:533 #: src/view/screens/Search/Search.tsx:533
#: src/view/shell/bottom-bar/BottomBar.tsx:146 #: src/view/shell/bottom-bar/BottomBar.tsx:138
#: src/view/shell/desktop/LeftNav.tsx:323 #: src/view/shell/desktop/LeftNav.tsx:315
#: src/view/shell/desktop/Search.tsx:161 #: src/view/shell/desktop/Search.tsx:161
#: src/view/shell/desktop/Search.tsx:170 #: src/view/shell/desktop/Search.tsx:170
#: src/view/shell/Drawer.tsx:351 #: src/view/shell/Drawer.tsx:343
#: src/view/shell/Drawer.tsx:352 #: src/view/shell/Drawer.tsx:344
msgid "Search" msgid "Search"
msgstr "" msgstr ""
@ -1870,8 +1870,8 @@ msgstr ""
msgid "Send Email" msgid "Send Email"
msgstr "" msgstr ""
#: src/view/shell/Drawer.tsx:284 #: src/view/shell/Drawer.tsx:276
#: src/view/shell/Drawer.tsx:305 #: src/view/shell/Drawer.tsx:297
msgid "Send feedback" msgid "Send feedback"
msgstr "" msgstr ""
@ -1904,9 +1904,9 @@ msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your f
msgstr "" msgstr ""
#: src/view/screens/Settings.tsx:277 #: src/view/screens/Settings.tsx:277
#: src/view/shell/desktop/LeftNav.tsx:435 #: src/view/shell/desktop/LeftNav.tsx:427
#: src/view/shell/Drawer.tsx:554 #: src/view/shell/Drawer.tsx:546
#: src/view/shell/Drawer.tsx:555 #: src/view/shell/Drawer.tsx:547
msgid "Settings" msgid "Settings"
msgstr "" msgstr ""
@ -2447,7 +2447,7 @@ msgstr ""
#: src/view/screens/Settings.tsx:402 #: src/view/screens/Settings.tsx:402
#: src/view/shell/desktop/RightNav.tsx:127 #: src/view/shell/desktop/RightNav.tsx:127
#: src/view/shell/Drawer.tsx:644 #: src/view/shell/Drawer.tsx:636
msgid "Your invite codes are hidden when logged in using an App Password" msgid "Your invite codes are hidden when logged in using an App Password"
msgstr "" msgstr ""

View File

@ -38,12 +38,12 @@ msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite
msgstr "" msgstr ""
#: src/view/screens/Settings.tsx:407 #: src/view/screens/Settings.tsx:407
#: src/view/shell/Drawer.tsx:648 #: src/view/shell/Drawer.tsx:640
msgid "{invitesAvailable} invite code available" msgid "{invitesAvailable} invite code available"
msgstr "" msgstr ""
#: src/view/screens/Settings.tsx:409 #: src/view/screens/Settings.tsx:409
#: src/view/shell/Drawer.tsx:650 #: src/view/shell/Drawer.tsx:642
msgid "{invitesAvailable} invite codes available" msgid "{invitesAvailable} invite codes available"
msgstr "" msgstr ""
@ -826,16 +826,16 @@ msgid "Feed Preferences"
msgstr "फ़ीड प्राथमिकता" msgstr "फ़ीड प्राथमिकता"
#: src/view/shell/desktop/RightNav.tsx:64 #: src/view/shell/desktop/RightNav.tsx:64
#: src/view/shell/Drawer.tsx:300 #: src/view/shell/Drawer.tsx:292
msgid "Feedback" msgid "Feedback"
msgstr "प्रतिक्रिया" msgstr "प्रतिक्रिया"
#: src/view/screens/Feeds.tsx:475 #: src/view/screens/Feeds.tsx:475
#: src/view/screens/Profile.tsx:164 #: src/view/screens/Profile.tsx:164
#: src/view/shell/bottom-bar/BottomBar.tsx:168 #: src/view/shell/bottom-bar/BottomBar.tsx:160
#: src/view/shell/desktop/LeftNav.tsx:341 #: src/view/shell/desktop/LeftNav.tsx:333
#: src/view/shell/Drawer.tsx:463 #: src/view/shell/Drawer.tsx:455
#: src/view/shell/Drawer.tsx:464 #: src/view/shell/Drawer.tsx:456
msgid "Feeds" msgid "Feeds"
msgstr "सभी फ़ीड" msgstr "सभी फ़ीड"
@ -920,7 +920,7 @@ msgstr "प्रारंभ करें"
#: src/view/com/auth/LoggedOut.tsx:68 #: src/view/com/auth/LoggedOut.tsx:68
#: src/view/com/auth/LoggedOut.tsx:69 #: src/view/com/auth/LoggedOut.tsx:69
#: src/view/com/util/moderation/ScreenHider.tsx:105 #: src/view/com/util/moderation/ScreenHider.tsx:105
#: src/view/shell/desktop/LeftNav.tsx:106 #: src/view/shell/desktop/LeftNav.tsx:103
msgid "Go back" msgid "Go back"
msgstr "वापस जाओ" msgstr "वापस जाओ"
@ -942,7 +942,7 @@ msgid "Handle"
msgstr "हैंडल" msgstr "हैंडल"
#: src/view/shell/desktop/RightNav.tsx:93 #: src/view/shell/desktop/RightNav.tsx:93
#: src/view/shell/Drawer.tsx:310 #: src/view/shell/Drawer.tsx:302
msgid "Help" msgid "Help"
msgstr "सहायता" msgstr "सहायता"
@ -986,10 +986,10 @@ msgstr ""
#~ msgid "Hmmm, we're having trouble finding this feed. It may have been deleted." #~ msgid "Hmmm, we're having trouble finding this feed. It may have been deleted."
#~ msgstr "" #~ msgstr ""
#: src/view/shell/bottom-bar/BottomBar.tsx:124 #: src/view/shell/bottom-bar/BottomBar.tsx:116
#: src/view/shell/desktop/LeftNav.tsx:305 #: src/view/shell/desktop/LeftNav.tsx:297
#: src/view/shell/Drawer.tsx:387 #: src/view/shell/Drawer.tsx:379
#: src/view/shell/Drawer.tsx:388 #: src/view/shell/Drawer.tsx:380
msgid "Home" msgid "Home"
msgstr "होम फीड" msgstr "होम फीड"
@ -1055,7 +1055,7 @@ msgstr "आमंत्रण कोड"
msgid "Invite code not accepted. Check that you input it correctly and try again." msgid "Invite code not accepted. Check that you input it correctly and try again."
msgstr "" msgstr ""
#: src/view/shell/Drawer.tsx:629 #: src/view/shell/Drawer.tsx:621
msgid "Invite codes: {invitesAvailable} available" msgid "Invite codes: {invitesAvailable} available"
msgstr "" msgstr ""
@ -1154,9 +1154,9 @@ msgid "List Name"
msgstr "सूची का नाम" msgstr "सूची का नाम"
#: src/view/screens/Profile.tsx:165 #: src/view/screens/Profile.tsx:165
#: src/view/shell/desktop/LeftNav.tsx:381 #: src/view/shell/desktop/LeftNav.tsx:373
#: src/view/shell/Drawer.tsx:479 #: src/view/shell/Drawer.tsx:471
#: src/view/shell/Drawer.tsx:480 #: src/view/shell/Drawer.tsx:472
msgid "Lists" msgid "Lists"
msgstr "सूची" msgstr "सूची"
@ -1165,7 +1165,7 @@ msgstr "सूची"
msgid "Load more posts" msgid "Load more posts"
msgstr "अधिक पोस्ट लोड करें" msgstr "अधिक पोस्ट लोड करें"
#: src/view/screens/Notifications.tsx:130 #: src/view/screens/Notifications.tsx:141
msgid "Load new notifications" msgid "Load new notifications"
msgstr "नई सूचनाएं लोड करें" msgstr "नई सूचनाएं लोड करें"
@ -1216,9 +1216,9 @@ msgstr ""
#: src/view/screens/Moderation.tsx:63 #: src/view/screens/Moderation.tsx:63
#: src/view/screens/Settings.tsx:563 #: src/view/screens/Settings.tsx:563
#: src/view/shell/desktop/LeftNav.tsx:399 #: src/view/shell/desktop/LeftNav.tsx:391
#: src/view/shell/Drawer.tsx:498 #: src/view/shell/Drawer.tsx:490
#: src/view/shell/Drawer.tsx:499 #: src/view/shell/Drawer.tsx:491
msgid "Moderation" msgid "Moderation"
msgstr "मॉडरेशन" msgstr "मॉडरेशन"
@ -1292,7 +1292,7 @@ msgstr "जन्मदिन"
msgid "My Feeds" msgid "My Feeds"
msgstr "मेरी फ़ीड" msgstr "मेरी फ़ीड"
#: src/view/shell/desktop/LeftNav.tsx:67 #: src/view/shell/desktop/LeftNav.tsx:64
msgid "My Profile" msgid "My Profile"
msgstr "मेरी प्रोफाइल" msgstr "मेरी प्रोफाइल"
@ -1320,11 +1320,11 @@ msgstr "नया"
#: src/view/screens/ProfileFeed.tsx:451 #: src/view/screens/ProfileFeed.tsx:451
#: src/view/screens/ProfileList.tsx:212 #: src/view/screens/ProfileList.tsx:212
#: src/view/screens/ProfileList.tsx:244 #: src/view/screens/ProfileList.tsx:244
#: src/view/shell/desktop/LeftNav.tsx:254 #: src/view/shell/desktop/LeftNav.tsx:246
msgid "New post" msgid "New post"
msgstr "नई पोस्ट" msgstr "नई पोस्ट"
#: src/view/shell/desktop/LeftNav.tsx:264 #: src/view/shell/desktop/LeftNav.tsx:256
msgid "New Post" msgid "New Post"
msgstr "नई पोस्ट" msgstr "नई पोस्ट"
@ -1394,12 +1394,12 @@ msgstr ""
#~ msgid "Note: Third-party apps that display Bluesky content may not respect this setting." #~ msgid "Note: Third-party apps that display Bluesky content may not respect this setting."
#~ msgstr "" #~ msgstr ""
#: src/view/screens/Notifications.tsx:97 #: src/view/screens/Notifications.tsx:108
#: src/view/screens/Notifications.tsx:121 #: src/view/screens/Notifications.tsx:132
#: src/view/shell/bottom-bar/BottomBar.tsx:195 #: src/view/shell/bottom-bar/BottomBar.tsx:187
#: src/view/shell/desktop/LeftNav.tsx:363 #: src/view/shell/desktop/LeftNav.tsx:355
#: src/view/shell/Drawer.tsx:424 #: src/view/shell/Drawer.tsx:416
#: src/view/shell/Drawer.tsx:425 #: src/view/shell/Drawer.tsx:417
msgid "Notifications" msgid "Notifications"
msgstr "सूचनाएं" msgstr "सूचनाएं"
@ -1424,7 +1424,7 @@ msgid "Opens configurable language settings"
msgstr "भाषा सेटिंग्स खोलें" msgstr "भाषा सेटिंग्स खोलें"
#: src/view/shell/desktop/RightNav.tsx:146 #: src/view/shell/desktop/RightNav.tsx:146
#: src/view/shell/Drawer.tsx:630 #: src/view/shell/Drawer.tsx:622
msgid "Opens list of invite codes" msgid "Opens list of invite codes"
msgstr "" msgstr ""
@ -1584,10 +1584,10 @@ msgstr "गोपनीयता नीति"
msgid "Processing..." msgid "Processing..."
msgstr "प्रसंस्करण..." msgstr "प्रसंस्करण..."
#: src/view/shell/bottom-bar/BottomBar.tsx:237 #: src/view/shell/bottom-bar/BottomBar.tsx:229
#: src/view/shell/Drawer.tsx:72 #: src/view/shell/Drawer.tsx:69
#: src/view/shell/Drawer.tsx:533 #: src/view/shell/Drawer.tsx:525
#: src/view/shell/Drawer.tsx:534 #: src/view/shell/Drawer.tsx:526
msgid "Profile" msgid "Profile"
msgstr "प्रोफ़ाइल" msgstr "प्रोफ़ाइल"
@ -1805,12 +1805,12 @@ msgstr "सहेजे गए फ़ीड"
#: src/view/com/util/forms/SearchInput.tsx:64 #: src/view/com/util/forms/SearchInput.tsx:64
#: src/view/screens/Search/Search.tsx:381 #: src/view/screens/Search/Search.tsx:381
#: src/view/screens/Search/Search.tsx:533 #: src/view/screens/Search/Search.tsx:533
#: src/view/shell/bottom-bar/BottomBar.tsx:146 #: src/view/shell/bottom-bar/BottomBar.tsx:138
#: src/view/shell/desktop/LeftNav.tsx:323 #: src/view/shell/desktop/LeftNav.tsx:315
#: src/view/shell/desktop/Search.tsx:161 #: src/view/shell/desktop/Search.tsx:161
#: src/view/shell/desktop/Search.tsx:170 #: src/view/shell/desktop/Search.tsx:170
#: src/view/shell/Drawer.tsx:351 #: src/view/shell/Drawer.tsx:343
#: src/view/shell/Drawer.tsx:352 #: src/view/shell/Drawer.tsx:344
msgid "Search" msgid "Search"
msgstr "खोज" msgstr "खोज"
@ -1862,8 +1862,8 @@ msgstr "ईमेल भेजें"
msgid "Send Email" msgid "Send Email"
msgstr "ईमेल भेजें" msgstr "ईमेल भेजें"
#: src/view/shell/Drawer.tsx:284 #: src/view/shell/Drawer.tsx:276
#: src/view/shell/Drawer.tsx:305 #: src/view/shell/Drawer.tsx:297
msgid "Send feedback" msgid "Send feedback"
msgstr "प्रतिक्रिया भेजें" msgstr "प्रतिक्रिया भेजें"
@ -1896,9 +1896,9 @@ msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your f
msgstr "इस सेटिंग को अपने निम्नलिखित फ़ीड में अपने सहेजे गए फ़ीड के नमूने दिखाने के लिए \"हाँ\" पर सेट करें। यह एक प्रयोगात्मक विशेषता है।।" msgstr "इस सेटिंग को अपने निम्नलिखित फ़ीड में अपने सहेजे गए फ़ीड के नमूने दिखाने के लिए \"हाँ\" पर सेट करें। यह एक प्रयोगात्मक विशेषता है।।"
#: src/view/screens/Settings.tsx:277 #: src/view/screens/Settings.tsx:277
#: src/view/shell/desktop/LeftNav.tsx:435 #: src/view/shell/desktop/LeftNav.tsx:427
#: src/view/shell/Drawer.tsx:554 #: src/view/shell/Drawer.tsx:546
#: src/view/shell/Drawer.tsx:555 #: src/view/shell/Drawer.tsx:547
msgid "Settings" msgid "Settings"
msgstr "सेटिंग्स" msgstr "सेटिंग्स"
@ -2439,7 +2439,7 @@ msgstr "आपका होस्टिंग प्रदाता"
#: src/view/screens/Settings.tsx:402 #: src/view/screens/Settings.tsx:402
#: src/view/shell/desktop/RightNav.tsx:127 #: src/view/shell/desktop/RightNav.tsx:127
#: src/view/shell/Drawer.tsx:644 #: src/view/shell/Drawer.tsx:636
msgid "Your invite codes are hidden when logged in using an App Password" msgid "Your invite codes are hidden when logged in using an App Password"
msgstr "" msgstr ""

View File

@ -16,7 +16,7 @@
* 3. Don't call this query's `refetch()` if you're trying to sync latest; call `checkUnread()` instead. * 3. Don't call this query's `refetch()` if you're trying to sync latest; call `checkUnread()` instead.
*/ */
import {useEffect} from 'react' import {useEffect, useRef} from 'react'
import {AppBskyFeedDefs} from '@atproto/api' import {AppBskyFeedDefs} from '@atproto/api'
import { import {
useInfiniteQuery, useInfiniteQuery,
@ -49,6 +49,8 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
const threadMutes = useMutedThreads() const threadMutes = useMutedThreads()
const unreads = useUnreadNotificationsApi() const unreads = useUnreadNotificationsApi()
const enabled = opts?.enabled !== false const enabled = opts?.enabled !== false
// state tracked across page fetches
const pageState = useRef({pageNum: 0, hasMarkedRead: false})
const query = useInfiniteQuery< const query = useInfiniteQuery<
FeedPage, FeedPage,
@ -60,17 +62,44 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
staleTime: STALE.INFINITY, staleTime: STALE.INFINITY,
queryKey: RQKEY(), queryKey: RQKEY(),
async queryFn({pageParam}: {pageParam: RQPageParam}) { async queryFn({pageParam}: {pageParam: RQPageParam}) {
let page = await fetchPage({ let page
if (!pageParam) {
// for the first page, we check the cached page held by the unread-checker first
page = unreads.getCachedUnreadPage()
// reset the page state
pageState.current = {pageNum: 0, hasMarkedRead: false}
}
if (!page) {
page = await fetchPage({
limit: PAGE_SIZE, limit: PAGE_SIZE,
cursor: pageParam, cursor: pageParam,
queryClient, queryClient,
moderationOpts, moderationOpts,
threadMutes, threadMutes,
}) })
}
// if the first page has an unread, mark all read // NOTE
if (!pageParam && page.items[0] && !page.items[0].notification.isRead) { // this section checks to see if we need to mark notifs read
// we want to wait until we've seen a read notification because
// of a timing challenge; marking read on the first page would
// cause subsequent pages of unread notifs to incorrectly come
// back as "read". we use page 6 as an abort condition, which means
// after ~180 notifs we give up on tracking unread state correctly
// -prf
if (!pageState.current.hasMarkedRead) {
let hasMarkedRead = false
if (
pageState.current.pageNum > 5 ||
page.items.some(item => item.notification.isRead)
) {
unreads.markAllRead() unreads.markAllRead()
hasMarkedRead = true
}
pageState.current = {
pageNum: pageState.current.pageNum + 1,
hasMarkedRead,
}
} }
return page return page

View File

@ -28,7 +28,10 @@ export interface FeedPage {
} }
export interface CachedFeedPage { export interface CachedFeedPage {
sessDid: string // used to invalidate on session changes /**
* if true, the cached page is recent enough to use as the response
*/
usableInFeed: boolean
syncedAt: Date syncedAt: Date
data: FeedPage | undefined data: FeedPage | undefined
} }

View File

@ -37,7 +37,7 @@ const apiContext = React.createContext<ApiContext>({
}) })
export function Provider({children}: React.PropsWithChildren<{}>) { export function Provider({children}: React.PropsWithChildren<{}>) {
const {hasSession, currentAccount} = useSession() const {hasSession} = useSession()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const moderationOpts = useModerationOpts() const moderationOpts = useModerationOpts()
const threadMutes = useMutedThreads() const threadMutes = useMutedThreads()
@ -46,7 +46,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
const checkUnreadRef = React.useRef<ApiContext['checkUnread'] | null>(null) const checkUnreadRef = React.useRef<ApiContext['checkUnread'] | null>(null)
const cacheRef = React.useRef<CachedFeedPage>({ const cacheRef = React.useRef<CachedFeedPage>({
sessDid: currentAccount?.did || '', usableInFeed: false,
syncedAt: new Date(), syncedAt: new Date(),
data: undefined, data: undefined,
}) })
@ -65,7 +65,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
React.useEffect(() => { React.useEffect(() => {
const listener = ({data}: MessageEvent) => { const listener = ({data}: MessageEvent) => {
cacheRef.current = { cacheRef.current = {
sessDid: currentAccount?.did || '', usableInFeed: false,
syncedAt: new Date(), syncedAt: new Date(),
data: undefined, data: undefined,
} }
@ -75,7 +75,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
return () => { return () => {
broadcast.removeEventListener('message', listener) broadcast.removeEventListener('message', listener)
} }
}, [setNumUnread, currentAccount]) }, [setNumUnread])
// create API // create API
const api = React.useMemo<ApiContext>(() => { const api = React.useMemo<ApiContext>(() => {
@ -119,7 +119,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
const lastIndexed = const lastIndexed =
page.items[0] && new Date(page.items[0].notification.indexedAt) page.items[0] && new Date(page.items[0].notification.indexedAt)
cacheRef.current = { cacheRef.current = {
sessDid: currentAccount?.did || '', usableInFeed: !!invalidate, // will be used immediately
data: page, data: page,
syncedAt: !lastIndexed || now > lastIndexed ? now : lastIndexed, syncedAt: !lastIndexed || now > lastIndexed ? now : lastIndexed,
} }
@ -136,14 +136,13 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
}, },
getCachedUnreadPage() { getCachedUnreadPage() {
// return cached page if was for the current user // return cached page if it's marked as fresh enough
// (protects against session changes serving data from the past session) if (cacheRef.current.usableInFeed) {
if (cacheRef.current.sessDid === currentAccount?.did) {
return cacheRef.current.data return cacheRef.current.data
} }
}, },
} }
}, [setNumUnread, queryClient, moderationOpts, threadMutes, currentAccount]) }, [setNumUnread, queryClient, moderationOpts, threadMutes])
checkUnreadRef.current = api.checkUnread checkUnreadRef.current = api.checkUnread
return ( return (

View File

@ -119,8 +119,7 @@ function groupNotifications(
Math.abs(ts2 - ts) < MS_2DAY && Math.abs(ts2 - ts) < MS_2DAY &&
notif.reason === groupedNotif.notification.reason && notif.reason === groupedNotif.notification.reason &&
notif.reasonSubject === groupedNotif.notification.reasonSubject && notif.reasonSubject === groupedNotif.notification.reasonSubject &&
notif.author.did !== groupedNotif.notification.author.did && notif.author.did !== groupedNotif.notification.author.did
notif.isRead === groupedNotif.notification.isRead
) { ) {
groupedNotif.additional = groupedNotif.additional || [] groupedNotif.additional = groupedNotif.additional || []
groupedNotif.additional.push(notif) groupedNotif.additional.push(notif)

View File

@ -37,6 +37,7 @@ export function NotificationsScreen({}: Props) {
const setMinimalShellMode = useSetMinimalShellMode() const setMinimalShellMode = useSetMinimalShellMode()
const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll() const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll()
const scrollElRef = React.useRef<FlatList>(null) const scrollElRef = React.useRef<FlatList>(null)
const checkLatestRef = React.useRef<() => void | null>()
const {screen} = useAnalytics() const {screen} = useAnalytics()
const pal = usePalette('default') const pal = usePalette('default')
const {isDesktop} = useWebMediaQueries() const {isDesktop} = useWebMediaQueries()
@ -63,16 +64,26 @@ export function NotificationsScreen({}: Props) {
} }
}, [scrollToTop, queryClient, unreadApi, hasNew]) }, [scrollToTop, queryClient, unreadApi, hasNew])
const onFocusCheckLatest = React.useCallback(() => {
// on focus, check for latest, but only invalidate if the user
// isnt scrolled down to avoid moving content underneath them
unreadApi.checkUnread({invalidate: !isScrolledDown})
}, [unreadApi, isScrolledDown])
checkLatestRef.current = onFocusCheckLatest
// on-visible setup // on-visible setup
// = // =
useFocusEffect( useFocusEffect(
React.useCallback(() => { React.useCallback(() => {
setMinimalShellMode(false) setMinimalShellMode(false)
logger.debug('NotificationsScreen: Updating feed') logger.debug('NotificationsScreen: Focus')
screen('Notifications') screen('Notifications')
return listenSoftReset(onPressLoadLatest) checkLatestRef.current?.()
}, [screen, onPressLoadLatest, setMinimalShellMode]), }, [screen, setMinimalShellMode]),
) )
React.useEffect(() => {
return listenSoftReset(onPressLoadLatest)
}, [onPressLoadLatest])
const ListHeaderComponent = React.useCallback(() => { const ListHeaderComponent = React.useCallback(() => {
if (isDesktop) { if (isDesktop) {

View File

@ -14,7 +14,6 @@ import {
FontAwesomeIcon, FontAwesomeIcon,
FontAwesomeIconStyle, FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome' } from '@fortawesome/react-native-fontawesome'
import {useQueryClient} from '@tanstack/react-query'
import {s, colors} from 'lib/styles' import {s, colors} from 'lib/styles'
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from 'lib/constants' import {FEEDBACK_FORM_URL, HELP_DESK_URL} from 'lib/constants'
import { import {
@ -51,9 +50,7 @@ import {useProfileQuery} from '#/state/queries/profile'
import {useUnreadNotifications} from '#/state/queries/notifications/unread' import {useUnreadNotifications} from '#/state/queries/notifications/unread'
import {emitSoftReset} from '#/state/events' import {emitSoftReset} from '#/state/events'
import {useInviteCodesQuery} from '#/state/queries/invites' import {useInviteCodesQuery} from '#/state/queries/invites'
import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed'
import {NavSignupCard} from '#/view/shell/NavSignupCard' import {NavSignupCard} from '#/view/shell/NavSignupCard'
import {truncateAndInvalidate} from '#/state/queries/util'
let DrawerProfileCard = ({ let DrawerProfileCard = ({
account, account,
@ -109,7 +106,6 @@ export {DrawerProfileCard}
let DrawerContent = ({}: {}): React.ReactNode => { let DrawerContent = ({}: {}): React.ReactNode => {
const theme = useTheme() const theme = useTheme()
const pal = usePalette('default') const pal = usePalette('default')
const queryClient = useQueryClient()
const setDrawerOpen = useSetDrawerOpen() const setDrawerOpen = useSetDrawerOpen()
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
const {track} = useAnalytics() const {track} = useAnalytics()
@ -140,16 +136,12 @@ let DrawerContent = ({}: {}): React.ReactNode => {
} else if (tabState === TabState.Inside) { } else if (tabState === TabState.Inside) {
navigation.dispatch(StackActions.popToTop()) navigation.dispatch(StackActions.popToTop())
} else { } else {
if (tab === 'Notifications') {
// fetch new notifs on view
truncateAndInvalidate(queryClient, NOTIFS_RQKEY())
}
// @ts-ignore must be Home, Search, Notifications, or MyProfile // @ts-ignore must be Home, Search, Notifications, or MyProfile
navigation.navigate(`${tab}Tab`) navigation.navigate(`${tab}Tab`)
} }
} }
}, },
[track, navigation, setDrawerOpen, currentAccount, queryClient], [track, navigation, setDrawerOpen, currentAccount],
) )
const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab]) const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab])

View File

@ -1,7 +1,6 @@
import React, {ComponentProps} from 'react' import React, {ComponentProps} from 'react'
import {GestureResponderEvent, TouchableOpacity, View} from 'react-native' import {GestureResponderEvent, TouchableOpacity, View} from 'react-native'
import Animated from 'react-native-reanimated' import Animated from 'react-native-reanimated'
import {useQueryClient} from '@tanstack/react-query'
import {StackActions} from '@react-navigation/native' import {StackActions} from '@react-navigation/native'
import {BottomTabBarProps} from '@react-navigation/bottom-tabs' import {BottomTabBarProps} from '@react-navigation/bottom-tabs'
import {useSafeAreaInsets} from 'react-native-safe-area-context' import {useSafeAreaInsets} from 'react-native-safe-area-context'
@ -31,8 +30,6 @@ import {useUnreadNotifications} from '#/state/queries/notifications/unread'
import {emitSoftReset} from '#/state/events' import {emitSoftReset} from '#/state/events'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {useProfileQuery} from '#/state/queries/profile' import {useProfileQuery} from '#/state/queries/profile'
import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed'
import {truncateAndInvalidate} from '#/state/queries/util'
type TabOptions = 'Home' | 'Search' | 'Notifications' | 'MyProfile' | 'Feeds' type TabOptions = 'Home' | 'Search' | 'Notifications' | 'MyProfile' | 'Feeds'
@ -41,7 +38,6 @@ export function BottomBar({navigation}: BottomTabBarProps) {
const {hasSession, currentAccount} = useSession() const {hasSession, currentAccount} = useSession()
const pal = usePalette('default') const pal = usePalette('default')
const {_} = useLingui() const {_} = useLingui()
const queryClient = useQueryClient()
const safeAreaInsets = useSafeAreaInsets() const safeAreaInsets = useSafeAreaInsets()
const {track} = useAnalytics() const {track} = useAnalytics()
const {footerHeight} = useShellLayout() const {footerHeight} = useShellLayout()
@ -61,14 +57,10 @@ export function BottomBar({navigation}: BottomTabBarProps) {
} else if (tabState === TabState.Inside) { } else if (tabState === TabState.Inside) {
navigation.dispatch(StackActions.popToTop()) navigation.dispatch(StackActions.popToTop())
} else { } else {
if (tab === 'Notifications') {
// fetch new notifs on view
truncateAndInvalidate(queryClient, NOTIFS_RQKEY())
}
navigation.navigate(`${tab}Tab`) navigation.navigate(`${tab}Tab`)
} }
}, },
[track, navigation, queryClient], [track, navigation],
) )
const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab]) const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab])
const onPressSearch = React.useCallback( const onPressSearch = React.useCallback(

View File

@ -45,10 +45,7 @@ import {useUnreadNotifications} from '#/state/queries/notifications/unread'
import {useComposerControls} from '#/state/shell/composer' import {useComposerControls} from '#/state/shell/composer'
import {useFetchHandle} from '#/state/queries/handle' import {useFetchHandle} from '#/state/queries/handle'
import {emitSoftReset} from '#/state/events' import {emitSoftReset} from '#/state/events'
import {useQueryClient} from '@tanstack/react-query'
import {RQKEY as NOTIFS_RQKEY} from '#/state/queries/notifications/feed'
import {NavSignupCard} from '#/view/shell/NavSignupCard' import {NavSignupCard} from '#/view/shell/NavSignupCard'
import {truncateAndInvalidate} from '#/state/queries/util'
function ProfileCard() { function ProfileCard() {
const {currentAccount} = useSession() const {currentAccount} = useSession()
@ -123,7 +120,6 @@ interface NavItemProps {
} }
function NavItem({count, href, icon, iconFilled, label}: NavItemProps) { function NavItem({count, href, icon, iconFilled, label}: NavItemProps) {
const pal = usePalette('default') const pal = usePalette('default')
const queryClient = useQueryClient()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const {isDesktop, isTablet} = useWebMediaQueries() const {isDesktop, isTablet} = useWebMediaQueries()
const [pathName] = React.useMemo(() => router.matchPath(href), [href]) const [pathName] = React.useMemo(() => router.matchPath(href), [href])
@ -149,14 +145,10 @@ function NavItem({count, href, icon, iconFilled, label}: NavItemProps) {
if (isCurrent) { if (isCurrent) {
emitSoftReset() emitSoftReset()
} else { } else {
if (href === '/notifications') {
// fetch new notifs on view
truncateAndInvalidate(queryClient, NOTIFS_RQKEY())
}
onPress() onPress()
} }
}, },
[onPress, isCurrent, queryClient, href], [onPress, isCurrent],
) )
return ( return (