about summary refs log tree commit diff
path: root/src/state
diff options
context:
space:
mode:
Diffstat (limited to 'src/state')
-rw-r--r--src/state/modals/index.tsx6
-rw-r--r--src/state/persisted/schema.ts2
-rw-r--r--src/state/preferences/in-app-browser.tsx79
-rw-r--r--src/state/preferences/index.tsx5
4 files changed, 91 insertions, 1 deletions
diff --git a/src/state/modals/index.tsx b/src/state/modals/index.tsx
index 8c32c472a..45856e108 100644
--- a/src/state/modals/index.tsx
+++ b/src/state/modals/index.tsx
@@ -187,6 +187,11 @@ export interface EmbedConsentModal {
   onAccept: () => void
 }
 
+export interface InAppBrowserConsentModal {
+  name: 'in-app-browser-consent'
+  href: string
+}
+
 export type Modal =
   // Account
   | AddAppPasswordModal
@@ -231,6 +236,7 @@ export type Modal =
   | ConfirmModal
   | LinkWarningModal
   | EmbedConsentModal
+  | InAppBrowserConsentModal
 
 const ModalContext = React.createContext<{
   isModalActive: boolean
diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts
index 6a26cedae..a6f2ea06a 100644
--- a/src/state/persisted/schema.ts
+++ b/src/state/persisted/schema.ts
@@ -53,6 +53,7 @@ export const schema = z.object({
     step: z.string(),
   }),
   hiddenPosts: z.array(z.string()).optional(), // should move to server
+  useInAppBrowser: z.boolean().optional(),
 })
 export type Schema = z.infer<typeof schema>
 
@@ -84,4 +85,5 @@ export const defaults: Schema = {
     step: 'Home',
   },
   hiddenPosts: [],
+  useInAppBrowser: undefined,
 }
diff --git a/src/state/preferences/in-app-browser.tsx b/src/state/preferences/in-app-browser.tsx
new file mode 100644
index 000000000..628663af4
--- /dev/null
+++ b/src/state/preferences/in-app-browser.tsx
@@ -0,0 +1,79 @@
+import React from 'react'
+import * as persisted from '#/state/persisted'
+import {Linking} from 'react-native'
+import * as WebBrowser from 'expo-web-browser'
+import {isNative} from '#/platform/detection'
+import {useModalControls} from '../modals'
+
+type StateContext = persisted.Schema['useInAppBrowser']
+type SetContext = (v: persisted.Schema['useInAppBrowser']) => void
+
+const stateContext = React.createContext<StateContext>(
+  persisted.defaults.useInAppBrowser,
+)
+const setContext = React.createContext<SetContext>(
+  (_: persisted.Schema['useInAppBrowser']) => {},
+)
+
+export function Provider({children}: React.PropsWithChildren<{}>) {
+  const [state, setState] = React.useState(persisted.get('useInAppBrowser'))
+
+  const setStateWrapped = React.useCallback(
+    (inAppBrowser: persisted.Schema['useInAppBrowser']) => {
+      setState(inAppBrowser)
+      persisted.write('useInAppBrowser', inAppBrowser)
+    },
+    [setState],
+  )
+
+  React.useEffect(() => {
+    return persisted.onUpdate(() => {
+      setState(persisted.get('useInAppBrowser'))
+    })
+  }, [setStateWrapped])
+
+  return (
+    <stateContext.Provider value={state}>
+      <setContext.Provider value={setStateWrapped}>
+        {children}
+      </setContext.Provider>
+    </stateContext.Provider>
+  )
+}
+
+export function useInAppBrowser() {
+  return React.useContext(stateContext)
+}
+
+export function useSetInAppBrowser() {
+  return React.useContext(setContext)
+}
+
+export function useOpenLink() {
+  const {openModal} = useModalControls()
+  const enabled = useInAppBrowser()
+
+  const openLink = React.useCallback(
+    (url: string, override?: boolean) => {
+      if (isNative && !url.startsWith('mailto:')) {
+        if (override === undefined && enabled === undefined) {
+          openModal({
+            name: 'in-app-browser-consent',
+            href: url,
+          })
+          return
+        } else if (override ?? enabled) {
+          WebBrowser.openBrowserAsync(url, {
+            presentationStyle:
+              WebBrowser.WebBrowserPresentationStyle.FULL_SCREEN,
+          })
+          return
+        }
+      }
+      Linking.openURL(url)
+    },
+    [enabled, openModal],
+  )
+
+  return openLink
+}
diff --git a/src/state/preferences/index.tsx b/src/state/preferences/index.tsx
index cc2d9244c..a442b763a 100644
--- a/src/state/preferences/index.tsx
+++ b/src/state/preferences/index.tsx
@@ -3,6 +3,7 @@ import {Provider as LanguagesProvider} from './languages'
 import {Provider as AltTextRequiredProvider} from '../preferences/alt-text-required'
 import {Provider as HiddenPostsProvider} from '../preferences/hidden-posts'
 import {Provider as ExternalEmbedsProvider} from './external-embeds-prefs'
+import {Provider as InAppBrowserProvider} from './in-app-browser'
 
 export {useLanguagePrefs, useLanguagePrefsApi} from './languages'
 export {
@@ -20,7 +21,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
     <LanguagesProvider>
       <AltTextRequiredProvider>
         <ExternalEmbedsProvider>
-          <HiddenPostsProvider>{children}</HiddenPostsProvider>
+          <HiddenPostsProvider>
+            <InAppBrowserProvider>{children}</InAppBrowserProvider>
+          </HiddenPostsProvider>
         </ExternalEmbedsProvider>
       </AltTextRequiredProvider>
     </LanguagesProvider>