diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js --- a/lib/types/thread-types.js +++ b/lib/types/thread-types.js @@ -61,12 +61,19 @@ ); return threadType; } -export const communityThreadTypes: Array = Object.freeze([ +export const communityThreadTypes: $ReadOnlyArray = Object.freeze([ threadTypes.COMMUNITY_ROOT, threadTypes.COMMUNITY_ANNOUNCEMENT_ROOT, threadTypes.GENESIS, ]); +export const communitySubthreads: $ReadOnlyArray = Object.freeze([ + threadTypes.COMMUNITY_OPEN_SUBTHREAD, + threadTypes.COMMUNITY_OPEN_ANNOUNCEMENT_SUBTHREAD, + threadTypes.COMMUNITY_SECRET_SUBTHREAD, + threadTypes.COMMUNITY_SECRET_ANNOUNCEMENT_SUBTHREAD, +]); + export function threadTypeIsCommunityRoot(threadType: ThreadType): boolean { return communityThreadTypes.includes(threadType); } diff --git a/native/navigation/community-drawer-content.react.js b/native/navigation/community-drawer-content.react.js new file mode 100644 --- /dev/null +++ b/native/navigation/community-drawer-content.react.js @@ -0,0 +1,128 @@ +// @flow + +import * as React from 'react'; +import { View, FlatList } from 'react-native'; +import { useSelector } from 'react-redux'; + +import { + childThreadInfos, + communityThreadSelector, +} from 'lib/selectors/thread-selectors'; +import { type ThreadInfo, communitySubthreads } from 'lib/types/thread-types'; + +import { useNavigateToThread } from '../chat/message-list-types'; +import { useStyles } from '../themes/colors'; +import CommunityDrawerItemCommunity from './community-drawer-item-cummunity.react'; + +const maxDepth = 2; + +function CommunityDrawerContent(): React.Node { + const communities = useSelector(communityThreadSelector); + const communitiesSuffixed = React.useMemo(() => appendSuffix(communities), [ + communities, + ]); + const styles = useStyles(unboundStyles); + + const [openCommunity, setOpenCommunity] = React.useState( + communitiesSuffixed.length === 1 ? communitiesSuffixed[0].id : null, + ); + + const navigateToThread = useNavigateToThread(); + const childThreadInfosMap = useSelector(childThreadInfos); + + const setOpenCommunnityOrClose = React.useCallback((index: string) => { + setOpenCommunity(open => (open === index ? null : index)); + }, []); + + const renderItem = React.useCallback( + ({ item }) => { + const itemData = { + threadInfo: item.threadInfo, + itemChildren: item.itemChildren, + }; + return ( + + ); + }, + [navigateToThread, openCommunity, setOpenCommunnityOrClose], + ); + + const drawerItemsData = React.useMemo( + () => + createRecursiveDrawerItemsData(childThreadInfosMap, communitiesSuffixed), + [childThreadInfosMap, communitiesSuffixed], + ); + + return ( + + + + ); +} + +function createRecursiveDrawerItemsData( + childThreadInfosMap: { +[id: string]: $ReadOnlyArray }, + communities: $ReadOnlyArray, +) { + const result = communities.map(community => ({ + key: community.id, + threadInfo: community, + itemChildren: [], + })); + let queue = result.map(item => [item, 0]); + + for (let i = 0; i < queue.length; i++) { + const [item, lvl] = queue[i]; + const itemChildThreadInfos = childThreadInfosMap[item.threadInfo.id] ?? []; + + if (lvl < maxDepth) { + item.itemChildren = itemChildThreadInfos + .filter(childItem => communitySubthreads.includes(childItem.type)) + .map(childItem => ({ + threadInfo: childItem, + itemChildren: [], + })); + queue = queue.concat( + item.itemChildren.map(childItem => [childItem, lvl + 1]), + ); + } + } + return result; +} + +function appendSuffix(chats: $ReadOnlyArray): ThreadInfo[] { + const result = []; + const names = new Map(); + + for (const chat of chats) { + let name = chat.uiName; + const numberOfOccurrences = names.get(name); + names.set(name, (numberOfOccurrences ?? 0) + 1); + if (numberOfOccurrences) { + name = `${name} (${numberOfOccurrences.toString()})`; + } + result.push({ ...chat, uiName: name }); + } + return result; +} + +const unboundStyles = { + drawerContent: { + flex: 1, + paddingRight: 8, + paddingTop: 52, + backgroundColor: 'drawerBackgroud', + }, +}; + +const MemoizedCommunityDrawerContent: React.ComponentType<{}> = React.memo( + CommunityDrawerContent, +); + +export default MemoizedCommunityDrawerContent; diff --git a/native/themes/colors.js b/native/themes/colors.js --- a/native/themes/colors.js +++ b/native/themes/colors.js @@ -91,6 +91,7 @@ drawerExpandButtonDisabled: '#404040', drawerItemLabel: '#CCCCCC', drawerOpenCommunityBackground: '#333333', + drawerBackgroud: '#404040', }); export type Colors = $Exact; @@ -175,6 +176,7 @@ drawerExpandButtonDisabled: '#404040', drawerItemLabel: '#CCCCCC', drawerOpenCommunityBackground: '#333333', + drawerBackgroud: '#404040', }); const colors = { light, dark };