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,
|
UsePreferencesQueryResponse,
|
||||||
ThreadViewPreferences,
|
ThreadViewPreferences,
|
||||||
} from '#/state/queries/preferences/types'
|
} from '#/state/queries/preferences/types'
|
||||||
|
import {DEFAULT_LOGGED_OUT_LABEL_PREFERENCES} from '#/state/queries/preferences/moderation'
|
||||||
|
|
||||||
export const DEFAULT_HOME_FEED_PREFS: UsePreferencesQueryResponse['feedViewPrefs'] =
|
export const DEFAULT_HOME_FEED_PREFS: UsePreferencesQueryResponse['feedViewPrefs'] =
|
||||||
{
|
{
|
||||||
|
@ -25,3 +26,26 @@ export const DEFAULT_PROD_FEEDS = {
|
||||||
pinned: [DEFAULT_PROD_FEED_PREFIX('whats-hot')],
|
pinned: [DEFAULT_PROD_FEED_PREFIX('whats-hot')],
|
||||||
saved: [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 {
|
import {
|
||||||
DEFAULT_HOME_FEED_PREFS,
|
DEFAULT_HOME_FEED_PREFS,
|
||||||
DEFAULT_THREAD_VIEW_PREFS,
|
DEFAULT_THREAD_VIEW_PREFS,
|
||||||
|
DEFAULT_LOGGED_OUT_PREFERENCES,
|
||||||
} from '#/state/queries/preferences/const'
|
} from '#/state/queries/preferences/const'
|
||||||
import {getModerationOpts} from '#/state/queries/preferences/moderation'
|
import {getModerationOpts} from '#/state/queries/preferences/moderation'
|
||||||
import {STALE} from '#/state/queries'
|
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/moderation'
|
||||||
export * from '#/state/queries/preferences/const'
|
export * from '#/state/queries/preferences/const'
|
||||||
|
|
||||||
export const usePreferencesQueryKey = ['getPreferences']
|
export const preferencesQueryKey = ['getPreferences']
|
||||||
|
|
||||||
export function usePreferencesQuery() {
|
export function usePreferencesQuery() {
|
||||||
const {hasSession} = useSession()
|
|
||||||
return useQuery({
|
return useQuery({
|
||||||
enabled: hasSession,
|
|
||||||
staleTime: STALE.MINUTES.ONE,
|
staleTime: STALE.MINUTES.ONE,
|
||||||
queryKey: usePreferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
queryFn: async () => {
|
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 = {
|
const preferences: UsePreferencesQueryResponse = {
|
||||||
...res,
|
...res,
|
||||||
feeds: {
|
feeds: {
|
||||||
|
@ -80,6 +84,7 @@ export function usePreferencesQuery() {
|
||||||
userAge: res.birthDate ? getAge(res.birthDate) : undefined,
|
userAge: res.birthDate ? getAge(res.birthDate) : undefined,
|
||||||
}
|
}
|
||||||
return preferences
|
return preferences
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -107,7 +112,7 @@ export function useClearPreferencesMutation() {
|
||||||
await getAgent().app.bsky.actor.putPreferences({preferences: []})
|
await getAgent().app.bsky.actor.putPreferences({preferences: []})
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: usePreferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -125,7 +130,7 @@ export function usePreferencesSetContentLabelMutation() {
|
||||||
await getAgent().setContentLabelPref(labelGroup, visibility)
|
await getAgent().setContentLabelPref(labelGroup, visibility)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: usePreferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -139,7 +144,7 @@ export function usePreferencesSetAdultContentMutation() {
|
||||||
await getAgent().setAdultContentEnabled(enabled)
|
await getAgent().setAdultContentEnabled(enabled)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: usePreferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -153,7 +158,7 @@ export function usePreferencesSetBirthDateMutation() {
|
||||||
await getAgent().setPersonalDetails({birthDate})
|
await getAgent().setPersonalDetails({birthDate})
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: usePreferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -167,7 +172,7 @@ export function useSetFeedViewPreferencesMutation() {
|
||||||
await getAgent().setFeedViewPrefs('home', prefs)
|
await getAgent().setFeedViewPrefs('home', prefs)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: usePreferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -181,7 +186,7 @@ export function useSetThreadViewPreferencesMutation() {
|
||||||
await getAgent().setThreadViewPrefs(prefs)
|
await getAgent().setThreadViewPrefs(prefs)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: usePreferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -199,7 +204,7 @@ export function useSetSaveFeedsMutation() {
|
||||||
await getAgent().setSavedFeeds(saved, pinned)
|
await getAgent().setSavedFeeds(saved, pinned)
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: usePreferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -214,7 +219,7 @@ export function useSaveFeedMutation() {
|
||||||
track('CustomFeed:Save')
|
track('CustomFeed:Save')
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: usePreferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -229,7 +234,7 @@ export function useRemoveFeedMutation() {
|
||||||
track('CustomFeed:Unsave')
|
track('CustomFeed:Unsave')
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: usePreferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -244,7 +249,7 @@ export function usePinFeedMutation() {
|
||||||
track('CustomFeed:Pin', {uri})
|
track('CustomFeed:Pin', {uri})
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: usePreferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -259,7 +264,7 @@ export function useUnpinFeedMutation() {
|
||||||
track('CustomFeed:Unpin', {uri})
|
track('CustomFeed:Unpin', {uri})
|
||||||
// triggers a refetch
|
// triggers a refetch
|
||||||
await queryClient.invalidateQueries({
|
await queryClient.invalidateQueries({
|
||||||
queryKey: usePreferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -34,6 +34,24 @@ export const DEFAULT_LABEL_PREFERENCES: Record<
|
||||||
impersonation: 'hide',
|
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 = {
|
export const ILLEGAL_LABEL_GROUP: LabelGroupConfig = {
|
||||||
id: 'illegal',
|
id: 'illegal',
|
||||||
title: 'Illegal Content',
|
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
|
sort: 'oldest' | 'newest' | 'most-likes' | 'random' | string
|
||||||
lab_treeViewEnabled?: boolean
|
lab_treeViewEnabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import * as persisted from '#/state/persisted'
|
||||||
import {PUBLIC_BSKY_AGENT} from '#/state/queries'
|
import {PUBLIC_BSKY_AGENT} from '#/state/queries'
|
||||||
import {IS_PROD} from '#/lib/constants'
|
import {IS_PROD} from '#/lib/constants'
|
||||||
import {emitSessionLoaded, emitSessionDropped} from '../events'
|
import {emitSessionLoaded, emitSessionDropped} from '../events'
|
||||||
|
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
|
||||||
|
|
||||||
let __globalAgent: BskyAgent = PUBLIC_BSKY_AGENT
|
let __globalAgent: BskyAgent = PUBLIC_BSKY_AGENT
|
||||||
|
|
||||||
|
@ -515,3 +516,19 @@ export function useSession() {
|
||||||
export function useSessionApi() {
|
export function useSessionApi() {
|
||||||
return React.useContext(ApiContext)
|
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 OnboardingProvider} from './onboarding'
|
||||||
import {Provider as ComposerProvider} from './composer'
|
import {Provider as ComposerProvider} from './composer'
|
||||||
import {Provider as TickEveryMinuteProvider} from './tick-every-minute'
|
import {Provider as TickEveryMinuteProvider} from './tick-every-minute'
|
||||||
|
import {Provider as LoggedOutViewProvider} from './logged-out'
|
||||||
|
|
||||||
export {useIsDrawerOpen, useSetDrawerOpen} from './drawer-open'
|
export {useIsDrawerOpen, useSetDrawerOpen} from './drawer-open'
|
||||||
export {
|
export {
|
||||||
|
@ -22,19 +23,23 @@ export {useTickEveryMinute} from './tick-every-minute'
|
||||||
export function Provider({children}: React.PropsWithChildren<{}>) {
|
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
return (
|
return (
|
||||||
<ShellLayoutProvder>
|
<ShellLayoutProvder>
|
||||||
|
<LoggedOutViewProvider>
|
||||||
<DrawerOpenProvider>
|
<DrawerOpenProvider>
|
||||||
<DrawerSwipableProvider>
|
<DrawerSwipableProvider>
|
||||||
<MinimalModeProvider>
|
<MinimalModeProvider>
|
||||||
<ColorModeProvider>
|
<ColorModeProvider>
|
||||||
<OnboardingProvider>
|
<OnboardingProvider>
|
||||||
<ComposerProvider>
|
<ComposerProvider>
|
||||||
<TickEveryMinuteProvider>{children}</TickEveryMinuteProvider>
|
<TickEveryMinuteProvider>
|
||||||
|
{children}
|
||||||
|
</TickEveryMinuteProvider>
|
||||||
</ComposerProvider>
|
</ComposerProvider>
|
||||||
</OnboardingProvider>
|
</OnboardingProvider>
|
||||||
</ColorModeProvider>
|
</ColorModeProvider>
|
||||||
</MinimalModeProvider>
|
</MinimalModeProvider>
|
||||||
</DrawerSwipableProvider>
|
</DrawerSwipableProvider>
|
||||||
</DrawerOpenProvider>
|
</DrawerOpenProvider>
|
||||||
|
</LoggedOutViewProvider>
|
||||||
</ShellLayoutProvder>
|
</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,
|
S_CreateAccount,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LoggedOut() {
|
export function LoggedOut({onDismiss}: {onDismiss?: () => void}) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
const {screen} = useAnalytics()
|
const {screen} = useAnalytics()
|
||||||
|
@ -31,6 +31,7 @@ export function LoggedOut() {
|
||||||
if (screenState === ScreenState.S_LoginOrCreateAccount) {
|
if (screenState === ScreenState.S_LoginOrCreateAccount) {
|
||||||
return (
|
return (
|
||||||
<SplashScreen
|
<SplashScreen
|
||||||
|
onDismiss={onDismiss}
|
||||||
onPressSignin={() => setScreenState(ScreenState.S_Login)}
|
onPressSignin={() => setScreenState(ScreenState.S_Login)}
|
||||||
onPressCreateAccount={() => setScreenState(ScreenState.S_CreateAccount)}
|
onPressCreateAccount={() => setScreenState(ScreenState.S_CreateAccount)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
import React from 'react'
|
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 {Text} from 'view/com/util/text/Text'
|
||||||
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
||||||
import {s, colors} from 'lib/styles'
|
import {s, colors} from 'lib/styles'
|
||||||
|
@ -9,9 +16,11 @@ import {Trans, msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
export const SplashScreen = ({
|
export const SplashScreen = ({
|
||||||
|
onDismiss,
|
||||||
onPressSignin,
|
onPressSignin,
|
||||||
onPressCreateAccount,
|
onPressCreateAccount,
|
||||||
}: {
|
}: {
|
||||||
|
onDismiss?: () => void
|
||||||
onPressSignin: () => void
|
onPressSignin: () => void
|
||||||
onPressCreateAccount: () => void
|
onPressCreateAccount: () => void
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -20,6 +29,27 @@ export const SplashScreen = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CenteredView style={[styles.container, pal.view]}>
|
<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}>
|
<SafeAreaView testID="noSessionView" style={styles.container}>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<View style={styles.hero}>
|
<View style={styles.hero}>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React from 'react'
|
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 {Text} from 'view/com/util/text/Text'
|
||||||
import {TextLink} from '../util/Link'
|
import {TextLink} from '../util/Link'
|
||||||
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
||||||
|
@ -11,9 +12,11 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||||
import {Trans} from '@lingui/macro'
|
import {Trans} from '@lingui/macro'
|
||||||
|
|
||||||
export const SplashScreen = ({
|
export const SplashScreen = ({
|
||||||
|
onDismiss,
|
||||||
onPressSignin,
|
onPressSignin,
|
||||||
onPressCreateAccount,
|
onPressCreateAccount,
|
||||||
}: {
|
}: {
|
||||||
|
onDismiss?: () => void
|
||||||
onPressSignin: () => void
|
onPressSignin: () => void
|
||||||
onPressCreateAccount: () => void
|
onPressCreateAccount: () => void
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -23,6 +26,28 @@ export const SplashScreen = ({
|
||||||
const isMobileWeb = isWeb && isTabletOrMobile
|
const isMobileWeb = isWeb && isTabletOrMobile
|
||||||
|
|
||||||
return (
|
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]}>
|
<CenteredView style={[styles.container, pal.view]}>
|
||||||
<View
|
<View
|
||||||
testID="noSessionView"
|
testID="noSessionView"
|
||||||
|
@ -64,6 +89,7 @@ export const SplashScreen = ({
|
||||||
</View>
|
</View>
|
||||||
<Footer styles={styles} />
|
<Footer styles={styles} />
|
||||||
</CenteredView>
|
</CenteredView>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,19 +13,34 @@ import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {STATUS_PAGE_URL} from 'lib/constants'
|
import {STATUS_PAGE_URL} from 'lib/constants'
|
||||||
import {useOnboardingState} from '#/state/shell'
|
import {useOnboardingState} from '#/state/shell'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
|
import {
|
||||||
|
useLoggedOutView,
|
||||||
|
useLoggedOutViewControls,
|
||||||
|
} from '#/state/shell/logged-out'
|
||||||
|
import {IS_PROD} from '#/env'
|
||||||
|
|
||||||
export const withAuthRequired = <P extends object>(
|
export const withAuthRequired = <P extends object>(
|
||||||
Component: React.ComponentType<P>,
|
Component: React.ComponentType<P>,
|
||||||
|
options: {
|
||||||
|
isPublic?: boolean // TODO(pwi) need to enable in TF somehow
|
||||||
|
} = {},
|
||||||
): React.FC<P> =>
|
): React.FC<P> =>
|
||||||
function AuthRequired(props: P) {
|
function AuthRequired(props: P) {
|
||||||
const {isInitialLoad, hasSession} = useSession()
|
const {isInitialLoad, hasSession} = useSession()
|
||||||
const onboardingState = useOnboardingState()
|
const onboardingState = useOnboardingState()
|
||||||
|
const {showLoggedOut} = useLoggedOutView()
|
||||||
|
const {setShowLoggedOut} = useLoggedOutViewControls()
|
||||||
|
|
||||||
if (isInitialLoad) {
|
if (isInitialLoad) {
|
||||||
return <Loading />
|
return <Loading />
|
||||||
}
|
}
|
||||||
if (!hasSession) {
|
if (!hasSession) {
|
||||||
|
if (showLoggedOut) {
|
||||||
|
return <LoggedOut onDismiss={() => setShowLoggedOut(false)} />
|
||||||
|
} else if (!options?.isPublic || IS_PROD) {
|
||||||
return <LoggedOut />
|
return <LoggedOut />
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (onboardingState.isActive) {
|
if (onboardingState.isActive) {
|
||||||
return <Onboarding />
|
return <Onboarding />
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import {
|
||||||
} from '#/state/queries/post'
|
} from '#/state/queries/post'
|
||||||
import {useComposerControls} from '#/state/shell/composer'
|
import {useComposerControls} from '#/state/shell/composer'
|
||||||
import {Shadow} from '#/state/cache/types'
|
import {Shadow} from '#/state/cache/types'
|
||||||
|
import {useRequireAuth} from '#/state/session'
|
||||||
|
|
||||||
export function PostCtrls({
|
export function PostCtrls({
|
||||||
big,
|
big,
|
||||||
|
@ -46,6 +47,7 @@ export function PostCtrls({
|
||||||
const postUnlikeMutation = usePostUnlikeMutation()
|
const postUnlikeMutation = usePostUnlikeMutation()
|
||||||
const postRepostMutation = usePostRepostMutation()
|
const postRepostMutation = usePostRepostMutation()
|
||||||
const postUnrepostMutation = usePostUnrepostMutation()
|
const postUnrepostMutation = usePostUnrepostMutation()
|
||||||
|
const requireAuth = useRequireAuth()
|
||||||
|
|
||||||
const defaultCtrlColor = React.useMemo(
|
const defaultCtrlColor = React.useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
@ -107,7 +109,9 @@ export function PostCtrls({
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
testID="replyBtn"
|
testID="replyBtn"
|
||||||
style={[styles.ctrl, !big && styles.ctrlPad, {paddingLeft: 0}]}
|
style={[styles.ctrl, !big && styles.ctrlPad, {paddingLeft: 0}]}
|
||||||
onPress={onPressReply}
|
onPress={() => {
|
||||||
|
requireAuth(() => onPressReply())
|
||||||
|
}}
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityLabel={`Reply (${post.replyCount} ${
|
accessibilityLabel={`Reply (${post.replyCount} ${
|
||||||
post.replyCount === 1 ? 'reply' : 'replies'
|
post.replyCount === 1 ? 'reply' : 'replies'
|
||||||
|
@ -135,7 +139,9 @@ export function PostCtrls({
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
testID="likeBtn"
|
testID="likeBtn"
|
||||||
style={[styles.ctrl, !big && styles.ctrlPad]}
|
style={[styles.ctrl, !big && styles.ctrlPad]}
|
||||||
onPress={onPressToggleLike}
|
onPress={() => {
|
||||||
|
requireAuth(() => onPressToggleLike())
|
||||||
|
}}
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityLabel={`${post.viewer?.like ? 'Unlike' : 'Like'} (${
|
accessibilityLabel={`${post.viewer?.like ? 'Unlike' : 'Like'} (${
|
||||||
post.likeCount
|
post.likeCount
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {Text} from '../text/Text'
|
||||||
import {pluralize} from 'lib/strings/helpers'
|
import {pluralize} from 'lib/strings/helpers'
|
||||||
import {HITSLOP_10, HITSLOP_20} from 'lib/constants'
|
import {HITSLOP_10, HITSLOP_20} from 'lib/constants'
|
||||||
import {useModalControls} from '#/state/modals'
|
import {useModalControls} from '#/state/modals'
|
||||||
|
import {useRequireAuth} from '#/state/session'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isReposted: boolean
|
isReposted: boolean
|
||||||
|
@ -25,6 +26,7 @@ export const RepostButton = ({
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const {openModal} = useModalControls()
|
const {openModal} = useModalControls()
|
||||||
|
const requireAuth = useRequireAuth()
|
||||||
|
|
||||||
const defaultControlColor = React.useMemo(
|
const defaultControlColor = React.useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
@ -45,7 +47,9 @@ export const RepostButton = ({
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
testID="repostBtn"
|
testID="repostBtn"
|
||||||
onPress={onPressToggleRepostWrapper}
|
onPress={() => {
|
||||||
|
requireAuth(() => onPressToggleRepostWrapper())
|
||||||
|
}}
|
||||||
style={[styles.control, !big && styles.controlPad]}
|
style={[styles.control, !big && styles.controlPad]}
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityLabel={`${
|
accessibilityLabel={`${
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react'
|
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 {RepostIcon} from 'lib/icons'
|
||||||
import {colors} from 'lib/styles'
|
import {colors} from 'lib/styles'
|
||||||
import {useTheme} from 'lib/ThemeContext'
|
import {useTheme} from 'lib/ThemeContext'
|
||||||
|
@ -12,6 +12,8 @@ import {
|
||||||
import {EventStopper} from '../EventStopper'
|
import {EventStopper} from '../EventStopper'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
|
import {useRequireAuth} from '#/state/session'
|
||||||
|
import {useSession} from '#/state/session'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isReposted: boolean
|
isReposted: boolean
|
||||||
|
@ -31,6 +33,8 @@ export const RepostButton = ({
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const {hasSession} = useSession()
|
||||||
|
const requireAuth = useRequireAuth()
|
||||||
|
|
||||||
const defaultControlColor = React.useMemo(
|
const defaultControlColor = React.useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
|
@ -62,12 +66,7 @@ export const RepostButton = ({
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
return (
|
const inner = (
|
||||||
<EventStopper>
|
|
||||||
<NativeDropdown
|
|
||||||
items={dropdownItems}
|
|
||||||
accessibilityLabel={_(msg`Repost or quote post`)}
|
|
||||||
accessibilityHint="">
|
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
styles.control,
|
styles.control,
|
||||||
|
@ -86,8 +85,27 @@ export const RepostButton = ({
|
||||||
</Text>
|
</Text>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
</View>
|
</View>
|
||||||
|
)
|
||||||
|
|
||||||
|
return hasSession ? (
|
||||||
|
<EventStopper>
|
||||||
|
<NativeDropdown
|
||||||
|
items={dropdownItems}
|
||||||
|
accessibilityLabel={_(msg`Repost or quote post`)}
|
||||||
|
accessibilityHint="">
|
||||||
|
{inner}
|
||||||
</NativeDropdown>
|
</NativeDropdown>
|
||||||
</EventStopper>
|
</EventStopper>
|
||||||
|
) : (
|
||||||
|
<Pressable
|
||||||
|
accessibilityRole="button"
|
||||||
|
onPress={() => {
|
||||||
|
requireAuth(() => {})
|
||||||
|
}}
|
||||||
|
accessibilityLabel={_(msg`Repost or quote post`)}
|
||||||
|
accessibilityHint="">
|
||||||
|
{inner}
|
||||||
|
</Pressable>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,9 +87,8 @@ type FlatlistSlice =
|
||||||
key: string
|
key: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FeedsScreen = withAuthRequired(function FeedsScreenImpl(
|
export const FeedsScreen = withAuthRequired(
|
||||||
_props: Props,
|
function FeedsScreenImpl(_props: Props) {
|
||||||
) {
|
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {openComposer} = useComposerControls()
|
const {openComposer} = useComposerControls()
|
||||||
const {isMobile, isTabletOrDesktop} = useWebMediaQueries()
|
const {isMobile, isTabletOrDesktop} = useWebMediaQueries()
|
||||||
|
@ -284,7 +283,9 @@ export const FeedsScreen = withAuthRequired(function FeedsScreenImpl(
|
||||||
for (const page of popularFeeds.pages || []) {
|
for (const page of popularFeeds.pages || []) {
|
||||||
slices = slices.concat(
|
slices = slices.concat(
|
||||||
page.feeds
|
page.feeds
|
||||||
.filter(feed => !preferences?.feeds?.saved.includes(feed.uri))
|
.filter(
|
||||||
|
feed => !preferences?.feeds?.saved.includes(feed.uri),
|
||||||
|
)
|
||||||
.map(feed => ({
|
.map(feed => ({
|
||||||
key: `popularFeed:${feed.uri}`,
|
key: `popularFeed:${feed.uri}`,
|
||||||
type: 'popularFeed',
|
type: 'popularFeed',
|
||||||
|
@ -506,7 +507,9 @@ export const FeedsScreen = withAuthRequired(function FeedsScreenImpl(
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
{isPublic: true},
|
||||||
|
)
|
||||||
|
|
||||||
function SavedFeed({feedUri}: {feedUri: string}) {
|
function SavedFeed({feedUri}: {feedUri: string}) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
|
|
|
@ -14,12 +14,18 @@ import {useSetMinimalShellMode, useSetDrawerSwipeDisabled} from '#/state/shell'
|
||||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||||
import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
|
import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
|
||||||
import {emitSoftReset} from '#/state/events'
|
import {emitSoftReset} from '#/state/events'
|
||||||
|
import {useSession} from '#/state/session'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
|
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
|
||||||
export const HomeScreen = withAuthRequired(function HomeScreenImpl(
|
export const HomeScreen = withAuthRequired(
|
||||||
props: Props,
|
function HomeScreenImpl(props: Props) {
|
||||||
) {
|
const {hasSession} = useSession()
|
||||||
const {data: preferences} = usePreferencesQuery()
|
const {data: preferences} = usePreferencesQuery()
|
||||||
|
|
||||||
|
if (!hasSession) {
|
||||||
|
return <HomeScreenPublic />
|
||||||
|
}
|
||||||
|
|
||||||
if (preferences) {
|
if (preferences) {
|
||||||
return <HomeScreenReady {...props} preferences={preferences} />
|
return <HomeScreenReady {...props} preferences={preferences} />
|
||||||
} else {
|
} else {
|
||||||
|
@ -29,7 +35,35 @@ export const HomeScreen = withAuthRequired(function HomeScreenImpl(
|
||||||
</View>
|
</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({
|
function HomeScreenReady({
|
||||||
preferences,
|
preferences,
|
||||||
|
@ -83,6 +117,7 @@ function HomeScreenReady({
|
||||||
emitSoftReset()
|
emitSoftReset()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// TODO(pwi) may need this in public view
|
||||||
const onPageScrollStateChanged = React.useCallback(
|
const onPageScrollStateChanged = React.useCallback(
|
||||||
(state: 'idle' | 'dragging' | 'settling') => {
|
(state: 'idle' | 'dragging' | 'settling') => {
|
||||||
if (state === 'dragging') {
|
if (state === 'dragging') {
|
||||||
|
|
|
@ -11,7 +11,8 @@ import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostLikedBy'>
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostLikedBy'>
|
||||||
export const PostLikedByScreen = withAuthRequired(({route}: Props) => {
|
export const PostLikedByScreen = withAuthRequired(
|
||||||
|
({route}: Props) => {
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
const {name, rkey} = route.params
|
const {name, rkey} = route.params
|
||||||
const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey)
|
const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey)
|
||||||
|
@ -29,4 +30,6 @@ export const PostLikedByScreen = withAuthRequired(({route}: Props) => {
|
||||||
<PostLikedByComponent uri={uri} />
|
<PostLikedByComponent uri={uri} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
{isPublic: true},
|
||||||
|
)
|
||||||
|
|
|
@ -11,7 +11,8 @@ import {useLingui} from '@lingui/react'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostRepostedBy'>
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostRepostedBy'>
|
||||||
export const PostRepostedByScreen = withAuthRequired(({route}: Props) => {
|
export const PostRepostedByScreen = withAuthRequired(
|
||||||
|
({route}: Props) => {
|
||||||
const {name, rkey} = route.params
|
const {name, rkey} = route.params
|
||||||
const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey)
|
const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey)
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
|
@ -29,4 +30,6 @@ export const PostRepostedByScreen = withAuthRequired(({route}: Props) => {
|
||||||
<PostRepostedByComponent uri={uri} />
|
<PostRepostedByComponent uri={uri} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
{isPublic: true},
|
||||||
|
)
|
||||||
|
|
|
@ -27,9 +27,8 @@ import {CenteredView} from '../com/util/Views'
|
||||||
import {useComposerControls} from '#/state/shell/composer'
|
import {useComposerControls} from '#/state/shell/composer'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'>
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'>
|
||||||
export const PostThreadScreen = withAuthRequired(function PostThreadScreenImpl({
|
export const PostThreadScreen = withAuthRequired(
|
||||||
route,
|
function PostThreadScreenImpl({route}: Props) {
|
||||||
}: Props) {
|
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {fabMinimalShellTransform} = useMinimalShellMode()
|
const {fabMinimalShellTransform} = useMinimalShellMode()
|
||||||
|
@ -104,7 +103,9 @@ export const PostThreadScreen = withAuthRequired(function PostThreadScreenImpl({
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
{isPublic: true},
|
||||||
|
)
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
prompt: {
|
prompt: {
|
||||||
|
|
|
@ -43,9 +43,8 @@ interface SectionRef {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'>
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'>
|
||||||
export const ProfileScreen = withAuthRequired(function ProfileScreenImpl({
|
export const ProfileScreen = withAuthRequired(
|
||||||
route,
|
function ProfileScreenImpl({route}: Props) {
|
||||||
}: Props) {
|
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const name =
|
const name =
|
||||||
route.params.name === 'me' ? currentAccount?.did : route.params.name
|
route.params.name === 'me' ? currentAccount?.did : route.params.name
|
||||||
|
@ -118,7 +117,11 @@ export const ProfileScreen = withAuthRequired(function ProfileScreenImpl({
|
||||||
/>
|
/>
|
||||||
</CenteredView>
|
</CenteredView>
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
{
|
||||||
|
isPublic: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
function ProfileScreenLoaded({
|
function ProfileScreenLoaded({
|
||||||
profile: profileUnshadowed,
|
profile: profileUnshadowed,
|
||||||
|
|
|
@ -129,6 +129,9 @@ export const ProfileFeedScreen = withAuthRequired(
|
||||||
</CenteredView>
|
</CenteredView>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
isPublic: true,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
function ProfileFeedScreenIntermediate({feedUri}: {feedUri: string}) {
|
function ProfileFeedScreenIntermediate({feedUri}: {feedUri: string}) {
|
||||||
|
|
|
@ -11,7 +11,8 @@ import {useLingui} from '@lingui/react'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFeedLikedBy'>
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFeedLikedBy'>
|
||||||
export const ProfileFeedLikedByScreen = withAuthRequired(({route}: Props) => {
|
export const ProfileFeedLikedByScreen = withAuthRequired(
|
||||||
|
({route}: Props) => {
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
const {name, rkey} = route.params
|
const {name, rkey} = route.params
|
||||||
const uri = makeRecordUri(name, 'app.bsky.feed.generator', rkey)
|
const uri = makeRecordUri(name, 'app.bsky.feed.generator', rkey)
|
||||||
|
@ -29,4 +30,6 @@ export const ProfileFeedLikedByScreen = withAuthRequired(({route}: Props) => {
|
||||||
<PostLikedByComponent uri={uri} />
|
<PostLikedByComponent uri={uri} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
{isPublic: true},
|
||||||
|
)
|
||||||
|
|
|
@ -10,7 +10,8 @@ import {useLingui} from '@lingui/react'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollowers'>
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollowers'>
|
||||||
export const ProfileFollowersScreen = withAuthRequired(({route}: Props) => {
|
export const ProfileFollowersScreen = withAuthRequired(
|
||||||
|
({route}: Props) => {
|
||||||
const {name} = route.params
|
const {name} = route.params
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
@ -27,4 +28,6 @@ export const ProfileFollowersScreen = withAuthRequired(({route}: Props) => {
|
||||||
<ProfileFollowersComponent name={name} />
|
<ProfileFollowersComponent name={name} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
{isPublic: true},
|
||||||
|
)
|
||||||
|
|
|
@ -10,7 +10,8 @@ import {useLingui} from '@lingui/react'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollows'>
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollows'>
|
||||||
export const ProfileFollowsScreen = withAuthRequired(({route}: Props) => {
|
export const ProfileFollowsScreen = withAuthRequired(
|
||||||
|
({route}: Props) => {
|
||||||
const {name} = route.params
|
const {name} = route.params
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
@ -27,4 +28,6 @@ export const ProfileFollowsScreen = withAuthRequired(({route}: Props) => {
|
||||||
<ProfileFollowsComponent name={name} />
|
<ProfileFollowsComponent name={name} />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
})
|
},
|
||||||
|
{isPublic: true},
|
||||||
|
)
|
||||||
|
|
|
@ -33,7 +33,7 @@ import {
|
||||||
usePinFeedMutation,
|
usePinFeedMutation,
|
||||||
useUnpinFeedMutation,
|
useUnpinFeedMutation,
|
||||||
useSetSaveFeedsMutation,
|
useSetSaveFeedsMutation,
|
||||||
usePreferencesQueryKey,
|
preferencesQueryKey,
|
||||||
UsePreferencesQueryResponse,
|
UsePreferencesQueryResponse,
|
||||||
} from '#/state/queries/preferences'
|
} from '#/state/queries/preferences'
|
||||||
|
|
||||||
|
@ -182,8 +182,9 @@ function ListItem({
|
||||||
const onPressUp = React.useCallback(async () => {
|
const onPressUp = React.useCallback(async () => {
|
||||||
if (!isPinned) return
|
if (!isPinned) return
|
||||||
|
|
||||||
const feeds = queryClient.getQueryData<UsePreferencesQueryResponse>(
|
const feeds =
|
||||||
usePreferencesQueryKey,
|
queryClient.getQueryData<UsePreferencesQueryResponse>(
|
||||||
|
preferencesQueryKey,
|
||||||
)?.feeds
|
)?.feeds
|
||||||
const pinned = feeds?.pinned ?? []
|
const pinned = feeds?.pinned ?? []
|
||||||
const index = pinned.indexOf(feedUri)
|
const index = pinned.indexOf(feedUri)
|
||||||
|
@ -206,8 +207,9 @@ function ListItem({
|
||||||
const onPressDown = React.useCallback(async () => {
|
const onPressDown = React.useCallback(async () => {
|
||||||
if (!isPinned) return
|
if (!isPinned) return
|
||||||
|
|
||||||
const feeds = queryClient.getQueryData<UsePreferencesQueryResponse>(
|
const feeds =
|
||||||
usePreferencesQueryKey,
|
queryClient.getQueryData<UsePreferencesQueryResponse>(
|
||||||
|
preferencesQueryKey,
|
||||||
)?.feeds
|
)?.feeds
|
||||||
const pinned = feeds?.pinned ?? []
|
const pinned = feeds?.pinned ?? []
|
||||||
const index = pinned.indexOf(feedUri)
|
const index = pinned.indexOf(feedUri)
|
||||||
|
|
Loading…
Reference in New Issue