* 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
95 lines
2.2 KiB
TypeScript
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)
|
|
}
|