about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/state/models/ui/shell.ts1
-rw-r--r--src/view/com/composer/Composer.tsx14
-rw-r--r--src/view/com/composer/text-input/TextInput.web.tsx60
-rw-r--r--src/view/screens/Profile.tsx4
-rw-r--r--src/view/shell/Composer.tsx3
-rw-r--r--src/view/shell/Composer.web.tsx3
-rw-r--r--src/view/shell/desktop/LeftNav.tsx17
-rw-r--r--src/view/shell/index.tsx1
-rw-r--r--src/view/shell/index.web.tsx1
9 files changed, 99 insertions, 5 deletions
diff --git a/src/state/models/ui/shell.ts b/src/state/models/ui/shell.ts
index 92d028c79..d1ea4ddf1 100644
--- a/src/state/models/ui/shell.ts
+++ b/src/state/models/ui/shell.ts
@@ -232,6 +232,7 @@ export interface ComposerOpts {
   replyTo?: ComposerOptsPostRef
   onPost?: () => void
   quote?: ComposerOptsQuote
+  mention?: string // handle of user to mention
 }
 
 export class ShellUiModel {
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index ecfef3ecd..cb66cc909 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -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])
diff --git a/src/view/com/composer/text-input/TextInput.web.tsx b/src/view/com/composer/text-input/TextInput.web.tsx
index f64880e15..b7ebdd989 100644
--- a/src/view/com/composer/text-input/TextInput.web.tsx
+++ b/src/view/com/composer/text-input/TextInput.web.tsx
@@ -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) {
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx
index a51fbcf50..ce437d6cb 100644
--- a/src/view/screens/Profile.tsx
+++ b/src/view/screens/Profile.tsx
@@ -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)
diff --git a/src/view/shell/Composer.tsx b/src/view/shell/Composer.tsx
index e87fea647..ac155887c 100644
--- a/src/view/shell/Composer.tsx
+++ b/src/view/shell/Composer.tsx
@@ -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>
     )
diff --git a/src/view/shell/Composer.web.tsx b/src/view/shell/Composer.web.tsx
index cf850aa4f..2effa0cca 100644
--- a/src/view/shell/Composer.web.tsx
+++ b/src/view/shell/Composer.web.tsx
@@ -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>
diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx
index 700857bbe..b37befba6 100644
--- a/src/view/shell/desktop/LeftNav.tsx
+++ b/src/view/shell/desktop/LeftNav.tsx
@@ -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
diff --git a/src/view/shell/index.tsx b/src/view/shell/index.tsx
index 7ab371d59..72e7facc8 100644
--- a/src/view/shell/index.tsx
+++ b/src/view/shell/index.tsx
@@ -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 />
diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx
index 5e3875268..16ed17a5b 100644
--- a/src/view/shell/index.web.tsx
+++ b/src/view/shell/index.web.tsx
@@ -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 />