[APP-834] Allow @ing someone in post directly from profile (#1241)
* setup `initMention` for mobile * setup creating post with profile tagged on webzio/stable
parent
3aadc43c89
commit
16b265a861
|
@ -232,6 +232,7 @@ export interface ComposerOpts {
|
|||
replyTo?: ComposerOptsPostRef
|
||||
onPost?: () => void
|
||||
quote?: ComposerOptsQuote
|
||||
mention?: string // handle of user to mention
|
||||
}
|
||||
|
||||
export class ShellUiModel {
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 />
|
||||
|
|
|
@ -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 />
|
||||
|
|
Loading…
Reference in New Issue