Merge branch 'scroll-refactor' into web-layout
This commit is contained in:
+2
-2
@@ -9,12 +9,12 @@ module.exports = function () {
|
|||||||
/**
|
/**
|
||||||
* iOS build number. Must be incremented for each TestFlight version.
|
* iOS build number. Must be incremented for each TestFlight version.
|
||||||
*/
|
*/
|
||||||
const IOS_BUILD_NUMBER = '1'
|
const IOS_BUILD_NUMBER = '2'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Android build number. Must be incremented for each release.
|
* Android build number. Must be incremented for each release.
|
||||||
*/
|
*/
|
||||||
const ANDROID_VERSION_CODE = 48
|
const ANDROID_VERSION_CODE = 49
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses built-in Expo env vars
|
* Uses built-in Expo env vars
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bsky.app",
|
"name": "bsky.app",
|
||||||
"version": "1.58.0",
|
"version": "1.59.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "is-ci || husky install",
|
"prepare": "is-ci || husky install",
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"intl:compile": "lingui compile"
|
"intl:compile": "lingui compile"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@atproto/api": "^0.7.2",
|
"@atproto/api": "^0.7.3",
|
||||||
"@bam.tech/react-native-image-resizer": "^3.0.4",
|
"@bam.tech/react-native-image-resizer": "^3.0.4",
|
||||||
"@braintree/sanitize-url": "^6.0.2",
|
"@braintree/sanitize-url": "^6.0.2",
|
||||||
"@emoji-mart/react": "^1.1.1",
|
"@emoji-mart/react": "^1.1.1",
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import React, {createContext, useContext, useMemo} from 'react'
|
||||||
|
import {ScrollHandlers} from 'react-native-reanimated'
|
||||||
|
|
||||||
|
const ScrollContext = createContext<ScrollHandlers<any>>({
|
||||||
|
onBeginDrag: undefined,
|
||||||
|
onEndDrag: undefined,
|
||||||
|
onScroll: undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
export function useScrollHandlers(): ScrollHandlers<any> {
|
||||||
|
return useContext(ScrollContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProviderProps = {children: React.ReactNode} & ScrollHandlers<any>
|
||||||
|
|
||||||
|
// Note: this completely *overrides* the parent handlers.
|
||||||
|
// It's up to you to compose them with the parent ones via useScrollHandlers() if needed.
|
||||||
|
export function ScrollProvider({
|
||||||
|
children,
|
||||||
|
onBeginDrag,
|
||||||
|
onEndDrag,
|
||||||
|
onScroll,
|
||||||
|
}: ProviderProps) {
|
||||||
|
const handlers = useMemo(
|
||||||
|
() => ({
|
||||||
|
onBeginDrag,
|
||||||
|
onEndDrag,
|
||||||
|
onScroll,
|
||||||
|
}),
|
||||||
|
[onBeginDrag, onEndDrag, onScroll],
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
<ScrollContext.Provider value={handlers}>{children}</ScrollContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
+38
-34
@@ -1,3 +1,4 @@
|
|||||||
|
import {useMemo} from 'react'
|
||||||
import {TextStyle, ViewStyle} from 'react-native'
|
import {TextStyle, ViewStyle} from 'react-native'
|
||||||
import {useTheme, PaletteColorName, PaletteColor} from '../ThemeContext'
|
import {useTheme, PaletteColorName, PaletteColor} from '../ThemeContext'
|
||||||
|
|
||||||
@@ -15,38 +16,41 @@ export interface UsePaletteValue {
|
|||||||
icon: TextStyle
|
icon: TextStyle
|
||||||
}
|
}
|
||||||
export function usePalette(color: PaletteColorName): UsePaletteValue {
|
export function usePalette(color: PaletteColorName): UsePaletteValue {
|
||||||
const palette = useTheme().palette[color]
|
const theme = useTheme()
|
||||||
return {
|
return useMemo(() => {
|
||||||
colors: palette,
|
const palette = theme.palette[color]
|
||||||
view: {
|
return {
|
||||||
backgroundColor: palette.background,
|
colors: palette,
|
||||||
},
|
view: {
|
||||||
viewLight: {
|
backgroundColor: palette.background,
|
||||||
backgroundColor: palette.backgroundLight,
|
},
|
||||||
},
|
viewLight: {
|
||||||
btn: {
|
backgroundColor: palette.backgroundLight,
|
||||||
backgroundColor: palette.backgroundLight,
|
},
|
||||||
},
|
btn: {
|
||||||
border: {
|
backgroundColor: palette.backgroundLight,
|
||||||
borderColor: palette.border,
|
},
|
||||||
},
|
border: {
|
||||||
borderDark: {
|
borderColor: palette.border,
|
||||||
borderColor: palette.borderDark,
|
},
|
||||||
},
|
borderDark: {
|
||||||
text: {
|
borderColor: palette.borderDark,
|
||||||
color: palette.text,
|
},
|
||||||
},
|
text: {
|
||||||
textLight: {
|
color: palette.text,
|
||||||
color: palette.textLight,
|
},
|
||||||
},
|
textLight: {
|
||||||
textInverted: {
|
color: palette.textLight,
|
||||||
color: palette.textInverted,
|
},
|
||||||
},
|
textInverted: {
|
||||||
link: {
|
color: palette.textInverted,
|
||||||
color: palette.link,
|
},
|
||||||
},
|
link: {
|
||||||
icon: {
|
color: palette.link,
|
||||||
color: palette.icon,
|
},
|
||||||
},
|
icon: {
|
||||||
}
|
color: palette.icon,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, [theme, color])
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ msgstr ""
|
|||||||
#~ msgid ". This warning is only available for posts with media attached."
|
#~ msgid ". This warning is only available for posts with media attached."
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:158
|
#: src/view/shell/desktop/RightNav.tsx:160
|
||||||
msgid "{0, plural, one {# invite code available} other {# invite codes available}}"
|
msgid "{0, plural, one {# invite code available} other {# invite codes available}}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ msgstr ""
|
|||||||
msgid "{0} {purposeLabel} List"
|
msgid "{0} {purposeLabel} List"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:141
|
#: src/view/shell/desktop/RightNav.tsx:143
|
||||||
msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite codes: # available}}"
|
msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite codes: # available}}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ msgstr ""
|
|||||||
msgid "Alt text describes images for blind and low-vision users, and helps give context to everyone."
|
msgid "Alt text describes images for blind and low-vision users, and helps give context to everyone."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:110
|
#: src/view/com/modals/VerifyEmail.tsx:118
|
||||||
msgid "An email has been sent to {0}. It includes a confirmation code which you can enter below."
|
msgid "An email has been sent to {0}. It includes a confirmation code which you can enter below."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -232,7 +232,7 @@ msgstr ""
|
|||||||
msgid "Are you sure?"
|
msgid "Are you sure?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:185
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:188
|
||||||
msgid "Are you sure? This cannot be undone."
|
msgid "Are you sure? This cannot be undone."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -287,7 +287,7 @@ msgstr ""
|
|||||||
msgid "Block these accounts?"
|
msgid "Block these accounts?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:121
|
#: src/view/screens/Moderation.tsx:123
|
||||||
msgid "Blocked accounts"
|
msgid "Blocked accounts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -331,7 +331,7 @@ msgstr ""
|
|||||||
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
|
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:222
|
#: src/view/screens/Moderation.tsx:225
|
||||||
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
|
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -344,7 +344,7 @@ msgid "Build version {0} {1}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/composer/photos/OpenCameraBtn.tsx:60
|
#: src/view/com/composer/photos/OpenCameraBtn.tsx:60
|
||||||
#: src/view/com/util/UserAvatar.tsx:217
|
#: src/view/com/util/UserAvatar.tsx:221
|
||||||
#: src/view/com/util/UserBanner.tsx:38
|
#: src/view/com/util/UserBanner.tsx:38
|
||||||
msgid "Camera"
|
msgid "Camera"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -420,7 +420,7 @@ msgstr ""
|
|||||||
msgid "Change Handle"
|
msgid "Change Handle"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:133
|
#: src/view/com/modals/VerifyEmail.tsx:141
|
||||||
msgid "Change my email"
|
msgid "Change my email"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -508,7 +508,7 @@ msgstr ""
|
|||||||
#: src/view/com/modals/AppealLabel.tsx:98
|
#: src/view/com/modals/AppealLabel.tsx:98
|
||||||
#: src/view/com/modals/Confirm.tsx:75
|
#: src/view/com/modals/Confirm.tsx:75
|
||||||
#: src/view/com/modals/SelfLabel.tsx:154
|
#: src/view/com/modals/SelfLabel.tsx:154
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:217
|
#: src/view/com/modals/VerifyEmail.tsx:225
|
||||||
#: src/view/screens/PreferencesHomeFeed.tsx:299
|
#: src/view/screens/PreferencesHomeFeed.tsx:299
|
||||||
#: src/view/screens/PreferencesThreads.tsx:153
|
#: src/view/screens/PreferencesThreads.tsx:153
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
@@ -529,7 +529,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: src/view/com/modals/ChangeEmail.tsx:157
|
#: src/view/com/modals/ChangeEmail.tsx:157
|
||||||
#: src/view/com/modals/DeleteAccount.tsx:176
|
#: src/view/com/modals/DeleteAccount.tsx:176
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:151
|
#: src/view/com/modals/VerifyEmail.tsx:159
|
||||||
msgid "Confirmation code"
|
msgid "Confirmation code"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -538,7 +538,7 @@ msgstr ""
|
|||||||
msgid "Connecting..."
|
msgid "Connecting..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:79
|
#: src/view/screens/Moderation.tsx:81
|
||||||
msgid "Content filtering"
|
msgid "Content filtering"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -577,7 +577,7 @@ msgstr ""
|
|||||||
msgid "Copy link to list"
|
msgid "Copy link to list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:126
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:129
|
||||||
msgid "Copy link to post"
|
msgid "Copy link to post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -585,7 +585,7 @@ msgstr ""
|
|||||||
msgid "Copy link to profile"
|
msgid "Copy link to profile"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:112
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:115
|
||||||
msgid "Copy post text"
|
msgid "Copy post text"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -656,11 +656,11 @@ msgstr ""
|
|||||||
msgid "Delete my account…"
|
msgid "Delete my account…"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:180
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:183
|
||||||
msgid "Delete post"
|
msgid "Delete post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:184
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:187
|
||||||
msgid "Delete this post?"
|
msgid "Delete this post?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -691,7 +691,7 @@ msgstr ""
|
|||||||
msgid "Discard draft"
|
msgid "Discard draft"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:204
|
#: src/view/screens/Moderation.tsx:207
|
||||||
msgid "Discourage apps from showing my account to logged-out users"
|
msgid "Discourage apps from showing my account to logged-out users"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -840,7 +840,7 @@ msgstr ""
|
|||||||
msgid "Feed Preferences"
|
msgid "Feed Preferences"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:64
|
#: src/view/shell/desktop/RightNav.tsx:65
|
||||||
#: src/view/shell/Drawer.tsx:292
|
#: src/view/shell/Drawer.tsx:292
|
||||||
msgid "Feedback"
|
msgid "Feedback"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -936,7 +936,7 @@ msgstr ""
|
|||||||
msgid "Gallery"
|
msgid "Gallery"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:175
|
#: src/view/com/modals/VerifyEmail.tsx:183
|
||||||
msgid "Get Started"
|
msgid "Get Started"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -964,7 +964,7 @@ msgstr ""
|
|||||||
msgid "Handle"
|
msgid "Handle"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:93
|
#: src/view/shell/desktop/RightNav.tsx:94
|
||||||
#: src/view/shell/Drawer.tsx:302
|
#: src/view/shell/Drawer.tsx:302
|
||||||
msgid "Help"
|
msgid "Help"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1031,7 +1031,7 @@ msgstr ""
|
|||||||
msgid "Hosting provider address"
|
msgid "Hosting provider address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:200
|
#: src/view/com/modals/VerifyEmail.tsx:208
|
||||||
msgid "I have a code"
|
msgid "I have a code"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1047,7 +1047,7 @@ msgstr ""
|
|||||||
msgid "Image alt text"
|
msgid "Image alt text"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/util/UserAvatar.tsx:304
|
#: src/view/com/util/UserAvatar.tsx:308
|
||||||
#: src/view/com/util/UserBanner.tsx:116
|
#: src/view/com/util/UserBanner.tsx:116
|
||||||
msgid "Image options"
|
msgid "Image options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1121,7 +1121,7 @@ msgstr ""
|
|||||||
msgid "Learn more about this warning"
|
msgid "Learn more about this warning"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:239
|
#: src/view/screens/Moderation.tsx:242
|
||||||
msgid "Learn more about what is public on Bluesky."
|
msgid "Learn more about what is public on Bluesky."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1138,7 +1138,7 @@ msgstr ""
|
|||||||
msgid "Let's get your password reset!"
|
msgid "Let's get your password reset!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/util/UserAvatar.tsx:241
|
#: src/view/com/util/UserAvatar.tsx:245
|
||||||
#: src/view/com/util/UserBanner.tsx:60
|
#: src/view/com/util/UserBanner.tsx:60
|
||||||
msgid "Library"
|
msgid "Library"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1208,7 +1208,7 @@ msgstr ""
|
|||||||
#~ msgid "Logged-out users"
|
#~ msgid "Logged-out users"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:134
|
#: src/view/screens/Moderation.tsx:136
|
||||||
msgid "Logged-out visibility"
|
msgid "Logged-out visibility"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1245,7 +1245,7 @@ msgstr ""
|
|||||||
msgid "Message from server"
|
msgid "Message from server"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:63
|
#: src/view/screens/Moderation.tsx:64
|
||||||
#: src/view/screens/Settings.tsx:563
|
#: src/view/screens/Settings.tsx:563
|
||||||
#: src/view/shell/desktop/LeftNav.tsx:391
|
#: src/view/shell/desktop/LeftNav.tsx:391
|
||||||
#: src/view/shell/Drawer.tsx:490
|
#: src/view/shell/Drawer.tsx:490
|
||||||
@@ -1253,7 +1253,7 @@ msgstr ""
|
|||||||
msgid "Moderation"
|
msgid "Moderation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:93
|
#: src/view/screens/Moderation.tsx:95
|
||||||
msgid "Moderation lists"
|
msgid "Moderation lists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1291,11 +1291,11 @@ msgstr ""
|
|||||||
msgid "Mute these accounts?"
|
msgid "Mute these accounts?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:144
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:147
|
||||||
msgid "Mute thread"
|
msgid "Mute thread"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:107
|
#: src/view/screens/Moderation.tsx:109
|
||||||
msgid "Muted accounts"
|
msgid "Muted accounts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1421,7 +1421,7 @@ msgstr ""
|
|||||||
#~ msgid "Note: Bluesky is an open and public network, and enabling this will not make your profile private or limit the ability of logged in users to see your posts. This setting only limits the visibility of posts on the Bluesky app and website; third-party apps that display Bluesky content may not respect this setting, and could show your content to logged-out users."
|
#~ msgid "Note: Bluesky is an open and public network, and enabling this will not make your profile private or limit the ability of logged in users to see your posts. This setting only limits the visibility of posts on the Bluesky app and website; third-party apps that display Bluesky content may not respect this setting, and could show your content to logged-out users."
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:229
|
#: src/view/screens/Moderation.tsx:232
|
||||||
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
|
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1462,7 +1462,7 @@ msgstr ""
|
|||||||
msgid "Opens configurable language settings"
|
msgid "Opens configurable language settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:146
|
#: src/view/shell/desktop/RightNav.tsx:148
|
||||||
#: src/view/shell/Drawer.tsx:622
|
#: src/view/shell/Drawer.tsx:622
|
||||||
msgid "Opens list of invite codes"
|
msgid "Opens list of invite codes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1611,7 +1611,7 @@ msgstr ""
|
|||||||
msgid "Prioritize Your Follows"
|
msgid "Prioritize Your Follows"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:75
|
#: src/view/shell/desktop/RightNav.tsx:76
|
||||||
msgid "Privacy"
|
msgid "Privacy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1671,7 +1671,7 @@ msgstr ""
|
|||||||
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
|
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
|
||||||
#: src/view/com/modals/SelfLabel.tsx:83
|
#: src/view/com/modals/SelfLabel.tsx:83
|
||||||
#: src/view/com/modals/UserAddRemoveLists.tsx:193
|
#: src/view/com/modals/UserAddRemoveLists.tsx:193
|
||||||
#: src/view/com/util/UserAvatar.tsx:278
|
#: src/view/com/util/UserAvatar.tsx:282
|
||||||
#: src/view/com/util/UserBanner.tsx:89
|
#: src/view/com/util/UserBanner.tsx:89
|
||||||
msgid "Remove"
|
msgid "Remove"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1744,7 +1744,7 @@ msgid "Report List"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/modals/report/SendReportButton.tsx:37
|
#: src/view/com/modals/report/SendReportButton.tsx:37
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:162
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:165
|
||||||
msgid "Report post"
|
msgid "Report post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1898,7 +1898,7 @@ msgstr ""
|
|||||||
msgid "Select your preferred language for translations in your feed."
|
msgid "Select your preferred language for translations in your feed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:188
|
#: src/view/com/modals/VerifyEmail.tsx:196
|
||||||
msgid "Send Confirmation Email"
|
msgid "Send Confirmation Email"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1955,7 +1955,7 @@ msgid "Sexual activity or erotic nudity."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/profile/ProfileHeader.tsx:338
|
#: src/view/com/profile/ProfileHeader.tsx:338
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:126
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:129
|
||||||
#: src/view/screens/ProfileList.tsx:407
|
#: src/view/screens/ProfileList.tsx:407
|
||||||
msgid "Share"
|
msgid "Share"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -2075,7 +2075,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: src/view/com/modals/AppealLabel.tsx:101
|
#: src/view/com/modals/AppealLabel.tsx:101
|
||||||
msgid "Submit"
|
msgid "Submit"
|
||||||
msgstr ">>>>>>> cb8a33b6 (Fix translations)"
|
msgstr "Submit"
|
||||||
|
|
||||||
#: src/view/screens/ProfileList.tsx:597
|
#: src/view/screens/ProfileList.tsx:597
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
@@ -2110,7 +2110,7 @@ msgstr ""
|
|||||||
msgid "Tall"
|
msgid "Tall"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:84
|
#: src/view/shell/desktop/RightNav.tsx:85
|
||||||
msgid "Terms"
|
msgid "Terms"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2175,7 +2175,7 @@ msgstr ""
|
|||||||
msgid "This information is not shared with other users."
|
msgid "This information is not shared with other users."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:105
|
#: src/view/com/modals/VerifyEmail.tsx:113
|
||||||
msgid "This is important in case you ever need to change your email or reset your password."
|
msgid "This is important in case you ever need to change your email or reset your password."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2212,9 +2212,9 @@ msgstr ""
|
|||||||
msgid "Transformations"
|
msgid "Transformations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/post-thread/PostThreadItem.tsx:704
|
|
||||||
#: src/view/com/post-thread/PostThreadItem.tsx:706
|
#: src/view/com/post-thread/PostThreadItem.tsx:706
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:98
|
#: src/view/com/post-thread/PostThreadItem.tsx:708
|
||||||
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:101
|
||||||
msgid "Translate"
|
msgid "Translate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2258,7 +2258,7 @@ msgstr ""
|
|||||||
msgid "Unmute Account"
|
msgid "Unmute Account"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:144
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:147
|
||||||
msgid "Unmute thread"
|
msgid "Unmute thread"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2493,7 +2493,7 @@ msgstr ""
|
|||||||
msgid "Your email has been updated but not verified. As a next step, please verify your new email."
|
msgid "Your email has been updated but not verified. As a next step, please verify your new email."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:100
|
#: src/view/com/modals/VerifyEmail.tsx:108
|
||||||
msgid "Your email has not yet been verified. This is an important security step which we recommend."
|
msgid "Your email has not yet been verified. This is an important security step which we recommend."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2507,7 +2507,7 @@ msgid "Your hosting provider"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Settings.tsx:402
|
#: src/view/screens/Settings.tsx:402
|
||||||
#: src/view/shell/desktop/RightNav.tsx:127
|
#: src/view/shell/desktop/RightNav.tsx:129
|
||||||
#: src/view/shell/Drawer.tsx:636
|
#: src/view/shell/Drawer.tsx:636
|
||||||
msgid "Your invite codes are hidden when logged in using an App Password"
|
msgid "Your invite codes are hidden when logged in using an App Password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ msgstr ""
|
|||||||
#~ msgid ". This warning is only available for posts with media attached."
|
#~ msgid ". This warning is only available for posts with media attached."
|
||||||
#~ msgstr "यह चेतावनी केवल मीडिया वाले पोस्ट के लिए उपलब्ध है।"
|
#~ msgstr "यह चेतावनी केवल मीडिया वाले पोस्ट के लिए उपलब्ध है।"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:158
|
#: src/view/shell/desktop/RightNav.tsx:160
|
||||||
msgid "{0, plural, one {# invite code available} other {# invite codes available}}"
|
msgid "{0, plural, one {# invite code available} other {# invite codes available}}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ msgstr "{0}"
|
|||||||
msgid "{0} {purposeLabel} List"
|
msgid "{0} {purposeLabel} List"
|
||||||
msgstr "{0} {purposeLabel} सूची"
|
msgstr "{0} {purposeLabel} सूची"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:141
|
#: src/view/shell/desktop/RightNav.tsx:143
|
||||||
msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite codes: # available}}"
|
msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite codes: # available}}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ msgstr "वैकल्पिक पाठ"
|
|||||||
msgid "Alt text describes images for blind and low-vision users, and helps give context to everyone."
|
msgid "Alt text describes images for blind and low-vision users, and helps give context to everyone."
|
||||||
msgstr "ऑल्ट टेक्स्ट अंधा और कम दृश्य लोगों के लिए छवियों का वर्णन करता है, और हर किसी को संदर्भ देने में मदद करता है।।"
|
msgstr "ऑल्ट टेक्स्ट अंधा और कम दृश्य लोगों के लिए छवियों का वर्णन करता है, और हर किसी को संदर्भ देने में मदद करता है।।"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:110
|
#: src/view/com/modals/VerifyEmail.tsx:118
|
||||||
msgid "An email has been sent to {0}. It includes a confirmation code which you can enter below."
|
msgid "An email has been sent to {0}. It includes a confirmation code which you can enter below."
|
||||||
msgstr "{0} को ईमेल भेजा गया है। इसमें एक OTP कोड शामिल है जिसे आप नीचे दर्ज कर सकते हैं।।"
|
msgstr "{0} को ईमेल भेजा गया है। इसमें एक OTP कोड शामिल है जिसे आप नीचे दर्ज कर सकते हैं।।"
|
||||||
|
|
||||||
@@ -232,7 +232,7 @@ msgstr "क्या आप वाकई इस ड्राफ्ट को ह
|
|||||||
msgid "Are you sure?"
|
msgid "Are you sure?"
|
||||||
msgstr "क्या आप वास्तव में इसे करना चाहते हैं?"
|
msgstr "क्या आप वास्तव में इसे करना चाहते हैं?"
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:185
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:188
|
||||||
msgid "Are you sure? This cannot be undone."
|
msgid "Are you sure? This cannot be undone."
|
||||||
msgstr "क्या आप वास्तव में इसे करना चाहते हैं? इसे असंपादित नहीं किया जा सकता है।"
|
msgstr "क्या आप वास्तव में इसे करना चाहते हैं? इसे असंपादित नहीं किया जा सकता है।"
|
||||||
|
|
||||||
@@ -287,7 +287,7 @@ msgstr ""
|
|||||||
msgid "Block these accounts?"
|
msgid "Block these accounts?"
|
||||||
msgstr "खाता ब्लॉक करें?"
|
msgstr "खाता ब्लॉक करें?"
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:121
|
#: src/view/screens/Moderation.tsx:123
|
||||||
msgid "Blocked accounts"
|
msgid "Blocked accounts"
|
||||||
msgstr "ब्लॉक किए गए खाते"
|
msgstr "ब्लॉक किए गए खाते"
|
||||||
|
|
||||||
@@ -331,7 +331,7 @@ msgstr "Bluesky सार्वजनिक है।।"
|
|||||||
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
|
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
|
||||||
msgstr "ब्लूस्की एक स्वस्थ समुदाय बनाने के लिए आमंत्रित करता है। यदि आप किसी को आमंत्रित नहीं करते हैं, तो आप प्रतीक्षा सूची के लिए साइन अप कर सकते हैं और हम जल्द ही एक भेज देंगे।।"
|
msgstr "ब्लूस्की एक स्वस्थ समुदाय बनाने के लिए आमंत्रित करता है। यदि आप किसी को आमंत्रित नहीं करते हैं, तो आप प्रतीक्षा सूची के लिए साइन अप कर सकते हैं और हम जल्द ही एक भेज देंगे।।"
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:222
|
#: src/view/screens/Moderation.tsx:225
|
||||||
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
|
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -344,7 +344,7 @@ msgid "Build version {0} {1}"
|
|||||||
msgstr "Build version {0} {1}"
|
msgstr "Build version {0} {1}"
|
||||||
|
|
||||||
#: src/view/com/composer/photos/OpenCameraBtn.tsx:60
|
#: src/view/com/composer/photos/OpenCameraBtn.tsx:60
|
||||||
#: src/view/com/util/UserAvatar.tsx:217
|
#: src/view/com/util/UserAvatar.tsx:221
|
||||||
#: src/view/com/util/UserBanner.tsx:38
|
#: src/view/com/util/UserBanner.tsx:38
|
||||||
msgid "Camera"
|
msgid "Camera"
|
||||||
msgstr "कैमरा"
|
msgstr "कैमरा"
|
||||||
@@ -420,7 +420,7 @@ msgstr "हैंडल बदलें"
|
|||||||
msgid "Change Handle"
|
msgid "Change Handle"
|
||||||
msgstr "हैंडल बदलें"
|
msgstr "हैंडल बदलें"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:133
|
#: src/view/com/modals/VerifyEmail.tsx:141
|
||||||
msgid "Change my email"
|
msgid "Change my email"
|
||||||
msgstr "मेरा ईमेल बदलें"
|
msgstr "मेरा ईमेल बदलें"
|
||||||
|
|
||||||
@@ -504,7 +504,7 @@ msgstr "जवाब लिखो"
|
|||||||
#: src/view/com/modals/AppealLabel.tsx:98
|
#: src/view/com/modals/AppealLabel.tsx:98
|
||||||
#: src/view/com/modals/Confirm.tsx:75
|
#: src/view/com/modals/Confirm.tsx:75
|
||||||
#: src/view/com/modals/SelfLabel.tsx:154
|
#: src/view/com/modals/SelfLabel.tsx:154
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:217
|
#: src/view/com/modals/VerifyEmail.tsx:225
|
||||||
#: src/view/screens/PreferencesHomeFeed.tsx:299
|
#: src/view/screens/PreferencesHomeFeed.tsx:299
|
||||||
#: src/view/screens/PreferencesThreads.tsx:153
|
#: src/view/screens/PreferencesThreads.tsx:153
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
@@ -525,7 +525,7 @@ msgstr "खाते को हटा दें"
|
|||||||
|
|
||||||
#: src/view/com/modals/ChangeEmail.tsx:157
|
#: src/view/com/modals/ChangeEmail.tsx:157
|
||||||
#: src/view/com/modals/DeleteAccount.tsx:176
|
#: src/view/com/modals/DeleteAccount.tsx:176
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:151
|
#: src/view/com/modals/VerifyEmail.tsx:159
|
||||||
msgid "Confirmation code"
|
msgid "Confirmation code"
|
||||||
msgstr "OTP कोड"
|
msgstr "OTP कोड"
|
||||||
|
|
||||||
@@ -534,7 +534,7 @@ msgstr "OTP कोड"
|
|||||||
msgid "Connecting..."
|
msgid "Connecting..."
|
||||||
msgstr "कनेक्टिंग ..।"
|
msgstr "कनेक्टिंग ..।"
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:79
|
#: src/view/screens/Moderation.tsx:81
|
||||||
msgid "Content filtering"
|
msgid "Content filtering"
|
||||||
msgstr "सामग्री फ़िल्टरिंग"
|
msgstr "सामग्री फ़िल्टरिंग"
|
||||||
|
|
||||||
@@ -573,7 +573,7 @@ msgstr "कॉपी"
|
|||||||
msgid "Copy link to list"
|
msgid "Copy link to list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:126
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:129
|
||||||
msgid "Copy link to post"
|
msgid "Copy link to post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -581,7 +581,7 @@ msgstr ""
|
|||||||
msgid "Copy link to profile"
|
msgid "Copy link to profile"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:112
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:115
|
||||||
msgid "Copy post text"
|
msgid "Copy post text"
|
||||||
msgstr "पोस्ट टेक्स्ट कॉपी करें"
|
msgstr "पोस्ट टेक्स्ट कॉपी करें"
|
||||||
|
|
||||||
@@ -652,11 +652,11 @@ msgstr "मेरा खाता हटाएं"
|
|||||||
msgid "Delete my account…"
|
msgid "Delete my account…"
|
||||||
msgstr "मेरा खाता हटाएं…"
|
msgstr "मेरा खाता हटाएं…"
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:180
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:183
|
||||||
msgid "Delete post"
|
msgid "Delete post"
|
||||||
msgstr "पोस्ट को हटाएं"
|
msgstr "पोस्ट को हटाएं"
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:184
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:187
|
||||||
msgid "Delete this post?"
|
msgid "Delete this post?"
|
||||||
msgstr "इस पोस्ट को डीलीट करें?"
|
msgstr "इस पोस्ट को डीलीट करें?"
|
||||||
|
|
||||||
@@ -687,7 +687,7 @@ msgstr ""
|
|||||||
msgid "Discard draft"
|
msgid "Discard draft"
|
||||||
msgstr "ड्राफ्ट हटाएं"
|
msgstr "ड्राफ्ट हटाएं"
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:204
|
#: src/view/screens/Moderation.tsx:207
|
||||||
msgid "Discourage apps from showing my account to logged-out users"
|
msgid "Discourage apps from showing my account to logged-out users"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -836,7 +836,7 @@ msgstr "फ़ीड ऑफ़लाइन है"
|
|||||||
msgid "Feed Preferences"
|
msgid "Feed Preferences"
|
||||||
msgstr "फ़ीड प्राथमिकता"
|
msgstr "फ़ीड प्राथमिकता"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:64
|
#: src/view/shell/desktop/RightNav.tsx:65
|
||||||
#: src/view/shell/Drawer.tsx:292
|
#: src/view/shell/Drawer.tsx:292
|
||||||
msgid "Feedback"
|
msgid "Feedback"
|
||||||
msgstr "प्रतिक्रिया"
|
msgstr "प्रतिक्रिया"
|
||||||
@@ -928,7 +928,7 @@ msgstr "पासवर्ड भूल गए"
|
|||||||
msgid "Gallery"
|
msgid "Gallery"
|
||||||
msgstr "गैलरी"
|
msgstr "गैलरी"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:175
|
#: src/view/com/modals/VerifyEmail.tsx:183
|
||||||
msgid "Get Started"
|
msgid "Get Started"
|
||||||
msgstr "प्रारंभ करें"
|
msgstr "प्रारंभ करें"
|
||||||
|
|
||||||
@@ -956,7 +956,7 @@ msgstr "अगला"
|
|||||||
msgid "Handle"
|
msgid "Handle"
|
||||||
msgstr "हैंडल"
|
msgstr "हैंडल"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:93
|
#: src/view/shell/desktop/RightNav.tsx:94
|
||||||
#: src/view/shell/Drawer.tsx:302
|
#: src/view/shell/Drawer.tsx:302
|
||||||
msgid "Help"
|
msgid "Help"
|
||||||
msgstr "सहायता"
|
msgstr "सहायता"
|
||||||
@@ -1023,7 +1023,7 @@ msgstr "होस्टिंग प्रदाता"
|
|||||||
msgid "Hosting provider address"
|
msgid "Hosting provider address"
|
||||||
msgstr "होस्टिंग प्रदाता पता"
|
msgstr "होस्टिंग प्रदाता पता"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:200
|
#: src/view/com/modals/VerifyEmail.tsx:208
|
||||||
msgid "I have a code"
|
msgid "I have a code"
|
||||||
msgstr "मेरे पास एक OTP कोड है"
|
msgstr "मेरे पास एक OTP कोड है"
|
||||||
|
|
||||||
@@ -1039,7 +1039,7 @@ msgstr "यदि किसी को चुना जाता है, तो
|
|||||||
msgid "Image alt text"
|
msgid "Image alt text"
|
||||||
msgstr "छवि alt पाठ"
|
msgstr "छवि alt पाठ"
|
||||||
|
|
||||||
#: src/view/com/util/UserAvatar.tsx:304
|
#: src/view/com/util/UserAvatar.tsx:308
|
||||||
#: src/view/com/util/UserBanner.tsx:116
|
#: src/view/com/util/UserBanner.tsx:116
|
||||||
msgid "Image options"
|
msgid "Image options"
|
||||||
msgstr "छवि विकल्प"
|
msgstr "छवि विकल्प"
|
||||||
@@ -1113,7 +1113,7 @@ msgstr "अधिक जानें"
|
|||||||
msgid "Learn more about this warning"
|
msgid "Learn more about this warning"
|
||||||
msgstr "इस चेतावनी के बारे में अधिक जानें"
|
msgstr "इस चेतावनी के बारे में अधिक जानें"
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:239
|
#: src/view/screens/Moderation.tsx:242
|
||||||
msgid "Learn more about what is public on Bluesky."
|
msgid "Learn more about what is public on Bluesky."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1130,7 +1130,7 @@ msgstr "लीविंग Bluesky"
|
|||||||
msgid "Let's get your password reset!"
|
msgid "Let's get your password reset!"
|
||||||
msgstr "चलो अपना पासवर्ड रीसेट करें!"
|
msgstr "चलो अपना पासवर्ड रीसेट करें!"
|
||||||
|
|
||||||
#: src/view/com/util/UserAvatar.tsx:241
|
#: src/view/com/util/UserAvatar.tsx:245
|
||||||
#: src/view/com/util/UserBanner.tsx:60
|
#: src/view/com/util/UserBanner.tsx:60
|
||||||
msgid "Library"
|
msgid "Library"
|
||||||
msgstr "चित्र पुस्तकालय"
|
msgstr "चित्र पुस्तकालय"
|
||||||
@@ -1200,7 +1200,7 @@ msgstr "स्थानीय देव सर्वर"
|
|||||||
#~ msgid "Logged-out users"
|
#~ msgid "Logged-out users"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:134
|
#: src/view/screens/Moderation.tsx:136
|
||||||
msgid "Logged-out visibility"
|
msgid "Logged-out visibility"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1237,7 +1237,7 @@ msgstr "मेनू"
|
|||||||
msgid "Message from server"
|
msgid "Message from server"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:63
|
#: src/view/screens/Moderation.tsx:64
|
||||||
#: src/view/screens/Settings.tsx:563
|
#: src/view/screens/Settings.tsx:563
|
||||||
#: src/view/shell/desktop/LeftNav.tsx:391
|
#: src/view/shell/desktop/LeftNav.tsx:391
|
||||||
#: src/view/shell/Drawer.tsx:490
|
#: src/view/shell/Drawer.tsx:490
|
||||||
@@ -1245,7 +1245,7 @@ msgstr ""
|
|||||||
msgid "Moderation"
|
msgid "Moderation"
|
||||||
msgstr "मॉडरेशन"
|
msgstr "मॉडरेशन"
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:93
|
#: src/view/screens/Moderation.tsx:95
|
||||||
msgid "Moderation lists"
|
msgid "Moderation lists"
|
||||||
msgstr "मॉडरेशन सूचियाँ"
|
msgstr "मॉडरेशन सूचियाँ"
|
||||||
|
|
||||||
@@ -1283,11 +1283,11 @@ msgstr ""
|
|||||||
msgid "Mute these accounts?"
|
msgid "Mute these accounts?"
|
||||||
msgstr "इन खातों को म्यूट करें?"
|
msgstr "इन खातों को म्यूट करें?"
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:144
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:147
|
||||||
msgid "Mute thread"
|
msgid "Mute thread"
|
||||||
msgstr "थ्रेड म्यूट करें"
|
msgstr "थ्रेड म्यूट करें"
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:107
|
#: src/view/screens/Moderation.tsx:109
|
||||||
msgid "Muted accounts"
|
msgid "Muted accounts"
|
||||||
msgstr "म्यूट किए गए खाते"
|
msgstr "म्यूट किए गए खाते"
|
||||||
|
|
||||||
@@ -1413,7 +1413,7 @@ msgstr "लागू नहीं।"
|
|||||||
#~ msgid "Note: Bluesky is an open and public network, and enabling this will not make your profile private or limit the ability of logged in users to see your posts. This setting only limits the visibility of posts on the Bluesky app and website; third-party apps that display Bluesky content may not respect this setting, and could show your content to logged-out users."
|
#~ msgid "Note: Bluesky is an open and public network, and enabling this will not make your profile private or limit the ability of logged in users to see your posts. This setting only limits the visibility of posts on the Bluesky app and website; third-party apps that display Bluesky content may not respect this setting, and could show your content to logged-out users."
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:229
|
#: src/view/screens/Moderation.tsx:232
|
||||||
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
|
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1454,7 +1454,7 @@ msgstr "ओपन नेविगेशन"
|
|||||||
msgid "Opens configurable language settings"
|
msgid "Opens configurable language settings"
|
||||||
msgstr "भाषा सेटिंग्स खोलें"
|
msgstr "भाषा सेटिंग्स खोलें"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:146
|
#: src/view/shell/desktop/RightNav.tsx:148
|
||||||
#: src/view/shell/Drawer.tsx:622
|
#: src/view/shell/Drawer.tsx:622
|
||||||
msgid "Opens list of invite codes"
|
msgid "Opens list of invite codes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1603,7 +1603,7 @@ msgstr "प्राथमिक भाषा"
|
|||||||
msgid "Prioritize Your Follows"
|
msgid "Prioritize Your Follows"
|
||||||
msgstr "अपने फ़ॉलोअर्स को प्राथमिकता दें"
|
msgstr "अपने फ़ॉलोअर्स को प्राथमिकता दें"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:75
|
#: src/view/shell/desktop/RightNav.tsx:76
|
||||||
msgid "Privacy"
|
msgid "Privacy"
|
||||||
msgstr "गोपनीयता"
|
msgstr "गोपनीयता"
|
||||||
|
|
||||||
@@ -1663,7 +1663,7 @@ msgstr "अनुशंसित लोग"
|
|||||||
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
|
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
|
||||||
#: src/view/com/modals/SelfLabel.tsx:83
|
#: src/view/com/modals/SelfLabel.tsx:83
|
||||||
#: src/view/com/modals/UserAddRemoveLists.tsx:193
|
#: src/view/com/modals/UserAddRemoveLists.tsx:193
|
||||||
#: src/view/com/util/UserAvatar.tsx:278
|
#: src/view/com/util/UserAvatar.tsx:282
|
||||||
#: src/view/com/util/UserBanner.tsx:89
|
#: src/view/com/util/UserBanner.tsx:89
|
||||||
msgid "Remove"
|
msgid "Remove"
|
||||||
msgstr "निकालें"
|
msgstr "निकालें"
|
||||||
@@ -1736,7 +1736,7 @@ msgid "Report List"
|
|||||||
msgstr "रिपोर्ट सूची"
|
msgstr "रिपोर्ट सूची"
|
||||||
|
|
||||||
#: src/view/com/modals/report/SendReportButton.tsx:37
|
#: src/view/com/modals/report/SendReportButton.tsx:37
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:162
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:165
|
||||||
msgid "Report post"
|
msgid "Report post"
|
||||||
msgstr "रिपोर्ट पोस्ट"
|
msgstr "रिपोर्ट पोस्ट"
|
||||||
|
|
||||||
@@ -1890,7 +1890,7 @@ msgstr "ऐप में प्रदर्शित होने वाले
|
|||||||
msgid "Select your preferred language for translations in your feed."
|
msgid "Select your preferred language for translations in your feed."
|
||||||
msgstr "अपने फ़ीड में अनुवाद के लिए अपनी पसंदीदा भाषा चुनें।"
|
msgstr "अपने फ़ीड में अनुवाद के लिए अपनी पसंदीदा भाषा चुनें।"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:188
|
#: src/view/com/modals/VerifyEmail.tsx:196
|
||||||
msgid "Send Confirmation Email"
|
msgid "Send Confirmation Email"
|
||||||
msgstr "पुष्टिकरण ईमेल भेजें"
|
msgstr "पुष्टिकरण ईमेल भेजें"
|
||||||
|
|
||||||
@@ -1947,7 +1947,7 @@ msgid "Sexual activity or erotic nudity."
|
|||||||
msgstr "यौन गतिविधि या कामुक नग्नता।।"
|
msgstr "यौन गतिविधि या कामुक नग्नता।।"
|
||||||
|
|
||||||
#: src/view/com/profile/ProfileHeader.tsx:338
|
#: src/view/com/profile/ProfileHeader.tsx:338
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:126
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:129
|
||||||
#: src/view/screens/ProfileList.tsx:407
|
#: src/view/screens/ProfileList.tsx:407
|
||||||
msgid "Share"
|
msgid "Share"
|
||||||
msgstr "शेयर"
|
msgstr "शेयर"
|
||||||
@@ -2102,7 +2102,7 @@ msgstr "सिस्टम लॉग"
|
|||||||
msgid "Tall"
|
msgid "Tall"
|
||||||
msgstr "लंबा"
|
msgstr "लंबा"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:84
|
#: src/view/shell/desktop/RightNav.tsx:85
|
||||||
msgid "Terms"
|
msgid "Terms"
|
||||||
msgstr "शर्तें"
|
msgstr "शर्तें"
|
||||||
|
|
||||||
@@ -2167,7 +2167,7 @@ msgstr ""
|
|||||||
msgid "This information is not shared with other users."
|
msgid "This information is not shared with other users."
|
||||||
msgstr "यह जानकारी अन्य उपयोगकर्ताओं के साथ साझा नहीं की जाती है।।"
|
msgstr "यह जानकारी अन्य उपयोगकर्ताओं के साथ साझा नहीं की जाती है।।"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:105
|
#: src/view/com/modals/VerifyEmail.tsx:113
|
||||||
msgid "This is important in case you ever need to change your email or reset your password."
|
msgid "This is important in case you ever need to change your email or reset your password."
|
||||||
msgstr "अगर आपको कभी अपना ईमेल बदलने या पासवर्ड रीसेट करने की आवश्यकता है तो यह महत्वपूर्ण है।।"
|
msgstr "अगर आपको कभी अपना ईमेल बदलने या पासवर्ड रीसेट करने की आवश्यकता है तो यह महत्वपूर्ण है।।"
|
||||||
|
|
||||||
@@ -2204,9 +2204,9 @@ msgstr "ड्रॉपडाउन टॉगल करें"
|
|||||||
msgid "Transformations"
|
msgid "Transformations"
|
||||||
msgstr "परिवर्तन"
|
msgstr "परिवर्तन"
|
||||||
|
|
||||||
#: src/view/com/post-thread/PostThreadItem.tsx:704
|
|
||||||
#: src/view/com/post-thread/PostThreadItem.tsx:706
|
#: src/view/com/post-thread/PostThreadItem.tsx:706
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:98
|
#: src/view/com/post-thread/PostThreadItem.tsx:708
|
||||||
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:101
|
||||||
msgid "Translate"
|
msgid "Translate"
|
||||||
msgstr "अनुवाद"
|
msgstr "अनुवाद"
|
||||||
|
|
||||||
@@ -2250,7 +2250,7 @@ msgstr ""
|
|||||||
msgid "Unmute Account"
|
msgid "Unmute Account"
|
||||||
msgstr "अनम्यूट खाता"
|
msgstr "अनम्यूट खाता"
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:144
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:147
|
||||||
msgid "Unmute thread"
|
msgid "Unmute thread"
|
||||||
msgstr "थ्रेड को अनम्यूट करें"
|
msgstr "थ्रेड को अनम्यूट करें"
|
||||||
|
|
||||||
@@ -2485,7 +2485,7 @@ msgstr "आपका ईमेल बचाया गया है! हम ज
|
|||||||
msgid "Your email has been updated but not verified. As a next step, please verify your new email."
|
msgid "Your email has been updated but not verified. As a next step, please verify your new email."
|
||||||
msgstr "आपका ईमेल अद्यतन किया गया है लेकिन सत्यापित नहीं किया गया है। अगले चरण के रूप में, कृपया अपना नया ईमेल सत्यापित करें।।"
|
msgstr "आपका ईमेल अद्यतन किया गया है लेकिन सत्यापित नहीं किया गया है। अगले चरण के रूप में, कृपया अपना नया ईमेल सत्यापित करें।।"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:100
|
#: src/view/com/modals/VerifyEmail.tsx:108
|
||||||
msgid "Your email has not yet been verified. This is an important security step which we recommend."
|
msgid "Your email has not yet been verified. This is an important security step which we recommend."
|
||||||
msgstr "आपका ईमेल अभी तक सत्यापित नहीं हुआ है। यह एक महत्वपूर्ण सुरक्षा कदम है जिसे हम अनुशंसा करते हैं।।"
|
msgstr "आपका ईमेल अभी तक सत्यापित नहीं हुआ है। यह एक महत्वपूर्ण सुरक्षा कदम है जिसे हम अनुशंसा करते हैं।।"
|
||||||
|
|
||||||
@@ -2499,7 +2499,7 @@ msgid "Your hosting provider"
|
|||||||
msgstr "आपका होस्टिंग प्रदाता"
|
msgstr "आपका होस्टिंग प्रदाता"
|
||||||
|
|
||||||
#: src/view/screens/Settings.tsx:402
|
#: src/view/screens/Settings.tsx:402
|
||||||
#: src/view/shell/desktop/RightNav.tsx:127
|
#: src/view/shell/desktop/RightNav.tsx:129
|
||||||
#: src/view/shell/Drawer.tsx:636
|
#: src/view/shell/Drawer.tsx:636
|
||||||
msgid "Your invite codes are hidden when logged in using an App Password"
|
msgid "Your invite codes are hidden when logged in using an App Password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ msgstr ""
|
|||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Plural-Forms: \n"
|
"Plural-Forms: \n"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:158
|
#: src/view/shell/desktop/RightNav.tsx:160
|
||||||
msgid "{0, plural, one {# invite code available} other {# invite codes available}}"
|
msgid "{0, plural, one {# invite code available} other {# invite codes available}}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ msgstr "{0}"
|
|||||||
msgid "{0} {purposeLabel} List"
|
msgid "{0} {purposeLabel} List"
|
||||||
msgstr "{0} {purposeLabel} リスト"
|
msgstr "{0} {purposeLabel} リスト"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:141
|
#: src/view/shell/desktop/RightNav.tsx:143
|
||||||
msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite codes: # available}}"
|
msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite codes: # available}}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ msgstr "ALTテキスト"
|
|||||||
msgid "Alt text describes images for blind and low-vision users, and helps give context to everyone."
|
msgid "Alt text describes images for blind and low-vision users, and helps give context to everyone."
|
||||||
msgstr "ALTテキストは、視覚障害者や低視力者のために画像を説明し、すべての人に文脈を与えるのに役立ちます。"
|
msgstr "ALTテキストは、視覚障害者や低視力者のために画像を説明し、すべての人に文脈を与えるのに役立ちます。"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:110
|
#: src/view/com/modals/VerifyEmail.tsx:118
|
||||||
msgid "An email has been sent to {0}. It includes a confirmation code which you can enter below."
|
msgid "An email has been sent to {0}. It includes a confirmation code which you can enter below."
|
||||||
msgstr "Eメールが{0}に送信されました。以下に入力できる確認コードが含まれています。"
|
msgstr "Eメールが{0}に送信されました。以下に入力できる確認コードが含まれています。"
|
||||||
|
|
||||||
@@ -208,7 +208,7 @@ msgstr "本当にこの下書きを破棄しますか?"
|
|||||||
msgid "Are you sure?"
|
msgid "Are you sure?"
|
||||||
msgstr "本当ですか?"
|
msgstr "本当ですか?"
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:185
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:188
|
||||||
msgid "Are you sure? This cannot be undone."
|
msgid "Are you sure? This cannot be undone."
|
||||||
msgstr "本当ですか?これは元に戻せません。"
|
msgstr "本当ですか?これは元に戻せません。"
|
||||||
|
|
||||||
@@ -259,7 +259,7 @@ msgstr ""
|
|||||||
msgid "Block these accounts?"
|
msgid "Block these accounts?"
|
||||||
msgstr "これらのアカウントをブロックしますか?"
|
msgstr "これらのアカウントをブロックしますか?"
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:121
|
#: src/view/screens/Moderation.tsx:123
|
||||||
msgid "Blocked accounts"
|
msgid "Blocked accounts"
|
||||||
msgstr "ブロックされたブロック"
|
msgstr "ブロックされたブロック"
|
||||||
|
|
||||||
@@ -303,7 +303,7 @@ msgstr "Blueskyはオープンです。"
|
|||||||
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
|
msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon."
|
||||||
msgstr "Blueskyはより健全なコミュニティを構築するために招待状を使用します。招待状をお持ちでない方の場合、waitlistに申し込めば招待状をお送りします。"
|
msgstr "Blueskyはより健全なコミュニティを構築するために招待状を使用します。招待状をお持ちでない方の場合、waitlistに申し込めば招待状をお送りします。"
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:222
|
#: src/view/screens/Moderation.tsx:225
|
||||||
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
|
msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -316,7 +316,7 @@ msgid "Build version {0} {1}"
|
|||||||
msgstr "ビルドバージョン {0} {1}"
|
msgstr "ビルドバージョン {0} {1}"
|
||||||
|
|
||||||
#: src/view/com/composer/photos/OpenCameraBtn.tsx:60
|
#: src/view/com/composer/photos/OpenCameraBtn.tsx:60
|
||||||
#: src/view/com/util/UserAvatar.tsx:217
|
#: src/view/com/util/UserAvatar.tsx:221
|
||||||
#: src/view/com/util/UserBanner.tsx:38
|
#: src/view/com/util/UserBanner.tsx:38
|
||||||
msgid "Camera"
|
msgid "Camera"
|
||||||
msgstr "カメラ"
|
msgstr "カメラ"
|
||||||
@@ -392,7 +392,7 @@ msgstr "ハンドルを変更"
|
|||||||
msgid "Change Handle"
|
msgid "Change Handle"
|
||||||
msgstr "ハンドルを変更"
|
msgstr "ハンドルを変更"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:133
|
#: src/view/com/modals/VerifyEmail.tsx:141
|
||||||
msgid "Change my email"
|
msgid "Change my email"
|
||||||
msgstr "Eメールの変更"
|
msgstr "Eメールの変更"
|
||||||
|
|
||||||
@@ -476,7 +476,7 @@ msgstr "返信を作成"
|
|||||||
#: src/view/com/modals/AppealLabel.tsx:98
|
#: src/view/com/modals/AppealLabel.tsx:98
|
||||||
#: src/view/com/modals/Confirm.tsx:75
|
#: src/view/com/modals/Confirm.tsx:75
|
||||||
#: src/view/com/modals/SelfLabel.tsx:154
|
#: src/view/com/modals/SelfLabel.tsx:154
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:217
|
#: src/view/com/modals/VerifyEmail.tsx:225
|
||||||
#: src/view/screens/PreferencesHomeFeed.tsx:299
|
#: src/view/screens/PreferencesHomeFeed.tsx:299
|
||||||
#: src/view/screens/PreferencesThreads.tsx:153
|
#: src/view/screens/PreferencesThreads.tsx:153
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
@@ -497,7 +497,7 @@ msgstr "アカウントの削除を確認"
|
|||||||
|
|
||||||
#: src/view/com/modals/ChangeEmail.tsx:157
|
#: src/view/com/modals/ChangeEmail.tsx:157
|
||||||
#: src/view/com/modals/DeleteAccount.tsx:176
|
#: src/view/com/modals/DeleteAccount.tsx:176
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:151
|
#: src/view/com/modals/VerifyEmail.tsx:159
|
||||||
msgid "Confirmation code"
|
msgid "Confirmation code"
|
||||||
msgstr "確認コード"
|
msgstr "確認コード"
|
||||||
|
|
||||||
@@ -506,7 +506,7 @@ msgstr "確認コード"
|
|||||||
msgid "Connecting..."
|
msgid "Connecting..."
|
||||||
msgstr "接続中..."
|
msgstr "接続中..."
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:79
|
#: src/view/screens/Moderation.tsx:81
|
||||||
msgid "Content filtering"
|
msgid "Content filtering"
|
||||||
msgstr "コンテンツフィルタリング"
|
msgstr "コンテンツフィルタリング"
|
||||||
|
|
||||||
@@ -545,7 +545,7 @@ msgstr "コピー"
|
|||||||
msgid "Copy link to list"
|
msgid "Copy link to list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:126
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:129
|
||||||
msgid "Copy link to post"
|
msgid "Copy link to post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -553,7 +553,7 @@ msgstr ""
|
|||||||
msgid "Copy link to profile"
|
msgid "Copy link to profile"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:112
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:115
|
||||||
msgid "Copy post text"
|
msgid "Copy post text"
|
||||||
msgstr "投稿テキストをコピー"
|
msgstr "投稿テキストをコピー"
|
||||||
|
|
||||||
@@ -620,11 +620,11 @@ msgstr "マイアカウントを削除"
|
|||||||
msgid "Delete my account…"
|
msgid "Delete my account…"
|
||||||
msgstr "マイアカウントを削除…"
|
msgstr "マイアカウントを削除…"
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:180
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:183
|
||||||
msgid "Delete post"
|
msgid "Delete post"
|
||||||
msgstr "投稿を削除"
|
msgstr "投稿を削除"
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:184
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:187
|
||||||
msgid "Delete this post?"
|
msgid "Delete this post?"
|
||||||
msgstr "この投稿を削除しますか?"
|
msgstr "この投稿を削除しますか?"
|
||||||
|
|
||||||
@@ -655,7 +655,7 @@ msgstr "破棄"
|
|||||||
msgid "Discard draft"
|
msgid "Discard draft"
|
||||||
msgstr "ドラフトを破棄"
|
msgstr "ドラフトを破棄"
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:204
|
#: src/view/screens/Moderation.tsx:207
|
||||||
msgid "Discourage apps from showing my account to logged-out users"
|
msgid "Discourage apps from showing my account to logged-out users"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -804,7 +804,7 @@ msgstr "フィードはオフライン"
|
|||||||
msgid "Feed Preferences"
|
msgid "Feed Preferences"
|
||||||
msgstr "フィード設定"
|
msgstr "フィード設定"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:64
|
#: src/view/shell/desktop/RightNav.tsx:65
|
||||||
#: src/view/shell/Drawer.tsx:292
|
#: src/view/shell/Drawer.tsx:292
|
||||||
msgid "Feedback"
|
msgid "Feedback"
|
||||||
msgstr "フィードバック"
|
msgstr "フィードバック"
|
||||||
@@ -896,7 +896,7 @@ msgstr "パスワードを失念"
|
|||||||
msgid "Gallery"
|
msgid "Gallery"
|
||||||
msgstr "ギャラリー"
|
msgstr "ギャラリー"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:175
|
#: src/view/com/modals/VerifyEmail.tsx:183
|
||||||
msgid "Get Started"
|
msgid "Get Started"
|
||||||
msgstr "はじめに"
|
msgstr "はじめに"
|
||||||
|
|
||||||
@@ -924,7 +924,7 @@ msgstr "次へ"
|
|||||||
msgid "Handle"
|
msgid "Handle"
|
||||||
msgstr "ハンドル"
|
msgstr "ハンドル"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:93
|
#: src/view/shell/desktop/RightNav.tsx:94
|
||||||
#: src/view/shell/Drawer.tsx:302
|
#: src/view/shell/Drawer.tsx:302
|
||||||
msgid "Help"
|
msgid "Help"
|
||||||
msgstr "ヘルプ"
|
msgstr "ヘルプ"
|
||||||
@@ -983,7 +983,7 @@ msgstr "ホスティングプロバイダー"
|
|||||||
msgid "Hosting provider address"
|
msgid "Hosting provider address"
|
||||||
msgstr "ホスティングプロバイダーアドレス"
|
msgstr "ホスティングプロバイダーアドレス"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:200
|
#: src/view/com/modals/VerifyEmail.tsx:208
|
||||||
msgid "I have a code"
|
msgid "I have a code"
|
||||||
msgstr "コードを持っている"
|
msgstr "コードを持っている"
|
||||||
|
|
||||||
@@ -999,7 +999,7 @@ msgstr "選択されていない場合は、すべての年齢に適していま
|
|||||||
msgid "Image alt text"
|
msgid "Image alt text"
|
||||||
msgstr "画像のALTテキスト"
|
msgstr "画像のALTテキスト"
|
||||||
|
|
||||||
#: src/view/com/util/UserAvatar.tsx:304
|
#: src/view/com/util/UserAvatar.tsx:308
|
||||||
#: src/view/com/util/UserBanner.tsx:116
|
#: src/view/com/util/UserBanner.tsx:116
|
||||||
msgid "Image options"
|
msgid "Image options"
|
||||||
msgstr "イメージオプション"
|
msgstr "イメージオプション"
|
||||||
@@ -1068,7 +1068,7 @@ msgstr "詳細"
|
|||||||
msgid "Learn more about this warning"
|
msgid "Learn more about this warning"
|
||||||
msgstr "この警告の詳細"
|
msgstr "この警告の詳細"
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:239
|
#: src/view/screens/Moderation.tsx:242
|
||||||
msgid "Learn more about what is public on Bluesky."
|
msgid "Learn more about what is public on Bluesky."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1085,7 +1085,7 @@ msgstr "Blueskyから離れる"
|
|||||||
msgid "Let's get your password reset!"
|
msgid "Let's get your password reset!"
|
||||||
msgstr "パスワードをリセットしましょう!"
|
msgstr "パスワードをリセットしましょう!"
|
||||||
|
|
||||||
#: src/view/com/util/UserAvatar.tsx:241
|
#: src/view/com/util/UserAvatar.tsx:245
|
||||||
#: src/view/com/util/UserBanner.tsx:60
|
#: src/view/com/util/UserBanner.tsx:60
|
||||||
msgid "Library"
|
msgid "Library"
|
||||||
msgstr "ライブラリー"
|
msgstr "ライブラリー"
|
||||||
@@ -1147,7 +1147,7 @@ msgstr "ローカル開発者サーバー"
|
|||||||
#~ msgid "Logged-out users"
|
#~ msgid "Logged-out users"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:134
|
#: src/view/screens/Moderation.tsx:136
|
||||||
msgid "Logged-out visibility"
|
msgid "Logged-out visibility"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1184,7 +1184,7 @@ msgstr "メニュー"
|
|||||||
msgid "Message from server"
|
msgid "Message from server"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:63
|
#: src/view/screens/Moderation.tsx:64
|
||||||
#: src/view/screens/Settings.tsx:563
|
#: src/view/screens/Settings.tsx:563
|
||||||
#: src/view/shell/desktop/LeftNav.tsx:391
|
#: src/view/shell/desktop/LeftNav.tsx:391
|
||||||
#: src/view/shell/Drawer.tsx:490
|
#: src/view/shell/Drawer.tsx:490
|
||||||
@@ -1192,7 +1192,7 @@ msgstr ""
|
|||||||
msgid "Moderation"
|
msgid "Moderation"
|
||||||
msgstr "モデレート"
|
msgstr "モデレート"
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:93
|
#: src/view/screens/Moderation.tsx:95
|
||||||
msgid "Moderation lists"
|
msgid "Moderation lists"
|
||||||
msgstr "モデレートリスト"
|
msgstr "モデレートリスト"
|
||||||
|
|
||||||
@@ -1226,11 +1226,11 @@ msgstr ""
|
|||||||
msgid "Mute these accounts?"
|
msgid "Mute these accounts?"
|
||||||
msgstr "これらのアカウントをミュートしますか?"
|
msgstr "これらのアカウントをミュートしますか?"
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:144
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:147
|
||||||
msgid "Mute thread"
|
msgid "Mute thread"
|
||||||
msgstr "スレッドをミュート"
|
msgstr "スレッドをミュート"
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:107
|
#: src/view/screens/Moderation.tsx:109
|
||||||
msgid "Muted accounts"
|
msgid "Muted accounts"
|
||||||
msgstr "ミュート済みアカウント"
|
msgstr "ミュート済みアカウント"
|
||||||
|
|
||||||
@@ -1343,7 +1343,7 @@ msgstr "該当なし。"
|
|||||||
#~ msgid "Note: Bluesky is an open and public network, and enabling this will not make your profile private or limit the ability of logged in users to see your posts. This setting only limits the visibility of posts on the Bluesky app and website; third-party apps that display Bluesky content may not respect this setting, and could show your content to logged-out users."
|
#~ msgid "Note: Bluesky is an open and public network, and enabling this will not make your profile private or limit the ability of logged in users to see your posts. This setting only limits the visibility of posts on the Bluesky app and website; third-party apps that display Bluesky content may not respect this setting, and could show your content to logged-out users."
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
|
||||||
#: src/view/screens/Moderation.tsx:229
|
#: src/view/screens/Moderation.tsx:232
|
||||||
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
|
msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1380,7 +1380,7 @@ msgstr "ナビゲーションを開く"
|
|||||||
msgid "Opens configurable language settings"
|
msgid "Opens configurable language settings"
|
||||||
msgstr "構成可能な言語設定を開く"
|
msgstr "構成可能な言語設定を開く"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:146
|
#: src/view/shell/desktop/RightNav.tsx:148
|
||||||
#: src/view/shell/Drawer.tsx:622
|
#: src/view/shell/Drawer.tsx:622
|
||||||
msgid "Opens list of invite codes"
|
msgid "Opens list of invite codes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -1529,7 +1529,7 @@ msgstr "第一言語"
|
|||||||
msgid "Prioritize Your Follows"
|
msgid "Prioritize Your Follows"
|
||||||
msgstr "フォローの優先順位付け"
|
msgstr "フォローの優先順位付け"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:75
|
#: src/view/shell/desktop/RightNav.tsx:76
|
||||||
msgid "Privacy"
|
msgid "Privacy"
|
||||||
msgstr "プライバシー"
|
msgstr "プライバシー"
|
||||||
|
|
||||||
@@ -1584,7 +1584,7 @@ msgstr "推奨ユーザー"
|
|||||||
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
|
#: src/view/com/modals/ListAddRemoveUsers.tsx:264
|
||||||
#: src/view/com/modals/SelfLabel.tsx:83
|
#: src/view/com/modals/SelfLabel.tsx:83
|
||||||
#: src/view/com/modals/UserAddRemoveLists.tsx:193
|
#: src/view/com/modals/UserAddRemoveLists.tsx:193
|
||||||
#: src/view/com/util/UserAvatar.tsx:278
|
#: src/view/com/util/UserAvatar.tsx:282
|
||||||
#: src/view/com/util/UserBanner.tsx:89
|
#: src/view/com/util/UserBanner.tsx:89
|
||||||
msgid "Remove"
|
msgid "Remove"
|
||||||
msgstr "削除"
|
msgstr "削除"
|
||||||
@@ -1657,7 +1657,7 @@ msgid "Report List"
|
|||||||
msgstr "レポートリスト"
|
msgstr "レポートリスト"
|
||||||
|
|
||||||
#: src/view/com/modals/report/SendReportButton.tsx:37
|
#: src/view/com/modals/report/SendReportButton.tsx:37
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:162
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:165
|
||||||
msgid "Report post"
|
msgid "Report post"
|
||||||
msgstr "レポート投稿"
|
msgstr "レポート投稿"
|
||||||
|
|
||||||
@@ -1795,7 +1795,7 @@ msgstr "アプリに表示するデフォルトのテキストのアプリ言語
|
|||||||
msgid "Select your preferred language for translations in your feed."
|
msgid "Select your preferred language for translations in your feed."
|
||||||
msgstr "フィード内の翻訳に使用する言語を選択します。"
|
msgstr "フィード内の翻訳に使用する言語を選択します。"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:188
|
#: src/view/com/modals/VerifyEmail.tsx:196
|
||||||
msgid "Send Confirmation Email"
|
msgid "Send Confirmation Email"
|
||||||
msgstr "確認Eメールを送信"
|
msgstr "確認Eメールを送信"
|
||||||
|
|
||||||
@@ -1852,7 +1852,7 @@ msgid "Sexual activity or erotic nudity."
|
|||||||
msgstr "性行為またはエロティックなヌード。"
|
msgstr "性行為またはエロティックなヌード。"
|
||||||
|
|
||||||
#: src/view/com/profile/ProfileHeader.tsx:338
|
#: src/view/com/profile/ProfileHeader.tsx:338
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:126
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:129
|
||||||
#: src/view/screens/ProfileList.tsx:407
|
#: src/view/screens/ProfileList.tsx:407
|
||||||
msgid "Share"
|
msgid "Share"
|
||||||
msgstr "共有"
|
msgstr "共有"
|
||||||
@@ -1999,7 +1999,7 @@ msgstr "システムログ"
|
|||||||
msgid "Tall"
|
msgid "Tall"
|
||||||
msgstr "トール"
|
msgstr "トール"
|
||||||
|
|
||||||
#: src/view/shell/desktop/RightNav.tsx:84
|
#: src/view/shell/desktop/RightNav.tsx:85
|
||||||
msgid "Terms"
|
msgid "Terms"
|
||||||
msgstr "条件"
|
msgstr "条件"
|
||||||
|
|
||||||
@@ -2064,7 +2064,7 @@ msgstr ""
|
|||||||
msgid "This information is not shared with other users."
|
msgid "This information is not shared with other users."
|
||||||
msgstr "この情報は他のユーザーと共有されません。"
|
msgstr "この情報は他のユーザーと共有されません。"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:105
|
#: src/view/com/modals/VerifyEmail.tsx:113
|
||||||
msgid "This is important in case you ever need to change your email or reset your password."
|
msgid "This is important in case you ever need to change your email or reset your password."
|
||||||
msgstr "これは、Eメールの変更やパスワードのリセットが必要な場合に重要です。"
|
msgstr "これは、Eメールの変更やパスワードのリセットが必要な場合に重要です。"
|
||||||
|
|
||||||
@@ -2101,9 +2101,9 @@ msgstr "トグルドロップダウン"
|
|||||||
msgid "Transformations"
|
msgid "Transformations"
|
||||||
msgstr "変換"
|
msgstr "変換"
|
||||||
|
|
||||||
#: src/view/com/post-thread/PostThreadItem.tsx:704
|
|
||||||
#: src/view/com/post-thread/PostThreadItem.tsx:706
|
#: src/view/com/post-thread/PostThreadItem.tsx:706
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:98
|
#: src/view/com/post-thread/PostThreadItem.tsx:708
|
||||||
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:101
|
||||||
msgid "Translate"
|
msgid "Translate"
|
||||||
msgstr "翻訳"
|
msgstr "翻訳"
|
||||||
|
|
||||||
@@ -2147,7 +2147,7 @@ msgstr "残念ながら、アカウントを作成するための要件を満た
|
|||||||
msgid "Unmute Account"
|
msgid "Unmute Account"
|
||||||
msgstr "アカウントのミュート解除"
|
msgstr "アカウントのミュート解除"
|
||||||
|
|
||||||
#: src/view/com/util/forms/PostDropdownBtn.tsx:144
|
#: src/view/com/util/forms/PostDropdownBtn.tsx:147
|
||||||
msgid "Unmute thread"
|
msgid "Unmute thread"
|
||||||
msgstr "スレッドのミュート解除"
|
msgstr "スレッドのミュート解除"
|
||||||
|
|
||||||
@@ -2366,7 +2366,7 @@ msgstr "Eメールが保存されました!すぐにご連絡いたします
|
|||||||
msgid "Your email has been updated but not verified. As a next step, please verify your new email."
|
msgid "Your email has been updated but not verified. As a next step, please verify your new email."
|
||||||
msgstr "Eメールは更新されましたが、確認されていません。次のステップとして、新しいEメールを確認してください。"
|
msgstr "Eメールは更新されましたが、確認されていません。次のステップとして、新しいEメールを確認してください。"
|
||||||
|
|
||||||
#: src/view/com/modals/VerifyEmail.tsx:100
|
#: src/view/com/modals/VerifyEmail.tsx:108
|
||||||
msgid "Your email has not yet been verified. This is an important security step which we recommend."
|
msgid "Your email has not yet been verified. This is an important security step which we recommend."
|
||||||
msgstr "Eメールはまだ確認されていません。これは、当社が推奨する重要なセキュリティステップです。"
|
msgstr "Eメールはまだ確認されていません。これは、当社が推奨する重要なセキュリティステップです。"
|
||||||
|
|
||||||
@@ -2380,7 +2380,7 @@ msgid "Your hosting provider"
|
|||||||
msgstr "ホスティングプロバイダー"
|
msgstr "ホスティングプロバイダー"
|
||||||
|
|
||||||
#: src/view/screens/Settings.tsx:402
|
#: src/view/screens/Settings.tsx:402
|
||||||
#: src/view/shell/desktop/RightNav.tsx:127
|
#: src/view/shell/desktop/RightNav.tsx:129
|
||||||
#: src/view/shell/Drawer.tsx:636
|
#: src/view/shell/Drawer.tsx:636
|
||||||
msgid "Your invite codes are hidden when logged in using an App Password"
|
msgid "Your invite codes are hidden when logged in using an App Password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
* 3. Don't call this query's `refetch()` if you're trying to sync latest; call `checkUnread()` instead.
|
* 3. Don't call this query's `refetch()` if you're trying to sync latest; call `checkUnread()` instead.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {useEffect, useRef} from 'react'
|
import {useEffect} from 'react'
|
||||||
import {AppBskyFeedDefs} from '@atproto/api'
|
import {AppBskyFeedDefs} from '@atproto/api'
|
||||||
import {
|
import {
|
||||||
useInfiniteQuery,
|
useInfiniteQuery,
|
||||||
@@ -49,8 +49,6 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
|
|||||||
const threadMutes = useMutedThreads()
|
const threadMutes = useMutedThreads()
|
||||||
const unreads = useUnreadNotificationsApi()
|
const unreads = useUnreadNotificationsApi()
|
||||||
const enabled = opts?.enabled !== false
|
const enabled = opts?.enabled !== false
|
||||||
// state tracked across page fetches
|
|
||||||
const pageState = useRef({pageNum: 0, hasMarkedRead: false})
|
|
||||||
|
|
||||||
const query = useInfiniteQuery<
|
const query = useInfiniteQuery<
|
||||||
FeedPage,
|
FeedPage,
|
||||||
@@ -66,8 +64,6 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
|
|||||||
if (!pageParam) {
|
if (!pageParam) {
|
||||||
// for the first page, we check the cached page held by the unread-checker first
|
// for the first page, we check the cached page held by the unread-checker first
|
||||||
page = unreads.getCachedUnreadPage()
|
page = unreads.getCachedUnreadPage()
|
||||||
// reset the page state
|
|
||||||
pageState.current = {pageNum: 0, hasMarkedRead: false}
|
|
||||||
}
|
}
|
||||||
if (!page) {
|
if (!page) {
|
||||||
page = await fetchPage({
|
page = await fetchPage({
|
||||||
@@ -80,27 +76,9 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE
|
// if the first page has an unread, mark all read
|
||||||
// this section checks to see if we need to mark notifs read
|
if (!pageParam && page.items[0] && !page.items[0].notification.isRead) {
|
||||||
// we want to wait until we've seen a read notification because
|
unreads.markAllRead()
|
||||||
// of a timing challenge; marking read on the first page would
|
|
||||||
// cause subsequent pages of unread notifs to incorrectly come
|
|
||||||
// back as "read". we use page 6 as an abort condition, which means
|
|
||||||
// after ~180 notifs we give up on tracking unread state correctly
|
|
||||||
// -prf
|
|
||||||
if (!pageState.current.hasMarkedRead) {
|
|
||||||
let hasMarkedRead = false
|
|
||||||
if (
|
|
||||||
pageState.current.pageNum > 5 ||
|
|
||||||
page.items.some(item => item.notification.isRead)
|
|
||||||
) {
|
|
||||||
unreads.markAllRead()
|
|
||||||
hasMarkedRead = true
|
|
||||||
}
|
|
||||||
pageState.current = {
|
|
||||||
pageNum: pageState.current.pageNum + 1,
|
|
||||||
hasMarkedRead,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return page
|
return page
|
||||||
@@ -108,6 +86,20 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
|
|||||||
initialPageParam: undefined,
|
initialPageParam: undefined,
|
||||||
getNextPageParam: lastPage => lastPage.cursor,
|
getNextPageParam: lastPage => lastPage.cursor,
|
||||||
enabled,
|
enabled,
|
||||||
|
select(data: InfiniteData<FeedPage>) {
|
||||||
|
// override 'isRead' using the first page's returned seenAt
|
||||||
|
// we do this because the `markAllRead()` call above will
|
||||||
|
// mark subsequent pages as read prematurely
|
||||||
|
const seenAt = data.pages[0]?.seenAt || new Date()
|
||||||
|
for (const page of data.pages) {
|
||||||
|
for (const item of page.items) {
|
||||||
|
item.notification.isRead =
|
||||||
|
seenAt > new Date(item.notification.indexedAt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -122,7 +114,13 @@ export function useNotificationFeedQuery(opts?: {enabled?: boolean}) {
|
|||||||
count += page.items.length
|
count += page.items.length
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isFetching && hasNextPage && count < PAGE_SIZE && numEmpties < 3) {
|
if (
|
||||||
|
!isFetching &&
|
||||||
|
hasNextPage &&
|
||||||
|
count < PAGE_SIZE &&
|
||||||
|
numEmpties < 3 &&
|
||||||
|
(data?.pages.length || 0) < 6
|
||||||
|
) {
|
||||||
query.fetchNextPage()
|
query.fetchNextPage()
|
||||||
}
|
}
|
||||||
}, [query])
|
}, [query])
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export interface FeedNotification {
|
|||||||
|
|
||||||
export interface FeedPage {
|
export interface FeedPage {
|
||||||
cursor: string | undefined
|
cursor: string | undefined
|
||||||
|
seenAt: Date
|
||||||
items: FeedNotification[]
|
items: FeedNotification[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,8 +68,14 @@ export async function fetchPage({
|
|||||||
notif => !isThreadMuted(notif, threadMutes),
|
notif => !isThreadMuted(notif, threadMutes),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let seenAt = res.data.seenAt ? new Date(res.data.seenAt) : new Date()
|
||||||
|
if (Number.isNaN(seenAt.getTime())) {
|
||||||
|
seenAt = new Date()
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cursor: res.data.cursor,
|
cursor: res.data.cursor,
|
||||||
|
seenAt,
|
||||||
items: notifsGrouped,
|
items: notifsGrouped,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -291,7 +291,13 @@ export function usePostFeedQuery(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isFetching && hasNextPage && count < PAGE_SIZE && numEmpties < 3) {
|
if (
|
||||||
|
!isFetching &&
|
||||||
|
hasNextPage &&
|
||||||
|
count < PAGE_SIZE &&
|
||||||
|
numEmpties < 3 &&
|
||||||
|
(data?.pages.length || 0) < 6
|
||||||
|
) {
|
||||||
query.fetchNextPage()
|
query.fetchNextPage()
|
||||||
}
|
}
|
||||||
}, [query])
|
}, [query])
|
||||||
|
|||||||
@@ -361,6 +361,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (canReusePrevSession) {
|
if (canReusePrevSession) {
|
||||||
|
logger.info(`session: attempting to reuse previous session`)
|
||||||
|
|
||||||
agent.session = prevSession
|
agent.session = prevSession
|
||||||
__globalAgent = agent
|
__globalAgent = agent
|
||||||
queryClient.clear()
|
queryClient.clear()
|
||||||
@@ -370,6 +372,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||||||
resumeSessionWithFreshAccount()
|
resumeSessionWithFreshAccount()
|
||||||
.then(freshAccount => {
|
.then(freshAccount => {
|
||||||
if (JSON.stringify(account) !== JSON.stringify(freshAccount)) {
|
if (JSON.stringify(account) !== JSON.stringify(freshAccount)) {
|
||||||
|
logger.info(
|
||||||
|
`session: reuse of previous session returned a fresh account, upserting`,
|
||||||
|
)
|
||||||
upsertAccount(freshAccount)
|
upsertAccount(freshAccount)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -385,6 +390,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||||||
__globalAgent = PUBLIC_BSKY_AGENT
|
__globalAgent = PUBLIC_BSKY_AGENT
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
logger.info(`session: attempting to resume using previous session`)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const freshAccount = await resumeSessionWithFreshAccount()
|
const freshAccount = await resumeSessionWithFreshAccount()
|
||||||
__globalAgent = agent
|
__globalAgent = agent
|
||||||
@@ -404,6 +411,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function resumeSessionWithFreshAccount(): Promise<SessionAccount> {
|
async function resumeSessionWithFreshAccount(): Promise<SessionAccount> {
|
||||||
|
logger.info(`session: resumeSessionWithFreshAccount`)
|
||||||
|
|
||||||
await networkRetry(1, () => agent.resumeSession(prevSession))
|
await networkRetry(1, () => agent.resumeSession(prevSession))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -7,13 +7,15 @@ import {useNavigation} from '@react-navigation/native'
|
|||||||
import {useAnalytics} from 'lib/analytics/analytics'
|
import {useAnalytics} from 'lib/analytics/analytics'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
|
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
|
||||||
import {useOnMainScroll} from 'lib/hooks/useOnMainScroll'
|
import {MainScrollProvider} from '../util/MainScrollProvider'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||||
|
import {useSetMinimalShellMode} from '#/state/shell'
|
||||||
import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed'
|
import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed'
|
||||||
import {ComposeIcon2} from 'lib/icons'
|
import {ComposeIcon2} from 'lib/icons'
|
||||||
import {colors, s} from 'lib/styles'
|
import {colors, s} from 'lib/styles'
|
||||||
import {FlatList, View, useWindowDimensions} from 'react-native'
|
import {View, useWindowDimensions} from 'react-native'
|
||||||
|
import {ListMethods} from '../util/List'
|
||||||
import {Feed} from '../posts/Feed'
|
import {Feed} from '../posts/Feed'
|
||||||
import {TextLink} from '../util/Link'
|
import {TextLink} from '../util/Link'
|
||||||
import {FAB} from '../util/fab/FAB'
|
import {FAB} from '../util/fab/FAB'
|
||||||
@@ -51,10 +53,11 @@ export function FeedPage({
|
|||||||
const {isDesktop} = useWebMediaQueries()
|
const {isDesktop} = useWebMediaQueries()
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const {openComposer} = useComposerControls()
|
const {openComposer} = useComposerControls()
|
||||||
const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll()
|
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
|
||||||
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
const {screen, track} = useAnalytics()
|
const {screen, track} = useAnalytics()
|
||||||
const headerOffset = useHeaderOffset()
|
const headerOffset = useHeaderOffset()
|
||||||
const scrollElRef = React.useRef<FlatList>(null)
|
const scrollElRef = React.useRef<ListMethods>(null)
|
||||||
const [hasNew, setHasNew] = React.useState(false)
|
const [hasNew, setHasNew] = React.useState(false)
|
||||||
|
|
||||||
const scrollToTop = React.useCallback(() => {
|
const scrollToTop = React.useCallback(() => {
|
||||||
@@ -62,8 +65,8 @@ export function FeedPage({
|
|||||||
animated: isNative,
|
animated: isNative,
|
||||||
offset: -headerOffset,
|
offset: -headerOffset,
|
||||||
})
|
})
|
||||||
resetMainScroll()
|
setMinimalShellMode(false)
|
||||||
}, [headerOffset, resetMainScroll])
|
}, [headerOffset, setMinimalShellMode])
|
||||||
|
|
||||||
const onSoftReset = React.useCallback(() => {
|
const onSoftReset = React.useCallback(() => {
|
||||||
const isScreenFocused =
|
const isScreenFocused =
|
||||||
@@ -164,21 +167,22 @@ export function FeedPage({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View testID={testID} style={s.h100pct}>
|
<View testID={testID} style={s.h100pct}>
|
||||||
<Feed
|
<MainScrollProvider>
|
||||||
testID={testID ? `${testID}-feed` : undefined}
|
<Feed
|
||||||
enabled={isPageFocused}
|
testID={testID ? `${testID}-feed` : undefined}
|
||||||
feed={feed}
|
enabled={isPageFocused}
|
||||||
feedParams={feedParams}
|
feed={feed}
|
||||||
pollInterval={POLL_FREQ}
|
feedParams={feedParams}
|
||||||
scrollElRef={scrollElRef}
|
pollInterval={POLL_FREQ}
|
||||||
onScroll={onMainScroll}
|
scrollElRef={scrollElRef}
|
||||||
onHasNew={setHasNew}
|
onScrolledDownChange={setIsScrolledDown}
|
||||||
scrollEventThrottle={1}
|
onHasNew={setHasNew}
|
||||||
renderEmptyState={renderEmptyState}
|
renderEmptyState={renderEmptyState}
|
||||||
renderEndOfFeed={renderEndOfFeed}
|
renderEndOfFeed={renderEndOfFeed}
|
||||||
ListHeaderComponent={ListHeaderComponent}
|
ListHeaderComponent={ListHeaderComponent}
|
||||||
headerOffset={headerOffset}
|
headerOffset={headerOffset}
|
||||||
/>
|
/>
|
||||||
|
</MainScrollProvider>
|
||||||
{(isScrolledDown || hasNew) && (
|
{(isScrolledDown || hasNew) && (
|
||||||
<LoadLatestBtn
|
<LoadLatestBtn
|
||||||
onPress={onPressLoadLatest}
|
onPress={onPressLoadLatest}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {MutableRefObject} from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
Dimensions,
|
Dimensions,
|
||||||
RefreshControl,
|
RefreshControl,
|
||||||
@@ -8,18 +8,16 @@ import {
|
|||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
import {FlatList} from '../util/Views'
|
import {List, ListRef} from '../util/List'
|
||||||
import {FeedSourceCardLoaded} from './FeedSourceCard'
|
import {FeedSourceCardLoaded} from './FeedSourceCard'
|
||||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useProfileFeedgensQuery, RQKEY} from '#/state/queries/profile-feedgens'
|
import {useProfileFeedgensQuery, RQKEY} from '#/state/queries/profile-feedgens'
|
||||||
import {OnScrollHandler} from '#/lib/hooks/useOnMainScroll'
|
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {Trans} from '@lingui/macro'
|
import {Trans} from '@lingui/macro'
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
|
||||||
import {useTheme} from '#/lib/ThemeContext'
|
import {useTheme} from '#/lib/ThemeContext'
|
||||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||||
import {hydrateFeedGenerator} from '#/state/queries/feed'
|
import {hydrateFeedGenerator} from '#/state/queries/feed'
|
||||||
@@ -37,9 +35,7 @@ interface SectionRef {
|
|||||||
|
|
||||||
interface ProfileFeedgensProps {
|
interface ProfileFeedgensProps {
|
||||||
did: string
|
did: string
|
||||||
scrollElRef: MutableRefObject<FlatList<any> | null>
|
scrollElRef: ListRef
|
||||||
onScroll?: OnScrollHandler
|
|
||||||
scrollEventThrottle?: number
|
|
||||||
headerOffset: number
|
headerOffset: number
|
||||||
enabled?: boolean
|
enabled?: boolean
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
@@ -50,16 +46,7 @@ export const ProfileFeedgens = React.forwardRef<
|
|||||||
SectionRef,
|
SectionRef,
|
||||||
ProfileFeedgensProps
|
ProfileFeedgensProps
|
||||||
>(function ProfileFeedgensImpl(
|
>(function ProfileFeedgensImpl(
|
||||||
{
|
{did, scrollElRef, headerOffset, enabled, style, testID},
|
||||||
did,
|
|
||||||
scrollElRef,
|
|
||||||
onScroll,
|
|
||||||
scrollEventThrottle,
|
|
||||||
headerOffset,
|
|
||||||
enabled,
|
|
||||||
style,
|
|
||||||
testID,
|
|
||||||
},
|
|
||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
@@ -185,10 +172,9 @@ export const ProfileFeedgens = React.forwardRef<
|
|||||||
[error, refetch, onPressRetryLoadMore, pal, preferences],
|
[error, refetch, onPressRetryLoadMore, pal, preferences],
|
||||||
)
|
)
|
||||||
|
|
||||||
const scrollHandler = useAnimatedScrollHandler(onScroll || {})
|
|
||||||
return (
|
return (
|
||||||
<View testID={testID} style={style}>
|
<View testID={testID} style={style}>
|
||||||
<FlatList
|
<List
|
||||||
testID={testID ? `${testID}-flatlist` : undefined}
|
testID={testID ? `${testID}-flatlist` : undefined}
|
||||||
ref={scrollElRef}
|
ref={scrollElRef}
|
||||||
data={items}
|
data={items}
|
||||||
@@ -207,8 +193,6 @@ export const ProfileFeedgens = React.forwardRef<
|
|||||||
minHeight: Dimensions.get('window').height * 1.5,
|
minHeight: Dimensions.get('window').height * 1.5,
|
||||||
}}
|
}}
|
||||||
style={{paddingTop: headerOffset}}
|
style={{paddingTop: headerOffset}}
|
||||||
onScroll={onScroll != null ? scrollHandler : undefined}
|
|
||||||
scrollEventThrottle={scrollEventThrottle}
|
|
||||||
indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'}
|
indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'}
|
||||||
removeClippedSubviews={true}
|
removeClippedSubviews={true}
|
||||||
contentOffset={{x: 0, y: headerOffset * -1}}
|
contentOffset={{x: 0, y: headerOffset * -1}}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {MutableRefObject} from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
Dimensions,
|
Dimensions,
|
||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {AppBskyActorDefs, AppBskyGraphDefs} from '@atproto/api'
|
import {AppBskyActorDefs, AppBskyGraphDefs} from '@atproto/api'
|
||||||
import {FlatList} from '../util/Views'
|
import {List, ListRef} from '../util/List'
|
||||||
import {ProfileCardFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
|
import {ProfileCardFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
|
||||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
||||||
@@ -18,10 +18,8 @@ import {useAnalytics} from 'lib/analytics/analytics'
|
|||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||||
import {useListMembersQuery} from '#/state/queries/list-members'
|
import {useListMembersQuery} from '#/state/queries/list-members'
|
||||||
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
|
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {useModalControls} from '#/state/modals'
|
import {useModalControls} from '#/state/modals'
|
||||||
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
|
|
||||||
@@ -34,24 +32,22 @@ export function ListMembers({
|
|||||||
list,
|
list,
|
||||||
style,
|
style,
|
||||||
scrollElRef,
|
scrollElRef,
|
||||||
onScroll,
|
onScrolledDownChange,
|
||||||
onPressTryAgain,
|
onPressTryAgain,
|
||||||
renderHeader,
|
renderHeader,
|
||||||
renderEmptyState,
|
renderEmptyState,
|
||||||
testID,
|
testID,
|
||||||
scrollEventThrottle,
|
|
||||||
headerOffset = 0,
|
headerOffset = 0,
|
||||||
desktopFixedHeightOffset,
|
desktopFixedHeightOffset,
|
||||||
}: {
|
}: {
|
||||||
list: string
|
list: string
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
scrollElRef?: MutableRefObject<FlatList<any> | null>
|
scrollElRef?: ListRef
|
||||||
onScroll: OnScrollHandler
|
onScrolledDownChange: (isScrolledDown: boolean) => void
|
||||||
onPressTryAgain?: () => void
|
onPressTryAgain?: () => void
|
||||||
renderHeader: () => JSX.Element
|
renderHeader: () => JSX.Element
|
||||||
renderEmptyState: () => JSX.Element
|
renderEmptyState: () => JSX.Element
|
||||||
testID?: string
|
testID?: string
|
||||||
scrollEventThrottle?: number
|
|
||||||
headerOffset?: number
|
headerOffset?: number
|
||||||
desktopFixedHeightOffset?: number
|
desktopFixedHeightOffset?: number
|
||||||
}) {
|
}) {
|
||||||
@@ -209,10 +205,9 @@ export function ListMembers({
|
|||||||
[isFetching],
|
[isFetching],
|
||||||
)
|
)
|
||||||
|
|
||||||
const scrollHandler = useAnimatedScrollHandler(onScroll)
|
|
||||||
return (
|
return (
|
||||||
<View testID={testID} style={style}>
|
<View testID={testID} style={style}>
|
||||||
<FlatList
|
<List
|
||||||
testID={testID ? `${testID}-flatlist` : undefined}
|
testID={testID ? `${testID}-flatlist` : undefined}
|
||||||
ref={scrollElRef}
|
ref={scrollElRef}
|
||||||
data={items}
|
data={items}
|
||||||
@@ -233,10 +228,9 @@ export function ListMembers({
|
|||||||
minHeight: Dimensions.get('window').height * 1.5,
|
minHeight: Dimensions.get('window').height * 1.5,
|
||||||
}}
|
}}
|
||||||
style={{paddingTop: headerOffset}}
|
style={{paddingTop: headerOffset}}
|
||||||
onScroll={scrollHandler}
|
onScrolledDownChange={onScrolledDownChange}
|
||||||
onEndReached={onEndReached}
|
onEndReached={onEndReached}
|
||||||
onEndReachedThreshold={0.6}
|
onEndReachedThreshold={0.6}
|
||||||
scrollEventThrottle={scrollEventThrottle}
|
|
||||||
removeClippedSubviews={true}
|
removeClippedSubviews={true}
|
||||||
contentOffset={{x: 0, y: headerOffset * -1}}
|
contentOffset={{x: 0, y: headerOffset * -1}}
|
||||||
// @ts-ignore our .web version only -prf
|
// @ts-ignore our .web version only -prf
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {ErrorMessage} from '../util/error/ErrorMessage'
|
|||||||
import {Text} from '../util/text/Text'
|
import {Text} from '../util/text/Text'
|
||||||
import {useAnalytics} from 'lib/analytics/analytics'
|
import {useAnalytics} from 'lib/analytics/analytics'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {FlatList} from '../util/Views'
|
import {List} from '../util/List'
|
||||||
import {s} from 'lib/styles'
|
import {s} from 'lib/styles'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {Trans} from '@lingui/macro'
|
import {Trans} from '@lingui/macro'
|
||||||
@@ -119,7 +119,7 @@ export function MyLists({
|
|||||||
[error, onRefresh, renderItem, pal],
|
[error, onRefresh, renderItem, pal],
|
||||||
)
|
)
|
||||||
|
|
||||||
const FlatListCom = inline ? RNFlatList : FlatList
|
const FlatListCom = inline ? RNFlatList : List
|
||||||
return (
|
return (
|
||||||
<View testID={testID} style={style}>
|
<View testID={testID} style={style}>
|
||||||
{items.length > 0 && (
|
{items.length > 0 && (
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {MutableRefObject} from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
Dimensions,
|
Dimensions,
|
||||||
RefreshControl,
|
RefreshControl,
|
||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
import {FlatList} from '../util/Views'
|
import {List, ListRef} from '../util/List'
|
||||||
import {ListCard} from './ListCard'
|
import {ListCard} from './ListCard'
|
||||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
||||||
@@ -16,11 +16,9 @@ import {Text} from '../util/text/Text'
|
|||||||
import {useAnalytics} from 'lib/analytics/analytics'
|
import {useAnalytics} from 'lib/analytics/analytics'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useProfileListsQuery, RQKEY} from '#/state/queries/profile-lists'
|
import {useProfileListsQuery, RQKEY} from '#/state/queries/profile-lists'
|
||||||
import {OnScrollHandler} from '#/lib/hooks/useOnMainScroll'
|
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {Trans} from '@lingui/macro'
|
import {Trans} from '@lingui/macro'
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
|
||||||
import {useTheme} from '#/lib/ThemeContext'
|
import {useTheme} from '#/lib/ThemeContext'
|
||||||
import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
|
import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
|
||||||
import {isNative} from '#/platform/detection'
|
import {isNative} from '#/platform/detection'
|
||||||
@@ -36,9 +34,7 @@ interface SectionRef {
|
|||||||
|
|
||||||
interface ProfileListsProps {
|
interface ProfileListsProps {
|
||||||
did: string
|
did: string
|
||||||
scrollElRef: MutableRefObject<FlatList<any> | null>
|
scrollElRef: ListRef
|
||||||
onScroll?: OnScrollHandler
|
|
||||||
scrollEventThrottle?: number
|
|
||||||
headerOffset: number
|
headerOffset: number
|
||||||
enabled?: boolean
|
enabled?: boolean
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
@@ -47,16 +43,7 @@ interface ProfileListsProps {
|
|||||||
|
|
||||||
export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
|
export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
|
||||||
function ProfileListsImpl(
|
function ProfileListsImpl(
|
||||||
{
|
{did, scrollElRef, headerOffset, enabled, style, testID},
|
||||||
did,
|
|
||||||
scrollElRef,
|
|
||||||
onScroll,
|
|
||||||
scrollEventThrottle,
|
|
||||||
headerOffset,
|
|
||||||
enabled,
|
|
||||||
style,
|
|
||||||
testID,
|
|
||||||
},
|
|
||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
@@ -187,10 +174,9 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
|
|||||||
[error, refetch, onPressRetryLoadMore, pal],
|
[error, refetch, onPressRetryLoadMore, pal],
|
||||||
)
|
)
|
||||||
|
|
||||||
const scrollHandler = useAnimatedScrollHandler(onScroll || {})
|
|
||||||
return (
|
return (
|
||||||
<View testID={testID} style={style}>
|
<View testID={testID} style={style}>
|
||||||
<FlatList
|
<List
|
||||||
testID={testID ? `${testID}-flatlist` : undefined}
|
testID={testID ? `${testID}-flatlist` : undefined}
|
||||||
ref={scrollElRef}
|
ref={scrollElRef}
|
||||||
data={items}
|
data={items}
|
||||||
@@ -209,8 +195,6 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
|
|||||||
minHeight: Dimensions.get('window').height * 1.5,
|
minHeight: Dimensions.get('window').height * 1.5,
|
||||||
}}
|
}}
|
||||||
style={{paddingTop: headerOffset}}
|
style={{paddingTop: headerOffset}}
|
||||||
onScroll={onScroll != null ? scrollHandler : undefined}
|
|
||||||
scrollEventThrottle={scrollEventThrottle}
|
|
||||||
indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'}
|
indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'}
|
||||||
removeClippedSubviews={true}
|
removeClippedSubviews={true}
|
||||||
contentOffset={{x: 0, y: headerOffset * -1}}
|
contentOffset={{x: 0, y: headerOffset * -1}}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {Trans, msg} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useModalControls} from '#/state/modals'
|
import {useModalControls} from '#/state/modals'
|
||||||
import {useSession, useSessionApi, getAgent} from '#/state/session'
|
import {useSession, useSessionApi, getAgent} from '#/state/session'
|
||||||
|
import {logger} from '#/logger'
|
||||||
|
|
||||||
export const snapPoints = ['90%']
|
export const snapPoints = ['90%']
|
||||||
|
|
||||||
@@ -45,6 +46,13 @@ export function Component({showReminder}: {showReminder?: boolean}) {
|
|||||||
const {isMobile} = useWebMediaQueries()
|
const {isMobile} = useWebMediaQueries()
|
||||||
const {openModal, closeModal} = useModalControls()
|
const {openModal, closeModal} = useModalControls()
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!currentAccount) {
|
||||||
|
logger.error(`VerifyEmail modal opened without currentAccount`)
|
||||||
|
closeModal()
|
||||||
|
}
|
||||||
|
}, [currentAccount, closeModal])
|
||||||
|
|
||||||
const onSendEmail = async () => {
|
const onSendEmail = async () => {
|
||||||
setError('')
|
setError('')
|
||||||
setIsProcessing(true)
|
setIsProcessing(true)
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import React, {MutableRefObject} from 'react'
|
import React from 'react'
|
||||||
import {CenteredView, FlatList} from '../util/Views'
|
import {CenteredView} from '../util/Views'
|
||||||
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
|
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
|
||||||
import {FeedItem} from './FeedItem'
|
import {FeedItem} from './FeedItem'
|
||||||
import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
|
import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
|
||||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
||||||
import {EmptyState} from '../util/EmptyState'
|
import {EmptyState} from '../util/EmptyState'
|
||||||
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
|
|
||||||
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
|
||||||
import {s} from 'lib/styles'
|
import {s} from 'lib/styles'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useNotificationFeedQuery} from '#/state/queries/notifications/feed'
|
import {useNotificationFeedQuery} from '#/state/queries/notifications/feed'
|
||||||
@@ -15,6 +13,7 @@ import {useUnreadNotificationsApi} from '#/state/queries/notifications/unread'
|
|||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
import {useModerationOpts} from '#/state/queries/preferences'
|
||||||
|
import {List, ListRef} from '../util/List'
|
||||||
|
|
||||||
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
|
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
|
||||||
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
|
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
|
||||||
@@ -23,12 +22,12 @@ const LOADING_ITEM = {_reactKey: '__loading__'}
|
|||||||
export function Feed({
|
export function Feed({
|
||||||
scrollElRef,
|
scrollElRef,
|
||||||
onPressTryAgain,
|
onPressTryAgain,
|
||||||
onScroll,
|
onScrolledDownChange,
|
||||||
ListHeaderComponent,
|
ListHeaderComponent,
|
||||||
}: {
|
}: {
|
||||||
scrollElRef?: MutableRefObject<FlatList<any> | null>
|
scrollElRef?: ListRef
|
||||||
onPressTryAgain?: () => void
|
onPressTryAgain?: () => void
|
||||||
onScroll?: OnScrollHandler
|
onScrolledDownChange: (isScrolledDown: boolean) => void
|
||||||
ListHeaderComponent?: () => JSX.Element
|
ListHeaderComponent?: () => JSX.Element
|
||||||
}) {
|
}) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
@@ -135,7 +134,6 @@ export function Feed({
|
|||||||
[isFetchingNextPage],
|
[isFetchingNextPage],
|
||||||
)
|
)
|
||||||
|
|
||||||
const scrollHandler = useAnimatedScrollHandler(onScroll || {})
|
|
||||||
return (
|
return (
|
||||||
<View style={s.hContentRegion}>
|
<View style={s.hContentRegion}>
|
||||||
{error && (
|
{error && (
|
||||||
@@ -146,7 +144,7 @@ export function Feed({
|
|||||||
/>
|
/>
|
||||||
</CenteredView>
|
</CenteredView>
|
||||||
)}
|
)}
|
||||||
<FlatList
|
<List
|
||||||
testID="notifsFeed"
|
testID="notifsFeed"
|
||||||
ref={scrollElRef}
|
ref={scrollElRef}
|
||||||
data={items}
|
data={items}
|
||||||
@@ -164,8 +162,7 @@ export function Feed({
|
|||||||
}
|
}
|
||||||
onEndReached={onEndReached}
|
onEndReached={onEndReached}
|
||||||
onEndReachedThreshold={0.6}
|
onEndReachedThreshold={0.6}
|
||||||
onScroll={scrollHandler}
|
onScrolledDownChange={onScrolledDownChange}
|
||||||
scrollEventThrottle={1}
|
|
||||||
contentContainerStyle={s.contentContainer}
|
contentContainerStyle={s.contentContainer}
|
||||||
// @ts-ignore our .web version only -prf
|
// @ts-ignore our .web version only -prf
|
||||||
desktopFixedHeight
|
desktopFixedHeight
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import {
|
import {
|
||||||
LayoutChangeEvent,
|
LayoutChangeEvent,
|
||||||
FlatList,
|
|
||||||
ScrollView,
|
ScrollView,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
View,
|
View,
|
||||||
@@ -19,17 +18,14 @@ import Animated, {
|
|||||||
} from 'react-native-reanimated'
|
} from 'react-native-reanimated'
|
||||||
import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager'
|
import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager'
|
||||||
import {TabBar} from './TabBar'
|
import {TabBar} from './TabBar'
|
||||||
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
|
|
||||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||||
|
import {ListMethods} from '../util/List'
|
||||||
const SCROLLED_DOWN_LIMIT = 200
|
import {ScrollProvider} from '#/lib/ScrollContext'
|
||||||
|
|
||||||
export interface PagerWithHeaderChildParams {
|
export interface PagerWithHeaderChildParams {
|
||||||
headerHeight: number
|
headerHeight: number
|
||||||
isFocused: boolean
|
isFocused: boolean
|
||||||
onScroll: OnScrollHandler
|
scrollElRef: React.MutableRefObject<ListMethods | ScrollView | null>
|
||||||
isScrolledDown: boolean
|
|
||||||
scrollElRef: React.MutableRefObject<FlatList<any> | ScrollView | null>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PagerWithHeaderProps {
|
export interface PagerWithHeaderProps {
|
||||||
@@ -61,7 +57,6 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
|||||||
const [currentPage, setCurrentPage] = React.useState(0)
|
const [currentPage, setCurrentPage] = React.useState(0)
|
||||||
const [tabBarHeight, setTabBarHeight] = React.useState(0)
|
const [tabBarHeight, setTabBarHeight] = React.useState(0)
|
||||||
const [headerOnlyHeight, setHeaderOnlyHeight] = React.useState(0)
|
const [headerOnlyHeight, setHeaderOnlyHeight] = React.useState(0)
|
||||||
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
|
|
||||||
const scrollY = useSharedValue(0)
|
const scrollY = useSharedValue(0)
|
||||||
const headerHeight = headerOnlyHeight + tabBarHeight
|
const headerHeight = headerOnlyHeight + tabBarHeight
|
||||||
|
|
||||||
@@ -120,13 +115,16 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
|||||||
)
|
)
|
||||||
|
|
||||||
const scrollRefs = useSharedValue<AnimatedRef<any>[]>([])
|
const scrollRefs = useSharedValue<AnimatedRef<any>[]>([])
|
||||||
const registerRef = (scrollRef: AnimatedRef<any>, index: number) => {
|
const registerRef = React.useCallback(
|
||||||
scrollRefs.modify(refs => {
|
(scrollRef: AnimatedRef<any> | null, atIndex: number) => {
|
||||||
'worklet'
|
scrollRefs.modify(refs => {
|
||||||
refs[index] = scrollRef
|
'worklet'
|
||||||
return refs
|
refs[atIndex] = scrollRef
|
||||||
})
|
return refs
|
||||||
}
|
})
|
||||||
|
},
|
||||||
|
[scrollRefs],
|
||||||
|
)
|
||||||
|
|
||||||
const lastForcedScrollY = useSharedValue(0)
|
const lastForcedScrollY = useSharedValue(0)
|
||||||
const adjustScrollForOtherPages = () => {
|
const adjustScrollForOtherPages = () => {
|
||||||
@@ -137,8 +135,7 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
|||||||
lastForcedScrollY.value = forcedScrollY
|
lastForcedScrollY.value = forcedScrollY
|
||||||
const refs = scrollRefs.value
|
const refs = scrollRefs.value
|
||||||
for (let i = 0; i < refs.length; i++) {
|
for (let i = 0; i < refs.length; i++) {
|
||||||
if (i !== currentPage) {
|
if (i !== currentPage && refs[i] != null) {
|
||||||
// This needs to run on the UI thread.
|
|
||||||
scrollTo(refs[i], 0, forcedScrollY, false)
|
scrollTo(refs[i], 0, forcedScrollY, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,15 +149,7 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
|||||||
if (!throttleTimeout.current) {
|
if (!throttleTimeout.current) {
|
||||||
throttleTimeout.current = setTimeout(() => {
|
throttleTimeout.current = setTimeout(() => {
|
||||||
throttleTimeout.current = null
|
throttleTimeout.current = null
|
||||||
|
|
||||||
runOnUI(adjustScrollForOtherPages)()
|
runOnUI(adjustScrollForOtherPages)()
|
||||||
|
|
||||||
const nextIsScrolledDown = scrollY.value > SCROLLED_DOWN_LIMIT
|
|
||||||
if (isScrolledDown !== nextIsScrolledDown) {
|
|
||||||
React.startTransition(() => {
|
|
||||||
setIsScrolledDown(nextIsScrolledDown)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, 80 /* Sync often enough you're unlikely to catch it unsynced */)
|
}, 80 /* Sync often enough you're unlikely to catch it unsynced */)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -205,11 +194,11 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
|||||||
<View key={i} collapsable={false}>
|
<View key={i} collapsable={false}>
|
||||||
<PagerItem
|
<PagerItem
|
||||||
headerHeight={headerHeight}
|
headerHeight={headerHeight}
|
||||||
|
index={i}
|
||||||
isReady={isReady}
|
isReady={isReady}
|
||||||
isFocused={i === currentPage}
|
isFocused={i === currentPage}
|
||||||
isScrolledDown={isScrolledDown}
|
|
||||||
onScrollWorklet={i === currentPage ? onScrollWorklet : noop}
|
onScrollWorklet={i === currentPage ? onScrollWorklet : noop}
|
||||||
registerRef={(r: AnimatedRef<any>) => registerRef(r, i)}
|
registerRef={registerRef}
|
||||||
renderTab={child}
|
renderTab={child}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@@ -282,42 +271,45 @@ PagerTabBar = React.memo(PagerTabBar)
|
|||||||
|
|
||||||
function PagerItem({
|
function PagerItem({
|
||||||
headerHeight,
|
headerHeight,
|
||||||
|
index,
|
||||||
isReady,
|
isReady,
|
||||||
isFocused,
|
isFocused,
|
||||||
isScrolledDown,
|
|
||||||
onScrollWorklet,
|
onScrollWorklet,
|
||||||
renderTab,
|
renderTab,
|
||||||
registerRef,
|
registerRef,
|
||||||
}: {
|
}: {
|
||||||
headerHeight: number
|
headerHeight: number
|
||||||
|
index: number
|
||||||
isFocused: boolean
|
isFocused: boolean
|
||||||
isReady: boolean
|
isReady: boolean
|
||||||
isScrolledDown: boolean
|
registerRef: (scrollRef: AnimatedRef<any> | null, atIndex: number) => void
|
||||||
registerRef: (scrollRef: AnimatedRef<any>) => void
|
|
||||||
onScrollWorklet: (e: NativeScrollEvent) => void
|
onScrollWorklet: (e: NativeScrollEvent) => void
|
||||||
renderTab: ((props: PagerWithHeaderChildParams) => JSX.Element) | null
|
renderTab: ((props: PagerWithHeaderChildParams) => JSX.Element) | null
|
||||||
}) {
|
}) {
|
||||||
const scrollElRef = useAnimatedRef()
|
const scrollElRef = useAnimatedRef()
|
||||||
registerRef(scrollElRef)
|
|
||||||
|
|
||||||
const scrollHandler = React.useMemo(
|
React.useEffect(() => {
|
||||||
() => ({onScroll: onScrollWorklet}),
|
registerRef(scrollElRef, index)
|
||||||
[onScrollWorklet],
|
return () => {
|
||||||
)
|
registerRef(null, index)
|
||||||
|
}
|
||||||
|
}, [scrollElRef, registerRef, index])
|
||||||
|
|
||||||
if (!isReady || renderTab == null) {
|
if (!isReady || renderTab == null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderTab({
|
return (
|
||||||
headerHeight,
|
<ScrollProvider onScroll={onScrollWorklet}>
|
||||||
isFocused,
|
{renderTab({
|
||||||
isScrolledDown,
|
headerHeight,
|
||||||
onScroll: scrollHandler,
|
isFocused,
|
||||||
scrollElRef: scrollElRef as React.MutableRefObject<
|
scrollElRef: scrollElRef as React.MutableRefObject<
|
||||||
FlatList<any> | ScrollView | null
|
ListMethods | ScrollView | null
|
||||||
>,
|
>,
|
||||||
})
|
})}
|
||||||
|
</ScrollProvider>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
|||||||
@@ -1,26 +1,15 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import {
|
import {FlatList, ScrollView, StyleSheet, View} from 'react-native'
|
||||||
FlatList,
|
import {useAnimatedRef} from 'react-native-reanimated'
|
||||||
ScrollView,
|
|
||||||
StyleSheet,
|
|
||||||
View,
|
|
||||||
NativeScrollEvent,
|
|
||||||
} from 'react-native'
|
|
||||||
import {useSharedValue, runOnJS, useAnimatedRef} from 'react-native-reanimated'
|
|
||||||
import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager'
|
import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager'
|
||||||
import {TabBar} from './TabBar'
|
import {TabBar} from './TabBar'
|
||||||
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
|
|
||||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
|
||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
import {usePalette} from '#/lib/hooks/usePalette'
|
||||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||||
|
import {ListMethods} from '../util/List'
|
||||||
const SCROLLED_DOWN_LIMIT = 200
|
|
||||||
|
|
||||||
export interface PagerWithHeaderChildParams {
|
export interface PagerWithHeaderChildParams {
|
||||||
headerHeight: number
|
headerHeight: number
|
||||||
isFocused: boolean
|
isFocused: boolean
|
||||||
onScroll: OnScrollHandler
|
|
||||||
isScrolledDown: boolean
|
|
||||||
scrollElRef: React.MutableRefObject<FlatList<any> | ScrollView | null>
|
scrollElRef: React.MutableRefObject<FlatList<any> | ScrollView | null>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,8 +39,6 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
|||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
const [currentPage, setCurrentPage] = React.useState(0)
|
const [currentPage, setCurrentPage] = React.useState(0)
|
||||||
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
|
|
||||||
const scrollY = useSharedValue(0)
|
|
||||||
|
|
||||||
const renderTabBar = React.useCallback(
|
const renderTabBar = React.useCallback(
|
||||||
(props: RenderTabBarFnProps) => {
|
(props: RenderTabBarFnProps) => {
|
||||||
@@ -69,34 +56,6 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
|||||||
[items, renderHeader, currentPage, onCurrentPageSelected, testID],
|
[items, renderHeader, currentPage, onCurrentPageSelected, testID],
|
||||||
)
|
)
|
||||||
|
|
||||||
const throttleTimeout = React.useRef<ReturnType<typeof setTimeout> | null>(
|
|
||||||
null,
|
|
||||||
)
|
|
||||||
const queueThrottledOnScroll = useNonReactiveCallback(() => {
|
|
||||||
if (!throttleTimeout.current) {
|
|
||||||
throttleTimeout.current = setTimeout(() => {
|
|
||||||
throttleTimeout.current = null
|
|
||||||
|
|
||||||
const nextIsScrolledDown = scrollY.value > SCROLLED_DOWN_LIMIT
|
|
||||||
if (isScrolledDown !== nextIsScrolledDown) {
|
|
||||||
React.startTransition(() => {
|
|
||||||
setIsScrolledDown(nextIsScrolledDown)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, 80)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const onScrollWorklet = React.useCallback(
|
|
||||||
(e: NativeScrollEvent) => {
|
|
||||||
'worklet'
|
|
||||||
const nextScrollY = e.contentOffset.y
|
|
||||||
scrollY.value = nextScrollY
|
|
||||||
runOnJS(queueThrottledOnScroll)()
|
|
||||||
},
|
|
||||||
[scrollY, queueThrottledOnScroll],
|
|
||||||
)
|
|
||||||
|
|
||||||
const onPageSelectedInner = React.useCallback(
|
const onPageSelectedInner = React.useCallback(
|
||||||
(index: number) => {
|
(index: number) => {
|
||||||
setCurrentPage(index)
|
setCurrentPage(index)
|
||||||
@@ -123,12 +82,7 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>(
|
|||||||
.map((child, i) => {
|
.map((child, i) => {
|
||||||
return (
|
return (
|
||||||
<View key={i} collapsable={false}>
|
<View key={i} collapsable={false}>
|
||||||
<PagerItem
|
<PagerItem isFocused={i === currentPage} renderTab={child} />
|
||||||
isFocused={i === currentPage}
|
|
||||||
isScrolledDown={isScrolledDown}
|
|
||||||
onScrollWorklet={i === currentPage ? onScrollWorklet : noop}
|
|
||||||
renderTab={child}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
@@ -182,30 +136,20 @@ PagerTabBar = React.memo(PagerTabBar)
|
|||||||
|
|
||||||
function PagerItem({
|
function PagerItem({
|
||||||
isFocused,
|
isFocused,
|
||||||
isScrolledDown,
|
|
||||||
onScrollWorklet,
|
|
||||||
renderTab,
|
renderTab,
|
||||||
}: {
|
}: {
|
||||||
isFocused: boolean
|
isFocused: boolean
|
||||||
isScrolledDown: boolean
|
|
||||||
onScrollWorklet: (e: NativeScrollEvent) => void
|
|
||||||
renderTab: ((props: PagerWithHeaderChildParams) => JSX.Element) | null
|
renderTab: ((props: PagerWithHeaderChildParams) => JSX.Element) | null
|
||||||
}) {
|
}) {
|
||||||
const scrollElRef = useAnimatedRef()
|
const scrollElRef = useAnimatedRef()
|
||||||
const scrollHandler = React.useMemo(
|
|
||||||
() => ({onScroll: onScrollWorklet}),
|
|
||||||
[onScrollWorklet],
|
|
||||||
)
|
|
||||||
if (renderTab == null) {
|
if (renderTab == null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return renderTab({
|
return renderTab({
|
||||||
headerHeight: 0,
|
headerHeight: 0,
|
||||||
isFocused,
|
isFocused,
|
||||||
isScrolledDown,
|
|
||||||
onScroll: scrollHandler,
|
|
||||||
scrollElRef: scrollElRef as React.MutableRefObject<
|
scrollElRef: scrollElRef as React.MutableRefObject<
|
||||||
FlatList<any> | ScrollView | null
|
ListMethods | ScrollView | null
|
||||||
>,
|
>,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -238,10 +182,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
function noop() {
|
|
||||||
'worklet'
|
|
||||||
}
|
|
||||||
|
|
||||||
function toArray<T>(v: T | T[]): T[] {
|
function toArray<T>(v: T | T[]): T[] {
|
||||||
if (Array.isArray(v)) {
|
if (Array.isArray(v)) {
|
||||||
return v
|
return v
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React, {useCallback, useMemo, useState} from 'react'
|
import React, {useCallback, useMemo, useState} from 'react'
|
||||||
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
|
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
|
||||||
import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api'
|
import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api'
|
||||||
import {CenteredView, FlatList} from '../util/Views'
|
import {CenteredView} from '../util/Views'
|
||||||
|
import {List} from '../util/List'
|
||||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
import {ProfileCardWithFollowBtn} from '../profile/ProfileCard'
|
import {ProfileCardWithFollowBtn} from '../profile/ProfileCard'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
@@ -84,7 +85,7 @@ export function PostLikedBy({uri}: {uri: string}) {
|
|||||||
// loaded
|
// loaded
|
||||||
// =
|
// =
|
||||||
return (
|
return (
|
||||||
<FlatList
|
<List
|
||||||
data={likes}
|
data={likes}
|
||||||
keyExtractor={item => item.actor.did}
|
keyExtractor={item => item.actor.did}
|
||||||
refreshControl={
|
refreshControl={
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React, {useMemo, useCallback, useState} from 'react'
|
import React, {useMemo, useCallback, useState} from 'react'
|
||||||
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
|
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
|
||||||
import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
|
import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
|
||||||
import {CenteredView, FlatList} from '../util/Views'
|
import {CenteredView} from '../util/Views'
|
||||||
|
import {List} from '../util/List'
|
||||||
import {ProfileCardWithFollowBtn} from '../profile/ProfileCard'
|
import {ProfileCardWithFollowBtn} from '../profile/ProfileCard'
|
||||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
@@ -85,7 +86,7 @@ export function PostRepostedBy({uri}: {uri: string}) {
|
|||||||
// loaded
|
// loaded
|
||||||
// =
|
// =
|
||||||
return (
|
return (
|
||||||
<FlatList
|
<List
|
||||||
data={repostedBy}
|
data={repostedBy}
|
||||||
keyExtractor={item => item.did}
|
keyExtractor={item => item.did}
|
||||||
refreshControl={
|
refreshControl={
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import {
|
|||||||
View,
|
View,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {AppBskyFeedDefs} from '@atproto/api'
|
import {AppBskyFeedDefs} from '@atproto/api'
|
||||||
import {CenteredView, FlatList} from '../util/Views'
|
import {CenteredView} from '../util/Views'
|
||||||
|
import {List, ListMethods} from '../util/List'
|
||||||
import {
|
import {
|
||||||
FontAwesomeIcon,
|
FontAwesomeIcon,
|
||||||
FontAwesomeIconStyle,
|
FontAwesomeIconStyle,
|
||||||
@@ -140,7 +141,7 @@ function PostThreadLoaded({
|
|||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {isTablet, isDesktop} = useWebMediaQueries()
|
const {isTablet, isDesktop} = useWebMediaQueries()
|
||||||
const ref = useRef<FlatList>(null)
|
const ref = useRef<ListMethods>(null)
|
||||||
const highlightedPostRef = useRef<View | null>(null)
|
const highlightedPostRef = useRef<View | null>(null)
|
||||||
const needsScrollAdjustment = useRef<boolean>(
|
const needsScrollAdjustment = useRef<boolean>(
|
||||||
!isNative || // web always uses scroll adjustment
|
!isNative || // web always uses scroll adjustment
|
||||||
@@ -335,7 +336,7 @@ function PostThreadLoaded({
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FlatList
|
<List
|
||||||
ref={ref}
|
ref={ref}
|
||||||
data={posts}
|
data={posts}
|
||||||
initialNumToRender={!isNative ? posts.length : undefined}
|
initialNumToRender={!isNative ? posts.length : undefined}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {memo, MutableRefObject} from 'react'
|
import React, {memo} from 'react'
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
AppState,
|
AppState,
|
||||||
@@ -10,15 +10,13 @@ import {
|
|||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
import {FlatList} from '../util/Views'
|
import {List, ListRef} from '../util/List'
|
||||||
import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
|
import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
|
||||||
import {FeedErrorMessage} from './FeedErrorMessage'
|
import {FeedErrorMessage} from './FeedErrorMessage'
|
||||||
import {FeedSlice} from './FeedSlice'
|
import {FeedSlice} from './FeedSlice'
|
||||||
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
||||||
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
|
|
||||||
import {useAnalytics} from 'lib/analytics/analytics'
|
import {useAnalytics} from 'lib/analytics/analytics'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
|
||||||
import {useTheme} from 'lib/ThemeContext'
|
import {useTheme} from 'lib/ThemeContext'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {
|
import {
|
||||||
@@ -45,9 +43,8 @@ let Feed = ({
|
|||||||
enabled,
|
enabled,
|
||||||
pollInterval,
|
pollInterval,
|
||||||
scrollElRef,
|
scrollElRef,
|
||||||
onScroll,
|
onScrolledDownChange,
|
||||||
onHasNew,
|
onHasNew,
|
||||||
scrollEventThrottle,
|
|
||||||
renderEmptyState,
|
renderEmptyState,
|
||||||
renderEndOfFeed,
|
renderEndOfFeed,
|
||||||
testID,
|
testID,
|
||||||
@@ -62,10 +59,9 @@ let Feed = ({
|
|||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
enabled?: boolean
|
enabled?: boolean
|
||||||
pollInterval?: number
|
pollInterval?: number
|
||||||
scrollElRef?: MutableRefObject<FlatList<any> | null>
|
scrollElRef?: ListRef
|
||||||
onHasNew?: (v: boolean) => void
|
onHasNew?: (v: boolean) => void
|
||||||
onScroll?: OnScrollHandler
|
onScrolledDownChange?: (isScrolledDown: boolean) => void
|
||||||
scrollEventThrottle?: number
|
|
||||||
renderEmptyState: () => JSX.Element
|
renderEmptyState: () => JSX.Element
|
||||||
renderEndOfFeed?: () => JSX.Element
|
renderEndOfFeed?: () => JSX.Element
|
||||||
testID?: string
|
testID?: string
|
||||||
@@ -167,8 +163,7 @@ let Feed = ({
|
|||||||
if (isFetched) {
|
if (isFetched) {
|
||||||
if (isError && isEmpty) {
|
if (isError && isEmpty) {
|
||||||
arr = arr.concat([ERROR_ITEM])
|
arr = arr.concat([ERROR_ITEM])
|
||||||
}
|
} else if (isEmpty) {
|
||||||
if (isEmpty) {
|
|
||||||
arr = arr.concat([EMPTY_FEED_ITEM])
|
arr = arr.concat([EMPTY_FEED_ITEM])
|
||||||
} else if (data) {
|
} else if (data) {
|
||||||
for (const page of data?.pages) {
|
for (const page of data?.pages) {
|
||||||
@@ -271,10 +266,9 @@ let Feed = ({
|
|||||||
)
|
)
|
||||||
}, [isFetchingNextPage, shouldRenderEndOfFeed, renderEndOfFeed, headerOffset])
|
}, [isFetchingNextPage, shouldRenderEndOfFeed, renderEndOfFeed, headerOffset])
|
||||||
|
|
||||||
const scrollHandler = useAnimatedScrollHandler(onScroll || {})
|
|
||||||
return (
|
return (
|
||||||
<View testID={testID} style={style}>
|
<View testID={testID} style={style}>
|
||||||
<FlatList
|
<List
|
||||||
testID={testID ? `${testID}-flatlist` : undefined}
|
testID={testID ? `${testID}-flatlist` : undefined}
|
||||||
ref={scrollElRef}
|
ref={scrollElRef}
|
||||||
data={feedItems}
|
data={feedItems}
|
||||||
@@ -295,8 +289,7 @@ let Feed = ({
|
|||||||
minHeight: Dimensions.get('window').height * 1.5,
|
minHeight: Dimensions.get('window').height * 1.5,
|
||||||
}}
|
}}
|
||||||
style={{paddingTop: headerOffset}}
|
style={{paddingTop: headerOffset}}
|
||||||
onScroll={onScroll != null ? scrollHandler : undefined}
|
onScrolledDownChange={onScrolledDownChange}
|
||||||
scrollEventThrottle={scrollEventThrottle}
|
|
||||||
indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'}
|
indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'}
|
||||||
onEndReached={onEndReached}
|
onEndReached={onEndReached}
|
||||||
onEndReachedThreshold={2} // number of posts left to trigger load more
|
onEndReachedThreshold={2} // number of posts left to trigger load more
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
|
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
|
||||||
import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
|
import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
|
||||||
import {CenteredView, FlatList} from '../util/Views'
|
import {CenteredView} from '../util/Views'
|
||||||
|
import {List} from '../util/List'
|
||||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
import {ProfileCardWithFollowBtn} from './ProfileCard'
|
import {ProfileCardWithFollowBtn} from './ProfileCard'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
@@ -86,7 +87,7 @@ export function ProfileFollowers({name}: {name: string}) {
|
|||||||
// loaded
|
// loaded
|
||||||
// =
|
// =
|
||||||
return (
|
return (
|
||||||
<FlatList
|
<List
|
||||||
data={followers}
|
data={followers}
|
||||||
keyExtractor={item => item.did}
|
keyExtractor={item => item.did}
|
||||||
refreshControl={
|
refreshControl={
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
|
import {ActivityIndicator, RefreshControl, StyleSheet, View} from 'react-native'
|
||||||
import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
|
import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
|
||||||
import {CenteredView, FlatList} from '../util/Views'
|
import {CenteredView} from '../util/Views'
|
||||||
|
import {List} from '../util/List'
|
||||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
import {ProfileCardWithFollowBtn} from './ProfileCard'
|
import {ProfileCardWithFollowBtn} from './ProfileCard'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
@@ -86,7 +87,7 @@ export function ProfileFollows({name}: {name: string}) {
|
|||||||
// loaded
|
// loaded
|
||||||
// =
|
// =
|
||||||
return (
|
return (
|
||||||
<FlatList
|
<List
|
||||||
data={follows}
|
data={follows}
|
||||||
keyExtractor={item => item.did}
|
keyExtractor={item => item.did}
|
||||||
refreshControl={
|
refreshControl={
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import React, {memo, startTransition} from 'react'
|
||||||
|
import {FlatListProps} from 'react-native'
|
||||||
|
import {FlatList_INTERNAL} from './Views'
|
||||||
|
import {useScrollHandlers} from '#/lib/ScrollContext'
|
||||||
|
import {runOnJS, useSharedValue} from 'react-native-reanimated'
|
||||||
|
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
||||||
|
|
||||||
|
export type ListMethods = FlatList_INTERNAL
|
||||||
|
export type ListProps<ItemT> = Omit<
|
||||||
|
FlatListProps<ItemT>,
|
||||||
|
'onScroll' // Use ScrollContext instead.
|
||||||
|
> & {
|
||||||
|
onScrolledDownChange?: (isScrolledDown: boolean) => void
|
||||||
|
}
|
||||||
|
export type ListRef = React.MutableRefObject<FlatList_INTERNAL | null>
|
||||||
|
|
||||||
|
const SCROLLED_DOWN_LIMIT = 200
|
||||||
|
|
||||||
|
function ListImpl<ItemT>(
|
||||||
|
{onScrolledDownChange, ...props}: ListProps<ItemT>,
|
||||||
|
ref: React.Ref<ListMethods>,
|
||||||
|
) {
|
||||||
|
const isScrolledDown = useSharedValue(false)
|
||||||
|
const contextScrollHandlers = useScrollHandlers()
|
||||||
|
|
||||||
|
function handleScrolledDownChange(didScrollDown: boolean) {
|
||||||
|
startTransition(() => {
|
||||||
|
onScrolledDownChange?.(didScrollDown)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const scrollHandler = useAnimatedScrollHandler({
|
||||||
|
onBeginDrag(e, ctx) {
|
||||||
|
contextScrollHandlers.onBeginDrag?.(e, ctx)
|
||||||
|
},
|
||||||
|
onEndDrag(e, ctx) {
|
||||||
|
contextScrollHandlers.onEndDrag?.(e, ctx)
|
||||||
|
},
|
||||||
|
onScroll(e, ctx) {
|
||||||
|
contextScrollHandlers.onScroll?.(e, ctx)
|
||||||
|
|
||||||
|
const didScrollDown = e.contentOffset.y > SCROLLED_DOWN_LIMIT
|
||||||
|
if (isScrolledDown.value !== didScrollDown) {
|
||||||
|
isScrolledDown.value = didScrollDown
|
||||||
|
if (onScrolledDownChange != null) {
|
||||||
|
runOnJS(handleScrolledDownChange)(didScrollDown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FlatList_INTERNAL
|
||||||
|
{...props}
|
||||||
|
onScroll={scrollHandler}
|
||||||
|
scrollEventThrottle={1}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const List = memo(React.forwardRef(ListImpl)) as <ItemT>(
|
||||||
|
props: ListProps<ItemT> & {ref?: React.Ref<ListMethods>},
|
||||||
|
) => React.ReactElement
|
||||||
@@ -1,30 +1,18 @@
|
|||||||
import {useState, useCallback, useMemo} from 'react'
|
import React, {useCallback} from 'react'
|
||||||
import {NativeSyntheticEvent, NativeScrollEvent} from 'react-native'
|
import {ScrollProvider} from '#/lib/ScrollContext'
|
||||||
|
import {NativeScrollEvent} from 'react-native'
|
||||||
import {useSetMinimalShellMode, useMinimalShellMode} from '#/state/shell'
|
import {useSetMinimalShellMode, useMinimalShellMode} from '#/state/shell'
|
||||||
import {useShellLayout} from '#/state/shell/shell-layout'
|
import {useShellLayout} from '#/state/shell/shell-layout'
|
||||||
import {s} from 'lib/styles'
|
|
||||||
import {isWeb} from 'platform/detection'
|
import {isWeb} from 'platform/detection'
|
||||||
import {
|
import {useSharedValue, interpolate} from 'react-native-reanimated'
|
||||||
useSharedValue,
|
|
||||||
interpolate,
|
|
||||||
runOnJS,
|
|
||||||
ScrollHandlers,
|
|
||||||
} from 'react-native-reanimated'
|
|
||||||
|
|
||||||
function clamp(num: number, min: number, max: number) {
|
function clamp(num: number, min: number, max: number) {
|
||||||
'worklet'
|
'worklet'
|
||||||
return Math.min(Math.max(num, min), max)
|
return Math.min(Math.max(num, min), max)
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OnScrollCb = (
|
export function MainScrollProvider({children}: {children: React.ReactNode}) {
|
||||||
event: NativeSyntheticEvent<NativeScrollEvent>,
|
|
||||||
) => void
|
|
||||||
export type OnScrollHandler = ScrollHandlers<any>
|
|
||||||
export type ResetCb = () => void
|
|
||||||
|
|
||||||
export function useOnMainScroll(): [OnScrollHandler, boolean, ResetCb] {
|
|
||||||
const {headerHeight} = useShellLayout()
|
const {headerHeight} = useShellLayout()
|
||||||
const [isScrolledDown, setIsScrolledDown] = useState(false)
|
|
||||||
const mode = useMinimalShellMode()
|
const mode = useMinimalShellMode()
|
||||||
const setMode = useSetMinimalShellMode()
|
const setMode = useSetMinimalShellMode()
|
||||||
const startDragOffset = useSharedValue<number | null>(null)
|
const startDragOffset = useSharedValue<number | null>(null)
|
||||||
@@ -58,13 +46,6 @@ export function useOnMainScroll(): [OnScrollHandler, boolean, ResetCb] {
|
|||||||
const onScroll = useCallback(
|
const onScroll = useCallback(
|
||||||
(e: NativeScrollEvent) => {
|
(e: NativeScrollEvent) => {
|
||||||
'worklet'
|
'worklet'
|
||||||
// Keep track of whether we want to show "scroll to top".
|
|
||||||
if (!isScrolledDown && e.contentOffset.y > s.window.height) {
|
|
||||||
runOnJS(setIsScrolledDown)(true)
|
|
||||||
} else if (isScrolledDown && e.contentOffset.y < s.window.height) {
|
|
||||||
runOnJS(setIsScrolledDown)(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startDragOffset.value === null || startMode.value === null) {
|
if (startDragOffset.value === null || startMode.value === null) {
|
||||||
if (mode.value !== 0 && e.contentOffset.y < headerHeight.value) {
|
if (mode.value !== 0 && e.contentOffset.y < headerHeight.value) {
|
||||||
// If we're close enough to the top, always show the shell.
|
// If we're close enough to the top, always show the shell.
|
||||||
@@ -102,24 +83,15 @@ export function useOnMainScroll(): [OnScrollHandler, boolean, ResetCb] {
|
|||||||
startMode.value = mode.value
|
startMode.value = mode.value
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[headerHeight, mode, setMode, isScrolledDown, startDragOffset, startMode],
|
[headerHeight, mode, setMode, startDragOffset, startMode],
|
||||||
)
|
)
|
||||||
|
|
||||||
const scrollHandler: ScrollHandlers<any> = useMemo(
|
return (
|
||||||
() => ({
|
<ScrollProvider
|
||||||
onBeginDrag,
|
onBeginDrag={onBeginDrag}
|
||||||
onEndDrag,
|
onEndDrag={onEndDrag}
|
||||||
onScroll,
|
onScroll={onScroll}>
|
||||||
}),
|
{children}
|
||||||
[onBeginDrag, onEndDrag, onScroll],
|
</ScrollProvider>
|
||||||
)
|
)
|
||||||
|
|
||||||
return [
|
|
||||||
scrollHandler,
|
|
||||||
isScrolledDown,
|
|
||||||
useCallback(() => {
|
|
||||||
setIsScrolledDown(false)
|
|
||||||
setMode(false)
|
|
||||||
}, [setMode]),
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
import React, {useEffect, useState} from 'react'
|
import React, {useEffect, useState} from 'react'
|
||||||
import {
|
import {
|
||||||
|
NativeSyntheticEvent,
|
||||||
|
NativeScrollEvent,
|
||||||
Pressable,
|
Pressable,
|
||||||
RefreshControl,
|
RefreshControl,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
View,
|
View,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {FlatList} from './Views'
|
import {FlatList_INTERNAL} from './Views'
|
||||||
import {OnScrollCb} from 'lib/hooks/useOnMainScroll'
|
|
||||||
import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
|
import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
|
||||||
import {Text} from './text/Text'
|
import {Text} from './text/Text'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
@@ -38,7 +39,7 @@ export const ViewSelector = React.forwardRef<
|
|||||||
| null
|
| null
|
||||||
| undefined
|
| undefined
|
||||||
onSelectView?: (viewIndex: number) => void
|
onSelectView?: (viewIndex: number) => void
|
||||||
onScroll?: OnScrollCb
|
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void
|
||||||
onRefresh?: () => void
|
onRefresh?: () => void
|
||||||
onEndReached?: (info: {distanceFromEnd: number}) => void
|
onEndReached?: (info: {distanceFromEnd: number}) => void
|
||||||
}
|
}
|
||||||
@@ -59,7 +60,7 @@ export const ViewSelector = React.forwardRef<
|
|||||||
) {
|
) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const [selectedIndex, setSelectedIndex] = useState<number>(0)
|
const [selectedIndex, setSelectedIndex] = useState<number>(0)
|
||||||
const flatListRef = React.useRef<FlatList>(null)
|
const flatListRef = React.useRef<FlatList_INTERNAL>(null)
|
||||||
|
|
||||||
// events
|
// events
|
||||||
// =
|
// =
|
||||||
@@ -110,7 +111,7 @@ export const ViewSelector = React.forwardRef<
|
|||||||
[items],
|
[items],
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<FlatList
|
<FlatList_INTERNAL
|
||||||
ref={flatListRef}
|
ref={flatListRef}
|
||||||
data={data}
|
data={data}
|
||||||
keyExtractor={keyExtractor}
|
keyExtractor={keyExtractor}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {ViewProps} from 'react-native'
|
import {ViewProps} from 'react-native'
|
||||||
export {FlatList, ScrollView} from 'react-native'
|
export {FlatList as FlatList_INTERNAL, ScrollView} from 'react-native'
|
||||||
export function CenteredView({
|
export function CenteredView({
|
||||||
style,
|
style,
|
||||||
sideBorders,
|
sideBorders,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import Animated from 'react-native-reanimated'
|
import Animated from 'react-native-reanimated'
|
||||||
|
|
||||||
export const FlatList = Animated.FlatList
|
export const FlatList_INTERNAL = Animated.FlatList
|
||||||
export const ScrollView = Animated.ScrollView
|
export const ScrollView = Animated.ScrollView
|
||||||
export function CenteredView(props) {
|
export function CenteredView(props) {
|
||||||
return <View {...props} />
|
return <View {...props} />
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export function CenteredView({
|
|||||||
return <View style={style} {...props} />
|
return <View style={style} {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FlatList = React.forwardRef(function FlatListImpl<ItemT>(
|
export const FlatList_INTERNAL = React.forwardRef(function FlatListImpl<ItemT>(
|
||||||
{
|
{
|
||||||
data,
|
data,
|
||||||
extraData,
|
extraData,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
import {ErrorMessage} from 'view/com/util/error/ErrorMessage'
|
import {ErrorMessage} from 'view/com/util/error/ErrorMessage'
|
||||||
import debounce from 'lodash.debounce'
|
import debounce from 'lodash.debounce'
|
||||||
import {Text} from 'view/com/util/text/Text'
|
import {Text} from 'view/com/util/text/Text'
|
||||||
import {FlatList} from 'view/com/util/Views'
|
import {List} from 'view/com/util/List'
|
||||||
import {useFocusEffect} from '@react-navigation/native'
|
import {useFocusEffect} from '@react-navigation/native'
|
||||||
import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
|
import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
|
||||||
import {Trans, msg} from '@lingui/macro'
|
import {Trans, msg} from '@lingui/macro'
|
||||||
@@ -481,7 +481,7 @@ export function FeedsScreen(_props: Props) {
|
|||||||
|
|
||||||
{preferences ? <View /> : <ActivityIndicator />}
|
{preferences ? <View /> : <ActivityIndicator />}
|
||||||
|
|
||||||
<FlatList
|
<List
|
||||||
style={[!isTabletOrDesktop && s.flex1, styles.list]}
|
style={[!isTabletOrDesktop && s.flex1, styles.list]}
|
||||||
data={items}
|
data={items}
|
||||||
keyExtractor={item => item.key}
|
keyExtractor={item => item.key}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {FlatList, View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {useFocusEffect} from '@react-navigation/native'
|
import {useFocusEffect} from '@react-navigation/native'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
import {
|
import {
|
||||||
@@ -9,8 +9,9 @@ import {
|
|||||||
import {ViewHeader} from '../com/util/ViewHeader'
|
import {ViewHeader} from '../com/util/ViewHeader'
|
||||||
import {Feed} from '../com/notifications/Feed'
|
import {Feed} from '../com/notifications/Feed'
|
||||||
import {TextLink} from 'view/com/util/Link'
|
import {TextLink} from 'view/com/util/Link'
|
||||||
|
import {ListMethods} from 'view/com/util/List'
|
||||||
import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn'
|
import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn'
|
||||||
import {useOnMainScroll} from 'lib/hooks/useOnMainScroll'
|
import {MainScrollProvider} from '../com/util/MainScrollProvider'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||||
import {s, colors} from 'lib/styles'
|
import {s, colors} from 'lib/styles'
|
||||||
@@ -35,8 +36,8 @@ type Props = NativeStackScreenProps<
|
|||||||
export function NotificationsScreen({}: Props) {
|
export function NotificationsScreen({}: Props) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll()
|
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
|
||||||
const scrollElRef = React.useRef<FlatList>(null)
|
const scrollElRef = React.useRef<ListMethods>(null)
|
||||||
const checkLatestRef = React.useRef<() => void | null>()
|
const checkLatestRef = React.useRef<() => void | null>()
|
||||||
const {screen} = useAnalytics()
|
const {screen} = useAnalytics()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
@@ -50,8 +51,8 @@ export function NotificationsScreen({}: Props) {
|
|||||||
// =
|
// =
|
||||||
const scrollToTop = React.useCallback(() => {
|
const scrollToTop = React.useCallback(() => {
|
||||||
scrollElRef.current?.scrollToOffset({animated: isNative, offset: 0})
|
scrollElRef.current?.scrollToOffset({animated: isNative, offset: 0})
|
||||||
resetMainScroll()
|
setMinimalShellMode(false)
|
||||||
}, [scrollElRef, resetMainScroll])
|
}, [scrollElRef, setMinimalShellMode])
|
||||||
|
|
||||||
const onPressLoadLatest = React.useCallback(() => {
|
const onPressLoadLatest = React.useCallback(() => {
|
||||||
scrollToTop()
|
scrollToTop()
|
||||||
@@ -130,11 +131,13 @@ export function NotificationsScreen({}: Props) {
|
|||||||
return (
|
return (
|
||||||
<View testID="notificationsScreen" style={s.hContentRegion}>
|
<View testID="notificationsScreen" style={s.hContentRegion}>
|
||||||
<ViewHeader title={_(msg`Notifications`)} canGoBack={false} />
|
<ViewHeader title={_(msg`Notifications`)} canGoBack={false} />
|
||||||
<Feed
|
<MainScrollProvider>
|
||||||
onScroll={onMainScroll}
|
<Feed
|
||||||
scrollElRef={scrollElRef}
|
onScrolledDownChange={setIsScrolledDown}
|
||||||
ListHeaderComponent={ListHeaderComponent}
|
scrollElRef={scrollElRef}
|
||||||
/>
|
ListHeaderComponent={ListHeaderComponent}
|
||||||
|
/>
|
||||||
|
</MainScrollProvider>
|
||||||
{(isScrolledDown || hasNew) && (
|
{(isScrolledDown || hasNew) && (
|
||||||
<LoadLatestBtn
|
<LoadLatestBtn
|
||||||
onPress={onPressLoadLatest}
|
onPress={onPressLoadLatest}
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api'
|
|||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
|
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
|
||||||
import {CenteredView, FlatList} from '../com/util/Views'
|
import {CenteredView} from '../com/util/Views'
|
||||||
|
import {ListRef} from '../com/util/List'
|
||||||
import {ScreenHider} from 'view/com/util/moderation/ScreenHider'
|
import {ScreenHider} from 'view/com/util/moderation/ScreenHider'
|
||||||
import {Feed} from 'view/com/posts/Feed'
|
import {Feed} from 'view/com/posts/Feed'
|
||||||
import {ProfileLists} from '../com/lists/ProfileLists'
|
import {ProfileLists} from '../com/lists/ProfileLists'
|
||||||
@@ -20,7 +21,6 @@ import {useAnalytics} from 'lib/analytics/analytics'
|
|||||||
import {ComposeIcon2} from 'lib/icons'
|
import {ComposeIcon2} from 'lib/icons'
|
||||||
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
||||||
import {combinedDisplayName} from 'lib/strings/display-names'
|
import {combinedDisplayName} from 'lib/strings/display-names'
|
||||||
import {OnScrollHandler} from '#/lib/hooks/useOnMainScroll'
|
|
||||||
import {FeedDescriptor} from '#/state/queries/post-feed'
|
import {FeedDescriptor} from '#/state/queries/post-feed'
|
||||||
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
|
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
|
||||||
import {useProfileQuery} from '#/state/queries/profile'
|
import {useProfileQuery} from '#/state/queries/profile'
|
||||||
@@ -277,103 +277,67 @@ function ProfileScreenLoaded({
|
|||||||
onPageSelected={onPageSelected}
|
onPageSelected={onPageSelected}
|
||||||
onCurrentPageSelected={onCurrentPageSelected}
|
onCurrentPageSelected={onCurrentPageSelected}
|
||||||
renderHeader={renderHeader}>
|
renderHeader={renderHeader}>
|
||||||
{({onScroll, headerHeight, isFocused, isScrolledDown, scrollElRef}) => (
|
{({headerHeight, isFocused, scrollElRef}) => (
|
||||||
<FeedSection
|
<FeedSection
|
||||||
ref={postsSectionRef}
|
ref={postsSectionRef}
|
||||||
feed={`author|${profile.did}|posts_and_author_threads`}
|
feed={`author|${profile.did}|posts_and_author_threads`}
|
||||||
onScroll={onScroll}
|
|
||||||
headerHeight={headerHeight}
|
headerHeight={headerHeight}
|
||||||
isFocused={isFocused}
|
isFocused={isFocused}
|
||||||
isScrolledDown={isScrolledDown}
|
scrollElRef={scrollElRef as ListRef}
|
||||||
scrollElRef={
|
|
||||||
scrollElRef as React.MutableRefObject<FlatList<any> | null>
|
|
||||||
}
|
|
||||||
ignoreFilterFor={profile.did}
|
ignoreFilterFor={profile.did}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showRepliesTab
|
{showRepliesTab
|
||||||
? ({
|
? ({headerHeight, isFocused, scrollElRef}) => (
|
||||||
onScroll,
|
|
||||||
headerHeight,
|
|
||||||
isFocused,
|
|
||||||
isScrolledDown,
|
|
||||||
scrollElRef,
|
|
||||||
}) => (
|
|
||||||
<FeedSection
|
<FeedSection
|
||||||
ref={repliesSectionRef}
|
ref={repliesSectionRef}
|
||||||
feed={`author|${profile.did}|posts_with_replies`}
|
feed={`author|${profile.did}|posts_with_replies`}
|
||||||
onScroll={onScroll}
|
|
||||||
headerHeight={headerHeight}
|
headerHeight={headerHeight}
|
||||||
isFocused={isFocused}
|
isFocused={isFocused}
|
||||||
isScrolledDown={isScrolledDown}
|
scrollElRef={scrollElRef as ListRef}
|
||||||
scrollElRef={
|
|
||||||
scrollElRef as React.MutableRefObject<FlatList<any> | null>
|
|
||||||
}
|
|
||||||
ignoreFilterFor={profile.did}
|
ignoreFilterFor={profile.did}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
: null}
|
: null}
|
||||||
{({onScroll, headerHeight, isFocused, isScrolledDown, scrollElRef}) => (
|
{({headerHeight, isFocused, scrollElRef}) => (
|
||||||
<FeedSection
|
<FeedSection
|
||||||
ref={mediaSectionRef}
|
ref={mediaSectionRef}
|
||||||
feed={`author|${profile.did}|posts_with_media`}
|
feed={`author|${profile.did}|posts_with_media`}
|
||||||
onScroll={onScroll}
|
|
||||||
headerHeight={headerHeight}
|
headerHeight={headerHeight}
|
||||||
isFocused={isFocused}
|
isFocused={isFocused}
|
||||||
isScrolledDown={isScrolledDown}
|
scrollElRef={scrollElRef as ListRef}
|
||||||
scrollElRef={
|
|
||||||
scrollElRef as React.MutableRefObject<FlatList<any> | null>
|
|
||||||
}
|
|
||||||
ignoreFilterFor={profile.did}
|
ignoreFilterFor={profile.did}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showLikesTab
|
{showLikesTab
|
||||||
? ({
|
? ({headerHeight, isFocused, scrollElRef}) => (
|
||||||
onScroll,
|
|
||||||
headerHeight,
|
|
||||||
isFocused,
|
|
||||||
isScrolledDown,
|
|
||||||
scrollElRef,
|
|
||||||
}) => (
|
|
||||||
<FeedSection
|
<FeedSection
|
||||||
ref={likesSectionRef}
|
ref={likesSectionRef}
|
||||||
feed={`likes|${profile.did}`}
|
feed={`likes|${profile.did}`}
|
||||||
onScroll={onScroll}
|
|
||||||
headerHeight={headerHeight}
|
headerHeight={headerHeight}
|
||||||
isFocused={isFocused}
|
isFocused={isFocused}
|
||||||
isScrolledDown={isScrolledDown}
|
scrollElRef={scrollElRef as ListRef}
|
||||||
scrollElRef={
|
|
||||||
scrollElRef as React.MutableRefObject<FlatList<any> | null>
|
|
||||||
}
|
|
||||||
ignoreFilterFor={profile.did}
|
ignoreFilterFor={profile.did}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
: null}
|
: null}
|
||||||
{showFeedsTab
|
{showFeedsTab
|
||||||
? ({onScroll, headerHeight, isFocused, scrollElRef}) => (
|
? ({headerHeight, isFocused, scrollElRef}) => (
|
||||||
<ProfileFeedgens
|
<ProfileFeedgens
|
||||||
ref={feedsSectionRef}
|
ref={feedsSectionRef}
|
||||||
did={profile.did}
|
did={profile.did}
|
||||||
scrollElRef={
|
scrollElRef={scrollElRef as ListRef}
|
||||||
scrollElRef as React.MutableRefObject<FlatList<any> | null>
|
|
||||||
}
|
|
||||||
onScroll={onScroll}
|
|
||||||
scrollEventThrottle={1}
|
|
||||||
headerOffset={headerHeight}
|
headerOffset={headerHeight}
|
||||||
enabled={isFocused}
|
enabled={isFocused}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
: null}
|
: null}
|
||||||
{showListsTab
|
{showListsTab
|
||||||
? ({onScroll, headerHeight, isFocused, scrollElRef}) => (
|
? ({headerHeight, isFocused, scrollElRef}) => (
|
||||||
<ProfileLists
|
<ProfileLists
|
||||||
ref={listsSectionRef}
|
ref={listsSectionRef}
|
||||||
did={profile.did}
|
did={profile.did}
|
||||||
scrollElRef={
|
scrollElRef={scrollElRef as ListRef}
|
||||||
scrollElRef as React.MutableRefObject<FlatList<any> | null>
|
|
||||||
}
|
|
||||||
onScroll={onScroll}
|
|
||||||
scrollEventThrottle={1}
|
|
||||||
headerOffset={headerHeight}
|
headerOffset={headerHeight}
|
||||||
enabled={isFocused}
|
enabled={isFocused}
|
||||||
/>
|
/>
|
||||||
@@ -396,28 +360,19 @@ function ProfileScreenLoaded({
|
|||||||
|
|
||||||
interface FeedSectionProps {
|
interface FeedSectionProps {
|
||||||
feed: FeedDescriptor
|
feed: FeedDescriptor
|
||||||
onScroll: OnScrollHandler
|
|
||||||
headerHeight: number
|
headerHeight: number
|
||||||
isFocused: boolean
|
isFocused: boolean
|
||||||
isScrolledDown: boolean
|
scrollElRef: ListRef
|
||||||
scrollElRef: React.MutableRefObject<FlatList<any> | null>
|
|
||||||
ignoreFilterFor?: string
|
ignoreFilterFor?: string
|
||||||
}
|
}
|
||||||
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
|
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
|
||||||
function FeedSectionImpl(
|
function FeedSectionImpl(
|
||||||
{
|
{feed, headerHeight, isFocused, scrollElRef, ignoreFilterFor},
|
||||||
feed,
|
|
||||||
onScroll,
|
|
||||||
headerHeight,
|
|
||||||
isFocused,
|
|
||||||
isScrolledDown,
|
|
||||||
scrollElRef,
|
|
||||||
ignoreFilterFor,
|
|
||||||
},
|
|
||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const [hasNew, setHasNew] = React.useState(false)
|
const [hasNew, setHasNew] = React.useState(false)
|
||||||
|
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
|
||||||
|
|
||||||
const onScrollToTop = React.useCallback(() => {
|
const onScrollToTop = React.useCallback(() => {
|
||||||
scrollElRef.current?.scrollToOffset({
|
scrollElRef.current?.scrollToOffset({
|
||||||
@@ -443,8 +398,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
|
|||||||
feed={feed}
|
feed={feed}
|
||||||
scrollElRef={scrollElRef}
|
scrollElRef={scrollElRef}
|
||||||
onHasNew={setHasNew}
|
onHasNew={setHasNew}
|
||||||
onScroll={onScroll}
|
onScrolledDownChange={setIsScrolledDown}
|
||||||
scrollEventThrottle={1}
|
|
||||||
renderEmptyState={renderPostsEmpty}
|
renderEmptyState={renderPostsEmpty}
|
||||||
headerOffset={headerHeight}
|
headerOffset={headerHeight}
|
||||||
renderEndOfFeed={ProfileEndOfFeed}
|
renderEndOfFeed={ProfileEndOfFeed}
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
import React, {useMemo, useCallback} from 'react'
|
import React, {useMemo, useCallback} from 'react'
|
||||||
import {
|
import {Dimensions, StyleSheet, View, ActivityIndicator} from 'react-native'
|
||||||
Dimensions,
|
|
||||||
StyleSheet,
|
|
||||||
View,
|
|
||||||
ActivityIndicator,
|
|
||||||
FlatList,
|
|
||||||
} from 'react-native'
|
|
||||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||||
import {useNavigation} from '@react-navigation/native'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
@@ -20,6 +14,7 @@ import {PagerWithHeader} from 'view/com/pager/PagerWithHeader'
|
|||||||
import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader'
|
import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader'
|
||||||
import {Feed} from 'view/com/posts/Feed'
|
import {Feed} from 'view/com/posts/Feed'
|
||||||
import {TextLink} from 'view/com/util/Link'
|
import {TextLink} from 'view/com/util/Link'
|
||||||
|
import {ListRef} from 'view/com/util/List'
|
||||||
import {Button} from 'view/com/util/forms/Button'
|
import {Button} from 'view/com/util/forms/Button'
|
||||||
import {Text} from 'view/com/util/text/Text'
|
import {Text} from 'view/com/util/text/Text'
|
||||||
import {RichText} from 'view/com/util/text/RichText'
|
import {RichText} from 'view/com/util/text/RichText'
|
||||||
@@ -29,12 +24,13 @@ import {EmptyState} from 'view/com/util/EmptyState'
|
|||||||
import * as Toast from 'view/com/util/Toast'
|
import * as Toast from 'view/com/util/Toast'
|
||||||
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
||||||
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
|
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
|
||||||
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
|
|
||||||
import {shareUrl} from 'lib/sharing'
|
import {shareUrl} from 'lib/sharing'
|
||||||
import {toShareUrl} from 'lib/strings/url-helpers'
|
import {toShareUrl} from 'lib/strings/url-helpers'
|
||||||
import {Haptics} from 'lib/haptics'
|
import {Haptics} from 'lib/haptics'
|
||||||
import {useAnalytics} from 'lib/analytics/analytics'
|
import {useAnalytics} from 'lib/analytics/analytics'
|
||||||
import {NativeDropdown, DropdownItem} from 'view/com/util/forms/NativeDropdown'
|
import {NativeDropdown, DropdownItem} from 'view/com/util/forms/NativeDropdown'
|
||||||
|
import {useScrollHandlers} from '#/lib/ScrollContext'
|
||||||
|
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
||||||
import {makeCustomFeedLink} from 'lib/routes/links'
|
import {makeCustomFeedLink} from 'lib/routes/links'
|
||||||
import {pluralize} from 'lib/strings/helpers'
|
import {pluralize} from 'lib/strings/helpers'
|
||||||
import {CenteredView, ScrollView} from 'view/com/util/Views'
|
import {CenteredView, ScrollView} from 'view/com/util/Views'
|
||||||
@@ -46,7 +42,6 @@ import {logger} from '#/logger'
|
|||||||
import {Trans, msg} from '@lingui/macro'
|
import {Trans, msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useModalControls} from '#/state/modals'
|
import {useModalControls} from '#/state/modals'
|
||||||
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
|
||||||
import {
|
import {
|
||||||
useFeedSourceInfoQuery,
|
useFeedSourceInfoQuery,
|
||||||
FeedSourceFeedInfo,
|
FeedSourceFeedInfo,
|
||||||
@@ -403,17 +398,13 @@ export function ProfileFeedScreenInner({
|
|||||||
isHeaderReady={true}
|
isHeaderReady={true}
|
||||||
renderHeader={renderHeader}
|
renderHeader={renderHeader}
|
||||||
onCurrentPageSelected={onCurrentPageSelected}>
|
onCurrentPageSelected={onCurrentPageSelected}>
|
||||||
{({onScroll, headerHeight, isScrolledDown, scrollElRef, isFocused}) =>
|
{({headerHeight, scrollElRef, isFocused}) =>
|
||||||
isPublicResponse?.isPublic ? (
|
isPublicResponse?.isPublic ? (
|
||||||
<FeedSection
|
<FeedSection
|
||||||
ref={feedSectionRef}
|
ref={feedSectionRef}
|
||||||
feed={`feedgen|${feedInfo.uri}`}
|
feed={`feedgen|${feedInfo.uri}`}
|
||||||
onScroll={onScroll}
|
|
||||||
headerHeight={headerHeight}
|
headerHeight={headerHeight}
|
||||||
isScrolledDown={isScrolledDown}
|
scrollElRef={scrollElRef as ListRef}
|
||||||
scrollElRef={
|
|
||||||
scrollElRef as React.MutableRefObject<FlatList<any> | null>
|
|
||||||
}
|
|
||||||
isFocused={isFocused}
|
isFocused={isFocused}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@@ -422,13 +413,12 @@ export function ProfileFeedScreenInner({
|
|||||||
</CenteredView>
|
</CenteredView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{({onScroll, headerHeight, scrollElRef}) => (
|
{({headerHeight, scrollElRef}) => (
|
||||||
<AboutSection
|
<AboutSection
|
||||||
feedOwnerDid={feedInfo.creatorDid}
|
feedOwnerDid={feedInfo.creatorDid}
|
||||||
feedRkey={feedInfo.route.params.rkey}
|
feedRkey={feedInfo.route.params.rkey}
|
||||||
feedInfo={feedInfo}
|
feedInfo={feedInfo}
|
||||||
headerHeight={headerHeight}
|
headerHeight={headerHeight}
|
||||||
onScroll={onScroll}
|
|
||||||
scrollElRef={
|
scrollElRef={
|
||||||
scrollElRef as React.MutableRefObject<ScrollView | null>
|
scrollElRef as React.MutableRefObject<ScrollView | null>
|
||||||
}
|
}
|
||||||
@@ -497,18 +487,14 @@ function NonPublicFeedMessage({rawError}: {rawError?: Error}) {
|
|||||||
|
|
||||||
interface FeedSectionProps {
|
interface FeedSectionProps {
|
||||||
feed: FeedDescriptor
|
feed: FeedDescriptor
|
||||||
onScroll: OnScrollHandler
|
|
||||||
headerHeight: number
|
headerHeight: number
|
||||||
isScrolledDown: boolean
|
scrollElRef: ListRef
|
||||||
scrollElRef: React.MutableRefObject<FlatList<any> | null>
|
|
||||||
isFocused: boolean
|
isFocused: boolean
|
||||||
}
|
}
|
||||||
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
|
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
|
||||||
function FeedSectionImpl(
|
function FeedSectionImpl({feed, headerHeight, scrollElRef, isFocused}, ref) {
|
||||||
{feed, onScroll, headerHeight, isScrolledDown, scrollElRef, isFocused},
|
|
||||||
ref,
|
|
||||||
) {
|
|
||||||
const [hasNew, setHasNew] = React.useState(false)
|
const [hasNew, setHasNew] = React.useState(false)
|
||||||
|
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
const onScrollToTop = useCallback(() => {
|
const onScrollToTop = useCallback(() => {
|
||||||
@@ -536,8 +522,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
|
|||||||
pollInterval={30e3}
|
pollInterval={30e3}
|
||||||
scrollElRef={scrollElRef}
|
scrollElRef={scrollElRef}
|
||||||
onHasNew={setHasNew}
|
onHasNew={setHasNew}
|
||||||
onScroll={onScroll}
|
onScrolledDownChange={setIsScrolledDown}
|
||||||
scrollEventThrottle={5}
|
|
||||||
renderEmptyState={renderPostsEmpty}
|
renderEmptyState={renderPostsEmpty}
|
||||||
headerOffset={headerHeight}
|
headerOffset={headerHeight}
|
||||||
/>
|
/>
|
||||||
@@ -558,7 +543,6 @@ function AboutSection({
|
|||||||
feedRkey,
|
feedRkey,
|
||||||
feedInfo,
|
feedInfo,
|
||||||
headerHeight,
|
headerHeight,
|
||||||
onScroll,
|
|
||||||
scrollElRef,
|
scrollElRef,
|
||||||
isOwner,
|
isOwner,
|
||||||
}: {
|
}: {
|
||||||
@@ -566,13 +550,13 @@ function AboutSection({
|
|||||||
feedRkey: string
|
feedRkey: string
|
||||||
feedInfo: FeedSourceFeedInfo
|
feedInfo: FeedSourceFeedInfo
|
||||||
headerHeight: number
|
headerHeight: number
|
||||||
onScroll: OnScrollHandler
|
|
||||||
scrollElRef: React.MutableRefObject<ScrollView | null>
|
scrollElRef: React.MutableRefObject<ScrollView | null>
|
||||||
isOwner: boolean
|
isOwner: boolean
|
||||||
}) {
|
}) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const scrollHandler = useAnimatedScrollHandler(onScroll)
|
const scrollHandlers = useScrollHandlers()
|
||||||
|
const onScroll = useAnimatedScrollHandler(scrollHandlers)
|
||||||
const [likeUri, setLikeUri] = React.useState(feedInfo.likeUri)
|
const [likeUri, setLikeUri] = React.useState(feedInfo.likeUri)
|
||||||
const {hasSession} = useSession()
|
const {hasSession} = useSession()
|
||||||
const {track} = useAnalytics()
|
const {track} = useAnalytics()
|
||||||
@@ -608,12 +592,12 @@ function AboutSection({
|
|||||||
return (
|
return (
|
||||||
<ScrollView
|
<ScrollView
|
||||||
ref={scrollElRef}
|
ref={scrollElRef}
|
||||||
|
onScroll={onScroll}
|
||||||
scrollEventThrottle={1}
|
scrollEventThrottle={1}
|
||||||
contentContainerStyle={{
|
contentContainerStyle={{
|
||||||
paddingTop: headerHeight,
|
paddingTop: headerHeight,
|
||||||
minHeight: Dimensions.get('window').height * 1.5,
|
minHeight: Dimensions.get('window').height * 1.5,
|
||||||
}}
|
}}>
|
||||||
onScroll={scrollHandler}>
|
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
import React, {useCallback, useMemo} from 'react'
|
import React, {useCallback, useMemo} from 'react'
|
||||||
import {
|
import {ActivityIndicator, Pressable, StyleSheet, View} from 'react-native'
|
||||||
ActivityIndicator,
|
|
||||||
FlatList,
|
|
||||||
Pressable,
|
|
||||||
StyleSheet,
|
|
||||||
View,
|
|
||||||
} from 'react-native'
|
|
||||||
import {useFocusEffect} from '@react-navigation/native'
|
import {useFocusEffect} from '@react-navigation/native'
|
||||||
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
|
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
|
||||||
import {useNavigation} from '@react-navigation/native'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
@@ -22,6 +16,7 @@ import {EmptyState} from 'view/com/util/EmptyState'
|
|||||||
import {RichText} from 'view/com/util/text/RichText'
|
import {RichText} from 'view/com/util/text/RichText'
|
||||||
import {Button} from 'view/com/util/forms/Button'
|
import {Button} from 'view/com/util/forms/Button'
|
||||||
import {TextLink} from 'view/com/util/Link'
|
import {TextLink} from 'view/com/util/Link'
|
||||||
|
import {ListRef} from 'view/com/util/List'
|
||||||
import * as Toast from 'view/com/util/Toast'
|
import * as Toast from 'view/com/util/Toast'
|
||||||
import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn'
|
import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn'
|
||||||
import {FAB} from 'view/com/util/fab/FAB'
|
import {FAB} from 'view/com/util/fab/FAB'
|
||||||
@@ -31,7 +26,6 @@ import {usePalette} from 'lib/hooks/usePalette'
|
|||||||
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
||||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||||
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
|
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
|
||||||
import {OnScrollHandler} from 'lib/hooks/useOnMainScroll'
|
|
||||||
import {NavigationProp} from 'lib/routes/types'
|
import {NavigationProp} from 'lib/routes/types'
|
||||||
import {toShareUrl} from 'lib/strings/url-helpers'
|
import {toShareUrl} from 'lib/strings/url-helpers'
|
||||||
import {shareUrl} from 'lib/sharing'
|
import {shareUrl} from 'lib/sharing'
|
||||||
@@ -165,36 +159,22 @@ function ProfileListScreenLoaded({
|
|||||||
isHeaderReady={true}
|
isHeaderReady={true}
|
||||||
renderHeader={renderHeader}
|
renderHeader={renderHeader}
|
||||||
onCurrentPageSelected={onCurrentPageSelected}>
|
onCurrentPageSelected={onCurrentPageSelected}>
|
||||||
{({
|
{({headerHeight, scrollElRef, isFocused}) => (
|
||||||
onScroll,
|
|
||||||
headerHeight,
|
|
||||||
isScrolledDown,
|
|
||||||
scrollElRef,
|
|
||||||
isFocused,
|
|
||||||
}) => (
|
|
||||||
<FeedSection
|
<FeedSection
|
||||||
ref={feedSectionRef}
|
ref={feedSectionRef}
|
||||||
feed={`list|${uri}`}
|
feed={`list|${uri}`}
|
||||||
scrollElRef={
|
scrollElRef={scrollElRef as ListRef}
|
||||||
scrollElRef as React.MutableRefObject<FlatList<any> | null>
|
|
||||||
}
|
|
||||||
onScroll={onScroll}
|
|
||||||
headerHeight={headerHeight}
|
headerHeight={headerHeight}
|
||||||
isScrolledDown={isScrolledDown}
|
|
||||||
isFocused={isFocused}
|
isFocused={isFocused}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{({onScroll, headerHeight, isScrolledDown, scrollElRef}) => (
|
{({headerHeight, scrollElRef}) => (
|
||||||
<AboutSection
|
<AboutSection
|
||||||
ref={aboutSectionRef}
|
ref={aboutSectionRef}
|
||||||
scrollElRef={
|
scrollElRef={scrollElRef as ListRef}
|
||||||
scrollElRef as React.MutableRefObject<FlatList<any> | null>
|
|
||||||
}
|
|
||||||
list={list}
|
list={list}
|
||||||
onPressAddUser={onPressAddUser}
|
onPressAddUser={onPressAddUser}
|
||||||
onScroll={onScroll}
|
|
||||||
headerHeight={headerHeight}
|
headerHeight={headerHeight}
|
||||||
isScrolledDown={isScrolledDown}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</PagerWithHeader>
|
</PagerWithHeader>
|
||||||
@@ -221,16 +201,12 @@ function ProfileListScreenLoaded({
|
|||||||
items={SECTION_TITLES_MOD}
|
items={SECTION_TITLES_MOD}
|
||||||
isHeaderReady={true}
|
isHeaderReady={true}
|
||||||
renderHeader={renderHeader}>
|
renderHeader={renderHeader}>
|
||||||
{({onScroll, headerHeight, isScrolledDown, scrollElRef}) => (
|
{({headerHeight, scrollElRef}) => (
|
||||||
<AboutSection
|
<AboutSection
|
||||||
list={list}
|
list={list}
|
||||||
scrollElRef={
|
scrollElRef={scrollElRef as ListRef}
|
||||||
scrollElRef as React.MutableRefObject<FlatList<any> | null>
|
|
||||||
}
|
|
||||||
onPressAddUser={onPressAddUser}
|
onPressAddUser={onPressAddUser}
|
||||||
onScroll={onScroll}
|
|
||||||
headerHeight={headerHeight}
|
headerHeight={headerHeight}
|
||||||
isScrolledDown={isScrolledDown}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</PagerWithHeader>
|
</PagerWithHeader>
|
||||||
@@ -615,19 +591,15 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
|
|||||||
|
|
||||||
interface FeedSectionProps {
|
interface FeedSectionProps {
|
||||||
feed: FeedDescriptor
|
feed: FeedDescriptor
|
||||||
onScroll: OnScrollHandler
|
|
||||||
headerHeight: number
|
headerHeight: number
|
||||||
isScrolledDown: boolean
|
scrollElRef: ListRef
|
||||||
scrollElRef: React.MutableRefObject<FlatList<any> | null>
|
|
||||||
isFocused: boolean
|
isFocused: boolean
|
||||||
}
|
}
|
||||||
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
|
const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
|
||||||
function FeedSectionImpl(
|
function FeedSectionImpl({feed, scrollElRef, headerHeight, isFocused}, ref) {
|
||||||
{feed, scrollElRef, onScroll, headerHeight, isScrolledDown, isFocused},
|
|
||||||
ref,
|
|
||||||
) {
|
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const [hasNew, setHasNew] = React.useState(false)
|
const [hasNew, setHasNew] = React.useState(false)
|
||||||
|
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
|
||||||
|
|
||||||
const onScrollToTop = useCallback(() => {
|
const onScrollToTop = useCallback(() => {
|
||||||
scrollElRef.current?.scrollToOffset({
|
scrollElRef.current?.scrollToOffset({
|
||||||
@@ -654,8 +626,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
|
|||||||
pollInterval={30e3}
|
pollInterval={30e3}
|
||||||
scrollElRef={scrollElRef}
|
scrollElRef={scrollElRef}
|
||||||
onHasNew={setHasNew}
|
onHasNew={setHasNew}
|
||||||
onScroll={onScroll}
|
onScrolledDownChange={setIsScrolledDown}
|
||||||
scrollEventThrottle={1}
|
|
||||||
renderEmptyState={renderPostsEmpty}
|
renderEmptyState={renderPostsEmpty}
|
||||||
headerOffset={headerHeight}
|
headerOffset={headerHeight}
|
||||||
/>
|
/>
|
||||||
@@ -674,20 +645,19 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
|
|||||||
interface AboutSectionProps {
|
interface AboutSectionProps {
|
||||||
list: AppBskyGraphDefs.ListView
|
list: AppBskyGraphDefs.ListView
|
||||||
onPressAddUser: () => void
|
onPressAddUser: () => void
|
||||||
onScroll: OnScrollHandler
|
|
||||||
headerHeight: number
|
headerHeight: number
|
||||||
isScrolledDown: boolean
|
scrollElRef: ListRef
|
||||||
scrollElRef: React.MutableRefObject<FlatList<any> | null>
|
|
||||||
}
|
}
|
||||||
const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
|
const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
|
||||||
function AboutSectionImpl(
|
function AboutSectionImpl(
|
||||||
{list, onPressAddUser, onScroll, headerHeight, isScrolledDown, scrollElRef},
|
{list, onPressAddUser, headerHeight, scrollElRef},
|
||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {isMobile} = useWebMediaQueries()
|
const {isMobile} = useWebMediaQueries()
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
|
const [isScrolledDown, setIsScrolledDown] = React.useState(false)
|
||||||
const isCurateList = list.purpose === 'app.bsky.graph.defs#curatelist'
|
const isCurateList = list.purpose === 'app.bsky.graph.defs#curatelist'
|
||||||
const isOwner = list.creator.did === currentAccount?.did
|
const isOwner = list.creator.did === currentAccount?.did
|
||||||
|
|
||||||
@@ -817,8 +787,7 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
|
|||||||
renderHeader={renderHeader}
|
renderHeader={renderHeader}
|
||||||
renderEmptyState={renderEmptyState}
|
renderEmptyState={renderEmptyState}
|
||||||
headerOffset={headerHeight}
|
headerOffset={headerHeight}
|
||||||
onScroll={onScroll}
|
onScrolledDownChange={setIsScrolledDown}
|
||||||
scrollEventThrottle={1}
|
|
||||||
/>
|
/>
|
||||||
{isScrolledDown && (
|
{isScrolledDown && (
|
||||||
<LoadLatestBtn
|
<LoadLatestBtn
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import {
|
|||||||
Pressable,
|
Pressable,
|
||||||
Platform,
|
Platform,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {FlatList, ScrollView, CenteredView} from '#/view/com/util/Views'
|
import {ScrollView, CenteredView} from '#/view/com/util/Views'
|
||||||
|
import {List} from '#/view/com/util/List'
|
||||||
import {AppBskyActorDefs, AppBskyFeedDefs, moderateProfile} from '@atproto/api'
|
import {AppBskyActorDefs, AppBskyFeedDefs, moderateProfile} from '@atproto/api'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
@@ -155,7 +156,7 @@ function SearchScreenSuggestedFollows() {
|
|||||||
}, [currentAccount, setSuggestions, getSuggestedFollowsByActor])
|
}, [currentAccount, setSuggestions, getSuggestedFollowsByActor])
|
||||||
|
|
||||||
return suggestions.length ? (
|
return suggestions.length ? (
|
||||||
<FlatList
|
<List
|
||||||
data={suggestions}
|
data={suggestions}
|
||||||
renderItem={({item}) => <ProfileCardWithFollowBtn profile={item} noBg />}
|
renderItem={({item}) => <ProfileCardWithFollowBtn profile={item} noBg />}
|
||||||
keyExtractor={item => item.did}
|
keyExtractor={item => item.did}
|
||||||
@@ -243,7 +244,7 @@ function SearchScreenPostResults({query}: {query: string}) {
|
|||||||
{isFetched ? (
|
{isFetched ? (
|
||||||
<>
|
<>
|
||||||
{posts.length ? (
|
{posts.length ? (
|
||||||
<FlatList
|
<List
|
||||||
data={items}
|
data={items}
|
||||||
renderItem={({item}) => {
|
renderItem={({item}) => {
|
||||||
if (item.type === 'post') {
|
if (item.type === 'post') {
|
||||||
@@ -284,7 +285,7 @@ function SearchScreenUserResults({query}: {query: string}) {
|
|||||||
return isFetched && results ? (
|
return isFetched && results ? (
|
||||||
<>
|
<>
|
||||||
{results.length ? (
|
{results.length ? (
|
||||||
<FlatList
|
<List
|
||||||
data={results}
|
data={results}
|
||||||
renderItem={({item}) => (
|
renderItem={({item}) => (
|
||||||
<ProfileCardWithFollowBtn profile={item} noBg />
|
<ProfileCardWithFollowBtn profile={item} noBg />
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
import {Plural, Trans, msg, plural} from '@lingui/macro'
|
import {Plural, Trans, msg, plural} from '@lingui/macro'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useInviteCodesQuery} from '#/state/queries/invites'
|
import {useInviteCodesQuery} from '#/state/queries/invites'
|
||||||
import {ScrollView} from '#/view/com/util/Views'
|
|
||||||
|
|
||||||
export function DesktopRightNav() {
|
export function DesktopRightNav() {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
@@ -30,77 +29,75 @@ export function DesktopRightNav() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.rightNav, pal.view]}>
|
<View style={[styles.rightNav, pal.view]}>
|
||||||
<ScrollView contentContainerStyle={{borderWidth: 0}}>
|
<View style={{paddingVertical: 20}}>
|
||||||
<View style={{paddingVertical: 20}}>
|
<DesktopSearch />
|
||||||
<DesktopSearch />
|
|
||||||
|
|
||||||
{hasSession && (
|
{hasSession && (
|
||||||
<View style={{paddingTop: 18, marginBottom: 18}}>
|
<View style={{paddingTop: 18, marginBottom: 18}}>
|
||||||
<DesktopFeeds />
|
<DesktopFeeds />
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
styles.message,
|
|
||||||
{
|
|
||||||
paddingTop: hasSession ? 0 : 18,
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
{isSandbox ? (
|
|
||||||
<View style={[palError.view, styles.messageLine, s.p10]}>
|
|
||||||
<Text type="md" style={[palError.text, s.bold]}>
|
|
||||||
SANDBOX. Posts and accounts are not permanent.
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
) : undefined}
|
|
||||||
<View style={[s.flexRow]}>
|
|
||||||
{hasSession && (
|
|
||||||
<>
|
|
||||||
<TextLink
|
|
||||||
type="md"
|
|
||||||
style={pal.link}
|
|
||||||
href={FEEDBACK_FORM_URL({
|
|
||||||
email: currentAccount?.email,
|
|
||||||
handle: currentAccount?.handle,
|
|
||||||
})}
|
|
||||||
text={_(msg`Feedback`)}
|
|
||||||
/>
|
|
||||||
<Text type="md" style={pal.textLight}>
|
|
||||||
·
|
|
||||||
</Text>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<TextLink
|
|
||||||
type="md"
|
|
||||||
style={pal.link}
|
|
||||||
href="https://blueskyweb.xyz/support/privacy-policy"
|
|
||||||
text={_(msg`Privacy`)}
|
|
||||||
/>
|
|
||||||
<Text type="md" style={pal.textLight}>
|
|
||||||
·
|
|
||||||
</Text>
|
|
||||||
<TextLink
|
|
||||||
type="md"
|
|
||||||
style={pal.link}
|
|
||||||
href="https://blueskyweb.xyz/support/tos"
|
|
||||||
text={_(msg`Terms`)}
|
|
||||||
/>
|
|
||||||
<Text type="md" style={pal.textLight}>
|
|
||||||
·
|
|
||||||
</Text>
|
|
||||||
<TextLink
|
|
||||||
type="md"
|
|
||||||
style={pal.link}
|
|
||||||
href={HELP_DESK_URL}
|
|
||||||
text={_(msg`Help`)}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
{hasSession && <InviteCodes />}
|
<View
|
||||||
|
style={[
|
||||||
|
styles.message,
|
||||||
|
{
|
||||||
|
paddingTop: hasSession ? 0 : 18,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
{isSandbox ? (
|
||||||
|
<View style={[palError.view, styles.messageLine, s.p10]}>
|
||||||
|
<Text type="md" style={[palError.text, s.bold]}>
|
||||||
|
SANDBOX. Posts and accounts are not permanent.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
) : undefined}
|
||||||
|
<View style={[s.flexRow]}>
|
||||||
|
{hasSession && (
|
||||||
|
<>
|
||||||
|
<TextLink
|
||||||
|
type="md"
|
||||||
|
style={pal.link}
|
||||||
|
href={FEEDBACK_FORM_URL({
|
||||||
|
email: currentAccount?.email,
|
||||||
|
handle: currentAccount?.handle,
|
||||||
|
})}
|
||||||
|
text={_(msg`Feedback`)}
|
||||||
|
/>
|
||||||
|
<Text type="md" style={pal.textLight}>
|
||||||
|
·
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<TextLink
|
||||||
|
type="md"
|
||||||
|
style={pal.link}
|
||||||
|
href="https://blueskyweb.xyz/support/privacy-policy"
|
||||||
|
text={_(msg`Privacy`)}
|
||||||
|
/>
|
||||||
|
<Text type="md" style={pal.textLight}>
|
||||||
|
·
|
||||||
|
</Text>
|
||||||
|
<TextLink
|
||||||
|
type="md"
|
||||||
|
style={pal.link}
|
||||||
|
href="https://blueskyweb.xyz/support/tos"
|
||||||
|
text={_(msg`Terms`)}
|
||||||
|
/>
|
||||||
|
<Text type="md" style={pal.textLight}>
|
||||||
|
·
|
||||||
|
</Text>
|
||||||
|
<TextLink
|
||||||
|
type="md"
|
||||||
|
style={pal.link}
|
||||||
|
href={HELP_DESK_URL}
|
||||||
|
text={_(msg`Help`)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
|
||||||
|
{hasSession && <InviteCodes />}
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -177,7 +174,8 @@ const styles = StyleSheet.create({
|
|||||||
// @ts-ignore web only
|
// @ts-ignore web only
|
||||||
left: 'calc(50vw + 320px)',
|
left: 'calc(50vw + 320px)',
|
||||||
width: 304,
|
width: 304,
|
||||||
height: '100%',
|
maxHeight: '100%',
|
||||||
|
overflowY: 'auto',
|
||||||
},
|
},
|
||||||
|
|
||||||
message: {
|
message: {
|
||||||
|
|||||||
@@ -48,6 +48,20 @@
|
|||||||
typed-emitter "^2.1.0"
|
typed-emitter "^2.1.0"
|
||||||
zod "^3.21.4"
|
zod "^3.21.4"
|
||||||
|
|
||||||
|
"@atproto/api@^0.7.3":
|
||||||
|
version "0.7.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.7.3.tgz#3224000353619970d5e397a157c6e189e195ef47"
|
||||||
|
integrity sha512-fKU+W+S4kKxClE6IcPBHPZAjcyBYxG28S0FW/bv3T/ZYDkNxGzDV4xuoHOyEDGtB30slltl5U83njuuRZs5xtw==
|
||||||
|
dependencies:
|
||||||
|
"@atproto/common-web" "^0.2.3"
|
||||||
|
"@atproto/lexicon" "^0.3.1"
|
||||||
|
"@atproto/syntax" "^0.1.5"
|
||||||
|
"@atproto/xrpc" "^0.4.1"
|
||||||
|
multiformats "^9.9.0"
|
||||||
|
tlds "^1.234.0"
|
||||||
|
typed-emitter "^2.1.0"
|
||||||
|
zod "^3.21.4"
|
||||||
|
|
||||||
"@atproto/aws@^0.1.6":
|
"@atproto/aws@^0.1.6":
|
||||||
version "0.1.6"
|
version "0.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/@atproto/aws/-/aws-0.1.6.tgz#c6ecbfd92b325f3c5433688534d47f43358b415b"
|
resolved "https://registry.yarnpkg.com/@atproto/aws/-/aws-0.1.6.tgz#c6ecbfd92b325f3c5433688534d47f43358b415b"
|
||||||
|
|||||||
Reference in New Issue
Block a user