bsky-app/src/state/shell/composer.tsx
Hailey d451f82f54
Share Extension/Intents (#2587)
* add native ios code outside of ios project

* helper script

* going to be a lot of these commits to squash...backing up

* save

* start of an expo plugin

* create info.plist

* copy the view controller

* maybe working

* working

* wait working now

* working plugin

* use current scheme

* update intent path

* use better params

* support text in uri

* build

* use better encoding

* handle images

* cleanup ios plugin

* android

* move bash script to /scripts

* handle cases where loaded data is uiimage rather than uri

* remove unnecessary logic, allow more than 4 images and just take first 4

* android build plugin

* limit images to four on android

* use js for plugins, no need to build

* revert changes to app config

* use correct scheme on android

* android readme

* move ios extension to /modules

* remove unnecessary event

* revert typo

* plugin readme

* scripts readme

* add configurable scheme to .env, default to `bluesky`

* remove debug

* revert .gitignore change

* add comment about updating .env to app.config.js for those modifying scheme

* modify .env

* update android module to use the proper url

* update ios extension

* remove comment

* parse and validate incoming image uris

* fix types

* rm oops

* fix a few typos
2024-02-27 15:22:03 -08:00

95 lines
2.2 KiB
TypeScript

import React from 'react'
import {
AppBskyEmbedRecord,
AppBskyRichtextFacet,
PostModeration,
} from '@atproto/api'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
export interface ComposerOptsPostRef {
uri: string
cid: string
text: string
author: {
handle: string
displayName?: string
avatar?: string
}
embed?: AppBskyEmbedRecord.ViewRecord['embed']
moderation?: PostModeration
}
export interface ComposerOptsQuote {
uri: string
cid: string
text: string
facets?: AppBskyRichtextFacet.Main[]
indexedAt: string
author: {
did: string
handle: string
displayName?: string
avatar?: string
}
embeds?: AppBskyEmbedRecord.ViewRecord['embeds']
}
export interface ComposerOpts {
replyTo?: ComposerOptsPostRef
onPost?: () => void
quote?: ComposerOptsQuote
mention?: string // handle of user to mention
openPicker?: (pos: DOMRect | undefined) => void
text?: string
imageUris?: {uri: string; width: number; height: number}[]
}
type StateContext = ComposerOpts | undefined
type ControlsContext = {
openComposer: (opts: ComposerOpts) => void
closeComposer: () => boolean
}
const stateContext = React.createContext<StateContext>(undefined)
const controlsContext = React.createContext<ControlsContext>({
openComposer(_opts: ComposerOpts) {},
closeComposer() {
return false
},
})
export function Provider({children}: React.PropsWithChildren<{}>) {
const [state, setState] = React.useState<StateContext>()
const openComposer = useNonReactiveCallback((opts: ComposerOpts) => {
setState(opts)
})
const closeComposer = useNonReactiveCallback(() => {
let wasOpen = !!state
setState(undefined)
return wasOpen
})
const api = React.useMemo(
() => ({
openComposer,
closeComposer,
}),
[openComposer, closeComposer],
)
return (
<stateContext.Provider value={state}>
<controlsContext.Provider value={api}>
{children}
</controlsContext.Provider>
</stateContext.Provider>
)
}
export function useComposerState() {
return React.useContext(stateContext)
}
export function useComposerControls() {
return React.useContext(controlsContext)
}