From 374b71630a9f2cb63b0ddf5e225057803d70d085 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 16 Aug 2022 14:20:21 +1000 Subject: [PATCH] feat: wrap up the new Join Community overlay --- _locales/en/messages.json | 21 ++-- stylesheets/_modules.scss | 7 -- stylesheets/_session_left_pane.scss | 33 ------ ts/components/leftpane/ActionsPanel.tsx | 13 --- ts/components/leftpane/LeftPane.tsx | 18 ---- .../leftpane/LeftPaneContactSection.tsx | 62 ----------- ts/components/leftpane/LeftPaneList.tsx | 9 ++ .../leftpane/LeftPaneMessageSection.tsx | 64 +++++------ .../leftpane/LeftPaneSectionHeader.tsx | 3 - .../leftpane/LeftPaneSettingSection.tsx | 5 +- ...rlayOpenGroup.tsx => OverlayCommunity.tsx} | 18 ++-- .../leftpane/overlay/OverlayMessage.tsx | 7 +- .../choose-action/ContactsListWithBreaks.tsx | 100 ++++++++++++++++++ .../OverlayChooseAction.tsx | 16 +-- ts/state/ducks/section.tsx | 3 +- ts/state/selectors/conversations.ts | 5 + ts/types/LocalizerKeys.ts | 1 + 17 files changed, 187 insertions(+), 198 deletions(-) delete mode 100644 ts/components/leftpane/LeftPaneContactSection.tsx create mode 100644 ts/components/leftpane/LeftPaneList.tsx rename ts/components/leftpane/overlay/{OverlayOpenGroup.tsx => OverlayCommunity.tsx} (89%) create mode 100644 ts/components/leftpane/overlay/choose-action/ContactsListWithBreaks.tsx rename ts/components/leftpane/overlay/{ => choose-action}/OverlayChooseAction.tsx (75%) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 43e9c9179..354b5fd5d 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -28,9 +28,9 @@ "viewMenuToggleFullScreen": "Toggle Full Screen", "viewMenuToggleDevTools": "Toggle Developer Tools", "contextMenuNoSuggestions": "No Suggestions", - "openGroupInvitation": "Open group invitation", + "openGroupInvitation": "Community invitation", "joinOpenGroupAfterInvitationConfirmationTitle": "Join $roomName$?", - "joinOpenGroupAfterInvitationConfirmationDesc": "Are you sure you want to join the $roomName$ open group?", + "joinOpenGroupAfterInvitationConfirmationDesc": "Are you sure you want to join the $roomName$ community?", "couldntFindServerMatching": "Couldn't find the corresponding opengroup server", "enterSessionIDOrONSName": "Enter Session ID or ONS name", "loading": "Loading...", @@ -138,10 +138,10 @@ "typingIndicatorsSettingDescription": "See and share when messages are being typed (applies to all sessions).", "typingIndicatorsSettingTitle": "Typing Indicators", "zoomFactorSettingTitle": "Zoom Factor", - "pruneSettingTitle": "Prune Old Open Group Messages", - "pruneSettingDescription": "Prune messages older than 6 months from Open Groups on start", - "pruningOpengroupDialogTitle": "Open group pruning", - "pruningOpengroupDialogMessage": "Pruning old open group messages improves performance. Enable pruning for open group messages older than 6 months?", + "pruneSettingTitle": "Prune Old Community Messages", + "pruneSettingDescription": "Prune messages older than 6 months from Communities on start", + "pruningOpengroupDialogTitle": "Community pruning", + "pruningOpengroupDialogMessage": "Pruning old communities messages improves performance. Enable pruning for communities messages older than 6 months?", "pruningOpengroupDialogSubMessage": "You can change this setting in the Session settings menu", "enable": "Enable", "keepDisabled": "Keep disabled", @@ -281,10 +281,10 @@ "setPasswordToastDescription": "Your password has been set. Please keep it safe.", "changePasswordToastDescription": "Your password has been changed. Please keep it safe.", "removePasswordToastDescription": "You have removed your password.", - "publicChatExists": "You are already connected to this open group", + "publicChatExists": "You are already connected to this community", "connectToServerFail": "Couldn't join group", "connectingToServer": "Connecting...", - "connectToServerSuccess": "Successfully connected to open group", + "connectToServerSuccess": "Successfully connected to community", "setPasswordFail": "Failed to set password", "passwordLengthError": "Password must be between 6 and 64 characters long", "passwordTypeError": "Password must be a string", @@ -337,12 +337,13 @@ "recoveryPhraseEmpty": "Enter your recovery phrase", "displayNameEmpty": "Please enter a display name", "members": "$count$ members", + "join": "Join", "joinOpenGroup": "Join Community", "createGroup": "Create Group", "createClosedGroupNamePrompt": "Group Name", "createClosedGroupPlaceholder": "Enter a group name", - "openGroupURL": "Open Group URL", - "enterAnOpenGroupURL": "Enter an open group URL", + "openGroupURL": "Community URL", + "enterAnOpenGroupURL": "Enter a community URL", "next": "Next", "invalidGroupNameTooShort": "Please enter a group name", "invalidGroupNameTooLong": "Please enter a shorter group name", diff --git a/stylesheets/_modules.scss b/stylesheets/_modules.scss index db29b76a6..5f05f5b3e 100644 --- a/stylesheets/_modules.scss +++ b/stylesheets/_modules.scss @@ -1278,13 +1278,6 @@ height: 100%; } -.module-left-pane__list { - flex-grow: 1; - flex-shrink: 1; - overflow-y: auto; - overflow-x: hidden; -} - .module-left-pane__virtual-list { outline: none; } diff --git a/stylesheets/_session_left_pane.scss b/stylesheets/_session_left_pane.scss index e8db2aa38..0093765d9 100644 --- a/stylesheets/_session_left_pane.scss +++ b/stylesheets/_session_left_pane.scss @@ -119,10 +119,6 @@ $session-compose-margin: 20px; flex-grow: 1; } - &__list { - height: -webkit-fill-available; - } - &-overlay { background: var(--color-left-pane-overlay-background); @@ -262,35 +258,6 @@ $session-compose-margin: 20px; } } -.left-pane-contact { - &-section, - &-content { - display: flex; - flex-direction: column; - overflow: hidden; - flex: 1; - - .module-conversation-list-item { - &__header__date, - &__message { - display: none; - } - - &__buttons { - display: flex; - - .session-button { - font-size: 11px; - padding: 6px; - height: auto; - margin: 0px; - line-height: 14px; - } - } - } - } -} - .left-pane-setting { &-bottom-buttons { @include bottom-buttons(); diff --git a/ts/components/leftpane/ActionsPanel.tsx b/ts/components/leftpane/ActionsPanel.tsx index cb314dc90..37e6856a2 100644 --- a/ts/components/leftpane/ActionsPanel.tsx +++ b/ts/components/leftpane/ActionsPanel.tsx @@ -120,18 +120,6 @@ const Section = (props: { type: SectionType }) => { isSelected={isSelected} /> ); - case SectionType.Contact: - return ( - - ); case SectionType.Settings: return ( {
-
diff --git a/ts/components/leftpane/LeftPane.tsx b/ts/components/leftpane/LeftPane.tsx index 54beff741..0dd609fbf 100644 --- a/ts/components/leftpane/LeftPane.tsx +++ b/ts/components/leftpane/LeftPane.tsx @@ -8,20 +8,9 @@ import { getSearchResults, isSearching } from '../../state/selectors/search'; import { getFocusedSection, getOverlayMode } from '../../state/selectors/section'; import { getHideMessageRequestBanner } from '../../state/selectors/userConfig'; import { ActionsPanel } from './ActionsPanel'; -import { LeftPaneContactSection } from './LeftPaneContactSection'; import { LeftPaneMessageSection } from './LeftPaneMessageSection'; import { LeftPaneSettingSection } from './LeftPaneSettingSection'; -// from https://github.com/bvaughn/react-virtualized/blob/fb3484ed5dcc41bffae8eab029126c0fb8f7abc0/source/List/types.js#L5 -export type RowRendererParamsType = { - index: number; - isScrolling: boolean; - isVisible: boolean; - key: string; - parent: Object; - style: Object; -}; - const InnerLeftPaneMessageSection = () => { const showSearch = useSelector(isSearching); @@ -43,10 +32,6 @@ const InnerLeftPaneMessageSection = () => { ); }; -const InnerLeftPaneContactSection = () => { - return ; -}; - const LeftPaneSection = () => { const focusedSection = useSelector(getFocusedSection); @@ -54,9 +39,6 @@ const LeftPaneSection = () => { return ; } - if (focusedSection === SectionType.Contact) { - return ; - } if (focusedSection === SectionType.Settings) { return ; } diff --git a/ts/components/leftpane/LeftPaneContactSection.tsx b/ts/components/leftpane/LeftPaneContactSection.tsx deleted file mode 100644 index 11b4c0a1f..000000000 --- a/ts/components/leftpane/LeftPaneContactSection.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react'; - -import { MemoConversationListItemWithDetails } from './conversation-list-item/ConversationListItem'; -import { AutoSizer, List } from 'react-virtualized'; -import { LeftPaneSectionHeader } from './LeftPaneSectionHeader'; -import { useSelector } from 'react-redux'; -import { getDirectContacts } from '../../state/selectors/conversations'; -import { RowRendererParamsType } from './LeftPane'; - -const renderRow = (props: RowRendererParamsType) => { - const { index, key, style } = props; - - const directContacts = (props.parent as any)?.props?.directContacts || []; - - const item = directContacts?.[index]; - - if (!item) { - return null; - } - - return ; -}; - -const ContactListItemSection = () => { - const directContacts = useSelector(getDirectContacts); - - if (!directContacts) { - return null; - } - - const length = Number(directContacts.length); - - return ( -
- - {({ height, width }) => ( - - )} - -
- ); -}; - -export const LeftPaneContactSection = () => { - return ( -
- -
- -
-
- ); -}; diff --git a/ts/components/leftpane/LeftPaneList.tsx b/ts/components/leftpane/LeftPaneList.tsx new file mode 100644 index 000000000..5cd0650cd --- /dev/null +++ b/ts/components/leftpane/LeftPaneList.tsx @@ -0,0 +1,9 @@ +import styled from 'styled-components'; + +export const StyledLeftPaneList = styled.div` + height: -webkit-fill-available; + flex-grow: 1; + flex-shrink: 1; + overflow-y: auto; + overflow-x: hidden; +`; diff --git a/ts/components/leftpane/LeftPaneMessageSection.tsx b/ts/components/leftpane/LeftPaneMessageSection.tsx index 1d571ed00..477273adc 100644 --- a/ts/components/leftpane/LeftPaneMessageSection.tsx +++ b/ts/components/leftpane/LeftPaneMessageSection.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { AutoSizer, List } from 'react-virtualized'; +import { AutoSizer, List, ListRowProps } from 'react-virtualized'; import { ConversationListItemProps, MemoConversationListItemWithDetails, @@ -12,14 +12,16 @@ import _ from 'lodash'; import { MessageRequestsBanner } from './MessageRequestsBanner'; import { SessionSearchInput } from '../SessionSearchInput'; -import { RowRendererParamsType } from './LeftPane'; -import { OverlayOpenGroup } from './overlay/OverlayOpenGroup'; +import { OverlayCommunity } from './overlay/OverlayCommunity'; import { OverlayMessageRequest } from './overlay/OverlayMessageRequest'; import { OverlayMessage } from './overlay/OverlayMessage'; import { OverlayClosedGroup } from './overlay/OverlayClosedGroup'; import { OverlayMode, setOverlayMode } from '../../state/ducks/section'; -import { OverlayChooseAction } from './overlay/OverlayChooseAction'; +import { OverlayChooseAction } from './overlay/choose-action/OverlayChooseAction'; import styled from 'styled-components'; +import { useSelector } from 'react-redux'; +import { getOverlayMode } from '../../state/selectors/section'; +import { StyledLeftPaneList } from './LeftPaneList'; export interface Props { contacts: Array; @@ -40,6 +42,25 @@ const StyledConversationListContent = styled.div` background: var(--color-conversation-list); `; +const ClosableOverlay = () => { + const overlayMode = useSelector(getOverlayMode); + + switch (overlayMode) { + case 'choose-action': + return ; + case 'open-group': + return ; + case 'closed-group': + return ; + case 'message': + return ; + case 'message-requests': + return ; + default: + return null; + } +}; + export class LeftPaneMessageSection extends React.Component { public constructor(props: Props) { super(props); @@ -47,7 +68,7 @@ export class LeftPaneMessageSection extends React.Component { autoBind(this); } - public renderRow = ({ index, key, style }: RowRendererParamsType): JSX.Element | null => { + public renderRow = ({ index, key, style }: ListRowProps): JSX.Element | null => { const { conversations } = this.props; //assume conversations that have been marked unapproved should be filtered out by selector. @@ -63,7 +84,7 @@ export class LeftPaneMessageSection extends React.Component { return ; }; - public renderList(): JSX.Element | Array { + public renderList(): JSX.Element { const { conversations, searchResults } = this.props; if (searchResults) { @@ -76,12 +97,12 @@ export class LeftPaneMessageSection extends React.Component { const length = conversations.length; - const listKey = 0; // Note: conversations is not a known prop for List, but it is required to ensure that // it re-renders when our conversation data changes. Otherwise it would just render // on startup and scroll. - const list = ( -
+ + return ( + {({ height, width }) => ( { /> )} -
+ ); - - return [list]; } public render(): JSX.Element { @@ -108,7 +127,7 @@ export class LeftPaneMessageSection extends React.Component { return (
- {overlayMode ? this.renderClosableOverlay() : this.renderConversations()} + {overlayMode ? : this.renderConversations()}
); } @@ -126,23 +145,4 @@ export class LeftPaneMessageSection extends React.Component { ); } - - private renderClosableOverlay() { - const { overlayMode } = this.props; - - switch (overlayMode) { - case 'choose-action': - return ; - case 'open-group': - return ; - case 'closed-group': - return ; - case 'message': - return ; - case 'message-requests': - return ; - default: - return null; - } - } } diff --git a/ts/components/leftpane/LeftPaneSectionHeader.tsx b/ts/components/leftpane/LeftPaneSectionHeader.tsx index 8bd375869..0b92959d5 100644 --- a/ts/components/leftpane/LeftPaneSectionHeader.tsx +++ b/ts/components/leftpane/LeftPaneSectionHeader.tsx @@ -32,9 +32,6 @@ export const LeftPaneSectionHeader = () => { const showBackButton = isMessageRequestOverlay && isMessageSection; switch (focusedSection) { - case SectionType.Contact: - label = window.i18n('contactsHeader'); - break; case SectionType.Settings: label = window.i18n('settingsHeader'); break; diff --git a/ts/components/leftpane/LeftPaneSettingSection.tsx b/ts/components/leftpane/LeftPaneSettingSection.tsx index 84964ef17..f53d1eec8 100644 --- a/ts/components/leftpane/LeftPaneSettingSection.tsx +++ b/ts/components/leftpane/LeftPaneSettingSection.tsx @@ -15,6 +15,7 @@ import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/S import { SessionIcon } from '../icon'; import { SessionSettingCategory } from '../settings/SessionSettings'; import { resetConversationExternal } from '../../state/ducks/conversations'; +import { StyledLeftPaneList } from './LeftPaneList'; const getCategories = () => { return [ @@ -89,13 +90,13 @@ const LeftPaneSettingsCategories = () => { const categories = getCategories(); return ( -
+
{categories.map(item => { return ; })}
-
+ ); }; diff --git a/ts/components/leftpane/overlay/OverlayOpenGroup.tsx b/ts/components/leftpane/overlay/OverlayCommunity.tsx similarity index 89% rename from ts/components/leftpane/overlay/OverlayOpenGroup.tsx rename to ts/components/leftpane/overlay/OverlayCommunity.tsx index 48bfd05ea..d228e28f9 100644 --- a/ts/components/leftpane/overlay/OverlayOpenGroup.tsx +++ b/ts/components/leftpane/overlay/OverlayCommunity.tsx @@ -26,7 +26,7 @@ async function joinOpenGroup(serverUrl: string) { } } -export const OverlayOpenGroup = () => { +export const OverlayCommunity = () => { const dispatch = useDispatch(); const [loading, setLoading] = useState(false); const [groupUrl, setGroupUrl] = useState(''); @@ -56,7 +56,7 @@ export const OverlayOpenGroup = () => { useKey('Escape', closeOverlay); const title = window.i18n('joinOpenGroup'); - const buttonText = window.i18n('next'); + const buttonText = window.i18n('join'); const subtitle = window.i18n('openGroupURL'); const placeholder = window.i18n('enterAnOpenGroupURL'); @@ -78,12 +78,14 @@ export const OverlayOpenGroup = () => { - + {groupUrl && ( + + )} ); }; diff --git a/ts/components/leftpane/overlay/OverlayMessage.tsx b/ts/components/leftpane/overlay/OverlayMessage.tsx index 026bab8e7..6d494b5a7 100644 --- a/ts/components/leftpane/overlay/OverlayMessage.tsx +++ b/ts/components/leftpane/overlay/OverlayMessage.tsx @@ -114,7 +114,12 @@ export const OverlayMessage = () => { - + diff --git a/ts/components/leftpane/overlay/choose-action/ContactsListWithBreaks.tsx b/ts/components/leftpane/overlay/choose-action/ContactsListWithBreaks.tsx new file mode 100644 index 000000000..8df435569 --- /dev/null +++ b/ts/components/leftpane/overlay/choose-action/ContactsListWithBreaks.tsx @@ -0,0 +1,100 @@ +import React from 'react'; +import { useSelector } from 'react-redux'; +import { AutoSizer, List, ListRowProps } from 'react-virtualized'; +import styled from 'styled-components'; +import { + getDirectContacts, + getDirectContactsCount, +} from '../../../../state/selectors/conversations'; +import { MemoConversationListItemWithDetails } from '../../conversation-list-item/ConversationListItem'; +import { StyledLeftPaneList } from '../../LeftPaneList'; +import { StyledChooseActionTitle } from './OverlayChooseAction'; +// tslint:disable: use-simple-attributes no-submodule-imports + +const renderRow = (props: ListRowProps) => { + const { index, key, style, parent } = props; + + // ugly, but it seems react-viurtualized do not support very well functional components just yet + // https://stackoverflow.com/questions/54488954/how-to-pass-prop-into-rowrender-of-react-virtualized + const directContacts = (parent as any).props.directContacts; + const item = directContacts?.[index]; + if (!item) { + return null; + } + + return ; +}; + +const ContactListItemSection = () => { + const directContacts = useSelector(getDirectContacts); + + if (!directContacts) { + return null; + } + + const length = Number(directContacts.length); + + return ( + + + {({ height }) => { + return ( + + ); + }} + + + ); +}; + +const StyledContactSection = styled.div` + display: flex; + flex-direction: column; + overflow: hidden; + flex: 1; + width: 100%; + + .module-conversation-list-item __header__date, + .module-conversation-list-item __message { + display: none; + } + + .module-conversation-list-item __buttons { + display: flex; + + .session-button { + font-size: 11px; + padding: 6px; + height: auto; + margin: 0px; + line-height: 14px; + } + } +`; + +const ContactsTitle = () => { + const contactsCount = useSelector(getDirectContactsCount); + if (contactsCount <= 0) { + return null; + } + + return {window.i18n('contactsHeader')}; +}; + +export const ContactsListWithBreaks = () => { + return ( + + + + + ); +}; diff --git a/ts/components/leftpane/overlay/OverlayChooseAction.tsx b/ts/components/leftpane/overlay/choose-action/OverlayChooseAction.tsx similarity index 75% rename from ts/components/leftpane/overlay/OverlayChooseAction.tsx rename to ts/components/leftpane/overlay/choose-action/OverlayChooseAction.tsx index ed912b4b9..268413cc5 100644 --- a/ts/components/leftpane/overlay/OverlayChooseAction.tsx +++ b/ts/components/leftpane/overlay/choose-action/OverlayChooseAction.tsx @@ -2,18 +2,19 @@ import React from 'react'; // tslint:disable: use-simple-attributes no-submodule-imports import { useDispatch } from 'react-redux'; -import { resetOverlayMode, setOverlayMode } from '../../../state/ducks/section'; +import { resetOverlayMode, setOverlayMode } from '../../../../state/ducks/section'; import useKey from 'react-use/lib/useKey'; import styled from 'styled-components'; -import { SessionIcon, SessionIconType } from '../../icon'; +import { SessionIcon, SessionIconType } from '../../../icon'; +import { ContactsListWithBreaks } from './ContactsListWithBreaks'; const StyledActionRow = styled.button` border: none; - width: 100%; display: flex; align-items: center; border-bottom: 1px var(--color-session-border) solid; transition-duration: 0.25s; + width: 100%; &:first-child { border-top: 1px var(--color-session-border) solid; @@ -24,7 +25,7 @@ const StyledActionRow = styled.button` } `; -const StyledActionText = styled.span` +export const StyledChooseActionTitle = styled.span` color: var(--color-text); font-size: 18px; padding: 5px 0px 5px 10px; @@ -67,16 +68,17 @@ export const OverlayChooseAction = () => {
- {window.i18n('newMessage')} + {window.i18n('newMessage')} - {window.i18n('createGroup')} + {window.i18n('createGroup')} - {window.i18n('joinOpenGroup')} + {window.i18n('joinOpenGroup')} +
); }; diff --git a/ts/state/ducks/section.tsx b/ts/state/ducks/section.tsx index 6e8b8af92..52b63dc22 100644 --- a/ts/state/ducks/section.tsx +++ b/ts/state/ducks/section.tsx @@ -9,7 +9,6 @@ export const RESET_OVERLAY_MODE = 'RESET_OVERLAY_MODE'; export enum SectionType { Profile, Message, - Contact, Settings, Moon, PathIndicator, @@ -95,7 +94,7 @@ export const initialSectionState: SectionStateType = { focusedSection: SectionType.Message, focusedSettingsSection: undefined, isAppFocused: false, - overlayMode: 'message', + overlayMode: 'choose-action', }; export type SectionStateType = { diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index b3a8e7595..831e6047c 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -533,6 +533,11 @@ export const getDirectContacts = createSelector( }) => state.contacts ); +export const getDirectContactsCount = createSelector( + getDirectContacts, + (contacts: Array) => contacts.length +); + export const getUnreadMessageCount = createSelector(getLeftPaneLists, (state): number => { return state.unreadCount; }); diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts index e38de9b92..07fc63c19 100644 --- a/ts/types/LocalizerKeys.ts +++ b/ts/types/LocalizerKeys.ts @@ -391,6 +391,7 @@ export type LocalizerKeys = | 'closedGroupMaxSize' | 'messagesHeader' | 'joinOpenGroup' + | 'join' | 'callMediaPermissionsDialogContent' | 'timerOption_1_day_abbreviated' | 'about'