[APP-834] Allow @ing someone in post directly from profile (#1241)

* setup `initMention` for mobile

* setup creating post with profile tagged on web
zio/stable
Ansh 2023-08-22 11:01:00 -07:00 committed by GitHub
parent 3aadc43c89
commit 16b265a861
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 99 additions and 5 deletions

View File

@ -232,6 +232,7 @@ export interface ComposerOpts {
replyTo?: ComposerOptsPostRef
onPost?: () => void
quote?: ComposerOptsQuote
mention?: string // handle of user to mention
}
export class ShellUiModel {

View File

@ -45,6 +45,7 @@ import {Gallery} from './photos/Gallery'
import {MAX_GRAPHEME_LENGTH} from 'lib/constants'
import {LabelsBtn} from './labels/LabelsBtn'
import {SelectLangBtn} from './select-language/SelectLangBtn'
import {insertMentionAt} from 'lib/strings/mention-manip'
type Props = ComposerOpts & {
onClose: () => void
@ -55,6 +56,7 @@ export const ComposePost = observer(function ComposePost({
onPost,
onClose,
quote: initQuote,
mention: initMention,
}: Props) {
const {track} = useAnalytics()
const pal = usePalette('default')
@ -64,7 +66,17 @@ export const ComposePost = observer(function ComposePost({
const [isProcessing, setIsProcessing] = useState(false)
const [processingState, setProcessingState] = useState('')
const [error, setError] = useState('')
const [richtext, setRichText] = useState(new RichText({text: ''}))
const [richtext, setRichText] = useState(
new RichText({
text: initMention
? insertMentionAt(
`@${initMention}`,
initMention.length + 1,
`${initMention}`,
) // insert mention if passed in
: '',
}),
)
const graphemeLength = useMemo(() => {
return shortenLinks(richtext).graphemeLength
}, [richtext])

View File

@ -114,7 +114,10 @@ export const TextInput = React.forwardRef(
}
},
},
content: richtext.text.toString(),
content: textToEditorJson(richtext.text.toString()),
onFocus: ({editor: e}) => {
e.chain().focus().setTextSelection(richtext.text.length).run() // focus to the end of the text
},
autofocus: true,
editable: true,
injectCSS: true,
@ -166,6 +169,61 @@ function editorJsonToText(json: JSONContent): string {
return text
}
function textToEditorJson(text: string): JSONContent {
if (text === '' || text.length === 0) {
return {
text: '',
}
}
const lines = text.split('\n')
const docContent: JSONContent[] = []
for (const line of lines) {
if (line.trim() === '') {
continue // skip empty lines
}
const paragraphContent: JSONContent[] = []
let position = 0
while (position < line.length) {
if (line[position] === '@') {
// Handle mentions
let endPosition = position + 1
while (endPosition < line.length && /\S/.test(line[endPosition])) {
endPosition++
}
const mentionId = line.substring(position + 1, endPosition)
paragraphContent.push({
type: 'mention',
attrs: {id: mentionId},
})
position = endPosition
} else {
// Handle regular text
let endPosition = line.indexOf('@', position)
if (endPosition === -1) endPosition = line.length
paragraphContent.push({
type: 'text',
text: line.substring(position, endPosition),
})
position = endPosition
}
}
docContent.push({
type: 'paragraph',
content: paragraphContent,
})
}
return {
type: 'doc',
content: docContent,
}
}
function editorJsonToLinks(json: JSONContent): string[] {
let links: string[] = []
if (json.content?.length) {

View File

@ -92,8 +92,8 @@ export const ProfileScreen = withAuthRequired(
const onPressCompose = React.useCallback(() => {
track('ProfileScreen:PressCompose')
store.shell.openComposer({})
}, [store, track])
store.shell.openComposer({mention: uiState.profile.handle})
}, [store, track, uiState])
const onSelectView = React.useCallback(
(index: number) => {
uiState.setSelectedViewIndex(index)

View File

@ -14,6 +14,7 @@ export const Composer = observer(
onPost,
onClose,
quote,
mention,
}: {
active: boolean
winHeight: number
@ -21,6 +22,7 @@ export const Composer = observer(
onPost?: ComposerOpts['onPost']
onClose: () => void
quote?: ComposerOpts['quote']
mention?: ComposerOpts['mention']
}) => {
const pal = usePalette('default')
const initInterp = useAnimatedValue(0)
@ -65,6 +67,7 @@ export const Composer = observer(
onPost={onPost}
onClose={onClose}
quote={quote}
mention={mention}
/>
</Animated.View>
)

View File

@ -15,6 +15,7 @@ export const Composer = observer(
quote,
onPost,
onClose,
mention,
}: {
active: boolean
winHeight: number
@ -22,6 +23,7 @@ export const Composer = observer(
quote: ComposerOpts['quote']
onPost?: ComposerOpts['onPost']
onClose: () => void
mention?: ComposerOpts['mention']
}) => {
const pal = usePalette('default')
@ -40,6 +42,7 @@ export const Composer = observer(
quote={quote}
onPost={onPost}
onClose={onClose}
mention={mention}
/>
</View>
</View>

View File

@ -150,7 +150,22 @@ const NavItem = observer(
function ComposeBtn() {
const store = useStores()
const onPressCompose = () => store.shell.openComposer({})
const {getState} = useNavigation()
const getProfileHandle = () => {
const {routes} = getState()
const currentRoute = routes[routes.length - 1]
if (currentRoute.name === 'Profile') {
const {name: handle} =
currentRoute.params as CommonNavigatorParams['Profile']
if (handle === store.me.handle) return undefined
return handle
}
return undefined
}
const onPressCompose = () =>
store.shell.openComposer({mention: getProfileHandle()})
return (
<TouchableOpacity

View File

@ -68,6 +68,7 @@ const ShellInner = observer(() => {
replyTo={store.shell.composerOpts?.replyTo}
onPost={store.shell.composerOpts?.onPost}
quote={store.shell.composerOpts?.quote}
mention={store.shell.composerOpts?.mention}
/>
<ModalsContainer />
<Lightbox />

View File

@ -49,6 +49,7 @@ const ShellInner = observer(() => {
replyTo={store.shell.composerOpts?.replyTo}
quote={store.shell.composerOpts?.quote}
onPost={store.shell.composerOpts?.onPost}
mention={store.shell.composerOpts?.mention}
/>
{!isDesktop && <BottomBarWeb />}
<ModalsContainer />