add toggle for experimental oauth

This commit is contained in:
Hailey
2025-07-18 19:57:46 -07:00
parent ddeb3b0768
commit a00d04d0da
9 changed files with 315 additions and 210 deletions
+5 -2
View File
@@ -4,6 +4,7 @@ import {useLingui} from '@lingui/react'
import {logger} from '#/logger'
import {isWeb} from '#/platform/detection'
import {useExperimentalOauthEnabled} from '#/state/preferences/experimental-oauth'
import {type SessionAccount, useSessionApi} from '#/state/session'
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
import * as Toast from '#/view/com/util/Toast'
@@ -17,6 +18,8 @@ export function useAccountSwitcher() {
const {resumeSession} = useSessionApi()
const {requestSwitchToAccount} = useLoggedOutViewControls()
const shouldUseOauth = useExperimentalOauthEnabled() || USE_OAUTH
const onPressSwitchAccount = useCallback(
async (
account: SessionAccount,
@@ -29,7 +32,7 @@ export function useAccountSwitcher() {
try {
setPendingDid(account.did)
// TODO: this should be checking if it is an oauth session
if (USE_OAUTH || account.accessJwt) {
if (shouldUseOauth || account.accessJwt) {
if (isWeb) {
// We're switching accounts, which remounts the entire app.
// On mobile, this gets us Home, but on the web we also need reset the URL.
@@ -61,7 +64,7 @@ export function useAccountSwitcher() {
setPendingDid(null)
}
},
[_, resumeSession, requestSwitchToAccount, pendingDid],
[_, resumeSession, requestSwitchToAccount, pendingDid, shouldUseOauth],
)
return {onPressSwitchAccount, pendingDid}
File diff suppressed because it is too large Load Diff
+5 -1
View File
@@ -6,6 +6,7 @@ import {useLingui} from '@lingui/react'
import {USE_OAUTH} from '#/lib/app-info'
import {logEvent} from '#/lib/statsig/statsig'
import {logger} from '#/logger'
import {useExperimentalOauthEnabled} from '#/state/preferences/experimental-oauth'
import {type SessionAccount, useSession, useSessionApi} from '#/state/session'
import {useLoggedOutViewControls} from '#/state/shell/logged-out'
import * as Toast from '#/view/com/util/Toast'
@@ -28,6 +29,8 @@ export const ChooseAccountForm = ({
const {resumeSession} = useSessionApi()
const {setShowLoggedOut} = useLoggedOutViewControls()
const shouldUseOauth = useExperimentalOauthEnabled() || USE_OAUTH
const onSelect = React.useCallback(
async (account: SessionAccount) => {
if (pendingDid) {
@@ -35,7 +38,7 @@ export const ChooseAccountForm = ({
return
}
// TODO: this should be checking if it is an oauth session
if (!USE_OAUTH && !account.accessJwt) {
if (!shouldUseOauth && !account.accessJwt) {
// Move to login form.
onSelectAccount(account)
return
@@ -69,6 +72,7 @@ export const ChooseAccountForm = ({
pendingDid,
onSelectAccount,
setShowLoggedOut,
shouldUseOauth,
_,
],
)
+4 -1
View File
@@ -20,6 +20,7 @@ import {cleanError} from '#/lib/strings/errors'
import {createFullHandle} from '#/lib/strings/handles'
import {logger} from '#/logger'
import {isWeb} from '#/platform/detection'
import {useExperimentalOauthEnabled} from '#/state/preferences/experimental-oauth'
import {useSetHasCheckedForStarterPack} from '#/state/preferences/used-starter-packs'
import {useSessionApi} from '#/state/session'
import {getNativeOAuthClient} from '#/state/session/oauth-native-client'
@@ -54,7 +55,9 @@ interface LoginFormProps {
}
export function LoginForm(props: LoginFormProps) {
if (USE_OAUTH) {
const shouldUseOauth = useExperimentalOauthEnabled() || USE_OAUTH
if (shouldUseOauth) {
return <OAuthLoginFormInner {...props} />
} else {
return <LoginFormInner {...props} />
+2
View File
@@ -123,6 +123,7 @@ const schema = z.object({
kawaii: z.boolean().optional(),
hasCheckedForStarterPack: z.boolean().optional(),
subtitlesEnabled: z.boolean().optional(),
experimentalOauthEnabled: z.boolean().optional(),
/** @deprecated */
mutedThreads: z.array(z.string()),
trendingDisabled: z.boolean().optional(),
@@ -172,6 +173,7 @@ export const defaults: Schema = {
kawaii: false,
hasCheckedForStarterPack: false,
subtitlesEnabled: true,
experimentalOauthEnabled: false,
trendingDisabled: false,
trendingVideoDisabled: false,
}
@@ -0,0 +1,47 @@
import React from 'react'
import * as persisted from '#/state/persisted'
type StateContext = boolean
type SetContext = (v: boolean) => void
const stateContext = React.createContext<StateContext>(
Boolean(persisted.defaults.experimentalOauthEnabled),
)
const setContext = React.createContext<SetContext>((_: boolean) => {})
export function Provider({children}: {children: React.ReactNode}) {
const [state, setState] = React.useState(
Boolean(persisted.get('experimentalOauthEnabled')),
)
const setStateWrapped = React.useCallback(
(
experimentalOauthEnabled: persisted.Schema['experimentalOauthEnabled'],
) => {
setState(Boolean(experimentalOauthEnabled))
persisted.write('experimentalOauthEnabled', experimentalOauthEnabled)
},
[setState],
)
React.useEffect(() => {
return persisted.onUpdate(
'experimentalOauthEnabled',
experimentalOauthEnabled => {
setState(Boolean(experimentalOauthEnabled))
},
)
}, [setStateWrapped])
return (
<stateContext.Provider value={state}>
<setContext.Provider value={setStateWrapped}>
{children}
</setContext.Provider>
</stateContext.Provider>
)
}
export const useExperimentalOauthEnabled = () => React.useContext(stateContext)
export const useSetExperimentalOauthEnabled = () => React.useContext(setContext)
+5 -2
View File
@@ -1,8 +1,9 @@
import React from 'react'
import type React from 'react'
import {Provider as AltTextRequiredProvider} from './alt-text-required'
import {Provider as AutoplayProvider} from './autoplay'
import {Provider as DisableHapticsProvider} from './disable-haptics'
import {Provider as ExperimentalOauthProvider} from './experimental-oauth'
import {Provider as ExternalEmbedsProvider} from './external-embeds-prefs'
import {Provider as HiddenPostsProvider} from './hidden-posts'
import {Provider as InAppBrowserProvider} from './in-app-browser'
@@ -41,7 +42,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
<UsedStarterPacksProvider>
<SubtitlesProvider>
<TrendingSettingsProvider>
<KawaiiProvider>{children}</KawaiiProvider>
<ExperimentalOauthProvider>
<KawaiiProvider>{children}</KawaiiProvider>
</ExperimentalOauthProvider>
</TrendingSettingsProvider>
</SubtitlesProvider>
</UsedStarterPacksProvider>
+7 -4
View File
@@ -26,6 +26,7 @@ import {
type SessionApiContext,
type SessionStateContext,
} from '#/state/session/types'
import {useExperimentalOauthEnabled} from '../preferences/experimental-oauth'
import {
type OauthBskyAppAgent,
oauthCreateAgent,
@@ -57,6 +58,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
return initialState
})
const shouldUseOauth = useExperimentalOauthEnabled() || USE_OAUTH
const onAgentSessionChange = React.useCallback(
(agent: BskyAgent, accountDid: string, sessionEvent: AtpSessionEvent) => {
const refreshedAccount = agentToSessionAccount(agent) // Mutable, so snapshot it right away.
@@ -187,7 +190,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
account: SessionAccount
}
if (USE_OAUTH) {
if (shouldUseOauth) {
agentAccount = await oauthResumeSession(storedAccount)
} else {
agentAccount = await createAgentAndResume(
@@ -209,7 +212,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
})
addSessionDebugLog({type: 'method:end', method: 'resumeSession', account})
},
[onAgentSessionChange, cancelPendingTask],
[onAgentSessionChange, cancelPendingTask, shouldUseOauth],
)
const removeAccount = React.useCallback<SessionApiContext['removeAccount']>(
@@ -256,7 +259,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
a => a.did === synced.currentAccount?.did,
)
// TODO: this should be checking if it is an oauth session
if (syncedAccount && (USE_OAUTH || syncedAccount?.refreshJwt)) {
if (syncedAccount && (shouldUseOauth || syncedAccount?.refreshJwt)) {
if (syncedAccount.did !== state.currentAgentState.did) {
resumeSession(syncedAccount)
} else {
@@ -272,7 +275,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
}
}
})
}, [state, resumeSession])
}, [state, resumeSession, shouldUseOauth])
const stateContext = React.useMemo(
() => ({
+31 -3
View File
@@ -1,5 +1,5 @@
import React from 'react'
import {StyleSheet, TouchableOpacity, View} from 'react-native'
import {Pressable, StyleSheet, TouchableOpacity, View} from 'react-native'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
@@ -7,12 +7,20 @@ import {useFocusEffect} from '@react-navigation/native'
import {usePalette} from '#/lib/hooks/usePalette'
import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {
type CommonNavigatorParams,
type NativeStackScreenProps,
} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {getEntries} from '#/logger/logDump'
import {
useExperimentalOauthEnabled,
useSetExperimentalOauthEnabled,
} from '#/state/preferences/experimental-oauth'
import {useTickEveryMinute} from '#/state/shell'
import {useSetMinimalShellMode} from '#/state/shell'
import {Text} from '#/view/com/util/text/Text'
import * as Toast from '#/view/com/util/Toast'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import {ScrollView} from '#/view/com/util/Views'
import * as Layout from '#/components/Layout'
@@ -28,6 +36,11 @@ export function LogScreen({}: NativeStackScreenProps<
const timeAgo = useGetTimeAgo()
const tick = useTickEveryMinute()
const experimentalOauthEnabled = useExperimentalOauthEnabled()
const setExperimentalOauthEnabled = useSetExperimentalOauthEnabled()
const titlePressCount = React.useRef(0)
useFocusEffect(
React.useCallback(() => {
setMinimalShellMode(false)
@@ -44,7 +57,22 @@ export function LogScreen({}: NativeStackScreenProps<
return (
<Layout.Screen>
<ViewHeader title="Log" />
<Pressable
accessibilityRole="button"
onPress={() => {
titlePressCount.current += 1
if (titlePressCount.current === 7) {
Toast.show(
experimentalOauthEnabled
? _(msg`Experimental OAuth Disabled`)
: _(msg`Experimental OAuth Enabled`),
)
setExperimentalOauthEnabled(!experimentalOauthEnabled)
titlePressCount.current = 0
}
}}>
<ViewHeader title="Log" />
</Pressable>
<ScrollView style={s.flex1}>
{getEntries()
.slice(0)