Skip to content

Commit

Permalink
Rework composer to use RQ
Browse files Browse the repository at this point in the history
  • Loading branch information
pfrazee committed Nov 14, 2023
1 parent a78a12c commit 866178c
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 87 deletions.
13 changes: 6 additions & 7 deletions src/lib/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,11 @@ interface PostOpts {
extLink?: ExternalEmbedDraft
images?: ImageModel[]
labels?: string[]
knownHandles?: Set<string>
onStateChange?: (state: string) => void
langs?: string[]
}

export async function post(store: RootStoreModel, opts: PostOpts) {
export async function post(agent: BskyAgent, opts: PostOpts) {
let embed:
| AppBskyEmbedImages.Main
| AppBskyEmbedExternal.Main
Expand All @@ -103,7 +102,7 @@ export async function post(store: RootStoreModel, opts: PostOpts) {
)

opts.onStateChange?.('Processing...')
await rt.detectFacets(store.agent)
await rt.detectFacets(agent)
rt = shortenLinks(rt)

// filter out any mention facets that didn't map to a user
Expand Down Expand Up @@ -136,7 +135,7 @@ export async function post(store: RootStoreModel, opts: PostOpts) {
await image.compress()
const path = image.compressed?.path ?? image.path
const {width, height} = image.compressed || image
const res = await uploadBlob(store.agent, path, 'image/jpeg')
const res = await uploadBlob(agent, path, 'image/jpeg')
images.push({
image: res.data.blob,
alt: image.altText ?? '',
Expand Down Expand Up @@ -186,7 +185,7 @@ export async function post(store: RootStoreModel, opts: PostOpts) {
}
if (encoding) {
const thumbUploadRes = await uploadBlob(
store.agent,
agent,
opts.extLink.localThumb.path,
encoding,
)
Expand Down Expand Up @@ -225,7 +224,7 @@ export async function post(store: RootStoreModel, opts: PostOpts) {
// add replyTo if post is a reply to another post
if (opts.replyTo) {
const replyToUrip = new AtUri(opts.replyTo)
const parentPost = await store.agent.getPost({
const parentPost = await agent.getPost({
repo: replyToUrip.host,
rkey: replyToUrip.rkey,
})
Expand Down Expand Up @@ -258,7 +257,7 @@ export async function post(store: RootStoreModel, opts: PostOpts) {

try {
opts.onStateChange?.('Posting...')
return await store.agent.post({
return await agent.post({
text: rt.text,
facets: rt.facets,
reply,
Expand Down
11 changes: 2 additions & 9 deletions src/lib/media/picker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
openCropper as openCropperFn,
Image as RNImage,
} from 'react-native-image-crop-picker'
import {RootStoreModel} from 'state/index'
import {CameraOpts, CropperOptions} from './types'
export {openPicker} from './picker.shared'

Expand All @@ -16,10 +15,7 @@ export {openPicker} from './picker.shared'
* -prf
*/

export async function openCamera(
_store: RootStoreModel,
opts: CameraOpts,
): Promise<RNImage> {
export async function openCamera(opts: CameraOpts): Promise<RNImage> {
const item = await openCameraFn({
width: opts.width,
height: opts.height,
Expand All @@ -39,10 +35,7 @@ export async function openCamera(
}
}

export async function openCropper(
_store: RootStoreModel,
opts: CropperOptions,
) {
export async function openCropper(opts: CropperOptions) {
const item = await openCropperFn({
...opts,
forceJpg: true, // ios only
Expand Down
11 changes: 2 additions & 9 deletions src/lib/media/picker.web.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
/// <reference lib="dom" />

import {CameraOpts, CropperOptions} from './types'
import {RootStoreModel} from 'state/index'
import {Image as RNImage} from 'react-native-image-crop-picker'
export {openPicker} from './picker.shared'
import {unstable__openModal} from '#/state/modals'

export async function openCamera(
_store: RootStoreModel,
_opts: CameraOpts,
): Promise<RNImage> {
export async function openCamera(_opts: CameraOpts): Promise<RNImage> {
// const mediaType = opts.mediaType || 'photo' TODO
throw new Error('TODO')
}

export async function openCropper(
_store: RootStoreModel,
opts: CropperOptions,
): Promise<RNImage> {
export async function openCropper(opts: CropperOptions): Promise<RNImage> {
// TODO handle more opts
return new Promise((resolve, reject) => {
unstable__openModal({
Expand Down
9 changes: 3 additions & 6 deletions src/state/models/media/gallery.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {makeAutoObservable, runInAction} from 'mobx'
import {RootStoreModel} from 'state/index'
import {ImageModel} from './image'
import {Image as RNImage} from 'react-native-image-crop-picker'
import {openPicker} from 'lib/media/picker'
Expand All @@ -8,10 +7,8 @@ import {getImageDim} from 'lib/media/manip'
export class GalleryModel {
images: ImageModel[] = []

constructor(public rootStore: RootStoreModel) {
makeAutoObservable(this, {
rootStore: false,
})
constructor() {
makeAutoObservable(this)
}

get isEmpty() {
Expand All @@ -33,7 +30,7 @@ export class GalleryModel {

// Temporarily enforce uniqueness but can eventually also use index
if (!this.images.some(i => i.path === image_.path)) {
const image = new ImageModel(this.rootStore, image_)
const image = new ImageModel(image_)

// Initial resize
image.manipulate({})
Expand Down
9 changes: 3 additions & 6 deletions src/state/models/media/image.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {Image as RNImage} from 'react-native-image-crop-picker'
import {RootStoreModel} from 'state/index'
import {makeAutoObservable, runInAction} from 'mobx'
import {POST_IMG_MAX} from 'lib/constants'
import * as ImageManipulator from 'expo-image-manipulator'
Expand Down Expand Up @@ -42,10 +41,8 @@ export class ImageModel implements Omit<RNImage, 'size'> {
}
prevAttributes: ImageManipulationAttributes = {}

constructor(public rootStore: RootStoreModel, image: Omit<RNImage, 'size'>) {
makeAutoObservable(this, {
rootStore: false,
})
constructor(image: Omit<RNImage, 'size'>) {
makeAutoObservable(this)

this.path = image.path
this.width = image.width
Expand Down Expand Up @@ -178,7 +175,7 @@ export class ImageModel implements Omit<RNImage, 'size'> {
height: this.height,
})

const cropped = await openCropper(this.rootStore, {
const cropped = await openCropper({
mediaType: 'photo',
path: this.path,
freeStyleCropEnabled: true,
Expand Down
54 changes: 53 additions & 1 deletion src/state/queries/actor-autocomplete.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {AppBskyActorDefs} from '@atproto/api'
import {AppBskyActorDefs, BskyAgent} from '@atproto/api'
import {useQuery} from '@tanstack/react-query'
import {useSession} from '../session'
import {useMyFollowsQuery} from './my-follows'
import AwaitLock from 'await-lock'

export const RQKEY = (prefix: string) => ['actor-autocomplete', prefix]

Expand All @@ -21,6 +22,57 @@ export function useActorAutocompleteQuery(prefix: string) {
})
}

export class ActorAutocomplete {
// state
isLoading = false
isActive = false
prefix = ''
lock = new AwaitLock()

// data
suggestions: AppBskyActorDefs.ProfileViewBasic[] = []

constructor(
public agent: BskyAgent,
public follows?: AppBskyActorDefs.ProfileViewBasic[] | undefined,
) {}

setFollows(follows: AppBskyActorDefs.ProfileViewBasic[]) {
this.follows = follows
}

async query(prefix: string) {
const origPrefix = prefix.trim().toLocaleLowerCase()
this.prefix = origPrefix
await this.lock.acquireAsync()
try {
if (this.prefix) {
if (this.prefix !== origPrefix) {
return // another prefix was set before we got our chance
}

// start with follow results
this.suggestions = computeSuggestions(this.prefix, this.follows)

// ask backend
const res = await this.agent.searchActorsTypeahead({
term: this.prefix,
limit: 8,
})
this.suggestions = computeSuggestions(
this.prefix,
this.follows,
res.data.actors,
)
} else {
this.suggestions = computeSuggestions(this.prefix, this.follows)
}
} finally {
this.lock.release()
}
}
}

function computeSuggestions(
prefix: string,
follows: AppBskyActorDefs.ProfileViewBasic[] = [],
Expand Down
30 changes: 11 additions & 19 deletions src/view/com/composer/Composer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import LinearGradient from 'react-native-linear-gradient'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {RichText} from '@atproto/api'
import {useAnalytics} from 'lib/analytics/analytics'
import {UserAutocompleteModel} from 'state/models/discovery/user-autocomplete'
import {useIsKeyboardVisible} from 'lib/hooks/useIsKeyboardVisible'
import {ExternalEmbed} from './ExternalEmbed'
import {Text} from '../util/text/Text'
Expand Down Expand Up @@ -57,6 +56,9 @@ import {
useLanguagePrefsApi,
toPostLanguages,
} from '#/state/preferences/languages'
import {useSession} from '#/state/session'
import {useProfileQuery} from '#/state/queries/profile'
import {useComposerControls} from '#/state/shell/composer'

type Props = ComposerOpts
export const ComposePost = observer(function ComposePost({
Expand All @@ -65,12 +67,14 @@ export const ComposePost = observer(function ComposePost({
quote: initQuote,
mention: initMention,
}: Props) {
const {agent, currentAccount} = useSession()
const {data: currentProfile} = useProfileQuery({did: currentAccount!.did})
const {activeModals} = useModals()
const {openModal, closeModal} = useModalControls()
const {closeComposer} = useComposerControls()
const {track} = useAnalytics()
const pal = usePalette('default')
const {isDesktop, isMobile} = useWebMediaQueries()
const store = useStores()
const {_} = useLingui()
const requireAltTextEnabled = useRequireAltTextEnabled()
const langPrefs = useLanguagePrefs()
Expand Down Expand Up @@ -100,15 +104,10 @@ export const ComposePost = observer(function ComposePost({
const {extLink, setExtLink} = useExternalLinkFetch({setQuote})
const [labels, setLabels] = useState<string[]>([])
const [suggestedLinks, setSuggestedLinks] = useState<Set<string>>(new Set())
const gallery = useMemo(() => new GalleryModel(store), [store])
const gallery = useMemo(() => new GalleryModel(), [])
const onClose = useCallback(() => {
store.shell.closeComposer()
}, [store])

const autocompleteView = useMemo<UserAutocompleteModel>(
() => new UserAutocompleteModel(store),
[store],
)
closeComposer()
}, [closeComposer])

const insets = useSafeAreaInsets()
const viewStyles = useMemo(
Expand Down Expand Up @@ -161,11 +160,6 @@ export const ComposePost = observer(function ComposePost({
}
}, [onPressCancel])

// initial setup
useEffect(() => {
autocompleteView.setup()
}, [autocompleteView])

// listen to escape key on desktop web
const onEscape = useCallback(
(e: KeyboardEvent) => {
Expand Down Expand Up @@ -215,15 +209,14 @@ export const ComposePost = observer(function ComposePost({
setIsProcessing(true)

try {
await apilib.post(store, {
await apilib.post(agent, {
rawText: richtext.text,
replyTo: replyTo?.uri,
images: gallery.images,
quote,
extLink,
labels,
onStateChange: setProcessingState,
knownHandles: autocompleteView.knownHandles,
langs: toPostLanguages(langPrefs.postLanguage),
})
} catch (e: any) {
Expand Down Expand Up @@ -380,13 +373,12 @@ export const ComposePost = observer(function ComposePost({
styles.textInputLayout,
isNative && styles.textInputLayoutMobile,
]}>
<UserAvatar avatar={store.me.avatar} size={50} />
<UserAvatar avatar={currentProfile?.avatar} size={50} />
<TextInput
ref={textInput}
richtext={richtext}
placeholder={selectTextInputPlaceholder}
suggestedLinks={suggestedLinks}
autocompleteView={autocompleteView}
autoFocus={true}
setRichText={setRichText}
onPhotoPasted={onPhotoPasted}
Expand Down
Loading

0 comments on commit 866178c

Please sign in to comment.