diff --git a/lib/shared/threads/protocols/dm-thread-protocol.js b/lib/shared/threads/protocols/dm-thread-protocol.js --- a/lib/shared/threads/protocols/dm-thread-protocol.js +++ b/lib/shared/threads/protocols/dm-thread-protocol.js @@ -910,6 +910,10 @@ description: 'Comm DMs are end-to-end encrypted and stored locally on your ' + 'device for maximum privacy.', + topLevelThread: { + type: 'label', + label: 'Local DM', + }, }, supportsEncryptedMultimedia: true, diff --git a/lib/shared/threads/protocols/farcaster-thread-protocol.js b/lib/shared/threads/protocols/farcaster-thread-protocol.js --- a/lib/shared/threads/protocols/farcaster-thread-protocol.js +++ b/lib/shared/threads/protocols/farcaster-thread-protocol.js @@ -956,6 +956,10 @@ 'Farcaster Direct Casts are the native messaging protocol in ' + 'Farcaster. They are not end-to-end encrypted, and the Farcaster ' + 'team can see the contents of your messages.', + topLevelThread: { + type: 'label', + label: 'Farcaster', + }, }, supportsEncryptedMultimedia: false, diff --git a/lib/shared/threads/protocols/keyserver-thread-protocol.js b/lib/shared/threads/protocols/keyserver-thread-protocol.js --- a/lib/shared/threads/protocols/keyserver-thread-protocol.js +++ b/lib/shared/threads/protocols/keyserver-thread-protocol.js @@ -713,6 +713,9 @@ "Genesis chats are a legacy chat type hosted on Ashoat's keyserver. " + 'They are not end-to-end encrypted, and Ashoat can see the contents ' + 'of your messages.', + topLevelThread: { + type: 'keyserverAdmin', + }, }, supportsEncryptedMultimedia: true, diff --git a/lib/shared/threads/thread-spec.js b/lib/shared/threads/thread-spec.js --- a/lib/shared/threads/thread-spec.js +++ b/lib/shared/threads/thread-spec.js @@ -503,6 +503,9 @@ +threadAncestorLabel: (ancestorPath: React.Node) => React.Node, +protocolIcon: 'lock' | 'server' | 'farcaster', +description: string, + +topLevelThread: + | { +type: 'keyserverAdmin' } + | { +type: 'label', +label: 'Farcaster' | 'Local DM' }, }, +supportsEncryptedMultimedia: boolean, +supportsSendingVideos: boolean, diff --git a/native/chat/parent-thread-header.react.js b/native/chat/parent-thread-header.react.js --- a/native/chat/parent-thread-header.react.js +++ b/native/chat/parent-thread-header.react.js @@ -9,8 +9,8 @@ import { useNavigateToThread } from './message-list-types.js'; import Button from '../components/button.react.js'; -import CommunityPill from '../components/community-pill.react.js'; import ThreadVisibility from '../components/thread-visibility.react.js'; +import TopLevelThreadPill from '../components/top-level-thread-pill.react.js'; import { useColors, useStyles } from '../themes/colors.js'; type Props = { @@ -38,7 +38,7 @@ <> within ); diff --git a/native/components/community-pill.react.js b/native/components/community-pill.react.js deleted file mode 100644 --- a/native/components/community-pill.react.js +++ /dev/null @@ -1,68 +0,0 @@ -// @flow - -import * as React from 'react'; -import { StyleSheet, View } from 'react-native'; - -import { useKeyserverAdmin } from 'lib/shared/user-utils.js'; -import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; - -import CommIcon from './comm-icon.react.js'; -import Pill from './pill.react.js'; -import ThreadPill from './thread-pill.react.js'; -import { useColors } from '../themes/colors.js'; - -const threadPillRoundCorners = { left: false, right: true }; - -type Props = { - +community: ThreadInfo, -}; -function CommunityPill(props: Props): React.Node { - const { community } = props; - - const keyserverAdmin = useKeyserverAdmin(community); - const keyserverOperatorUsername = keyserverAdmin?.username; - - const colors = useColors(); - const keyserverOperatorLabel: ?React.Node = React.useMemo(() => { - if (!keyserverOperatorUsername) { - return undefined; - } - const icon = ( - - ); - return ( - - ); - }, [ - colors.codeBackground, - colors.panelForegroundLabel, - keyserverOperatorUsername, - ]); - - return ( - - {keyserverOperatorLabel} - - - ); -} - -const styles = StyleSheet.create({ - container: { - flexDirection: 'row', - }, -}); - -export default CommunityPill; diff --git a/native/components/thread-ancestors.react.js b/native/components/thread-ancestors.react.js --- a/native/components/thread-ancestors.react.js +++ b/native/components/thread-ancestors.react.js @@ -9,8 +9,8 @@ import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import Button from './button.react.js'; -import CommunityPill from './community-pill.react.js'; import ThreadPill from './thread-pill.react.js'; +import TopLevelThreadPill from './top-level-thread-pill.react.js'; import { useNavigateToThread } from '../chat/message-list-types.js'; import { useSelector } from '../redux/redux-utils.js'; import { useColors, useStyles } from '../themes/colors.js'; @@ -47,7 +47,7 @@ const isLastThread = idx === ancestorThreads.length - 1; const pill = idx === 0 ? ( - + ) : ( ); diff --git a/native/components/thread-icon.react.js b/native/components/thread-icon.react.js --- a/native/components/thread-icon.react.js +++ b/native/components/thread-icon.react.js @@ -2,12 +2,13 @@ import EntypoIcon from '@expo/vector-icons/Entypo.js'; import * as React from 'react'; -import { StyleSheet } from 'react-native'; +import { StyleSheet, View } from 'react-native'; import { threadTypeIsSidebar } from 'lib/shared/threads/thread-specs.js'; import { threadTypes, type ThreadType } from 'lib/types/thread-types-enum.js'; import SWMansionIcon from './swmansion-icon.react.js'; +import FarcasterLogo from '../vectors/farcaster-logo.react.js'; type Props = { +threadType: ThreadType, @@ -31,12 +32,30 @@ ); } else if (threadType === threadTypes.GENESIS_PERSONAL) { return ; + } else if ( + threadType === threadTypes.FARCASTER_GROUP || + threadType === threadTypes.FARCASTER_PERSONAL + ) { + return ( + + + + ); } else { return ; } } const styles = StyleSheet.create({ + farcasterIcon: { + alignItems: 'center', + backgroundColor: '#855DCD', + borderRadius: 9, + height: 18, + justifyContent: 'center', + opacity: 0.7, + width: 18, + }, sidebarIcon: { paddingTop: 2, }, diff --git a/native/components/top-level-thread-pill.react.js b/native/components/top-level-thread-pill.react.js new file mode 100644 --- /dev/null +++ b/native/components/top-level-thread-pill.react.js @@ -0,0 +1,107 @@ +// @flow + +import * as React from 'react'; +import { StyleSheet, View } from 'react-native'; + +import { threadSpecs } from 'lib/shared/threads/thread-specs.js'; +import { useKeyserverAdmin } from 'lib/shared/user-utils.js'; +import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; + +import CommIcon from './comm-icon.react.js'; +import Pill from './pill.react.js'; +import SWMansionIcon from './swmansion-icon.react.js'; +import ThreadPill from './thread-pill.react.js'; +import { useColors } from '../themes/colors.js'; +import FarcasterLogo from '../vectors/farcaster-logo.react.js'; + +const threadPillRoundCorners = { left: false, right: true }; + +type Props = { + +threadInfo: ThreadInfo, +}; +function TopLevelThreadPill(props: Props): React.Node { + const { threadInfo } = props; + + const keyserverAdmin = useKeyserverAdmin(threadInfo); + const keyserverOperatorUsername = keyserverAdmin?.username; + + const colors = useColors(); + const keyserverOperatorLabel: ?React.Node = React.useMemo(() => { + const topLevelThreadConfig = + threadSpecs[threadInfo.type].protocol().presentationDetails + .topLevelThread; + + let label; + let icon; + if (topLevelThreadConfig.type === 'keyserverAdmin') { + if (!keyserverOperatorUsername) { + return undefined; + } + icon = ( + + ); + label = keyserverOperatorUsername; + } else if (topLevelThreadConfig.label === 'Local DM') { + label = 'Local DM'; + icon = ( + + ); + } else { + label = 'Farcaster'; + icon = ( + + + + ); + } + + return ( + + ); + }, [ + colors.codeBackground, + colors.panelForegroundLabel, + keyserverOperatorUsername, + threadInfo.type, + ]); + + return ( + + {keyserverOperatorLabel} + + + ); +} + +const styles = StyleSheet.create({ + container: { + flexDirection: 'row', + }, + farcasterIcon: { + alignItems: 'center', + backgroundColor: '#855DCD', + borderRadius: 9, + height: 18, + justifyContent: 'center', + opacity: 0.7, + width: 18, + }, +}); + +export default TopLevelThreadPill;