Intent handler (#2992)
* Handle URL params * Add resources * Add other params * refactor for scope * modify the pr to support intents rather than utm remove linebreak remove linebreak handle web adjust path check to work on web add a short delay for opening the composer setup compose intent, move to `intents` directory fix intent logic ignore incoming intents in the navigation router * refactor --------- Co-authored-by: Eric Bailey <git@esb.lol>zio/stable
parent
c8d02a791a
commit
2a04546c73
|
@ -89,6 +89,10 @@ module.exports = function (config) {
|
||||||
scheme: 'https',
|
scheme: 'https',
|
||||||
host: 'bsky.app',
|
host: 'bsky.app',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
scheme: 'http',
|
||||||
|
host: 'localhost:19006',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
category: ['BROWSABLE', 'DEFAULT'],
|
category: ['BROWSABLE', 'DEFAULT'],
|
||||||
},
|
},
|
||||||
|
|
|
@ -109,6 +109,7 @@
|
||||||
"expo-image": "~1.10.3",
|
"expo-image": "~1.10.3",
|
||||||
"expo-image-manipulator": "^11.8.0",
|
"expo-image-manipulator": "^11.8.0",
|
||||||
"expo-image-picker": "~14.7.1",
|
"expo-image-picker": "~14.7.1",
|
||||||
|
"expo-linking": "^6.2.2",
|
||||||
"expo-localization": "~14.8.2",
|
"expo-localization": "~14.8.2",
|
||||||
"expo-media-library": "~15.9.1",
|
"expo-media-library": "~15.9.1",
|
||||||
"expo-notifications": "~0.27.3",
|
"expo-notifications": "~0.27.3",
|
||||||
|
|
|
@ -45,6 +45,7 @@ import {Splash} from '#/Splash'
|
||||||
import {Provider as PortalProvider} from '#/components/Portal'
|
import {Provider as PortalProvider} from '#/components/Portal'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
import {useIntentHandler} from 'lib/hooks/useIntentHandler'
|
||||||
|
|
||||||
SplashScreen.preventAutoHideAsync()
|
SplashScreen.preventAutoHideAsync()
|
||||||
|
|
||||||
|
@ -53,6 +54,7 @@ function InnerApp() {
|
||||||
const {resumeSession} = useSessionApi()
|
const {resumeSession} = useSessionApi()
|
||||||
const theme = useColorModeTheme()
|
const theme = useColorModeTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
useIntentHandler()
|
||||||
|
|
||||||
// init
|
// init
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -32,11 +32,13 @@ import {
|
||||||
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
|
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
|
||||||
import * as persisted from '#/state/persisted'
|
import * as persisted from '#/state/persisted'
|
||||||
import {Provider as PortalProvider} from '#/components/Portal'
|
import {Provider as PortalProvider} from '#/components/Portal'
|
||||||
|
import {useIntentHandler} from 'lib/hooks/useIntentHandler'
|
||||||
|
|
||||||
function InnerApp() {
|
function InnerApp() {
|
||||||
const {isInitialLoad, currentAccount} = useSession()
|
const {isInitialLoad, currentAccount} = useSession()
|
||||||
const {resumeSession} = useSessionApi()
|
const {resumeSession} = useSessionApi()
|
||||||
const theme = useColorModeTheme()
|
const theme = useColorModeTheme()
|
||||||
|
useIntentHandler()
|
||||||
|
|
||||||
// init
|
// init
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -460,7 +460,8 @@ const FlatNavigator = () => {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const LINKING = {
|
const LINKING = {
|
||||||
prefixes: ['bsky://', 'https://bsky.app'],
|
// TODO figure out what we are going to use
|
||||||
|
prefixes: ['bsky://', 'bluesky://', 'https://bsky.app'],
|
||||||
|
|
||||||
getPathFromState(state: State) {
|
getPathFromState(state: State) {
|
||||||
// find the current node in the navigation tree
|
// find the current node in the navigation tree
|
||||||
|
@ -478,6 +479,11 @@ const LINKING = {
|
||||||
},
|
},
|
||||||
|
|
||||||
getStateFromPath(path: string) {
|
getStateFromPath(path: string) {
|
||||||
|
// Any time we receive a url that starts with `intent/` we want to ignore it here. It will be handled in the
|
||||||
|
// intent handler hook. We should check for the trailing slash, because if there isn't one then it isn't a valid
|
||||||
|
// intent
|
||||||
|
if (path.includes('intent/')) return
|
||||||
|
|
||||||
const [name, params] = router.matchPath(path)
|
const [name, params] = router.matchPath(path)
|
||||||
if (isNative) {
|
if (isNative) {
|
||||||
if (name === 'Search') {
|
if (name === 'Search') {
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
import React from 'react'
|
||||||
|
import * as Linking from 'expo-linking'
|
||||||
|
import {isNative} from 'platform/detection'
|
||||||
|
import {useComposerControls} from 'state/shell'
|
||||||
|
import {useSession} from 'state/session'
|
||||||
|
|
||||||
|
type IntentType = 'compose'
|
||||||
|
|
||||||
|
export function useIntentHandler() {
|
||||||
|
const incomingUrl = Linking.useURL()
|
||||||
|
const composeIntent = useComposeIntent()
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const handleIncomingURL = (url: string) => {
|
||||||
|
const urlp = new URL(url)
|
||||||
|
const [_, intentTypeNative, intentTypeWeb] = urlp.pathname.split('/')
|
||||||
|
|
||||||
|
// On native, our links look like bluesky://intent/SomeIntent, so we have to check the hostname for the
|
||||||
|
// intent check. On web, we have to check the first part of the path since we have an actual hostname
|
||||||
|
const intentType = isNative ? intentTypeNative : intentTypeWeb
|
||||||
|
const isIntent = isNative
|
||||||
|
? urlp.hostname === 'intent'
|
||||||
|
: intentTypeNative === 'intent'
|
||||||
|
const params = urlp.searchParams
|
||||||
|
|
||||||
|
if (!isIntent) return
|
||||||
|
|
||||||
|
switch (intentType as IntentType) {
|
||||||
|
case 'compose': {
|
||||||
|
composeIntent({
|
||||||
|
text: params.get('text'),
|
||||||
|
imageUris: params.get('imageUris'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (incomingUrl) handleIncomingURL(incomingUrl)
|
||||||
|
}, [incomingUrl, composeIntent])
|
||||||
|
}
|
||||||
|
|
||||||
|
function useComposeIntent() {
|
||||||
|
const {openComposer} = useComposerControls()
|
||||||
|
const {hasSession} = useSession()
|
||||||
|
|
||||||
|
return React.useCallback(
|
||||||
|
({
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
text,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
imageUris,
|
||||||
|
}: {
|
||||||
|
text: string | null
|
||||||
|
imageUris: string | null // unused for right now, will be used later with intents
|
||||||
|
}) => {
|
||||||
|
if (!hasSession) return
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
openComposer({}) // will pass in values to the composer here in the share extension
|
||||||
|
}, 500)
|
||||||
|
},
|
||||||
|
[openComposer, hasSession],
|
||||||
|
)
|
||||||
|
}
|
|
@ -11739,6 +11739,14 @@ expo-keep-awake@~12.8.1:
|
||||||
resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-12.8.1.tgz#3c8df9d86c265741b5e7bdd36965aa0c6fc17df0"
|
resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-12.8.1.tgz#3c8df9d86c265741b5e7bdd36965aa0c6fc17df0"
|
||||||
integrity sha512-P/VZFV02Rzgj13skMwH+ceGOGZSEdaUu5n7pCS3wThh2LppZjPJ7sBxUwyzeLa3DXEVUtwLZi+BiQ91wPwy9Gg==
|
integrity sha512-P/VZFV02Rzgj13skMwH+ceGOGZSEdaUu5n7pCS3wThh2LppZjPJ7sBxUwyzeLa3DXEVUtwLZi+BiQ91wPwy9Gg==
|
||||||
|
|
||||||
|
expo-linking@^6.2.2:
|
||||||
|
version "6.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/expo-linking/-/expo-linking-6.2.2.tgz#b7e148068ae49fd9ad814428c16fdf7a236e8aca"
|
||||||
|
integrity sha512-FEe6lP4f7xFT/vjoHRG+tt6EPVtkEGaWNK1smpaUevmNdyCJKqW0PDB8o8sfG6y7fly8ULe8qg3HhKh5J7aqUQ==
|
||||||
|
dependencies:
|
||||||
|
expo-constants "~15.4.3"
|
||||||
|
invariant "^2.2.4"
|
||||||
|
|
||||||
expo-localization@~14.8.2:
|
expo-localization@~14.8.2:
|
||||||
version "14.8.2"
|
version "14.8.2"
|
||||||
resolved "https://registry.yarnpkg.com/expo-localization/-/expo-localization-14.8.2.tgz#e0bbed2293265834d21a1c58d3a5f8d265bd04ae"
|
resolved "https://registry.yarnpkg.com/expo-localization/-/expo-localization-14.8.2.tgz#e0bbed2293265834d21a1c58d3a5f8d265bd04ae"
|
||||||
|
|
Loading…
Reference in New Issue