PWI Base (#1964)
* Base work for public view * Make default moderation settings more restrictive * Fix type * Handle showing sign-in on authed actions * Fix hoc logic * Simplify prefs logic * Remove duplicate method * Add todo * Clean up RepostButton.web * Fix x button color * Add todo * Retain existing label prefs for now, use separate logged out settings * Clean up useAuthedMethod, rename to useRequireAuth * Add todos * Move dismiss logic to withAuthRequired * Ooops add web * Block public view in prod * Add todo * Fix bad importzio/stable
parent
71b59021b9
commit
f18b9b32b0
|
@ -2,6 +2,7 @@ import {
|
|||
UsePreferencesQueryResponse,
|
||||
ThreadViewPreferences,
|
||||
} from '#/state/queries/preferences/types'
|
||||
import {DEFAULT_LOGGED_OUT_LABEL_PREFERENCES} from '#/state/queries/preferences/moderation'
|
||||
|
||||
export const DEFAULT_HOME_FEED_PREFS: UsePreferencesQueryResponse['feedViewPrefs'] =
|
||||
{
|
||||
|
@ -25,3 +26,26 @@ export const DEFAULT_PROD_FEEDS = {
|
|||
pinned: [DEFAULT_PROD_FEED_PREFIX('whats-hot')],
|
||||
saved: [DEFAULT_PROD_FEED_PREFIX('whats-hot')],
|
||||
}
|
||||
|
||||
export const DEFAULT_LOGGED_OUT_PREFERENCES: UsePreferencesQueryResponse = {
|
||||
birthDate: new Date('2022-11-17'), // TODO(pwi)
|
||||
adultContentEnabled: false,
|
||||
feeds: {
|
||||
saved: [],
|
||||
pinned: [],
|
||||
unpinned: [],
|
||||
},
|
||||
// labels are undefined until set by user
|
||||
contentLabels: {
|
||||
nsfw: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.nsfw,
|
||||
nudity: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.nudity,
|
||||
suggestive: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.suggestive,
|
||||
gore: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.gore,
|
||||
hate: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.hate,
|
||||
spam: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.spam,
|
||||
impersonation: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.impersonation,
|
||||
},
|
||||
feedViewPrefs: DEFAULT_HOME_FEED_PREFS,
|
||||
threadViewPrefs: DEFAULT_THREAD_VIEW_PREFS,
|
||||
userAge: 13, // TODO(pwi)
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import {temp__migrateLabelPref} from '#/state/queries/preferences/util'
|
|||
import {
|
||||
DEFAULT_HOME_FEED_PREFS,
|
||||
DEFAULT_THREAD_VIEW_PREFS,
|
||||
DEFAULT_LOGGED_OUT_PREFERENCES,
|
||||
} from '#/state/queries/preferences/const'
|
||||
import {getModerationOpts} from '#/state/queries/preferences/moderation'
|
||||
import {STALE} from '#/state/queries'
|
||||
|
@ -23,16 +24,19 @@ export * from '#/state/queries/preferences/types'
|
|||
export * from '#/state/queries/preferences/moderation'
|
||||
export * from '#/state/queries/preferences/const'
|
||||
|
||||
export const usePreferencesQueryKey = ['getPreferences']
|
||||
export const preferencesQueryKey = ['getPreferences']
|
||||
|
||||
export function usePreferencesQuery() {
|
||||
const {hasSession} = useSession()
|
||||
return useQuery({
|
||||
enabled: hasSession,
|
||||
staleTime: STALE.MINUTES.ONE,
|
||||
queryKey: usePreferencesQueryKey,
|
||||
queryKey: preferencesQueryKey,
|
||||
queryFn: async () => {
|
||||
const res = await getAgent().getPreferences()
|
||||
const agent = getAgent()
|
||||
|
||||
if (agent.session?.did === undefined) {
|
||||
return DEFAULT_LOGGED_OUT_PREFERENCES
|
||||
} else {
|
||||
const res = await agent.getPreferences()
|
||||
const preferences: UsePreferencesQueryResponse = {
|
||||
...res,
|
||||
feeds: {
|
||||
|
@ -80,6 +84,7 @@ export function usePreferencesQuery() {
|
|||
userAge: res.birthDate ? getAge(res.birthDate) : undefined,
|
||||
}
|
||||
return preferences
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -107,7 +112,7 @@ export function useClearPreferencesMutation() {
|
|||
await getAgent().app.bsky.actor.putPreferences({preferences: []})
|
||||
// triggers a refetch
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: usePreferencesQueryKey,
|
||||
queryKey: preferencesQueryKey,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
@ -125,7 +130,7 @@ export function usePreferencesSetContentLabelMutation() {
|
|||
await getAgent().setContentLabelPref(labelGroup, visibility)
|
||||
// triggers a refetch
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: usePreferencesQueryKey,
|
||||
queryKey: preferencesQueryKey,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
@ -139,7 +144,7 @@ export function usePreferencesSetAdultContentMutation() {
|
|||
await getAgent().setAdultContentEnabled(enabled)
|
||||
// triggers a refetch
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: usePreferencesQueryKey,
|
||||
queryKey: preferencesQueryKey,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
@ -153,7 +158,7 @@ export function usePreferencesSetBirthDateMutation() {
|
|||
await getAgent().setPersonalDetails({birthDate})
|
||||
// triggers a refetch
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: usePreferencesQueryKey,
|
||||
queryKey: preferencesQueryKey,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
@ -167,7 +172,7 @@ export function useSetFeedViewPreferencesMutation() {
|
|||
await getAgent().setFeedViewPrefs('home', prefs)
|
||||
// triggers a refetch
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: usePreferencesQueryKey,
|
||||
queryKey: preferencesQueryKey,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
@ -181,7 +186,7 @@ export function useSetThreadViewPreferencesMutation() {
|
|||
await getAgent().setThreadViewPrefs(prefs)
|
||||
// triggers a refetch
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: usePreferencesQueryKey,
|
||||
queryKey: preferencesQueryKey,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
@ -199,7 +204,7 @@ export function useSetSaveFeedsMutation() {
|
|||
await getAgent().setSavedFeeds(saved, pinned)
|
||||
// triggers a refetch
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: usePreferencesQueryKey,
|
||||
queryKey: preferencesQueryKey,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
@ -214,7 +219,7 @@ export function useSaveFeedMutation() {
|
|||
track('CustomFeed:Save')
|
||||
// triggers a refetch
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: usePreferencesQueryKey,
|
||||
queryKey: preferencesQueryKey,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
@ -229,7 +234,7 @@ export function useRemoveFeedMutation() {
|
|||
track('CustomFeed:Unsave')
|
||||
// triggers a refetch
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: usePreferencesQueryKey,
|
||||
queryKey: preferencesQueryKey,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
@ -244,7 +249,7 @@ export function usePinFeedMutation() {
|
|||
track('CustomFeed:Pin', {uri})
|
||||
// triggers a refetch
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: usePreferencesQueryKey,
|
||||
queryKey: preferencesQueryKey,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
@ -259,7 +264,7 @@ export function useUnpinFeedMutation() {
|
|||
track('CustomFeed:Unpin', {uri})
|
||||
// triggers a refetch
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: usePreferencesQueryKey,
|
||||
queryKey: preferencesQueryKey,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
|
|
@ -34,6 +34,24 @@ export const DEFAULT_LABEL_PREFERENCES: Record<
|
|||
impersonation: 'hide',
|
||||
}
|
||||
|
||||
/**
|
||||
* More strict than our default settings for logged in users.
|
||||
*
|
||||
* TODO(pwi)
|
||||
*/
|
||||
export const DEFAULT_LOGGED_OUT_LABEL_PREFERENCES: Record<
|
||||
ConfigurableLabelGroup,
|
||||
LabelPreference
|
||||
> = {
|
||||
nsfw: 'hide',
|
||||
nudity: 'hide',
|
||||
suggestive: 'hide',
|
||||
gore: 'hide',
|
||||
hate: 'hide',
|
||||
spam: 'hide',
|
||||
impersonation: 'hide',
|
||||
}
|
||||
|
||||
export const ILLEGAL_LABEL_GROUP: LabelGroupConfig = {
|
||||
id: 'illegal',
|
||||
title: 'Illegal Content',
|
||||
|
|
|
@ -43,7 +43,10 @@ export type UsePreferencesQueryResponse = Omit<
|
|||
}
|
||||
}
|
||||
|
||||
export type ThreadViewPreferences = Omit<BskyThreadViewPreference, 'sort'> & {
|
||||
export type ThreadViewPreferences = Pick<
|
||||
BskyThreadViewPreference,
|
||||
'prioritizeFollowedUsers'
|
||||
> & {
|
||||
sort: 'oldest' | 'newest' | 'most-likes' | 'random' | string
|
||||
lab_treeViewEnabled?: boolean
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import * as persisted from '#/state/persisted'
|
|||
import {PUBLIC_BSKY_AGENT} from '#/state/queries'
|
||||
import {IS_PROD} from '#/lib/constants'
|
||||
import {emitSessionLoaded, emitSessionDropped} from '../events'
|
||||
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||
|
||||
let __globalAgent: BskyAgent = PUBLIC_BSKY_AGENT
|
||||
|
||||
|
@ -515,3 +516,19 @@ export function useSession() {
|
|||
export function useSessionApi() {
|
||||
return React.useContext(ApiContext)
|
||||
}
|
||||
|
||||
export function useRequireAuth() {
|
||||
const {hasSession} = useSession()
|
||||
const {setShowLoggedOut} = useLoggedOutViewControls()
|
||||
|
||||
return React.useCallback(
|
||||
(fn: () => void) => {
|
||||
if (hasSession) {
|
||||
fn()
|
||||
} else {
|
||||
setShowLoggedOut(true)
|
||||
}
|
||||
},
|
||||
[hasSession, setShowLoggedOut],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import {Provider as ColorModeProvider} from './color-mode'
|
|||
import {Provider as OnboardingProvider} from './onboarding'
|
||||
import {Provider as ComposerProvider} from './composer'
|
||||
import {Provider as TickEveryMinuteProvider} from './tick-every-minute'
|
||||
import {Provider as LoggedOutViewProvider} from './logged-out'
|
||||
|
||||
export {useIsDrawerOpen, useSetDrawerOpen} from './drawer-open'
|
||||
export {
|
||||
|
@ -22,19 +23,23 @@ export {useTickEveryMinute} from './tick-every-minute'
|
|||
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
return (
|
||||
<ShellLayoutProvder>
|
||||
<LoggedOutViewProvider>
|
||||
<DrawerOpenProvider>
|
||||
<DrawerSwipableProvider>
|
||||
<MinimalModeProvider>
|
||||
<ColorModeProvider>
|
||||
<OnboardingProvider>
|
||||
<ComposerProvider>
|
||||
<TickEveryMinuteProvider>{children}</TickEveryMinuteProvider>
|
||||
<TickEveryMinuteProvider>
|
||||
{children}
|
||||
</TickEveryMinuteProvider>
|
||||
</ComposerProvider>
|
||||
</OnboardingProvider>
|
||||
</ColorModeProvider>
|
||||
</MinimalModeProvider>
|
||||
</DrawerSwipableProvider>
|
||||
</DrawerOpenProvider>
|
||||
</LoggedOutViewProvider>
|
||||
</ShellLayoutProvder>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import React from 'react'
|
||||
|
||||
type StateContext = {
|
||||
showLoggedOut: boolean
|
||||
}
|
||||
|
||||
const StateContext = React.createContext<StateContext>({
|
||||
showLoggedOut: false,
|
||||
})
|
||||
const ControlsContext = React.createContext<{
|
||||
setShowLoggedOut: (show: boolean) => void
|
||||
}>({
|
||||
setShowLoggedOut: () => {},
|
||||
})
|
||||
|
||||
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||
const [showLoggedOut, setShowLoggedOut] = React.useState(false)
|
||||
|
||||
const state = React.useMemo(() => ({showLoggedOut}), [showLoggedOut])
|
||||
const controls = React.useMemo(() => ({setShowLoggedOut}), [setShowLoggedOut])
|
||||
|
||||
return (
|
||||
<StateContext.Provider value={state}>
|
||||
<ControlsContext.Provider value={controls}>
|
||||
{children}
|
||||
</ControlsContext.Provider>
|
||||
</StateContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useLoggedOutView() {
|
||||
return React.useContext(StateContext)
|
||||
}
|
||||
|
||||
export function useLoggedOutViewControls() {
|
||||
return React.useContext(ControlsContext)
|
||||
}
|
|
@ -15,7 +15,7 @@ enum ScreenState {
|
|||
S_CreateAccount,
|
||||
}
|
||||
|
||||
export function LoggedOut() {
|
||||
export function LoggedOut({onDismiss}: {onDismiss?: () => void}) {
|
||||
const pal = usePalette('default')
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const {screen} = useAnalytics()
|
||||
|
@ -31,6 +31,7 @@ export function LoggedOut() {
|
|||
if (screenState === ScreenState.S_LoginOrCreateAccount) {
|
||||
return (
|
||||
<SplashScreen
|
||||
onDismiss={onDismiss}
|
||||
onPressSignin={() => setScreenState(ScreenState.S_Login)}
|
||||
onPressCreateAccount={() => setScreenState(ScreenState.S_CreateAccount)}
|
||||
/>
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import React from 'react'
|
||||
import {SafeAreaView, StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {
|
||||
SafeAreaView,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
Pressable,
|
||||
View,
|
||||
} from 'react-native'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
||||
import {s, colors} from 'lib/styles'
|
||||
|
@ -9,9 +16,11 @@ import {Trans, msg} from '@lingui/macro'
|
|||
import {useLingui} from '@lingui/react'
|
||||
|
||||
export const SplashScreen = ({
|
||||
onDismiss,
|
||||
onPressSignin,
|
||||
onPressCreateAccount,
|
||||
}: {
|
||||
onDismiss?: () => void
|
||||
onPressSignin: () => void
|
||||
onPressCreateAccount: () => void
|
||||
}) => {
|
||||
|
@ -20,6 +29,27 @@ export const SplashScreen = ({
|
|||
|
||||
return (
|
||||
<CenteredView style={[styles.container, pal.view]}>
|
||||
{onDismiss && (
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 20,
|
||||
right: 20,
|
||||
padding: 20,
|
||||
zIndex: 100,
|
||||
}}
|
||||
onPress={onDismiss}>
|
||||
<FontAwesomeIcon
|
||||
icon="x"
|
||||
size={24}
|
||||
style={{
|
||||
color: String(pal.text.color),
|
||||
}}
|
||||
/>
|
||||
</Pressable>
|
||||
)}
|
||||
|
||||
<SafeAreaView testID="noSessionView" style={styles.container}>
|
||||
<ErrorBoundary>
|
||||
<View style={styles.hero}>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react'
|
||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {StyleSheet, TouchableOpacity, View, Pressable} from 'react-native'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {TextLink} from '../util/Link'
|
||||
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
||||
|
@ -11,9 +12,11 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
|||
import {Trans} from '@lingui/macro'
|
||||
|
||||
export const SplashScreen = ({
|
||||
onDismiss,
|
||||
onPressSignin,
|
||||
onPressCreateAccount,
|
||||
}: {
|
||||
onDismiss?: () => void
|
||||
onPressSignin: () => void
|
||||
onPressCreateAccount: () => void
|
||||
}) => {
|
||||
|
@ -23,6 +26,28 @@ export const SplashScreen = ({
|
|||
const isMobileWeb = isWeb && isTabletOrMobile
|
||||
|
||||
return (
|
||||
<>
|
||||
{onDismiss && (
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 20,
|
||||
right: 20,
|
||||
padding: 20,
|
||||
zIndex: 100,
|
||||
}}
|
||||
onPress={onDismiss}>
|
||||
<FontAwesomeIcon
|
||||
icon="x"
|
||||
size={24}
|
||||
style={{
|
||||
color: String(pal.text.color),
|
||||
}}
|
||||
/>
|
||||
</Pressable>
|
||||
)}
|
||||
|
||||
<CenteredView style={[styles.container, pal.view]}>
|
||||
<View
|
||||
testID="noSessionView"
|
||||
|
@ -64,6 +89,7 @@ export const SplashScreen = ({
|
|||
</View>
|
||||
<Footer styles={styles} />
|
||||
</CenteredView>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,19 +13,34 @@ import {usePalette} from 'lib/hooks/usePalette'
|
|||
import {STATUS_PAGE_URL} from 'lib/constants'
|
||||
import {useOnboardingState} from '#/state/shell'
|
||||
import {useSession} from '#/state/session'
|
||||
import {
|
||||
useLoggedOutView,
|
||||
useLoggedOutViewControls,
|
||||
} from '#/state/shell/logged-out'
|
||||
import {IS_PROD} from '#/env'
|
||||
|
||||
export const withAuthRequired = <P extends object>(
|
||||
Component: React.ComponentType<P>,
|
||||
options: {
|
||||
isPublic?: boolean // TODO(pwi) need to enable in TF somehow
|
||||
} = {},
|
||||
): React.FC<P> =>
|
||||
function AuthRequired(props: P) {
|
||||
const {isInitialLoad, hasSession} = useSession()
|
||||
const onboardingState = useOnboardingState()
|
||||
const {showLoggedOut} = useLoggedOutView()
|
||||
const {setShowLoggedOut} = useLoggedOutViewControls()
|
||||
|
||||
if (isInitialLoad) {
|
||||
return <Loading />
|
||||
}
|
||||
if (!hasSession) {
|
||||
if (showLoggedOut) {
|
||||
return <LoggedOut onDismiss={() => setShowLoggedOut(false)} />
|
||||
} else if (!options?.isPublic || IS_PROD) {
|
||||
return <LoggedOut />
|
||||
}
|
||||
}
|
||||
if (onboardingState.isActive) {
|
||||
return <Onboarding />
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import {
|
|||
} from '#/state/queries/post'
|
||||
import {useComposerControls} from '#/state/shell/composer'
|
||||
import {Shadow} from '#/state/cache/types'
|
||||
import {useRequireAuth} from '#/state/session'
|
||||
|
||||
export function PostCtrls({
|
||||
big,
|
||||
|
@ -46,6 +47,7 @@ export function PostCtrls({
|
|||
const postUnlikeMutation = usePostUnlikeMutation()
|
||||
const postRepostMutation = usePostRepostMutation()
|
||||
const postUnrepostMutation = usePostUnrepostMutation()
|
||||
const requireAuth = useRequireAuth()
|
||||
|
||||
const defaultCtrlColor = React.useMemo(
|
||||
() => ({
|
||||
|
@ -107,7 +109,9 @@ export function PostCtrls({
|
|||
<TouchableOpacity
|
||||
testID="replyBtn"
|
||||
style={[styles.ctrl, !big && styles.ctrlPad, {paddingLeft: 0}]}
|
||||
onPress={onPressReply}
|
||||
onPress={() => {
|
||||
requireAuth(() => onPressReply())
|
||||
}}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={`Reply (${post.replyCount} ${
|
||||
post.replyCount === 1 ? 'reply' : 'replies'
|
||||
|
@ -135,7 +139,9 @@ export function PostCtrls({
|
|||
<TouchableOpacity
|
||||
testID="likeBtn"
|
||||
style={[styles.ctrl, !big && styles.ctrlPad]}
|
||||
onPress={onPressToggleLike}
|
||||
onPress={() => {
|
||||
requireAuth(() => onPressToggleLike())
|
||||
}}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={`${post.viewer?.like ? 'Unlike' : 'Like'} (${
|
||||
post.likeCount
|
||||
|
|
|
@ -7,6 +7,7 @@ import {Text} from '../text/Text'
|
|||
import {pluralize} from 'lib/strings/helpers'
|
||||
import {HITSLOP_10, HITSLOP_20} from 'lib/constants'
|
||||
import {useModalControls} from '#/state/modals'
|
||||
import {useRequireAuth} from '#/state/session'
|
||||
|
||||
interface Props {
|
||||
isReposted: boolean
|
||||
|
@ -25,6 +26,7 @@ export const RepostButton = ({
|
|||
}: Props) => {
|
||||
const theme = useTheme()
|
||||
const {openModal} = useModalControls()
|
||||
const requireAuth = useRequireAuth()
|
||||
|
||||
const defaultControlColor = React.useMemo(
|
||||
() => ({
|
||||
|
@ -45,7 +47,9 @@ export const RepostButton = ({
|
|||
return (
|
||||
<TouchableOpacity
|
||||
testID="repostBtn"
|
||||
onPress={onPressToggleRepostWrapper}
|
||||
onPress={() => {
|
||||
requireAuth(() => onPressToggleRepostWrapper())
|
||||
}}
|
||||
style={[styles.control, !big && styles.controlPad]}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={`${
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react'
|
||||
import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
|
||||
import {StyleProp, StyleSheet, View, ViewStyle, Pressable} from 'react-native'
|
||||
import {RepostIcon} from 'lib/icons'
|
||||
import {colors} from 'lib/styles'
|
||||
import {useTheme} from 'lib/ThemeContext'
|
||||
|
@ -12,6 +12,8 @@ import {
|
|||
import {EventStopper} from '../EventStopper'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useRequireAuth} from '#/state/session'
|
||||
import {useSession} from '#/state/session'
|
||||
|
||||
interface Props {
|
||||
isReposted: boolean
|
||||
|
@ -31,6 +33,8 @@ export const RepostButton = ({
|
|||
}: Props) => {
|
||||
const theme = useTheme()
|
||||
const {_} = useLingui()
|
||||
const {hasSession} = useSession()
|
||||
const requireAuth = useRequireAuth()
|
||||
|
||||
const defaultControlColor = React.useMemo(
|
||||
() => ({
|
||||
|
@ -62,12 +66,7 @@ export const RepostButton = ({
|
|||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<EventStopper>
|
||||
<NativeDropdown
|
||||
items={dropdownItems}
|
||||
accessibilityLabel={_(msg`Repost or quote post`)}
|
||||
accessibilityHint="">
|
||||
const inner = (
|
||||
<View
|
||||
style={[
|
||||
styles.control,
|
||||
|
@ -86,8 +85,27 @@ export const RepostButton = ({
|
|||
</Text>
|
||||
) : undefined}
|
||||
</View>
|
||||
)
|
||||
|
||||
return hasSession ? (
|
||||
<EventStopper>
|
||||
<NativeDropdown
|
||||
items={dropdownItems}
|
||||
accessibilityLabel={_(msg`Repost or quote post`)}
|
||||
accessibilityHint="">
|
||||
{inner}
|
||||
</NativeDropdown>
|
||||
</EventStopper>
|
||||
) : (
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
onPress={() => {
|
||||
requireAuth(() => {})
|
||||
}}
|
||||
accessibilityLabel={_(msg`Repost or quote post`)}
|
||||
accessibilityHint="">
|
||||
{inner}
|
||||
</Pressable>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -87,9 +87,8 @@ type FlatlistSlice =
|
|||
key: string
|
||||
}
|
||||
|
||||
export const FeedsScreen = withAuthRequired(function FeedsScreenImpl(
|
||||
_props: Props,
|
||||
) {
|
||||
export const FeedsScreen = withAuthRequired(
|
||||
function FeedsScreenImpl(_props: Props) {
|
||||
const pal = usePalette('default')
|
||||
const {openComposer} = useComposerControls()
|
||||
const {isMobile, isTabletOrDesktop} = useWebMediaQueries()
|
||||
|
@ -284,7 +283,9 @@ export const FeedsScreen = withAuthRequired(function FeedsScreenImpl(
|
|||
for (const page of popularFeeds.pages || []) {
|
||||
slices = slices.concat(
|
||||
page.feeds
|
||||
.filter(feed => !preferences?.feeds?.saved.includes(feed.uri))
|
||||
.filter(
|
||||
feed => !preferences?.feeds?.saved.includes(feed.uri),
|
||||
)
|
||||
.map(feed => ({
|
||||
key: `popularFeed:${feed.uri}`,
|
||||
type: 'popularFeed',
|
||||
|
@ -506,7 +507,9 @@ export const FeedsScreen = withAuthRequired(function FeedsScreenImpl(
|
|||
/>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
},
|
||||
{isPublic: true},
|
||||
)
|
||||
|
||||
function SavedFeed({feedUri}: {feedUri: string}) {
|
||||
const pal = usePalette('default')
|
||||
|
|
|
@ -14,12 +14,18 @@ import {useSetMinimalShellMode, useSetDrawerSwipeDisabled} from '#/state/shell'
|
|||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
|
||||
import {emitSoftReset} from '#/state/events'
|
||||
import {useSession} from '#/state/session'
|
||||
|
||||
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
|
||||
export const HomeScreen = withAuthRequired(function HomeScreenImpl(
|
||||
props: Props,
|
||||
) {
|
||||
export const HomeScreen = withAuthRequired(
|
||||
function HomeScreenImpl(props: Props) {
|
||||
const {hasSession} = useSession()
|
||||
const {data: preferences} = usePreferencesQuery()
|
||||
|
||||
if (!hasSession) {
|
||||
return <HomeScreenPublic />
|
||||
}
|
||||
|
||||
if (preferences) {
|
||||
return <HomeScreenReady {...props} preferences={preferences} />
|
||||
} else {
|
||||
|
@ -29,7 +35,35 @@ export const HomeScreen = withAuthRequired(function HomeScreenImpl(
|
|||
</View>
|
||||
)
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
isPublic: true,
|
||||
},
|
||||
)
|
||||
|
||||
function HomeScreenPublic() {
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled()
|
||||
|
||||
const renderCustomFeedEmptyState = React.useCallback(() => {
|
||||
return <CustomFeedEmptyState />
|
||||
}, [])
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
setMinimalShellMode(false)
|
||||
setDrawerSwipeDisabled(false)
|
||||
}, [setDrawerSwipeDisabled, setMinimalShellMode]),
|
||||
)
|
||||
|
||||
return (
|
||||
<FeedPage
|
||||
isPageFocused
|
||||
feed={`feedgen|at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot`}
|
||||
renderEmptyState={renderCustomFeedEmptyState}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function HomeScreenReady({
|
||||
preferences,
|
||||
|
@ -83,6 +117,7 @@ function HomeScreenReady({
|
|||
emitSoftReset()
|
||||
}, [])
|
||||
|
||||
// TODO(pwi) may need this in public view
|
||||
const onPageScrollStateChanged = React.useCallback(
|
||||
(state: 'idle' | 'dragging' | 'settling') => {
|
||||
if (state === 'dragging') {
|
||||
|
|
|
@ -11,7 +11,8 @@ import {msg} from '@lingui/macro'
|
|||
import {useLingui} from '@lingui/react'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostLikedBy'>
|
||||
export const PostLikedByScreen = withAuthRequired(({route}: Props) => {
|
||||
export const PostLikedByScreen = withAuthRequired(
|
||||
({route}: Props) => {
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const {name, rkey} = route.params
|
||||
const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey)
|
||||
|
@ -29,4 +30,6 @@ export const PostLikedByScreen = withAuthRequired(({route}: Props) => {
|
|||
<PostLikedByComponent uri={uri} />
|
||||
</View>
|
||||
)
|
||||
})
|
||||
},
|
||||
{isPublic: true},
|
||||
)
|
||||
|
|
|
@ -11,7 +11,8 @@ import {useLingui} from '@lingui/react'
|
|||
import {msg} from '@lingui/macro'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostRepostedBy'>
|
||||
export const PostRepostedByScreen = withAuthRequired(({route}: Props) => {
|
||||
export const PostRepostedByScreen = withAuthRequired(
|
||||
({route}: Props) => {
|
||||
const {name, rkey} = route.params
|
||||
const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey)
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
|
@ -29,4 +30,6 @@ export const PostRepostedByScreen = withAuthRequired(({route}: Props) => {
|
|||
<PostRepostedByComponent uri={uri} />
|
||||
</View>
|
||||
)
|
||||
})
|
||||
},
|
||||
{isPublic: true},
|
||||
)
|
||||
|
|
|
@ -27,9 +27,8 @@ import {CenteredView} from '../com/util/Views'
|
|||
import {useComposerControls} from '#/state/shell/composer'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'>
|
||||
export const PostThreadScreen = withAuthRequired(function PostThreadScreenImpl({
|
||||
route,
|
||||
}: Props) {
|
||||
export const PostThreadScreen = withAuthRequired(
|
||||
function PostThreadScreenImpl({route}: Props) {
|
||||
const queryClient = useQueryClient()
|
||||
const {_} = useLingui()
|
||||
const {fabMinimalShellTransform} = useMinimalShellMode()
|
||||
|
@ -104,7 +103,9 @@ export const PostThreadScreen = withAuthRequired(function PostThreadScreenImpl({
|
|||
)}
|
||||
</View>
|
||||
)
|
||||
})
|
||||
},
|
||||
{isPublic: true},
|
||||
)
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
prompt: {
|
||||
|
|
|
@ -43,9 +43,8 @@ interface SectionRef {
|
|||
}
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'>
|
||||
export const ProfileScreen = withAuthRequired(function ProfileScreenImpl({
|
||||
route,
|
||||
}: Props) {
|
||||
export const ProfileScreen = withAuthRequired(
|
||||
function ProfileScreenImpl({route}: Props) {
|
||||
const {currentAccount} = useSession()
|
||||
const name =
|
||||
route.params.name === 'me' ? currentAccount?.did : route.params.name
|
||||
|
@ -118,7 +117,11 @@ export const ProfileScreen = withAuthRequired(function ProfileScreenImpl({
|
|||
/>
|
||||
</CenteredView>
|
||||
)
|
||||
})
|
||||
},
|
||||
{
|
||||
isPublic: true,
|
||||
},
|
||||
)
|
||||
|
||||
function ProfileScreenLoaded({
|
||||
profile: profileUnshadowed,
|
||||
|
|
|
@ -129,6 +129,9 @@ export const ProfileFeedScreen = withAuthRequired(
|
|||
</CenteredView>
|
||||
)
|
||||
},
|
||||
{
|
||||
isPublic: true,
|
||||
},
|
||||
)
|
||||
|
||||
function ProfileFeedScreenIntermediate({feedUri}: {feedUri: string}) {
|
||||
|
|
|
@ -11,7 +11,8 @@ import {useLingui} from '@lingui/react'
|
|||
import {msg} from '@lingui/macro'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFeedLikedBy'>
|
||||
export const ProfileFeedLikedByScreen = withAuthRequired(({route}: Props) => {
|
||||
export const ProfileFeedLikedByScreen = withAuthRequired(
|
||||
({route}: Props) => {
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const {name, rkey} = route.params
|
||||
const uri = makeRecordUri(name, 'app.bsky.feed.generator', rkey)
|
||||
|
@ -29,4 +30,6 @@ export const ProfileFeedLikedByScreen = withAuthRequired(({route}: Props) => {
|
|||
<PostLikedByComponent uri={uri} />
|
||||
</View>
|
||||
)
|
||||
})
|
||||
},
|
||||
{isPublic: true},
|
||||
)
|
||||
|
|
|
@ -10,7 +10,8 @@ import {useLingui} from '@lingui/react'
|
|||
import {msg} from '@lingui/macro'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollowers'>
|
||||
export const ProfileFollowersScreen = withAuthRequired(({route}: Props) => {
|
||||
export const ProfileFollowersScreen = withAuthRequired(
|
||||
({route}: Props) => {
|
||||
const {name} = route.params
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const {_} = useLingui()
|
||||
|
@ -27,4 +28,6 @@ export const ProfileFollowersScreen = withAuthRequired(({route}: Props) => {
|
|||
<ProfileFollowersComponent name={name} />
|
||||
</View>
|
||||
)
|
||||
})
|
||||
},
|
||||
{isPublic: true},
|
||||
)
|
||||
|
|
|
@ -10,7 +10,8 @@ import {useLingui} from '@lingui/react'
|
|||
import {msg} from '@lingui/macro'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollows'>
|
||||
export const ProfileFollowsScreen = withAuthRequired(({route}: Props) => {
|
||||
export const ProfileFollowsScreen = withAuthRequired(
|
||||
({route}: Props) => {
|
||||
const {name} = route.params
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const {_} = useLingui()
|
||||
|
@ -27,4 +28,6 @@ export const ProfileFollowsScreen = withAuthRequired(({route}: Props) => {
|
|||
<ProfileFollowsComponent name={name} />
|
||||
</View>
|
||||
)
|
||||
})
|
||||
},
|
||||
{isPublic: true},
|
||||
)
|
||||
|
|
|
@ -33,7 +33,7 @@ import {
|
|||
usePinFeedMutation,
|
||||
useUnpinFeedMutation,
|
||||
useSetSaveFeedsMutation,
|
||||
usePreferencesQueryKey,
|
||||
preferencesQueryKey,
|
||||
UsePreferencesQueryResponse,
|
||||
} from '#/state/queries/preferences'
|
||||
|
||||
|
@ -182,8 +182,9 @@ function ListItem({
|
|||
const onPressUp = React.useCallback(async () => {
|
||||
if (!isPinned) return
|
||||
|
||||
const feeds = queryClient.getQueryData<UsePreferencesQueryResponse>(
|
||||
usePreferencesQueryKey,
|
||||
const feeds =
|
||||
queryClient.getQueryData<UsePreferencesQueryResponse>(
|
||||
preferencesQueryKey,
|
||||
)?.feeds
|
||||
const pinned = feeds?.pinned ?? []
|
||||
const index = pinned.indexOf(feedUri)
|
||||
|
@ -206,8 +207,9 @@ function ListItem({
|
|||
const onPressDown = React.useCallback(async () => {
|
||||
if (!isPinned) return
|
||||
|
||||
const feeds = queryClient.getQueryData<UsePreferencesQueryResponse>(
|
||||
usePreferencesQueryKey,
|
||||
const feeds =
|
||||
queryClient.getQueryData<UsePreferencesQueryResponse>(
|
||||
preferencesQueryKey,
|
||||
)?.feeds
|
||||
const pinned = feeds?.pinned ?? []
|
||||
const index = pinned.indexOf(feedUri)
|
||||
|
|
Loading…
Reference in New Issue