about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--package.json2
-rw-r--r--src/lib/build-flags.ts1
-rw-r--r--src/lib/moderation.ts21
-rw-r--r--src/locale/locales/cs/messages.po84
-rw-r--r--src/locale/locales/en/messages.po84
-rw-r--r--src/locale/locales/es/messages.po84
-rw-r--r--src/locale/locales/fr/messages.po84
-rw-r--r--src/locale/locales/hi/messages.po84
-rw-r--r--src/view/com/composer/Composer.tsx2
-rw-r--r--src/view/com/composer/text-input/TextInput.web.tsx10
-rw-r--r--src/view/com/feeds/FeedPage.tsx2
-rw-r--r--src/view/com/pager/Pager.tsx2
-rw-r--r--src/view/com/pager/PagerWithHeader.tsx15
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx31
-rw-r--r--src/view/com/post/Post.tsx8
-rw-r--r--src/view/com/posts/Feed.tsx37
-rw-r--r--src/view/com/posts/FeedErrorMessage.tsx11
-rw-r--r--src/view/com/posts/FeedItem.tsx8
-rw-r--r--src/view/com/posts/FollowingEndOfFeed.tsx9
-rw-r--r--src/view/com/profile/ProfileCard.tsx3
-rw-r--r--src/view/com/profile/ProfileHeader.tsx32
-rw-r--r--src/view/com/profile/ProfileHeaderSuggestedFollows.tsx8
-rw-r--r--src/view/com/util/LoadingPlaceholder.tsx55
-rw-r--r--src/view/com/util/moderation/ContentHider.tsx43
-rw-r--r--src/view/com/util/moderation/PostHider.tsx126
-rw-r--r--src/view/com/util/moderation/ProfileHeaderAlerts.tsx16
-rw-r--r--src/view/com/util/post-embeds/index.tsx15
-rw-r--r--src/view/screens/Home.tsx9
-rw-r--r--src/view/screens/Profile.tsx19
-rw-r--r--src/view/screens/ProfileFeed.tsx7
-rw-r--r--src/view/screens/ProfileList.tsx55
-rw-r--r--src/view/shell/createNativeStackNavigatorWithAuth.tsx3
32 files changed, 618 insertions, 352 deletions
diff --git a/package.json b/package.json
index 0a0c75e7b..7a6efcd05 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,7 @@
     "perf:test:results": "NODE_ENV=test flashlight report .perf/results.json",
     "perf:measure": "NODE_ENV=test flashlight measure",
     "intl:build": "yarn intl:check && yarn intl:compile",
-    "intl:check": "yarn intl:extract && git diff-index --quiet HEAD || (echo '\n⚠️ i18n detected un-extracted translations\n' && exit 1)",
+    "intl:check": "yarn intl:extract && git diff-index -G'(^[^\\*# /])|(^#\\w)|(^\\s+[^\\*#/])' HEAD || (echo '\n⚠️ i18n detected un-extracted translations\n' && exit 1)",
     "intl:extract": "lingui extract",
     "intl:compile": "lingui compile"
   },
diff --git a/src/lib/build-flags.ts b/src/lib/build-flags.ts
index 28b650b6f..faefdd6ab 100644
--- a/src/lib/build-flags.ts
+++ b/src/lib/build-flags.ts
@@ -1 +1,2 @@
 export const LOGIN_INCLUDE_DEV_SERVERS = true
+export const PWI_ENABLED = false
diff --git a/src/lib/moderation.ts b/src/lib/moderation.ts
index 6c08606ee..8ba99128b 100644
--- a/src/lib/moderation.ts
+++ b/src/lib/moderation.ts
@@ -1,4 +1,4 @@
-import {ModerationCause, ProfileModeration} from '@atproto/api'
+import {ModerationCause, ProfileModeration, PostModeration} from '@atproto/api'
 
 export interface ModerationCauseDescription {
   name: string
@@ -92,6 +92,25 @@ export function getProfileModerationCauses(
   }) as ModerationCause[]
 }
 
+export function isPostMediaBlurred(
+  decisions: PostModeration['decisions'],
+): boolean {
+  return decisions.post.blurMedia
+}
+
+export function isQuoteBlurred(
+  decisions: PostModeration['decisions'],
+): boolean {
+  return (
+    decisions.quote?.blur ||
+    decisions.quote?.blurMedia ||
+    decisions.quote?.filter ||
+    decisions.quotedAccount?.blur ||
+    decisions.quotedAccount?.filter ||
+    false
+  )
+}
+
 export function isCauseALabelOnUri(
   cause: ModerationCause | undefined,
   uri: string,
diff --git a/src/locale/locales/cs/messages.po b/src/locale/locales/cs/messages.po
index 6cd60a889..c84625c25 100644
--- a/src/locale/locales/cs/messages.po
+++ b/src/locale/locales/cs/messages.po
@@ -83,7 +83,7 @@ msgstr ""
 
 #: src/view/com/modals/ListAddRemoveUsers.tsx:264
 #: src/view/com/modals/UserAddRemoveLists.tsx:187
-#: src/view/screens/ProfileList.tsx:675
+#: src/view/screens/ProfileList.tsx:684
 msgid "Add"
 msgstr ""
 
@@ -91,7 +91,7 @@ msgstr ""
 msgid "Add a content warning"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:665
+#: src/view/screens/ProfileList.tsx:674
 msgid "Add a user to this list"
 msgstr ""
 
@@ -199,7 +199,7 @@ msgstr ""
 msgid "Are you sure you'd like to discard this draft?"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:345
+#: src/view/screens/ProfileList.tsx:352
 msgid "Are you sure?"
 msgstr ""
 
@@ -242,11 +242,11 @@ msgstr ""
 msgid "Block Account"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:446
+#: src/view/screens/ProfileList.tsx:453
 msgid "Block accounts"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:302
+#: src/view/screens/ProfileList.tsx:309
 msgid "Block these accounts?"
 msgstr ""
 
@@ -270,7 +270,7 @@ msgstr ""
 msgid "Blocked post."
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:304
+#: src/view/screens/ProfileList.tsx:311
 msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you."
 msgstr ""
 
@@ -531,7 +531,7 @@ msgstr ""
 msgid "Copy"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:375
+#: src/view/screens/ProfileList.tsx:382
 msgid "Copy link to list"
 msgstr ""
 
@@ -555,7 +555,7 @@ msgstr ""
 msgid "Could not load feed"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:752
+#: src/view/screens/ProfileList.tsx:761
 msgid "Could not load list"
 msgstr ""
 
@@ -601,8 +601,8 @@ msgstr ""
 msgid "Delete app password"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:344
-#: src/view/screens/ProfileList.tsx:402
+#: src/view/screens/ProfileList.tsx:351
+#: src/view/screens/ProfileList.tsx:409
 msgid "Delete List"
 msgstr ""
 
@@ -691,7 +691,7 @@ msgstr ""
 msgid "Edit image"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:390
+#: src/view/screens/ProfileList.tsx:397
 msgid "Edit list details"
 msgstr ""
 
@@ -739,6 +739,10 @@ msgstr ""
 msgid "Enable this setting to only see replies between people you follow."
 msgstr ""
 
+#: src/view/screens/Profile.tsx:454
+msgid "End of feed"
+msgstr ""
+
 #: src/view/com/auth/create/Step1.tsx:71
 msgid "Enter the address of your provider:"
 msgstr ""
@@ -888,8 +892,8 @@ msgstr ""
 
 #: src/view/screens/ProfileFeed.tsx:111
 #: src/view/screens/ProfileFeed.tsx:116
-#: src/view/screens/ProfileList.tsx:761
-#: src/view/screens/ProfileList.tsx:766
+#: src/view/screens/ProfileList.tsx:770
+#: src/view/screens/ProfileList.tsx:775
 msgid "Go Back"
 msgstr ""
 
@@ -920,23 +924,23 @@ msgstr ""
 msgid "Hide user list"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:101
+#: src/view/com/posts/FeedErrorMessage.tsx:102
 msgid "Hmm, some kind of issue occured when contacting the feed server. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:89
+#: src/view/com/posts/FeedErrorMessage.tsx:90
 msgid "Hmm, the feed server appears to be misconfigured. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:95
+#: src/view/com/posts/FeedErrorMessage.tsx:96
 msgid "Hmm, the feed server appears to be offline. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:92
+#: src/view/com/posts/FeedErrorMessage.tsx:93
 msgid "Hmm, the feed server gave a bad response. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:86
+#: src/view/com/posts/FeedErrorMessage.tsx:87
 msgid "Hmmm, we're having trouble finding this feed. It may have been deleted."
 msgstr ""
 
@@ -1074,7 +1078,7 @@ msgstr ""
 #~ msgid "Light"
 #~ msgstr ""
 
-#: src/view/screens/ProfileFeed.tsx:627
+#: src/view/screens/ProfileFeed.tsx:630
 msgid "Like this feed"
 msgstr ""
 
@@ -1122,7 +1126,7 @@ msgstr ""
 msgid "Login to account that is not listed"
 msgstr ""
 
-#: src/view/screens/ProfileFeed.tsx:479
+#: src/view/screens/ProfileFeed.tsx:480
 msgid "Looks like this feed is only available to users with a Bluesky account. Please sign up or sign in to view this feed!"
 msgstr ""
 
@@ -1152,7 +1156,7 @@ msgstr ""
 
 #: src/view/com/profile/ProfileHeader.tsx:520
 #: src/view/screens/ProfileFeed.tsx:369
-#: src/view/screens/ProfileList.tsx:506
+#: src/view/screens/ProfileList.tsx:513
 msgid "More options"
 msgstr ""
 
@@ -1164,11 +1168,11 @@ msgstr ""
 msgid "Mute Account"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:434
+#: src/view/screens/ProfileList.tsx:441
 msgid "Mute accounts"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:267
+#: src/view/screens/ProfileList.tsx:274
 msgid "Mute these accounts?"
 msgstr ""
 
@@ -1188,7 +1192,7 @@ msgstr ""
 msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:269
+#: src/view/screens/ProfileList.tsx:276
 msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
 msgstr ""
 
@@ -1223,10 +1227,10 @@ msgstr ""
 
 #: src/view/com/feeds/FeedPage.tsx:188
 #: src/view/screens/Feeds.tsx:510
-#: src/view/screens/Profile.tsx:382
-#: src/view/screens/ProfileFeed.tsx:449
-#: src/view/screens/ProfileList.tsx:199
-#: src/view/screens/ProfileList.tsx:231
+#: src/view/screens/Profile.tsx:384
+#: src/view/screens/ProfileFeed.tsx:450
+#: src/view/screens/ProfileList.tsx:206
+#: src/view/screens/ProfileList.tsx:238
 #: src/view/shell/desktop/LeftNav.tsx:254
 msgid "New post"
 msgstr ""
@@ -1255,8 +1259,8 @@ msgstr ""
 msgid "No"
 msgstr ""
 
-#: src/view/screens/ProfileFeed.tsx:620
-#: src/view/screens/ProfileList.tsx:632
+#: src/view/screens/ProfileFeed.tsx:623
+#: src/view/screens/ProfileList.tsx:641
 msgid "No description"
 msgstr ""
 
@@ -1527,7 +1531,7 @@ msgstr ""
 msgid "Remove account"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:118
+#: src/view/com/posts/FeedErrorMessage.tsx:122
 msgid "Remove feed"
 msgstr ""
 
@@ -1544,7 +1548,7 @@ msgstr ""
 msgid "Remove image preview"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:119
+#: src/view/com/posts/FeedErrorMessage.tsx:123
 msgid "Remove this feed from your saved feeds?"
 msgstr ""
 
@@ -1569,7 +1573,7 @@ msgstr ""
 msgid "Report feed"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:416
+#: src/view/screens/ProfileList.tsx:423
 msgid "Report List"
 msgstr ""
 
@@ -1782,7 +1786,7 @@ msgstr ""
 
 #: src/view/com/profile/ProfileHeader.tsx:312
 #: src/view/com/util/forms/PostDropdownBtn.tsx:126
-#: src/view/screens/ProfileList.tsx:375
+#: src/view/screens/ProfileList.tsx:382
 msgid "Share"
 msgstr ""
 
@@ -1899,11 +1903,11 @@ msgstr ""
 msgid "Storybook"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:497
+#: src/view/screens/ProfileList.tsx:504
 msgid "Subscribe"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:493
+#: src/view/screens/ProfileList.tsx:500
 msgid "Subscribe to this list"
 msgstr ""
 
@@ -2108,7 +2112,7 @@ msgstr ""
 msgid "Username or email address"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:659
+#: src/view/screens/ProfileList.tsx:668
 msgid "Users"
 msgstr ""
 
@@ -2145,10 +2149,14 @@ msgstr ""
 msgid "We're so excited to have you join us!"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:98
+#: src/view/com/posts/FeedErrorMessage.tsx:99
 msgid "We're sorry, but this content is not viewable without a Bluesky account."
 msgstr ""
 
+#: src/view/com/posts/FeedErrorMessage.tsx:105
+msgid "We're sorry, but this feed is currently receiving high traffic and is temporarily unavailable. Please try again later."
+msgstr ""
+
 #: src/view/screens/Search/Search.tsx:236
 msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
 msgstr ""
diff --git a/src/locale/locales/en/messages.po b/src/locale/locales/en/messages.po
index 5e0aec468..330bec614 100644
--- a/src/locale/locales/en/messages.po
+++ b/src/locale/locales/en/messages.po
@@ -83,7 +83,7 @@ msgstr ""
 
 #: src/view/com/modals/ListAddRemoveUsers.tsx:264
 #: src/view/com/modals/UserAddRemoveLists.tsx:187
-#: src/view/screens/ProfileList.tsx:675
+#: src/view/screens/ProfileList.tsx:684
 msgid "Add"
 msgstr ""
 
@@ -91,7 +91,7 @@ msgstr ""
 msgid "Add a content warning"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:665
+#: src/view/screens/ProfileList.tsx:674
 msgid "Add a user to this list"
 msgstr ""
 
@@ -199,7 +199,7 @@ msgstr ""
 msgid "Are you sure you'd like to discard this draft?"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:345
+#: src/view/screens/ProfileList.tsx:352
 msgid "Are you sure?"
 msgstr ""
 
@@ -242,11 +242,11 @@ msgstr ""
 msgid "Block Account"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:446
+#: src/view/screens/ProfileList.tsx:453
 msgid "Block accounts"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:302
+#: src/view/screens/ProfileList.tsx:309
 msgid "Block these accounts?"
 msgstr ""
 
@@ -270,7 +270,7 @@ msgstr ""
 msgid "Blocked post."
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:304
+#: src/view/screens/ProfileList.tsx:311
 msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you."
 msgstr ""
 
@@ -531,7 +531,7 @@ msgstr ""
 msgid "Copy"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:375
+#: src/view/screens/ProfileList.tsx:382
 msgid "Copy link to list"
 msgstr ""
 
@@ -555,7 +555,7 @@ msgstr ""
 msgid "Could not load feed"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:752
+#: src/view/screens/ProfileList.tsx:761
 msgid "Could not load list"
 msgstr ""
 
@@ -601,8 +601,8 @@ msgstr ""
 msgid "Delete app password"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:344
-#: src/view/screens/ProfileList.tsx:402
+#: src/view/screens/ProfileList.tsx:351
+#: src/view/screens/ProfileList.tsx:409
 msgid "Delete List"
 msgstr ""
 
@@ -691,7 +691,7 @@ msgstr ""
 msgid "Edit image"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:390
+#: src/view/screens/ProfileList.tsx:397
 msgid "Edit list details"
 msgstr ""
 
@@ -739,6 +739,10 @@ msgstr ""
 msgid "Enable this setting to only see replies between people you follow."
 msgstr ""
 
+#: src/view/screens/Profile.tsx:454
+msgid "End of feed"
+msgstr ""
+
 #: src/view/com/auth/create/Step1.tsx:71
 msgid "Enter the address of your provider:"
 msgstr ""
@@ -888,8 +892,8 @@ msgstr ""
 
 #: src/view/screens/ProfileFeed.tsx:111
 #: src/view/screens/ProfileFeed.tsx:116
-#: src/view/screens/ProfileList.tsx:761
-#: src/view/screens/ProfileList.tsx:766
+#: src/view/screens/ProfileList.tsx:770
+#: src/view/screens/ProfileList.tsx:775
 msgid "Go Back"
 msgstr ""
 
@@ -920,23 +924,23 @@ msgstr ""
 msgid "Hide user list"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:101
+#: src/view/com/posts/FeedErrorMessage.tsx:102
 msgid "Hmm, some kind of issue occured when contacting the feed server. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:89
+#: src/view/com/posts/FeedErrorMessage.tsx:90
 msgid "Hmm, the feed server appears to be misconfigured. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:95
+#: src/view/com/posts/FeedErrorMessage.tsx:96
 msgid "Hmm, the feed server appears to be offline. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:92
+#: src/view/com/posts/FeedErrorMessage.tsx:93
 msgid "Hmm, the feed server gave a bad response. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:86
+#: src/view/com/posts/FeedErrorMessage.tsx:87
 msgid "Hmmm, we're having trouble finding this feed. It may have been deleted."
 msgstr ""
 
@@ -1074,7 +1078,7 @@ msgstr ""
 #~ msgid "Light"
 #~ msgstr ""
 
-#: src/view/screens/ProfileFeed.tsx:627
+#: src/view/screens/ProfileFeed.tsx:630
 msgid "Like this feed"
 msgstr ""
 
@@ -1122,7 +1126,7 @@ msgstr ""
 msgid "Login to account that is not listed"
 msgstr ""
 
-#: src/view/screens/ProfileFeed.tsx:479
+#: src/view/screens/ProfileFeed.tsx:480
 msgid "Looks like this feed is only available to users with a Bluesky account. Please sign up or sign in to view this feed!"
 msgstr ""
 
@@ -1152,7 +1156,7 @@ msgstr ""
 
 #: src/view/com/profile/ProfileHeader.tsx:520
 #: src/view/screens/ProfileFeed.tsx:369
-#: src/view/screens/ProfileList.tsx:506
+#: src/view/screens/ProfileList.tsx:513
 msgid "More options"
 msgstr ""
 
@@ -1164,11 +1168,11 @@ msgstr ""
 msgid "Mute Account"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:434
+#: src/view/screens/ProfileList.tsx:441
 msgid "Mute accounts"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:267
+#: src/view/screens/ProfileList.tsx:274
 msgid "Mute these accounts?"
 msgstr ""
 
@@ -1188,7 +1192,7 @@ msgstr ""
 msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:269
+#: src/view/screens/ProfileList.tsx:276
 msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
 msgstr ""
 
@@ -1223,10 +1227,10 @@ msgstr ""
 
 #: src/view/com/feeds/FeedPage.tsx:188
 #: src/view/screens/Feeds.tsx:510
-#: src/view/screens/Profile.tsx:382
-#: src/view/screens/ProfileFeed.tsx:449
-#: src/view/screens/ProfileList.tsx:199
-#: src/view/screens/ProfileList.tsx:231
+#: src/view/screens/Profile.tsx:384
+#: src/view/screens/ProfileFeed.tsx:450
+#: src/view/screens/ProfileList.tsx:206
+#: src/view/screens/ProfileList.tsx:238
 #: src/view/shell/desktop/LeftNav.tsx:254
 msgid "New post"
 msgstr ""
@@ -1255,8 +1259,8 @@ msgstr ""
 msgid "No"
 msgstr ""
 
-#: src/view/screens/ProfileFeed.tsx:620
-#: src/view/screens/ProfileList.tsx:632
+#: src/view/screens/ProfileFeed.tsx:623
+#: src/view/screens/ProfileList.tsx:641
 msgid "No description"
 msgstr ""
 
@@ -1527,7 +1531,7 @@ msgstr ""
 msgid "Remove account"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:118
+#: src/view/com/posts/FeedErrorMessage.tsx:122
 msgid "Remove feed"
 msgstr ""
 
@@ -1544,7 +1548,7 @@ msgstr ""
 msgid "Remove image preview"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:119
+#: src/view/com/posts/FeedErrorMessage.tsx:123
 msgid "Remove this feed from your saved feeds?"
 msgstr ""
 
@@ -1569,7 +1573,7 @@ msgstr ""
 msgid "Report feed"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:416
+#: src/view/screens/ProfileList.tsx:423
 msgid "Report List"
 msgstr ""
 
@@ -1782,7 +1786,7 @@ msgstr ""
 
 #: src/view/com/profile/ProfileHeader.tsx:312
 #: src/view/com/util/forms/PostDropdownBtn.tsx:126
-#: src/view/screens/ProfileList.tsx:375
+#: src/view/screens/ProfileList.tsx:382
 msgid "Share"
 msgstr ""
 
@@ -1899,11 +1903,11 @@ msgstr ""
 msgid "Storybook"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:497
+#: src/view/screens/ProfileList.tsx:504
 msgid "Subscribe"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:493
+#: src/view/screens/ProfileList.tsx:500
 msgid "Subscribe to this list"
 msgstr ""
 
@@ -2108,7 +2112,7 @@ msgstr ""
 msgid "Username or email address"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:659
+#: src/view/screens/ProfileList.tsx:668
 msgid "Users"
 msgstr ""
 
@@ -2145,10 +2149,14 @@ msgstr ""
 msgid "We're so excited to have you join us!"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:98
+#: src/view/com/posts/FeedErrorMessage.tsx:99
 msgid "We're sorry, but this content is not viewable without a Bluesky account."
 msgstr ""
 
+#: src/view/com/posts/FeedErrorMessage.tsx:105
+msgid "We're sorry, but this feed is currently receiving high traffic and is temporarily unavailable. Please try again later."
+msgstr ""
+
 #: src/view/screens/Search/Search.tsx:236
 msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
 msgstr ""
diff --git a/src/locale/locales/es/messages.po b/src/locale/locales/es/messages.po
index baab22c72..ae43a7323 100644
--- a/src/locale/locales/es/messages.po
+++ b/src/locale/locales/es/messages.po
@@ -83,7 +83,7 @@ msgstr ""
 
 #: src/view/com/modals/ListAddRemoveUsers.tsx:264
 #: src/view/com/modals/UserAddRemoveLists.tsx:187
-#: src/view/screens/ProfileList.tsx:675
+#: src/view/screens/ProfileList.tsx:684
 msgid "Add"
 msgstr ""
 
@@ -91,7 +91,7 @@ msgstr ""
 msgid "Add a content warning"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:665
+#: src/view/screens/ProfileList.tsx:674
 msgid "Add a user to this list"
 msgstr ""
 
@@ -199,7 +199,7 @@ msgstr ""
 msgid "Are you sure you'd like to discard this draft?"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:345
+#: src/view/screens/ProfileList.tsx:352
 msgid "Are you sure?"
 msgstr ""
 
@@ -242,11 +242,11 @@ msgstr ""
 msgid "Block Account"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:446
+#: src/view/screens/ProfileList.tsx:453
 msgid "Block accounts"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:302
+#: src/view/screens/ProfileList.tsx:309
 msgid "Block these accounts?"
 msgstr ""
 
@@ -270,7 +270,7 @@ msgstr ""
 msgid "Blocked post."
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:304
+#: src/view/screens/ProfileList.tsx:311
 msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you."
 msgstr ""
 
@@ -531,7 +531,7 @@ msgstr ""
 msgid "Copy"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:375
+#: src/view/screens/ProfileList.tsx:382
 msgid "Copy link to list"
 msgstr ""
 
@@ -555,7 +555,7 @@ msgstr ""
 msgid "Could not load feed"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:752
+#: src/view/screens/ProfileList.tsx:761
 msgid "Could not load list"
 msgstr ""
 
@@ -601,8 +601,8 @@ msgstr ""
 msgid "Delete app password"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:344
-#: src/view/screens/ProfileList.tsx:402
+#: src/view/screens/ProfileList.tsx:351
+#: src/view/screens/ProfileList.tsx:409
 msgid "Delete List"
 msgstr ""
 
@@ -691,7 +691,7 @@ msgstr ""
 msgid "Edit image"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:390
+#: src/view/screens/ProfileList.tsx:397
 msgid "Edit list details"
 msgstr ""
 
@@ -739,6 +739,10 @@ msgstr ""
 msgid "Enable this setting to only see replies between people you follow."
 msgstr ""
 
+#: src/view/screens/Profile.tsx:454
+msgid "End of feed"
+msgstr ""
+
 #: src/view/com/auth/create/Step1.tsx:71
 msgid "Enter the address of your provider:"
 msgstr ""
@@ -888,8 +892,8 @@ msgstr ""
 
 #: src/view/screens/ProfileFeed.tsx:111
 #: src/view/screens/ProfileFeed.tsx:116
-#: src/view/screens/ProfileList.tsx:761
-#: src/view/screens/ProfileList.tsx:766
+#: src/view/screens/ProfileList.tsx:770
+#: src/view/screens/ProfileList.tsx:775
 msgid "Go Back"
 msgstr ""
 
@@ -920,23 +924,23 @@ msgstr ""
 msgid "Hide user list"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:101
+#: src/view/com/posts/FeedErrorMessage.tsx:102
 msgid "Hmm, some kind of issue occured when contacting the feed server. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:89
+#: src/view/com/posts/FeedErrorMessage.tsx:90
 msgid "Hmm, the feed server appears to be misconfigured. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:95
+#: src/view/com/posts/FeedErrorMessage.tsx:96
 msgid "Hmm, the feed server appears to be offline. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:92
+#: src/view/com/posts/FeedErrorMessage.tsx:93
 msgid "Hmm, the feed server gave a bad response. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:86
+#: src/view/com/posts/FeedErrorMessage.tsx:87
 msgid "Hmmm, we're having trouble finding this feed. It may have been deleted."
 msgstr ""
 
@@ -1074,7 +1078,7 @@ msgstr ""
 #~ msgid "Light"
 #~ msgstr ""
 
-#: src/view/screens/ProfileFeed.tsx:627
+#: src/view/screens/ProfileFeed.tsx:630
 msgid "Like this feed"
 msgstr ""
 
@@ -1122,7 +1126,7 @@ msgstr ""
 msgid "Login to account that is not listed"
 msgstr ""
 
-#: src/view/screens/ProfileFeed.tsx:479
+#: src/view/screens/ProfileFeed.tsx:480
 msgid "Looks like this feed is only available to users with a Bluesky account. Please sign up or sign in to view this feed!"
 msgstr ""
 
@@ -1152,7 +1156,7 @@ msgstr ""
 
 #: src/view/com/profile/ProfileHeader.tsx:520
 #: src/view/screens/ProfileFeed.tsx:369
-#: src/view/screens/ProfileList.tsx:506
+#: src/view/screens/ProfileList.tsx:513
 msgid "More options"
 msgstr ""
 
@@ -1164,11 +1168,11 @@ msgstr ""
 msgid "Mute Account"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:434
+#: src/view/screens/ProfileList.tsx:441
 msgid "Mute accounts"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:267
+#: src/view/screens/ProfileList.tsx:274
 msgid "Mute these accounts?"
 msgstr ""
 
@@ -1188,7 +1192,7 @@ msgstr ""
 msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:269
+#: src/view/screens/ProfileList.tsx:276
 msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
 msgstr ""
 
@@ -1223,10 +1227,10 @@ msgstr ""
 
 #: src/view/com/feeds/FeedPage.tsx:188
 #: src/view/screens/Feeds.tsx:510
-#: src/view/screens/Profile.tsx:382
-#: src/view/screens/ProfileFeed.tsx:449
-#: src/view/screens/ProfileList.tsx:199
-#: src/view/screens/ProfileList.tsx:231
+#: src/view/screens/Profile.tsx:384
+#: src/view/screens/ProfileFeed.tsx:450
+#: src/view/screens/ProfileList.tsx:206
+#: src/view/screens/ProfileList.tsx:238
 #: src/view/shell/desktop/LeftNav.tsx:254
 msgid "New post"
 msgstr ""
@@ -1255,8 +1259,8 @@ msgstr ""
 msgid "No"
 msgstr ""
 
-#: src/view/screens/ProfileFeed.tsx:620
-#: src/view/screens/ProfileList.tsx:632
+#: src/view/screens/ProfileFeed.tsx:623
+#: src/view/screens/ProfileList.tsx:641
 msgid "No description"
 msgstr ""
 
@@ -1527,7 +1531,7 @@ msgstr ""
 msgid "Remove account"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:118
+#: src/view/com/posts/FeedErrorMessage.tsx:122
 msgid "Remove feed"
 msgstr ""
 
@@ -1544,7 +1548,7 @@ msgstr ""
 msgid "Remove image preview"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:119
+#: src/view/com/posts/FeedErrorMessage.tsx:123
 msgid "Remove this feed from your saved feeds?"
 msgstr ""
 
@@ -1569,7 +1573,7 @@ msgstr ""
 msgid "Report feed"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:416
+#: src/view/screens/ProfileList.tsx:423
 msgid "Report List"
 msgstr ""
 
@@ -1782,7 +1786,7 @@ msgstr ""
 
 #: src/view/com/profile/ProfileHeader.tsx:312
 #: src/view/com/util/forms/PostDropdownBtn.tsx:126
-#: src/view/screens/ProfileList.tsx:375
+#: src/view/screens/ProfileList.tsx:382
 msgid "Share"
 msgstr ""
 
@@ -1899,11 +1903,11 @@ msgstr ""
 msgid "Storybook"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:497
+#: src/view/screens/ProfileList.tsx:504
 msgid "Subscribe"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:493
+#: src/view/screens/ProfileList.tsx:500
 msgid "Subscribe to this list"
 msgstr ""
 
@@ -2108,7 +2112,7 @@ msgstr ""
 msgid "Username or email address"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:659
+#: src/view/screens/ProfileList.tsx:668
 msgid "Users"
 msgstr ""
 
@@ -2145,10 +2149,14 @@ msgstr ""
 msgid "We're so excited to have you join us!"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:98
+#: src/view/com/posts/FeedErrorMessage.tsx:99
 msgid "We're sorry, but this content is not viewable without a Bluesky account."
 msgstr ""
 
+#: src/view/com/posts/FeedErrorMessage.tsx:105
+msgid "We're sorry, but this feed is currently receiving high traffic and is temporarily unavailable. Please try again later."
+msgstr ""
+
 #: src/view/screens/Search/Search.tsx:236
 msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
 msgstr ""
diff --git a/src/locale/locales/fr/messages.po b/src/locale/locales/fr/messages.po
index 95b10a094..4c5351c89 100644
--- a/src/locale/locales/fr/messages.po
+++ b/src/locale/locales/fr/messages.po
@@ -83,7 +83,7 @@ msgstr ""
 
 #: src/view/com/modals/ListAddRemoveUsers.tsx:264
 #: src/view/com/modals/UserAddRemoveLists.tsx:187
-#: src/view/screens/ProfileList.tsx:675
+#: src/view/screens/ProfileList.tsx:684
 msgid "Add"
 msgstr ""
 
@@ -91,7 +91,7 @@ msgstr ""
 msgid "Add a content warning"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:665
+#: src/view/screens/ProfileList.tsx:674
 msgid "Add a user to this list"
 msgstr ""
 
@@ -199,7 +199,7 @@ msgstr ""
 msgid "Are you sure you'd like to discard this draft?"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:345
+#: src/view/screens/ProfileList.tsx:352
 msgid "Are you sure?"
 msgstr ""
 
@@ -242,11 +242,11 @@ msgstr ""
 msgid "Block Account"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:446
+#: src/view/screens/ProfileList.tsx:453
 msgid "Block accounts"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:302
+#: src/view/screens/ProfileList.tsx:309
 msgid "Block these accounts?"
 msgstr ""
 
@@ -270,7 +270,7 @@ msgstr ""
 msgid "Blocked post."
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:304
+#: src/view/screens/ProfileList.tsx:311
 msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you."
 msgstr ""
 
@@ -531,7 +531,7 @@ msgstr ""
 msgid "Copy"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:375
+#: src/view/screens/ProfileList.tsx:382
 msgid "Copy link to list"
 msgstr ""
 
@@ -555,7 +555,7 @@ msgstr ""
 msgid "Could not load feed"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:752
+#: src/view/screens/ProfileList.tsx:761
 msgid "Could not load list"
 msgstr ""
 
@@ -601,8 +601,8 @@ msgstr ""
 msgid "Delete app password"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:344
-#: src/view/screens/ProfileList.tsx:402
+#: src/view/screens/ProfileList.tsx:351
+#: src/view/screens/ProfileList.tsx:409
 msgid "Delete List"
 msgstr ""
 
@@ -691,7 +691,7 @@ msgstr ""
 msgid "Edit image"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:390
+#: src/view/screens/ProfileList.tsx:397
 msgid "Edit list details"
 msgstr ""
 
@@ -739,6 +739,10 @@ msgstr ""
 msgid "Enable this setting to only see replies between people you follow."
 msgstr ""
 
+#: src/view/screens/Profile.tsx:454
+msgid "End of feed"
+msgstr ""
+
 #: src/view/com/auth/create/Step1.tsx:71
 msgid "Enter the address of your provider:"
 msgstr ""
@@ -888,8 +892,8 @@ msgstr ""
 
 #: src/view/screens/ProfileFeed.tsx:111
 #: src/view/screens/ProfileFeed.tsx:116
-#: src/view/screens/ProfileList.tsx:761
-#: src/view/screens/ProfileList.tsx:766
+#: src/view/screens/ProfileList.tsx:770
+#: src/view/screens/ProfileList.tsx:775
 msgid "Go Back"
 msgstr ""
 
@@ -920,23 +924,23 @@ msgstr ""
 msgid "Hide user list"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:101
+#: src/view/com/posts/FeedErrorMessage.tsx:102
 msgid "Hmm, some kind of issue occured when contacting the feed server. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:89
+#: src/view/com/posts/FeedErrorMessage.tsx:90
 msgid "Hmm, the feed server appears to be misconfigured. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:95
+#: src/view/com/posts/FeedErrorMessage.tsx:96
 msgid "Hmm, the feed server appears to be offline. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:92
+#: src/view/com/posts/FeedErrorMessage.tsx:93
 msgid "Hmm, the feed server gave a bad response. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:86
+#: src/view/com/posts/FeedErrorMessage.tsx:87
 msgid "Hmmm, we're having trouble finding this feed. It may have been deleted."
 msgstr ""
 
@@ -1074,7 +1078,7 @@ msgstr ""
 #~ msgid "Light"
 #~ msgstr ""
 
-#: src/view/screens/ProfileFeed.tsx:627
+#: src/view/screens/ProfileFeed.tsx:630
 msgid "Like this feed"
 msgstr ""
 
@@ -1122,7 +1126,7 @@ msgstr ""
 msgid "Login to account that is not listed"
 msgstr ""
 
-#: src/view/screens/ProfileFeed.tsx:479
+#: src/view/screens/ProfileFeed.tsx:480
 msgid "Looks like this feed is only available to users with a Bluesky account. Please sign up or sign in to view this feed!"
 msgstr ""
 
@@ -1152,7 +1156,7 @@ msgstr ""
 
 #: src/view/com/profile/ProfileHeader.tsx:520
 #: src/view/screens/ProfileFeed.tsx:369
-#: src/view/screens/ProfileList.tsx:506
+#: src/view/screens/ProfileList.tsx:513
 msgid "More options"
 msgstr ""
 
@@ -1164,11 +1168,11 @@ msgstr ""
 msgid "Mute Account"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:434
+#: src/view/screens/ProfileList.tsx:441
 msgid "Mute accounts"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:267
+#: src/view/screens/ProfileList.tsx:274
 msgid "Mute these accounts?"
 msgstr ""
 
@@ -1188,7 +1192,7 @@ msgstr ""
 msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:269
+#: src/view/screens/ProfileList.tsx:276
 msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
 msgstr ""
 
@@ -1223,10 +1227,10 @@ msgstr ""
 
 #: src/view/com/feeds/FeedPage.tsx:188
 #: src/view/screens/Feeds.tsx:510
-#: src/view/screens/Profile.tsx:382
-#: src/view/screens/ProfileFeed.tsx:449
-#: src/view/screens/ProfileList.tsx:199
-#: src/view/screens/ProfileList.tsx:231
+#: src/view/screens/Profile.tsx:384
+#: src/view/screens/ProfileFeed.tsx:450
+#: src/view/screens/ProfileList.tsx:206
+#: src/view/screens/ProfileList.tsx:238
 #: src/view/shell/desktop/LeftNav.tsx:254
 msgid "New post"
 msgstr ""
@@ -1255,8 +1259,8 @@ msgstr ""
 msgid "No"
 msgstr ""
 
-#: src/view/screens/ProfileFeed.tsx:620
-#: src/view/screens/ProfileList.tsx:632
+#: src/view/screens/ProfileFeed.tsx:623
+#: src/view/screens/ProfileList.tsx:641
 msgid "No description"
 msgstr ""
 
@@ -1527,7 +1531,7 @@ msgstr ""
 msgid "Remove account"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:118
+#: src/view/com/posts/FeedErrorMessage.tsx:122
 msgid "Remove feed"
 msgstr ""
 
@@ -1544,7 +1548,7 @@ msgstr ""
 msgid "Remove image preview"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:119
+#: src/view/com/posts/FeedErrorMessage.tsx:123
 msgid "Remove this feed from your saved feeds?"
 msgstr ""
 
@@ -1569,7 +1573,7 @@ msgstr ""
 msgid "Report feed"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:416
+#: src/view/screens/ProfileList.tsx:423
 msgid "Report List"
 msgstr ""
 
@@ -1782,7 +1786,7 @@ msgstr ""
 
 #: src/view/com/profile/ProfileHeader.tsx:312
 #: src/view/com/util/forms/PostDropdownBtn.tsx:126
-#: src/view/screens/ProfileList.tsx:375
+#: src/view/screens/ProfileList.tsx:382
 msgid "Share"
 msgstr ""
 
@@ -1899,11 +1903,11 @@ msgstr ""
 msgid "Storybook"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:497
+#: src/view/screens/ProfileList.tsx:504
 msgid "Subscribe"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:493
+#: src/view/screens/ProfileList.tsx:500
 msgid "Subscribe to this list"
 msgstr ""
 
@@ -2108,7 +2112,7 @@ msgstr ""
 msgid "Username or email address"
 msgstr ""
 
-#: src/view/screens/ProfileList.tsx:659
+#: src/view/screens/ProfileList.tsx:668
 msgid "Users"
 msgstr ""
 
@@ -2145,10 +2149,14 @@ msgstr ""
 msgid "We're so excited to have you join us!"
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:98
+#: src/view/com/posts/FeedErrorMessage.tsx:99
 msgid "We're sorry, but this content is not viewable without a Bluesky account."
 msgstr ""
 
+#: src/view/com/posts/FeedErrorMessage.tsx:105
+msgid "We're sorry, but this feed is currently receiving high traffic and is temporarily unavailable. Please try again later."
+msgstr ""
+
 #: src/view/screens/Search/Search.tsx:236
 msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
 msgstr ""
diff --git a/src/locale/locales/hi/messages.po b/src/locale/locales/hi/messages.po
index e442483db..9e85e0a5c 100644
--- a/src/locale/locales/hi/messages.po
+++ b/src/locale/locales/hi/messages.po
@@ -83,7 +83,7 @@ msgstr "अकाउंट के विकल्प"
 
 #: src/view/com/modals/ListAddRemoveUsers.tsx:264
 #: src/view/com/modals/UserAddRemoveLists.tsx:187
-#: src/view/screens/ProfileList.tsx:675
+#: src/view/screens/ProfileList.tsx:684
 msgid "Add"
 msgstr "ऐड करो"
 
@@ -91,7 +91,7 @@ msgstr "ऐड करो"
 msgid "Add a content warning"
 msgstr "सामग्री चेतावनी जोड़ें"
 
-#: src/view/screens/ProfileList.tsx:665
+#: src/view/screens/ProfileList.tsx:674
 msgid "Add a user to this list"
 msgstr "इस सूची में किसी को जोड़ें"
 
@@ -199,7 +199,7 @@ msgstr "क्या आप वाकई ऐप पासवर्ड \"{name}\"
 msgid "Are you sure you'd like to discard this draft?"
 msgstr "क्या आप वाकई इस ड्राफ्ट को हटाना करना चाहेंगे?"
 
-#: src/view/screens/ProfileList.tsx:345
+#: src/view/screens/ProfileList.tsx:352
 msgid "Are you sure?"
 msgstr "क्या आप वास्तव में इसे करना चाहते हैं?"
 
@@ -242,11 +242,11 @@ msgstr "जन्मदिन:"
 msgid "Block Account"
 msgstr "खाता ब्लॉक करें"
 
-#: src/view/screens/ProfileList.tsx:446
+#: src/view/screens/ProfileList.tsx:453
 msgid "Block accounts"
 msgstr "खाता ब्लॉक करें"
 
-#: src/view/screens/ProfileList.tsx:302
+#: src/view/screens/ProfileList.tsx:309
 msgid "Block these accounts?"
 msgstr "खाता ब्लॉक करें?"
 
@@ -270,7 +270,7 @@ msgstr "अवरुद्ध खाते आपके थ्रेड्स 
 msgid "Blocked post."
 msgstr "ब्लॉक पोस्ट।"
 
-#: src/view/screens/ProfileList.tsx:304
+#: src/view/screens/ProfileList.tsx:311
 msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you."
 msgstr "अवरोधन सार्वजनिक है. अवरुद्ध खाते आपके थ्रेड्स में उत्तर नहीं दे सकते, आपका उल्लेख नहीं कर सकते, या अन्यथा आपके साथ बातचीत नहीं कर सकते।"
 
@@ -527,7 +527,7 @@ msgstr "कॉपी कर ली"
 msgid "Copy"
 msgstr "कॉपी"
 
-#: src/view/screens/ProfileList.tsx:375
+#: src/view/screens/ProfileList.tsx:382
 msgid "Copy link to list"
 msgstr ""
 
@@ -551,7 +551,7 @@ msgstr "कॉपीराइट नीति"
 msgid "Could not load feed"
 msgstr "फ़ीड लोड नहीं कर सकता"
 
-#: src/view/screens/ProfileList.tsx:752
+#: src/view/screens/ProfileList.tsx:761
 msgid "Could not load list"
 msgstr "सूची लोड नहीं कर सकता"
 
@@ -597,8 +597,8 @@ msgstr "खाता हटाएं"
 msgid "Delete app password"
 msgstr "अप्प पासवर्ड हटाएं"
 
-#: src/view/screens/ProfileList.tsx:344
-#: src/view/screens/ProfileList.tsx:402
+#: src/view/screens/ProfileList.tsx:351
+#: src/view/screens/ProfileList.tsx:409
 msgid "Delete List"
 msgstr "सूची हटाएँ"
 
@@ -687,7 +687,7 @@ msgstr "प्रत्येक कोड एक बार काम करत
 msgid "Edit image"
 msgstr "छवि संपादित करें"
 
-#: src/view/screens/ProfileList.tsx:390
+#: src/view/screens/ProfileList.tsx:397
 msgid "Edit list details"
 msgstr "सूची विवरण संपादित करें"
 
@@ -735,6 +735,10 @@ msgstr "ईमेल:"
 msgid "Enable this setting to only see replies between people you follow."
 msgstr "इस सेटिंग को केवल उन लोगों के बीच जवाब देखने में सक्षम करें जिन्हें आप फॉलो करते हैं।।"
 
+#: src/view/screens/Profile.tsx:454
+msgid "End of feed"
+msgstr ""
+
 #: src/view/com/auth/create/Step1.tsx:71
 msgid "Enter the address of your provider:"
 msgstr "अपने प्रदाता का पता दर्ज करें:"
@@ -880,8 +884,8 @@ msgstr "वापस जाओ"
 
 #: src/view/screens/ProfileFeed.tsx:111
 #: src/view/screens/ProfileFeed.tsx:116
-#: src/view/screens/ProfileList.tsx:761
-#: src/view/screens/ProfileList.tsx:766
+#: src/view/screens/ProfileList.tsx:770
+#: src/view/screens/ProfileList.tsx:775
 msgid "Go Back"
 msgstr "वापस जाओ"
 
@@ -912,23 +916,23 @@ msgstr "इसे छिपाएं"
 msgid "Hide user list"
 msgstr "उपयोगकर्ता सूची छुपाएँ"
 
-#: src/view/com/posts/FeedErrorMessage.tsx:101
+#: src/view/com/posts/FeedErrorMessage.tsx:102
 msgid "Hmm, some kind of issue occured when contacting the feed server. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:89
+#: src/view/com/posts/FeedErrorMessage.tsx:90
 msgid "Hmm, the feed server appears to be misconfigured. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:95
+#: src/view/com/posts/FeedErrorMessage.tsx:96
 msgid "Hmm, the feed server appears to be offline. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:92
+#: src/view/com/posts/FeedErrorMessage.tsx:93
 msgid "Hmm, the feed server gave a bad response. Please let the feed owner know about this issue."
 msgstr ""
 
-#: src/view/com/posts/FeedErrorMessage.tsx:86
+#: src/view/com/posts/FeedErrorMessage.tsx:87
 msgid "Hmmm, we're having trouble finding this feed. It may have been deleted."
 msgstr ""
 
@@ -1066,7 +1070,7 @@ msgstr "चित्र पुस्तकालय"
 #~ msgid "Light"
 #~ msgstr "लाइट मोड"
 
-#: src/view/screens/ProfileFeed.tsx:627
+#: src/view/screens/ProfileFeed.tsx:630
 msgid "Like this feed"
 msgstr "इस फ़ीड को लाइक करो"
 
@@ -1114,7 +1118,7 @@ msgstr "स्थानीय देव सर्वर"
 msgid "Login to account that is not listed"
 msgstr "उस खाते में लॉग इन करें जो सूचीबद्ध नहीं है"
 
-#: src/view/screens/ProfileFeed.tsx:479
+#: src/view/screens/ProfileFeed.tsx:480
 msgid "Looks like this feed is only available to users with a Bluesky account. Please sign up or sign in to view this feed!"
 msgstr ""
 
@@ -1144,7 +1148,7 @@ msgstr "अधिक फ़ीड"
 
 #: src/view/com/profile/ProfileHeader.tsx:520
 #: src/view/screens/ProfileFeed.tsx:369
-#: src/view/screens/ProfileList.tsx:506
+#: src/view/screens/ProfileList.tsx:513
 msgid "More options"
 msgstr "अधिक विकल्प"
 
@@ -1156,11 +1160,11 @@ msgstr "अधिक विकल्प"
 msgid "Mute Account"
 msgstr "खाता म्यूट करें"
 
-#: src/view/screens/ProfileList.tsx:434
+#: src/view/screens/ProfileList.tsx:441
 msgid "Mute accounts"
 msgstr "खातों को म्यूट करें"
 
-#: src/view/screens/ProfileList.tsx:267
+#: src/view/screens/ProfileList.tsx:274
 msgid "Mute these accounts?"
 msgstr "इन खातों को म्यूट करें?"
 
@@ -1180,7 +1184,7 @@ msgstr "म्यूट किए गए खाते"
 msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private."
 msgstr "म्यूट किए गए खातों की पोस्ट आपके फ़ीड और आपकी सूचनाओं से हटा दी जाती हैं। म्यूट पूरी तरह से निजी हैं."
 
-#: src/view/screens/ProfileList.tsx:269
+#: src/view/screens/ProfileList.tsx:276
 msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them."
 msgstr "म्यूट करना निजी है. म्यूट किए गए खाते आपके साथ इंटरैक्ट कर सकते हैं, लेकिन आप उनकी पोस्ट नहीं देखेंगे या उनसे सूचनाएं प्राप्त नहीं करेंगे।"
 
@@ -1215,10 +1219,10 @@ msgstr "नया"
 
 #: src/view/com/feeds/FeedPage.tsx:188
 #: src/view/screens/Feeds.tsx:510
-#: src/view/screens/Profile.tsx:382
-#: src/view/screens/ProfileFeed.tsx:449
-#: src/view/screens/ProfileList.tsx:199
-#: src/view/screens/ProfileList.tsx:231
+#: src/view/screens/Profile.tsx:384
+#: src/view/screens/ProfileFeed.tsx:450
+#: src/view/screens/ProfileList.tsx:206
+#: src/view/screens/ProfileList.tsx:238
 #: src/view/shell/desktop/LeftNav.tsx:254
 msgid "New post"
 msgstr "नई पोस्ट"
@@ -1247,8 +1251,8 @@ msgstr "अगली फोटो"
 msgid "No"
 msgstr "नहीं"
 
-#: src/view/screens/ProfileFeed.tsx:620
-#: src/view/screens/ProfileList.tsx:632
+#: src/view/screens/ProfileFeed.tsx:623
+#: src/view/screens/ProfileList.tsx:641
 msgid "No description"
 msgstr "कोई विवरण नहीं"
 
@@ -1519,7 +1523,7 @@ msgstr "मेरे फ़ीड से {0} हटाएं?"
 msgid "Remove account"
 msgstr "खाता हटाएं"
 
-#: src/view/com/posts/FeedErrorMessage.tsx:118
+#: src/view/com/posts/FeedErrorMessage.tsx:122
 msgid "Remove feed"
 msgstr "फ़ीड हटाएँ"
 
@@ -1536,7 +1540,7 @@ msgstr "छवि निकालें"
 msgid "Remove image preview"
 msgstr "छवि पूर्वावलोकन निकालें"
 
-#: src/view/com/posts/FeedErrorMessage.tsx:119
+#: src/view/com/posts/FeedErrorMessage.tsx:123
 msgid "Remove this feed from your saved feeds?"
 msgstr "इस फ़ीड को सहेजे गए फ़ीड से हटा दें?"
 
@@ -1561,7 +1565,7 @@ msgstr "रिपोर्ट"
 msgid "Report feed"
 msgstr "रिपोर्ट फ़ीड"
 
-#: src/view/screens/ProfileList.tsx:416
+#: src/view/screens/ProfileList.tsx:423
 msgid "Report List"
 msgstr "रिपोर्ट सूची"
 
@@ -1774,7 +1778,7 @@ msgstr "यौन गतिविधि या कामुक नग्नत
 
 #: src/view/com/profile/ProfileHeader.tsx:312
 #: src/view/com/util/forms/PostDropdownBtn.tsx:126
-#: src/view/screens/ProfileList.tsx:375
+#: src/view/screens/ProfileList.tsx:382
 msgid "Share"
 msgstr "शेयर"
 
@@ -1891,11 +1895,11 @@ msgstr "स्थिति पृष्ठ"
 msgid "Storybook"
 msgstr "Storybook"
 
-#: src/view/screens/ProfileList.tsx:497
+#: src/view/screens/ProfileList.tsx:504
 msgid "Subscribe"
 msgstr "सब्सक्राइब"
 
-#: src/view/screens/ProfileList.tsx:493
+#: src/view/screens/ProfileList.tsx:500
 msgid "Subscribe to this list"
 msgstr "इस सूची को सब्सक्राइब करें"
 
@@ -2100,7 +2104,7 @@ msgstr "लोग सूचियाँ"
 msgid "Username or email address"
 msgstr "यूजर नाम या ईमेल पता"
 
-#: src/view/screens/ProfileList.tsx:659
+#: src/view/screens/ProfileList.tsx:668
 msgid "Users"
 msgstr "यूजर लोग"
 
@@ -2137,10 +2141,14 @@ msgstr "साइट पर जाएं"
 msgid "We're so excited to have you join us!"
 msgstr "हम आपके हमारी सेवा में शामिल होने को लेकर बहुत उत्साहित हैं!"
 
-#: src/view/com/posts/FeedErrorMessage.tsx:98
+#: src/view/com/posts/FeedErrorMessage.tsx:99
 msgid "We're sorry, but this content is not viewable without a Bluesky account."
 msgstr ""
 
+#: src/view/com/posts/FeedErrorMessage.tsx:105
+msgid "We're sorry, but this feed is currently receiving high traffic and is temporarily unavailable. Please try again later."
+msgstr ""
+
 #: src/view/screens/Search/Search.tsx:236
 msgid "We're sorry, but your search could not be completed. Please try again in a few minutes."
 msgstr ""
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index 6f058d39e..7336f3b95 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -201,7 +201,7 @@ export const ComposePost = observer(function ComposePost({
 
     setError('')
 
-    if (richtext.text.trim().length === 0 && gallery.isEmpty) {
+    if (richtext.text.trim().length === 0 && gallery.isEmpty && !extLink) {
       setError('Did you want to say anything?')
       return
     }
diff --git a/src/view/com/composer/text-input/TextInput.web.tsx b/src/view/com/composer/text-input/TextInput.web.tsx
index 4c31da338..206a3205b 100644
--- a/src/view/com/composer/text-input/TextInput.web.tsx
+++ b/src/view/com/composer/text-input/TextInput.web.tsx
@@ -116,6 +116,16 @@ export const TextInput = React.forwardRef(function TextInputImpl(
       autofocus: 'end',
       editable: true,
       injectCSS: true,
+      onCreate({editor: editorProp}) {
+        // HACK
+        // the 'enter' animation sometimes causes autofocus to fail
+        // (see Composer.web.tsx in shell)
+        // so we wait 200ms (the anim is 150ms) and then focus manually
+        // -prf
+        setTimeout(() => {
+          editorProp.chain().focus('end').run()
+        }, 200)
+      },
       onUpdate({editor: editorProp}) {
         const json = editorProp.getJSON()
 
diff --git a/src/view/com/feeds/FeedPage.tsx b/src/view/com/feeds/FeedPage.tsx
index f06716fb0..f3f07a8bd 100644
--- a/src/view/com/feeds/FeedPage.tsx
+++ b/src/view/com/feeds/FeedPage.tsx
@@ -158,9 +158,9 @@ export function FeedPage({
     <View testID={testID} style={s.h100pct}>
       <Feed
         testID={testID ? `${testID}-feed` : undefined}
+        enabled={isPageFocused}
         feed={feed}
         feedParams={feedParams}
-        enabled={isPageFocused}
         pollInterval={POLL_FREQ}
         scrollElRef={scrollElRef}
         onScroll={onMainScroll}
diff --git a/src/view/com/pager/Pager.tsx b/src/view/com/pager/Pager.tsx
index d70087504..61c3609f2 100644
--- a/src/view/com/pager/Pager.tsx
+++ b/src/view/com/pager/Pager.tsx
@@ -81,12 +81,14 @@ export const Pager = forwardRef<PagerRef, React.PropsWithChildren<Props>>(
         if (scrollState.current === 'settling') {
           if (lastDirection.current === -1 && offset < lastOffset.current) {
             onPageSelecting?.(position)
+            setSelectedPage(position)
             lastDirection.current = 0
           } else if (
             lastDirection.current === 1 &&
             offset > lastOffset.current
           ) {
             onPageSelecting?.(position + 1)
+            setSelectedPage(position + 1)
             lastDirection.current = 0
           }
         } else {
diff --git a/src/view/com/pager/PagerWithHeader.tsx b/src/view/com/pager/PagerWithHeader.tsx
index 487c589e3..dcfc1eebb 100644
--- a/src/view/com/pager/PagerWithHeader.tsx
+++ b/src/view/com/pager/PagerWithHeader.tsx
@@ -69,13 +69,19 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
     // capture the header bar sizing
     const onTabBarLayout = React.useCallback(
       (evt: LayoutChangeEvent) => {
-        setTabBarHeight(evt.nativeEvent.layout.height)
+        const height = evt.nativeEvent.layout.height
+        if (height > 0) {
+          setTabBarHeight(height)
+        }
       },
       [setTabBarHeight],
     )
     const onHeaderOnlyLayout = React.useCallback(
       (evt: LayoutChangeEvent) => {
-        setHeaderOnlyHeight(evt.nativeEvent.layout.height)
+        const height = evt.nativeEvent.layout.height
+        if (height > 0) {
+          setHeaderOnlyHeight(height)
+        }
       },
       [setHeaderOnlyHeight],
     )
@@ -248,11 +254,14 @@ let PagerTabBar = ({
   }))
   return (
     <Animated.View
+      pointerEvents="box-none"
       style={[
         isMobile ? styles.tabBarMobile : styles.tabBarDesktop,
         headerTransform,
       ]}>
-      <View onLayout={onHeaderOnlyLayout}>{renderHeader?.()}</View>
+      <View onLayout={onHeaderOnlyLayout} pointerEvents="box-none">
+        {renderHeader?.()}
+      </View>
       <View
         onLayout={onTabBarLayout}
         style={{
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index a4b7a4a9c..86ea4eb39 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -351,11 +351,14 @@ let PostThreadItemLoaded = ({
               {post.embed && (
                 <ContentHider
                   moderation={moderation.embed}
+                  moderationDecisions={moderation.decisions}
                   ignoreMute={isEmbedByEmbedder(post.embed, post.author.did)}
+                  ignoreQuoteDecisions
                   style={s.mb10}>
                   <PostEmbeds
                     embed={post.embed}
                     moderation={moderation.embed}
+                    moderationDecisions={moderation.decisions}
                   />
                 </ContentHider>
               )}
@@ -414,7 +417,7 @@ let PostThreadItemLoaded = ({
       </>
     )
   } else {
-    const isThreadedChild = treeView && depth > 1
+    const isThreadedChild = treeView && depth > 0
     return (
       <PostOuterWrapper
         post={post}
@@ -426,7 +429,11 @@ let PostThreadItemLoaded = ({
           testID={`postThreadItem-by-${post.author.handle}`}
           href={postHref}
           style={[pal.view]}
-          moderation={moderation.content}>
+          moderation={moderation.content}
+          iconSize={isThreadedChild ? 26 : 38}
+          iconStyles={
+            isThreadedChild ? {marginRight: 4} : {marginLeft: 2, marginRight: 2}
+          }>
           <PostSandboxWarning />
 
           <View
@@ -491,10 +498,10 @@ let PostThreadItemLoaded = ({
                 timestamp={post.indexedAt}
                 postHref={postHref}
                 showAvatar={isThreadedChild}
-                avatarSize={26}
+                avatarSize={20}
                 displayNameType="md-bold"
                 displayNameStyle={isThreadedChild && s.ml2}
-                style={isThreadedChild && s.mb5}
+                style={isThreadedChild && s.mb2}
               />
               <PostAlerts
                 moderation={moderation.content}
@@ -522,10 +529,14 @@ let PostThreadItemLoaded = ({
               {post.embed && (
                 <ContentHider
                   style={styles.contentHider}
-                  moderation={moderation.embed}>
+                  moderation={moderation.embed}
+                  moderationDecisions={moderation.decisions}
+                  ignoreMute={isEmbedByEmbedder(post.embed, post.author.did)}
+                  ignoreQuoteDecisions>
                   <PostEmbeds
                     embed={post.embed}
                     moderation={moderation.embed}
+                    moderationDecisions={moderation.decisions}
                   />
                 </ContentHider>
               )}
@@ -583,7 +594,7 @@ function PostOuterWrapper({
   const {isMobile} = useWebMediaQueries()
   const pal = usePalette('default')
   const styles = useStyles()
-  if (treeView && depth > 1) {
+  if (treeView && depth > 0) {
     return (
       <View
         style={[
@@ -592,9 +603,9 @@ function PostOuterWrapper({
           styles.cursor,
           {
             flexDirection: 'row',
-            paddingLeft: 20,
+            paddingLeft: depth === 1 ? 10 : 20,
             borderTopWidth: depth === 1 ? 1 : 0,
-            paddingTop: depth === 1 ? 8 : 0,
+            paddingTop: depth === 1 ? 6 : 0,
           },
         ]}>
         {Array.from(Array(depth - 1)).map((_, n: number) => (
@@ -603,8 +614,8 @@ function PostOuterWrapper({
             style={{
               borderLeftWidth: 2,
               borderLeftColor: pal.colors.border,
-              marginLeft: n === 0 ? 14 : isMobile ? 6 : 14,
-              paddingLeft: n === 0 ? 18 : isMobile ? 6 : 12,
+              marginLeft: isMobile ? 6 : 14,
+              paddingLeft: isMobile ? 6 : 12,
             }}
           />
         ))}
diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx
index 2e8019e71..9b1bf7a49 100644
--- a/src/view/com/post/Post.tsx
+++ b/src/view/com/post/Post.tsx
@@ -196,8 +196,14 @@ function PostInner({
             {post.embed ? (
               <ContentHider
                 moderation={moderation.embed}
+                moderationDecisions={moderation.decisions}
+                ignoreQuoteDecisions
                 style={styles.contentHider}>
-                <PostEmbeds embed={post.embed} moderation={moderation.embed} />
+                <PostEmbeds
+                  embed={post.embed}
+                  moderation={moderation.embed}
+                  moderationDecisions={moderation.decisions}
+                />
               </ContentHider>
             ) : null}
           </ContentHider>
diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx
index 393c1bc91..b9ca9abdc 100644
--- a/src/view/com/posts/Feed.tsx
+++ b/src/view/com/posts/Feed.tsx
@@ -26,6 +26,7 @@ import {
   pollLatest,
 } from '#/state/queries/post-feed'
 import {useModerationOpts} from '#/state/queries/preferences'
+import {isWeb} from '#/platform/detection'
 
 const LOADING_ITEM = {_reactKey: '__loading__'}
 const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
@@ -89,7 +90,7 @@ let Feed = ({
   const isEmpty = !isFetching && !data?.pages[0]?.slices.length
 
   const checkForNew = React.useCallback(async () => {
-    if (!data?.pages[0] || isFetching || !onHasNew) {
+    if (!data?.pages[0] || isFetching || !onHasNew || !enabled) {
       return
     }
     try {
@@ -99,7 +100,7 @@ let Feed = ({
     } catch (e) {
       logger.error('Poll latest failed', {feed, error: String(e)})
     }
-  }, [feed, data, isFetching, onHasNew])
+  }, [feed, data, isFetching, onHasNew, enabled])
 
   React.useEffect(() => {
     // we store the interval handler in a ref to avoid needless
@@ -216,19 +217,25 @@ let Feed = ({
 
   const shouldRenderEndOfFeed =
     !hasNextPage && !isEmpty && !isFetching && !isError && !!renderEndOfFeed
-  const FeedFooter = React.useCallback(
-    () =>
-      isFetchingNextPage ? (
-        <View style={styles.feedFooter}>
-          <ActivityIndicator />
-        </View>
-      ) : shouldRenderEndOfFeed ? (
-        renderEndOfFeed()
-      ) : (
-        <View />
-      ),
-    [isFetchingNextPage, shouldRenderEndOfFeed, renderEndOfFeed],
-  )
+  const FeedFooter = React.useCallback(() => {
+    /**
+     * A bit of padding at the bottom of the feed as you scroll and when you
+     * reach the end, so that content isn't cut off by the bottom of the
+     * screen.
+     */
+    const offset = Math.max(headerOffset, 32) * (isWeb ? 1 : 2)
+
+    return isFetchingNextPage ? (
+      <View style={[styles.feedFooter]}>
+        <ActivityIndicator />
+        <View style={{height: offset}} />
+      </View>
+    ) : shouldRenderEndOfFeed ? (
+      <View style={{minHeight: offset}}>{renderEndOfFeed()}</View>
+    ) : (
+      <View style={{height: offset}} />
+    )
+  }, [isFetchingNextPage, shouldRenderEndOfFeed, renderEndOfFeed, headerOffset])
 
   const scrollHandler = useAnimatedScrollHandler(onScroll || {})
   return (
diff --git a/src/view/com/posts/FeedErrorMessage.tsx b/src/view/com/posts/FeedErrorMessage.tsx
index 63d9d5956..f63bc1a88 100644
--- a/src/view/com/posts/FeedErrorMessage.tsx
+++ b/src/view/com/posts/FeedErrorMessage.tsx
@@ -25,6 +25,7 @@ export enum KnownError {
   FeedgenOffline = 'FeedgenOffline',
   FeedgenUnknown = 'FeedgenUnknown',
   FeedNSFPublic = 'FeedNSFPublic',
+  FeedTooManyRequests = 'FeedTooManyRequests',
   Unknown = 'Unknown',
 }
 
@@ -100,6 +101,9 @@ function FeedgenErrorMessage({
         [KnownError.FeedgenUnknown]: _l(
           msgLingui`Hmm, some kind of issue occured when contacting the feed server. Please let the feed owner know about this issue.`,
         ),
+        [KnownError.FeedTooManyRequests]: _l(
+          msgLingui`We're sorry, but this feed is currently receiving high traffic and is temporarily unavailable. Please try again later.`,
+        ),
       }[knownError]),
     [_l, knownError],
   )
@@ -203,6 +207,13 @@ function detectKnownError(
   ) {
     return KnownError.Block
   }
+
+  // check status codes
+  if (error?.status === 429) {
+    return KnownError.FeedTooManyRequests
+  }
+
+  // convert error to string and continue
   if (typeof error !== 'string') {
     error = error.toString()
   }
diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx
index dfb0cfcf6..b6c509e92 100644
--- a/src/view/com/posts/FeedItem.tsx
+++ b/src/view/com/posts/FeedItem.tsx
@@ -320,9 +320,15 @@ let FeedItemInner = ({
               <ContentHider
                 testID="contentHider-embed"
                 moderation={moderation.embed}
+                moderationDecisions={moderation.decisions}
                 ignoreMute={isEmbedByEmbedder(post.embed, post.author.did)}
+                ignoreQuoteDecisions
                 style={styles.embed}>
-                <PostEmbeds embed={post.embed} moderation={moderation.embed} />
+                <PostEmbeds
+                  embed={post.embed}
+                  moderation={moderation.embed}
+                  moderationDecisions={moderation.decisions}
+                />
               </ContentHider>
             ) : null}
           </ContentHider>
diff --git a/src/view/com/posts/FollowingEndOfFeed.tsx b/src/view/com/posts/FollowingEndOfFeed.tsx
index 48724d8b3..6630b9a83 100644
--- a/src/view/com/posts/FollowingEndOfFeed.tsx
+++ b/src/view/com/posts/FollowingEndOfFeed.tsx
@@ -1,5 +1,5 @@
 import React from 'react'
-import {StyleSheet, View} from 'react-native'
+import {StyleSheet, View, Dimensions} from 'react-native'
 import {useNavigation} from '@react-navigation/native'
 import {
   FontAwesomeIcon,
@@ -36,7 +36,12 @@ export function FollowingEndOfFeed() {
   }, [navigation])
 
   return (
-    <View style={[styles.container, pal.border]}>
+    <View
+      style={[
+        styles.container,
+        pal.border,
+        {minHeight: Dimensions.get('window').height * 0.75},
+      ]}>
       <View style={styles.inner}>
         <Text type="xl-medium" style={[s.textCenter, pal.text]}>
           You've reached the end of your feed! Find some more accounts to
diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx
index 279e00d75..21972f274 100644
--- a/src/view/com/profile/ProfileCard.tsx
+++ b/src/view/com/profile/ProfileCard.tsx
@@ -228,6 +228,7 @@ const styles = StyleSheet.create({
   outer: {
     borderTopWidth: 1,
     paddingHorizontal: 6,
+    paddingVertical: 4,
   },
   outerNoBorder: {
     borderTopWidth: 0,
@@ -237,7 +238,7 @@ const styles = StyleSheet.create({
     alignItems: 'center',
   },
   layoutAvi: {
-    alignSelf: 'baseline',
+    alignSelf: 'flex-start',
     width: 54,
     paddingLeft: 4,
     paddingTop: 10,
diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index c1de10aa5..16e98ddf2 100644
--- a/src/view/com/profile/ProfileHeader.tsx
+++ b/src/view/com/profile/ProfileHeader.tsx
@@ -412,10 +412,12 @@ let ProfileHeaderLoaded = ({
   const pluralizedFollowers = pluralize(profile.followersCount || 0, 'follower')
 
   return (
-    <View style={pal.view}>
-      <UserBanner banner={profile.banner} moderation={moderation.avatar} />
-      <View style={styles.content}>
-        <View style={[styles.buttonsLine]}>
+    <View style={pal.view} pointerEvents="box-none">
+      <View pointerEvents="none">
+        <UserBanner banner={profile.banner} moderation={moderation.avatar} />
+      </View>
+      <View style={styles.content} pointerEvents="box-none">
+        <View style={[styles.buttonsLine]} pointerEvents="box-none">
           {isMe ? (
             <TouchableOpacity
               testID="profileHeaderEditProfileButton"
@@ -468,7 +470,7 @@ let ProfileHeaderLoaded = ({
                       pal.text,
                       {
                         color: showSuggestedFollows
-                          ? colors.white
+                          ? pal.textInverted.color
                           : pal.text.color,
                       },
                     ]}
@@ -525,7 +527,7 @@ let ProfileHeaderLoaded = ({
             </NativeDropdown>
           ) : undefined}
         </View>
-        <View>
+        <View pointerEvents="none">
           <Text
             testID="profileHeaderDisplayName"
             type="title-2xl"
@@ -536,7 +538,7 @@ let ProfileHeaderLoaded = ({
             )}
           </Text>
         </View>
-        <View style={styles.handleLine}>
+        <View style={styles.handleLine} pointerEvents="none">
           {profile.viewer?.followedBy && !blockHide ? (
             <View style={[styles.pill, pal.btn, s.mr5]}>
               <Text type="xs" style={[pal.text]}>
@@ -557,7 +559,7 @@ let ProfileHeaderLoaded = ({
         </View>
         {!blockHide && (
           <>
-            <View style={styles.metricsLine}>
+            <View style={styles.metricsLine} pointerEvents="box-none">
               <Link
                 testID="profileHeaderFollowersButton"
                 style={[s.flexRow, s.mr10]}
@@ -604,12 +606,14 @@ let ProfileHeaderLoaded = ({
               </Text>
             </View>
             {descriptionRT && !moderation.profile.blur ? (
-              <RichText
-                testID="profileHeaderDescription"
-                style={[styles.description, pal.text]}
-                numberOfLines={15}
-                richText={descriptionRT}
-              />
+              <View pointerEvents="none">
+                <RichText
+                  testID="profileHeaderDescription"
+                  style={[styles.description, pal.text]}
+                  numberOfLines={15}
+                  richText={descriptionRT}
+                />
+              </View>
             ) : undefined}
           </>
         )}
diff --git a/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx b/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx
index f648c9801..1d550aa5c 100644
--- a/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx
+++ b/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx
@@ -70,15 +70,19 @@ export function ProfileHeaderSuggestedFollows({
   })
 
   return (
-    <Animated.View style={[{overflow: 'hidden', opacity: 0}, animatedStyles]}>
-      <View style={{paddingVertical: OUTER_PADDING}}>
+    <Animated.View
+      pointerEvents="box-none"
+      style={[{overflow: 'hidden', opacity: 0}, animatedStyles]}>
+      <View style={{paddingVertical: OUTER_PADDING}} pointerEvents="box-none">
         <View
+          pointerEvents="box-none"
           style={{
             backgroundColor: pal.viewLight.backgroundColor,
             height: '100%',
             paddingTop: INNER_PADDING / 2,
           }}>
           <View
+            pointerEvents="box-none"
             style={{
               flexDirection: 'row',
               justifyContent: 'space-between',
diff --git a/src/view/com/util/LoadingPlaceholder.tsx b/src/view/com/util/LoadingPlaceholder.tsx
index 74e36ff7b..a07b33325 100644
--- a/src/view/com/util/LoadingPlaceholder.tsx
+++ b/src/view/com/util/LoadingPlaceholder.tsx
@@ -7,7 +7,7 @@ import {
   DimensionValue,
 } from 'react-native'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {HeartIcon} from 'lib/icons'
+import {HeartIcon, HeartIconSolid} from 'lib/icons'
 import {s} from 'lib/styles'
 import {useTheme} from 'lib/ThemeContext'
 import {usePalette} from 'lib/hooks/usePalette'
@@ -46,12 +46,22 @@ export function PostLoadingPlaceholder({
   const pal = usePalette('default')
   return (
     <View style={[styles.post, pal.view, style]}>
-      <LoadingPlaceholder width={52} height={52} style={styles.avatar} />
+      <LoadingPlaceholder
+        width={52}
+        height={52}
+        style={[
+          styles.avatar,
+          {
+            position: 'relative',
+            top: -6,
+          },
+        ]}
+      />
       <View style={[s.flex1]}>
-        <LoadingPlaceholder width={100} height={8} style={[s.mb10]} />
-        <LoadingPlaceholder width={200} height={8} style={[s.mb5]} />
-        <LoadingPlaceholder width={200} height={8} style={[s.mb5]} />
-        <LoadingPlaceholder width={120} height={8} style={[s.mb10]} />
+        <LoadingPlaceholder width={100} height={6} style={{marginBottom: 10}} />
+        <LoadingPlaceholder width="95%" height={6} style={{marginBottom: 8}} />
+        <LoadingPlaceholder width="95%" height={6} style={{marginBottom: 8}} />
+        <LoadingPlaceholder width="80%" height={6} style={{marginBottom: 15}} />
         <View style={s.flexRow}>
           <View style={s.flex1}>
             <FontAwesomeIcon
@@ -90,6 +100,8 @@ export function PostFeedLoadingPlaceholder() {
       <PostLoadingPlaceholder />
       <PostLoadingPlaceholder />
       <PostLoadingPlaceholder />
+      <PostLoadingPlaceholder />
+      <PostLoadingPlaceholder />
     </View>
   )
 }
@@ -102,11 +114,23 @@ export function NotificationLoadingPlaceholder({
   const pal = usePalette('default')
   return (
     <View style={[styles.notification, pal.view, style]}>
-      <View style={[s.flexRow, s.mb10]}>
-        <LoadingPlaceholder width={30} height={30} style={styles.smallAvatar} />
+      <View style={{paddingLeft: 30, paddingRight: 10}}>
+        <HeartIconSolid
+          style={{color: pal.colors.backgroundLight} as ViewStyle}
+          size={30}
+        />
+      </View>
+      <View style={{flex: 1}}>
+        <View style={[s.flexRow, s.mb10]}>
+          <LoadingPlaceholder
+            width={30}
+            height={30}
+            style={styles.smallAvatar}
+          />
+        </View>
+        <LoadingPlaceholder width="90%" height={6} style={[s.mb5]} />
+        <LoadingPlaceholder width="70%" height={6} style={[s.mb5]} />
       </View>
-      <LoadingPlaceholder width={200} height={8} style={[s.mb5]} />
-      <LoadingPlaceholder width={120} height={8} style={[s.mb5]} />
     </View>
   )
 }
@@ -239,18 +263,19 @@ const styles = StyleSheet.create({
   },
   post: {
     flexDirection: 'row',
-    padding: 10,
-    margin: 1,
+    alignItems: 'flex-start',
+    paddingHorizontal: 10,
+    paddingTop: 20,
+    paddingBottom: 5,
   },
   avatar: {
     borderRadius: 26,
     marginRight: 10,
-    marginLeft: 6,
+    marginLeft: 8,
   },
   notification: {
+    flexDirection: 'row',
     padding: 10,
-    paddingLeft: 46,
-    margin: 1,
   },
   profileCard: {
     flexDirection: 'row',
diff --git a/src/view/com/util/moderation/ContentHider.tsx b/src/view/com/util/moderation/ContentHider.tsx
index a13aae2b5..b1ea76621 100644
--- a/src/view/com/util/moderation/ContentHider.tsx
+++ b/src/view/com/util/moderation/ContentHider.tsx
@@ -1,36 +1,44 @@
 import React from 'react'
 import {Pressable, StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {usePalette} from 'lib/hooks/usePalette'
-import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
-import {ModerationUI} from '@atproto/api'
+import {ModerationUI, PostModeration} from '@atproto/api'
 import {Text} from '../text/Text'
 import {ShieldExclamation} from 'lib/icons'
 import {describeModerationCause} from 'lib/moderation'
 import {useLingui} from '@lingui/react'
 import {msg} from '@lingui/macro'
 import {useModalControls} from '#/state/modals'
+import {isPostMediaBlurred} from 'lib/moderation'
 
 export function ContentHider({
   testID,
   moderation,
+  moderationDecisions,
   ignoreMute,
+  ignoreQuoteDecisions,
   style,
   childContainerStyle,
   children,
 }: React.PropsWithChildren<{
   testID?: string
   moderation: ModerationUI
+  moderationDecisions?: PostModeration['decisions']
   ignoreMute?: boolean
+  ignoreQuoteDecisions?: boolean
   style?: StyleProp<ViewStyle>
   childContainerStyle?: StyleProp<ViewStyle>
 }>) {
   const pal = usePalette('default')
   const {_} = useLingui()
-  const {isMobile} = useWebMediaQueries()
   const [override, setOverride] = React.useState(false)
   const {openModal} = useModalControls()
 
-  if (!moderation.blur || (ignoreMute && moderation.cause?.type === 'muted')) {
+  if (
+    !moderation.blur ||
+    (ignoreMute && moderation.cause?.type === 'muted') ||
+    shouldIgnoreQuote(moderationDecisions, ignoreQuoteDecisions)
+  ) {
     return (
       <View testID={testID} style={[styles.outer, style]}>
         {children}
@@ -38,6 +46,7 @@ export function ContentHider({
     )
   }
 
+  const isMute = moderation.cause?.type === 'muted'
   const desc = describeModerationCause(moderation.cause, 'content')
   return (
     <View testID={testID} style={[styles.outer, style]}>
@@ -58,7 +67,6 @@ export function ContentHider({
         accessibilityLabel=""
         style={[
           styles.cover,
-          {paddingRight: isMobile ? 22 : 18},
           moderation.noOverride
             ? {borderWidth: 1, borderColor: pal.colors.borderDark}
             : pal.viewLight,
@@ -74,14 +82,22 @@ export function ContentHider({
           accessibilityRole="button"
           accessibilityLabel={_(msg`Learn more about this warning`)}
           accessibilityHint="">
-          <ShieldExclamation size={18} style={pal.text} />
+          {isMute ? (
+            <FontAwesomeIcon
+              icon={['far', 'eye-slash']}
+              size={18}
+              color={pal.colors.textLight}
+            />
+          ) : (
+            <ShieldExclamation size={18} style={pal.textLight} />
+          )}
         </Pressable>
-        <Text type="lg" style={pal.text}>
+        <Text type="md" style={pal.text}>
           {desc.name}
         </Text>
         {!moderation.noOverride && (
           <View style={styles.showBtn}>
-            <Text type="xl" style={pal.link}>
+            <Text type="lg" style={pal.link}>
               {override ? 'Hide' : 'Show'}
             </Text>
           </View>
@@ -92,6 +108,16 @@ export function ContentHider({
   )
 }
 
+function shouldIgnoreQuote(
+  decisions: PostModeration['decisions'] | undefined,
+  ignore: boolean | undefined,
+): boolean {
+  if (!decisions || !ignore) {
+    return false
+  }
+  return !isPostMediaBlurred(decisions)
+}
+
 const styles = StyleSheet.create({
   outer: {
     overflow: 'hidden',
@@ -104,6 +130,7 @@ const styles = StyleSheet.create({
     marginTop: 4,
     paddingVertical: 14,
     paddingLeft: 14,
+    paddingRight: 18,
   },
   showBtn: {
     marginLeft: 'auto',
diff --git a/src/view/com/util/moderation/PostHider.tsx b/src/view/com/util/moderation/PostHider.tsx
index c2b857f54..bffb7ea1a 100644
--- a/src/view/com/util/moderation/PostHider.tsx
+++ b/src/view/com/util/moderation/PostHider.tsx
@@ -1,8 +1,8 @@
 import React, {ComponentProps} from 'react'
-import {StyleSheet, Pressable, View} from 'react-native'
+import {StyleSheet, Pressable, View, ViewStyle, StyleProp} from 'react-native'
 import {ModerationUI} from '@atproto/api'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {usePalette} from 'lib/hooks/usePalette'
-import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {Link} from '../Link'
 import {Text} from '../text/Text'
 import {addStyle} from 'lib/styles'
@@ -13,9 +13,8 @@ import {msg} from '@lingui/macro'
 import {useModalControls} from '#/state/modals'
 
 interface Props extends ComponentProps<typeof Link> {
-  // testID?: string
-  // href?: string
-  // style: StyleProp<ViewStyle>
+  iconSize: number
+  iconStyles: StyleProp<ViewStyle>
   moderation: ModerationUI
 }
 
@@ -25,11 +24,12 @@ export function PostHider({
   moderation,
   style,
   children,
+  iconSize,
+  iconStyles,
   ...props
 }: Props) {
   const pal = usePalette('default')
   const {_} = useLingui()
-  const {isMobile} = useWebMediaQueries()
   const [override, setOverride] = React.useState(false)
   const {openModal} = useModalControls()
 
@@ -47,57 +47,74 @@ export function PostHider({
     )
   }
 
+  const isMute = moderation.cause?.type === 'muted'
   const desc = describeModerationCause(moderation.cause, 'content')
-  return (
-    <>
+  return !override ? (
+    <Pressable
+      onPress={() => {
+        if (!moderation.noOverride) {
+          setOverride(v => !v)
+        }
+      }}
+      accessibilityRole="button"
+      accessibilityHint={override ? 'Hide the content' : 'Show the content'}
+      accessibilityLabel=""
+      style={[
+        styles.description,
+        override ? {paddingBottom: 0} : undefined,
+        pal.view,
+      ]}>
       <Pressable
         onPress={() => {
-          if (!moderation.noOverride) {
-            setOverride(v => !v)
-          }
+          openModal({
+            name: 'moderation-details',
+            context: 'content',
+            moderation,
+          })
         }}
         accessibilityRole="button"
-        accessibilityHint={override ? 'Hide the content' : 'Show the content'}
-        accessibilityLabel=""
-        style={[
-          styles.description,
-          {paddingRight: isMobile ? 22 : 18},
-          pal.viewLight,
-        ]}>
-        <Pressable
-          onPress={() => {
-            openModal({
-              name: 'moderation-details',
-              context: 'content',
-              moderation,
-            })
-          }}
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Learn more about this warning`)}
-          accessibilityHint="">
-          <ShieldExclamation size={18} style={pal.text} />
-        </Pressable>
-        <Text type="lg" style={[{flex: 1}, pal.text]} numberOfLines={1}>
-          {desc.name}
-        </Text>
-        {!moderation.noOverride && (
-          <Text type="xl" style={[styles.showBtn, pal.link]}>
-            {override ? 'Hide' : 'Show'}
-          </Text>
-        )}
-      </Pressable>
-      {override && (
-        <View style={[styles.childrenContainer, pal.border, pal.viewLight]}>
-          <Link
-            testID={testID}
-            style={addStyle(style, styles.child)}
-            href={href}
-            noFeedback>
-            {children}
-          </Link>
+        accessibilityLabel={_(msg`Learn more about this warning`)}
+        accessibilityHint="">
+        <View
+          style={[
+            pal.viewLight,
+            {
+              width: iconSize,
+              height: iconSize,
+              borderRadius: iconSize,
+              alignItems: 'center',
+              justifyContent: 'center',
+            },
+            iconStyles,
+          ]}>
+          {isMute ? (
+            <FontAwesomeIcon
+              icon={['far', 'eye-slash']}
+              size={14}
+              color={pal.colors.textLight}
+            />
+          ) : (
+            <ShieldExclamation size={14} style={pal.textLight} />
+          )}
         </View>
+      </Pressable>
+      <Text type="sm" style={[{flex: 1}, pal.textLight]} numberOfLines={1}>
+        {desc.name}
+      </Text>
+      {!moderation.noOverride && (
+        <Text type="sm" style={[styles.showBtn, pal.link]}>
+          {override ? 'Hide' : 'Show'}
+        </Text>
       )}
-    </>
+    </Pressable>
+  ) : (
+    <Link
+      testID={testID}
+      style={addStyle(style, styles.child)}
+      href={href}
+      noFeedback>
+      {children}
+    </Link>
   )
 }
 
@@ -106,18 +123,15 @@ const styles = StyleSheet.create({
     flexDirection: 'row',
     alignItems: 'center',
     gap: 4,
-    paddingVertical: 14,
-    paddingLeft: 18,
+    paddingVertical: 10,
+    paddingLeft: 6,
+    paddingRight: 18,
     marginTop: 1,
   },
   showBtn: {
     marginLeft: 'auto',
     alignSelf: 'center',
   },
-  childrenContainer: {
-    paddingHorizontal: 4,
-    paddingBottom: 6,
-  },
   child: {
     borderWidth: 0,
     borderTopWidth: 0,
diff --git a/src/view/com/util/moderation/ProfileHeaderAlerts.tsx b/src/view/com/util/moderation/ProfileHeaderAlerts.tsx
index d2675ca54..0f07b679b 100644
--- a/src/view/com/util/moderation/ProfileHeaderAlerts.tsx
+++ b/src/view/com/util/moderation/ProfileHeaderAlerts.tsx
@@ -10,6 +10,7 @@ import {
 } from 'lib/moderation'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {useModalControls} from '#/state/modals'
 
 export function ProfileHeaderAlerts({
@@ -31,6 +32,7 @@ export function ProfileHeaderAlerts({
   return (
     <View style={styles.grid}>
       {causes.map(cause => {
+        const isMute = cause.type === 'muted'
         const desc = describeModerationCause(cause, 'account')
         return (
           <Pressable
@@ -47,11 +49,19 @@ export function ProfileHeaderAlerts({
             accessibilityLabel={_(msg`Learn more about this warning`)}
             accessibilityHint=""
             style={[styles.container, pal.viewLight, style]}>
-            <ShieldExclamation style={pal.text} size={24} />
-            <Text type="lg" style={[{flex: 1}, pal.text]}>
+            {isMute ? (
+              <FontAwesomeIcon
+                icon={['far', 'eye-slash']}
+                size={14}
+                color={pal.colors.textLight}
+              />
+            ) : (
+              <ShieldExclamation style={pal.text} size={18} />
+            )}
+            <Text type="sm" style={[{flex: 1}, pal.text]}>
               {desc.name}
             </Text>
-            <Text type="lg" style={[pal.link, styles.learnMoreBtn]}>
+            <Text type="sm" style={[pal.link, styles.learnMoreBtn]}>
               <Trans>Learn More</Trans>
             </Text>
           </Pressable>
diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx
index ca3bf1104..5c16a3b3e 100644
--- a/src/view/com/util/post-embeds/index.tsx
+++ b/src/view/com/util/post-embeds/index.tsx
@@ -16,6 +16,7 @@ import {
   AppBskyFeedDefs,
   AppBskyGraphDefs,
   ModerationUI,
+  PostModeration,
 } from '@atproto/api'
 import {Link} from '../Link'
 import {ImageLayoutGrid} from '../images/ImageLayoutGrid'
@@ -28,8 +29,9 @@ import {getYoutubeVideoId} from 'lib/strings/url-helpers'
 import {MaybeQuoteEmbed} from './QuoteEmbed'
 import {AutoSizedImage} from '../images/AutoSizedImage'
 import {ListEmbed} from './ListEmbed'
-import {isCauseALabelOnUri} from 'lib/moderation'
+import {isCauseALabelOnUri, isQuoteBlurred} from 'lib/moderation'
 import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
+import {ContentHider} from '../moderation/ContentHider'
 
 type Embed =
   | AppBskyEmbedRecord.View
@@ -41,10 +43,12 @@ type Embed =
 export function PostEmbeds({
   embed,
   moderation,
+  moderationDecisions,
   style,
 }: {
   embed?: Embed
   moderation: ModerationUI
+  moderationDecisions?: PostModeration['decisions']
   style?: StyleProp<ViewStyle>
 }) {
   const pal = usePalette('default')
@@ -55,14 +59,17 @@ export function PostEmbeds({
   // =
   if (AppBskyEmbedRecordWithMedia.isView(embed)) {
     const isModOnQuote =
-      AppBskyEmbedRecord.isViewRecord(embed.record.record) &&
-      isCauseALabelOnUri(moderation.cause, embed.record.record.uri)
+      (AppBskyEmbedRecord.isViewRecord(embed.record.record) &&
+        isCauseALabelOnUri(moderation.cause, embed.record.record.uri)) ||
+      (moderationDecisions && isQuoteBlurred(moderationDecisions))
     const mediaModeration = isModOnQuote ? {} : moderation
     const quoteModeration = isModOnQuote ? moderation : {}
     return (
       <View style={[styles.stackContainer, style]}>
         <PostEmbeds embed={embed.media} moderation={mediaModeration} />
-        <MaybeQuoteEmbed embed={embed.record} moderation={quoteModeration} />
+        <ContentHider moderation={quoteModeration}>
+          <MaybeQuoteEmbed embed={embed.record} moderation={quoteModeration} />
+        </ContentHider>
       </View>
     )
   }
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
index 6100d42db..d07fa0434 100644
--- a/src/view/screens/Home.tsx
+++ b/src/view/screens/Home.tsx
@@ -1,6 +1,6 @@
 import React from 'react'
 import {View, ActivityIndicator, StyleSheet} from 'react-native'
-import {useFocusEffect} from '@react-navigation/native'
+import {useFocusEffect, useIsFocused} from '@react-navigation/native'
 import {NativeStackScreenProps, HomeTabNavigatorParams} from 'lib/routes/types'
 import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed'
 import {FollowingEmptyState} from 'view/com/posts/FollowingEmptyState'
@@ -65,6 +65,7 @@ function HomeScreenReady({
   const {hasSession} = useSession()
   const setMinimalShellMode = useSetMinimalShellMode()
   const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
+  const isPageFocused = useIsFocused()
   const [selectedPage, setSelectedPage] = React.useState<string>(initialPage)
 
   /**
@@ -174,7 +175,7 @@ function HomeScreenReady({
       <FeedPage
         key="1"
         testID="followingFeedPage"
-        isPageFocused={selectedPageIndex === 0}
+        isPageFocused={selectedPageIndex === 0 && isPageFocused}
         feed={homeFeedParams.mergeFeedEnabled ? 'home' : 'following'}
         feedParams={homeFeedParams}
         renderEmptyState={renderFollowingEmptyState}
@@ -185,7 +186,7 @@ function HomeScreenReady({
           <FeedPage
             key={f}
             testID="customFeedPage"
-            isPageFocused={selectedPageIndex === 1 + index}
+            isPageFocused={selectedPageIndex === 1 + index && isPageFocused}
             feed={f}
             renderEmptyState={renderCustomFeedEmptyState}
           />
@@ -201,7 +202,7 @@ function HomeScreenReady({
       tabBarPosition="top">
       <FeedPage
         testID="customFeedPage"
-        isPageFocused
+        isPageFocused={isPageFocused}
         feed={`feedgen|at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot`}
         renderEmptyState={renderCustomFeedEmptyState}
       />
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx
index d5e378ccb..ea19515b5 100644
--- a/src/view/screens/Profile.tsx
+++ b/src/view/screens/Profile.tsx
@@ -2,7 +2,7 @@ import React, {useMemo} from 'react'
 import {StyleSheet, View} from 'react-native'
 import {useFocusEffect} from '@react-navigation/native'
 import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api'
-import {msg} from '@lingui/macro'
+import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
 import {CenteredView, FlatList} from '../com/util/Views'
@@ -36,6 +36,8 @@ import {useQueryClient} from '@tanstack/react-query'
 import {useComposerControls} from '#/state/shell/composer'
 import {listenSoftReset} from '#/state/events'
 import {truncateAndInvalidate} from '#/state/queries/util'
+import {Text} from '#/view/com/util/text/Text'
+import {usePalette} from 'lib/hooks/usePalette'
 
 interface SectionRef {
   scrollToTop: () => void
@@ -420,6 +422,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
       <View>
         <Feed
           testID="postsFeed"
+          enabled={isFocused}
           feed={feed}
           pollInterval={30e3}
           scrollElRef={scrollElRef}
@@ -428,7 +431,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
           scrollEventThrottle={1}
           renderEmptyState={renderPostsEmpty}
           headerOffset={headerHeight}
-          enabled={isFocused}
+          renderEndOfFeed={ProfileEndOfFeed}
         />
         {(isScrolledDown || hasNew) && (
           <LoadLatestBtn
@@ -442,6 +445,18 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
   },
 )
 
+function ProfileEndOfFeed() {
+  const pal = usePalette('default')
+
+  return (
+    <View style={[pal.border, {paddingTop: 32, borderTopWidth: 1}]}>
+      <Text style={[pal.textLight, pal.border, {textAlign: 'center'}]}>
+        <Trans>End of feed</Trans>
+      </Text>
+    </View>
+  )
+}
+
 const styles = StyleSheet.create({
   container: {
     flexDirection: 'column',
diff --git a/src/view/screens/ProfileFeed.tsx b/src/view/screens/ProfileFeed.tsx
index 659560a25..3a0bdcc0f 100644
--- a/src/view/screens/ProfileFeed.tsx
+++ b/src/view/screens/ProfileFeed.tsx
@@ -402,7 +402,7 @@ export function ProfileFeedScreenInner({
         isHeaderReady={true}
         renderHeader={renderHeader}
         onCurrentPageSelected={onCurrentPageSelected}>
-        {({onScroll, headerHeight, isScrolledDown, scrollElRef}) =>
+        {({onScroll, headerHeight, isScrolledDown, scrollElRef, isFocused}) =>
           isPublic ? (
             <FeedSection
               ref={feedSectionRef}
@@ -413,6 +413,7 @@ export function ProfileFeedScreenInner({
               scrollElRef={
                 scrollElRef as React.MutableRefObject<FlatList<any> | null>
               }
+              isFocused={isFocused}
             />
           ) : (
             <CenteredView sideBorders style={[{paddingTop: headerHeight}]}>
@@ -492,10 +493,11 @@ interface FeedSectionProps {
   headerHeight: number
   isScrolledDown: boolean
   scrollElRef: React.MutableRefObject<FlatList<any> | null>
+  isFocused: boolean
 }
 const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
   function FeedSectionImpl(
-    {feed, onScroll, headerHeight, isScrolledDown, scrollElRef},
+    {feed, onScroll, headerHeight, isScrolledDown, scrollElRef, isFocused},
     ref,
   ) {
     const [hasNew, setHasNew] = React.useState(false)
@@ -518,6 +520,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
     return (
       <View>
         <Feed
+          enabled={isFocused}
           feed={feed}
           pollInterval={30e3}
           scrollElRef={scrollElRef}
diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx
index 1396b8269..3e568c8cc 100644
--- a/src/view/screens/ProfileList.tsx
+++ b/src/view/screens/ProfileList.tsx
@@ -56,6 +56,12 @@ import {useSession} from '#/state/session'
 import {useComposerControls} from '#/state/shell/composer'
 import {isWeb} from '#/platform/detection'
 import {truncateAndInvalidate} from '#/state/queries/util'
+import {
+  usePreferencesQuery,
+  usePinFeedMutation,
+  useUnpinFeedMutation,
+} from '#/state/queries/preferences'
+import {logger} from '#/logger'
 
 const SECTION_TITLES_CURATE = ['Posts', 'About']
 const SECTION_TITLES_MOD = ['About']
@@ -129,7 +135,6 @@ function ProfileListScreenLoaded({
       list,
       onChange() {
         if (isCurateList) {
-          // TODO(eric) should construct these strings with a fn too
           truncateAndInvalidate(queryClient, FEED_RQKEY(`list|${list.uri}`))
         }
       },
@@ -159,7 +164,13 @@ function ProfileListScreenLoaded({
           isHeaderReady={true}
           renderHeader={renderHeader}
           onCurrentPageSelected={onCurrentPageSelected}>
-          {({onScroll, headerHeight, isScrolledDown, scrollElRef}) => (
+          {({
+            onScroll,
+            headerHeight,
+            isScrolledDown,
+            scrollElRef,
+            isFocused,
+          }) => (
             <FeedSection
               ref={feedSectionRef}
               feed={`list|${uri}`}
@@ -169,6 +180,7 @@ function ProfileListScreenLoaded({
               onScroll={onScroll}
               headerHeight={headerHeight}
               isScrolledDown={isScrolledDown}
+              isFocused={isFocused}
             />
           )}
           {({onScroll, headerHeight, isScrolledDown, scrollElRef}) => (
@@ -247,19 +259,31 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
   const listDeleteMutation = useListDeleteMutation()
   const isCurateList = list.purpose === 'app.bsky.graph.defs#curatelist'
   const isModList = list.purpose === 'app.bsky.graph.defs#modlist'
-  const isPinned = false // TODO
   const isBlocking = !!list.viewer?.blocked
   const isMuting = !!list.viewer?.muted
   const isOwner = list.creator.did === currentAccount?.did
+  const {isPending: isPinPending, mutateAsync: pinFeed} = usePinFeedMutation()
+  const {isPending: isUnpinPending, mutateAsync: unpinFeed} =
+    useUnpinFeedMutation()
+  const isPending = isPinPending || isUnpinPending
+  const {data: preferences} = usePreferencesQuery()
 
-  const onTogglePinned = useCallback(async () => {
+  const isPinned = preferences?.feeds?.pinned?.includes(list.uri)
+
+  const onTogglePinned = React.useCallback(async () => {
     Haptics.default()
-    // TODO
-    // list.togglePin().catch(e => {
-    //   Toast.show('There was an issue contacting the server')
-    //   logger.error('Failed to toggle pinned list', {error: e})
-    // })
-  }, [])
+
+    try {
+      if (isPinned) {
+        await unpinFeed({uri: list.uri})
+      } else {
+        await pinFeed({uri: list.uri})
+      }
+    } catch (e) {
+      Toast.show('There was an issue contacting the server')
+      logger.error('Failed to toggle pinned feed', {error: e})
+    }
+  }, [list.uri, isPinned, pinFeed, unpinFeed])
 
   const onSubscribeMute = useCallback(() => {
     openModal({
@@ -466,10 +490,11 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
       avatarType="list">
       {isCurateList || isPinned ? (
         <Button
-          testID={list.isPinned ? 'unpinBtn' : 'pinBtn'}
-          type={list.isPinned ? 'default' : 'inverted'}
-          label={list.isPinned ? 'Unpin' : 'Pin to home'}
+          testID={isPinned ? 'unpinBtn' : 'pinBtn'}
+          type={isPinned ? 'default' : 'inverted'}
+          label={isPinned ? 'Unpin' : 'Pin to home'}
           onPress={onTogglePinned}
+          disabled={isPending}
         />
       ) : isModList ? (
         isBlocking ? (
@@ -519,10 +544,11 @@ interface FeedSectionProps {
   headerHeight: number
   isScrolledDown: boolean
   scrollElRef: React.MutableRefObject<FlatList<any> | null>
+  isFocused: boolean
 }
 const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
   function FeedSectionImpl(
-    {feed, scrollElRef, onScroll, headerHeight, isScrolledDown},
+    {feed, scrollElRef, onScroll, headerHeight, isScrolledDown, isFocused},
     ref,
   ) {
     const queryClient = useQueryClient()
@@ -545,6 +571,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
       <View>
         <Feed
           testID="listFeed"
+          enabled={isFocused}
           feed={feed}
           pollInterval={30e3}
           scrollElRef={scrollElRef}
diff --git a/src/view/shell/createNativeStackNavigatorWithAuth.tsx b/src/view/shell/createNativeStackNavigatorWithAuth.tsx
index c7b5d1d2e..43dc28159 100644
--- a/src/view/shell/createNativeStackNavigatorWithAuth.tsx
+++ b/src/view/shell/createNativeStackNavigatorWithAuth.tsx
@@ -1,5 +1,6 @@
 import * as React from 'react'
 import {View} from 'react-native'
+import {PWI_ENABLED} from '#/lib/build-flags'
 
 // Based on @react-navigation/native-stack/src/createNativeStackNavigator.ts
 // MIT License
@@ -99,7 +100,7 @@ function NativeStackNavigator({
   const {showLoggedOut} = useLoggedOutView()
   const {setShowLoggedOut} = useLoggedOutViewControls()
   const {isMobile} = useWebMediaQueries()
-  if (activeRouteRequiresAuth && !hasSession) {
+  if ((!PWI_ENABLED || activeRouteRequiresAuth) && !hasSession) {
     return <LoggedOut />
   }
   if (showLoggedOut) {