diff --git a/preload.js b/preload.js index 986307062..4622d12b7 100644 --- a/preload.js +++ b/preload.js @@ -3,7 +3,6 @@ /* global window: false */ const path = require('path'); const electron = require('electron'); -const Data = require('./js/modules/data'); const { webFrame } = electron; const semver = require('semver'); @@ -111,9 +110,6 @@ window.wrapDeferred = deferredToPromise; const ipc = electron.ipcRenderer; const localeMessages = ipc.sendSync('locale-data'); -// Initialise Data -Data.init(); - window.blake2b = input => new Promise((resolve, reject) => { ipc.once('blake2b-digest-response', (event, error, res) => { diff --git a/ts/components/session/LeftPaneMessageSection.tsx b/ts/components/session/LeftPaneMessageSection.tsx index 4c825a427..d390b9a5c 100644 --- a/ts/components/session/LeftPaneMessageSection.tsx +++ b/ts/components/session/LeftPaneMessageSection.tsx @@ -17,28 +17,23 @@ import { cleanSearchTerm } from '../../util/cleanSearchTerm'; import { SearchOptions } from '../../types/Search'; import { validateNumber } from '../../types/PhoneNumber'; import { LeftPane, RowRendererParamsType } from '../LeftPane'; -import { SessionClosableOverlay } from './SessionClosableOverlay'; -import { SessionIconButton, SessionIconSize, SessionIconType } from './icon'; +import { + SessionClosableOverlay, + SessionClosableOverlayType, +} from './SessionClosableOverlay'; +import { SessionIconType } from './icon'; +import { ContactType } from './SessionMemberListItem'; import { SessionButton, SessionButtonColor, SessionButtonType, } from './SessionButton'; -import { SessionSpinner } from './SessionSpinner'; -import { joinChannelStateManager } from './LeftPaneChannelSection'; - -// HIJACKING BUTTON FOR TESTING -import { PendingMessageCache } from '../../session/sending/PendingMessageCache'; -import { MessageQueue } from '../../session/sending'; -import { ExampleMessage } from '../../session/sending/MessageQueue'; - export interface Props { searchTerm: string; isSecondaryDevice: boolean; conversations?: Array; - searchResults?: SearchResultsProps; updateSearchTerm: (searchTerm: string) => void; @@ -47,21 +42,40 @@ export interface Props { clearSearch: () => void; } -export class LeftPaneMessageSection extends React.Component { +export enum SessionComposeToType { + Message = 'message', + OpenGroup = 'open-group', + ClosedGroup = 'closed-group', +} + +export const SessionGroupType = { + OpenGroup: SessionComposeToType.OpenGroup, + ClosedGroup: SessionComposeToType.ClosedGroup, +}; +export type SessionGroupType = SessionComposeToType; + +interface State { + loading: boolean; + overlay: false | SessionComposeToType; + valuePasted: string; + connectSuccess: boolean; +} + +export class LeftPaneMessageSection extends React.Component { private readonly updateSearchBound: (searchedString: string) => void; private readonly debouncedSearch: (searchTerm: string) => void; - // HIJACKED FOR TESTING - private readonly messageQueue: any; - private readonly pendingMessageCache: any; - public constructor(props: Props) { super(props); + this.state = { + loading: false, + overlay: false, + valuePasted: '', + connectSuccess: false, + }; + const conversations = this.getCurrentConversations(); - const renderOnboardingSetting = window.getSettingValue( - 'render-message-onboarding' - ); const realConversations: Array = []; if (conversations) { @@ -74,29 +88,22 @@ export class LeftPaneMessageSection extends React.Component { }); } - const length = realConversations.length; - - this.state = { - showComposeView: false, - pubKeyPasted: '', - shouldRenderMessageOnboarding: - length === 0 && renderOnboardingSetting && false, - connectSuccess: false, - loading: false, - }; - this.updateSearchBound = this.updateSearch.bind(this); + + this.handleOnPaste = this.handleOnPaste.bind(this); this.handleToggleOverlay = this.handleToggleOverlay.bind(this); - this.handleCloseOnboarding = this.handleCloseOnboarding.bind(this); - this.handleJoinPublicChat = this.handleJoinPublicChat.bind(this); - this.handleOnPasteSessionID = this.handleOnPasteSessionID.bind(this); this.handleMessageButtonClick = this.handleMessageButtonClick.bind(this); - this.debouncedSearch = debounce(this.search.bind(this), 20); + this.handleNewSessionButtonClick = this.handleNewSessionButtonClick.bind( + this + ); + this.handleJoinChannelButtonClick = this.handleJoinChannelButtonClick.bind( + this + ); + this.onCreateClosedGroup = this.onCreateClosedGroup.bind(this); - // HIJACKING FOR TESTING - this.messageQueue = new MessageQueue(); - this.pendingMessageCache = new PendingMessageCache(); + this.renderClosableOverlay = this.renderClosableOverlay.bind(this); + this.debouncedSearch = debounce(this.search.bind(this), 20); } public componentWillUnmount() { @@ -212,17 +219,20 @@ export class LeftPaneMessageSection extends React.Component { return LeftPane.RENDER_HEADER( labels, null, - window.i18n('newSession'), - this.handleToggleOverlay + undefined, + SessionIconType.Plus, + this.handleNewSessionButtonClick ); } public render(): JSX.Element { + const { overlay } = this.state; + return (
{this.renderHeader()} - {this.state.showComposeView - ? this.renderClosableOverlay() + {overlay + ? this.renderClosableOverlay(overlay) : this.renderConversations()}
); @@ -231,90 +241,17 @@ export class LeftPaneMessageSection extends React.Component { public renderConversations() { return (
- {this.state.shouldRenderMessageOnboarding ? ( - <>{this.renderMessageOnboarding()} - ) : ( - <> - - {this.renderList()} - - )} -
- ); - } - - public renderMessageOnboarding() { - return ( -
-
- -
- -
-
-

{window.i18n('welcomeToSession')}

-
- -
- -
- -
-
- {window.i18n('noMessagesTitle')} -
-
- {window.i18n('noMessagesSubtitle')} -
-
- - <> - {this.state.loading ? ( -
- -
- ) : ( -
- - -
- )} - -
+ + {this.renderList()} + {this.renderBottomButtons()}
); } - public handleCloseOnboarding() { - window.setSettingValue('render-message-onboarding', false); - - this.setState({ - shouldRenderMessageOnboarding: false, - }); - } - public updateSearch(searchTerm: string) { const { updateSearchTerm, clearSearch } = this.props; @@ -323,8 +260,9 @@ export class LeftPaneMessageSection extends React.Component { return; } + // reset our pubKeyPasted, we can either have a pasted sessionID or a sessionID got from a search - this.setState({ pubKeyPasted: '' }); + this.setState({ valuePasted: '' }); if (updateSearchTerm) { updateSearchTerm(searchTerm); @@ -360,58 +298,126 @@ export class LeftPaneMessageSection extends React.Component { } } - private renderClosableOverlay() { + private renderClosableOverlay(overlay: SessionComposeToType) { const { searchTerm, searchResults } = this.props; + const { loading } = this.state; - return ( + const openGroupElement = ( + { + this.handleToggleOverlay(undefined); + }} + onButtonClick={this.handleJoinChannelButtonClick} + searchTerm={searchTerm} + updateSearch={this.updateSearchBound} + showSpinner={loading} + /> + ); + + const closedGroupElement = ( + { + this.handleToggleOverlay(undefined); + }} + onButtonClick={async ( + groupName: string, + groupMembers: Array, + senderKeys: boolean + ) => this.onCreateClosedGroup(groupName, groupMembers, senderKeys)} + searchTerm={searchTerm} + updateSearch={this.updateSearchBound} + showSpinner={loading} + /> + ); + + const messageElement = ( { + this.handleToggleOverlay(undefined); + }} onButtonClick={this.handleMessageButtonClick} searchTerm={searchTerm} searchResults={searchResults} updateSearch={this.updateSearchBound} /> ); + + let overlayElement; + switch (overlay) { + case SessionComposeToType.OpenGroup: + overlayElement = openGroupElement; + break; + case SessionComposeToType.ClosedGroup: + overlayElement = closedGroupElement; + break; + default: + overlayElement = messageElement; + } + + return overlayElement; } - private async handleToggleOverlay() { - // HIJACKING BUTTON FOR TESTING - console.log('[vince] pendingMessageCache:', this.pendingMessageCache); + private renderBottomButtons(): JSX.Element { + const edit = window.i18n('edit'); + const joinOpenGroup = window.i18n('joinOpenGroup'); + const createClosedGroup = window.i18n('createClosedGroup'); + const showEditButton = false; - const pubkey = window.textsecure.storage.user.getNumber(); - const exampleMessage = new ExampleMessage(); + return ( +
+ {showEditButton && ( + + )} - console.log('[vince] exampleMessage:', exampleMessage); + { + this.handleToggleOverlay(SessionComposeToType.OpenGroup); + }} + /> + { + this.handleToggleOverlay(SessionComposeToType.ClosedGroup); + }} + /> +
+ ); + } - const devices = this.pendingMessageCache.getPendingDevices(); - console.log('[vince] devices:', devices); + private handleToggleOverlay(conversationType?: SessionComposeToType) { + const { overlay } = this.state; - if ($('.session-search-input input').val()) { - this.pendingMessageCache.removePendingMessageByIdentifier(exampleMessage.identifier); - } else { - this.pendingMessageCache.addPendingMessage(pubkey, exampleMessage); - } + const overlayState = overlay ? false : conversationType || false; - // this.setState((state: any) => { - // return { showComposeView: !state.showComposeView }; - // }); - // // empty our generalized searchedString (one for the whole app) - // this.updateSearch(''); - } + this.setState({ overlay: overlayState }); - private handleOnPasteSessionID(value: string) { - // reset our search, we can either have a pasted sessionID or a sessionID got from a search + // empty our generalized searchedString (one for the whole app) this.updateSearch(''); + } - this.setState({ pubKeyPasted: value }); + private handleOnPaste(value: string) { + this.setState({ valuePasted: value }); } private handleMessageButtonClick() { const { openConversationInternal } = this.props; - if (!this.state.pubKeyPasted && !this.props.searchTerm) { + if (!this.state.valuePasted && !this.props.searchTerm) { window.pushToast({ title: window.i18n('invalidNumberError'), type: 'error', @@ -421,7 +427,7 @@ export class LeftPaneMessageSection extends React.Component { return; } let pubkey: string; - pubkey = this.state.pubKeyPasted || this.props.searchTerm; + pubkey = this.state.valuePasted || this.props.searchTerm; pubkey = pubkey.trim(); const error = validateNumber(pubkey); @@ -436,8 +442,64 @@ export class LeftPaneMessageSection extends React.Component { } } - private handleJoinPublicChat() { - const serverURL = window.CONSTANTS.DEFAULT_PUBLIC_CHAT_URL; - joinChannelStateManager(this, serverURL, this.handleCloseOnboarding); + private handleJoinChannelButtonClick(groupUrl: string) { + const { loading } = this.state; + + if (loading) { + return false; + } + + // longest TLD is now (20/02/06) 24 characters per https://jasontucker.blog/8945/what-is-the-longest-tld-you-can-get-for-a-domain-name + const regexURL = /(http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,24}(:[0-9]{1,5})?(\/.*)?/; + + if (groupUrl.length <= 0) { + window.pushToast({ + title: window.i18n('noServerURL'), + type: 'error', + id: 'connectToServerFail', + }); + + return false; + } + + if (!regexURL.test(groupUrl)) { + window.pushToast({ + title: window.i18n('noServerURL'), + type: 'error', + id: 'connectToServerFail', + }); + + return false; + } + + MainViewController.joinChannelStateManager(this, groupUrl, () => { + this.handleToggleOverlay(undefined); + }); + + return true; } -} \ No newline at end of file + + private async onCreateClosedGroup( + groupName: string, + groupMembers: Array, + senderKeys: boolean + ) { + await MainViewController.createClosedGroup( + groupName, + groupMembers, + senderKeys, + () => { + this.handleToggleOverlay(undefined); + + window.pushToast({ + title: window.i18n('closedGroupCreatedToastTitle'), + type: 'success', + }); + } + ); + } + + private handleNewSessionButtonClick() { + this.handleToggleOverlay(SessionComposeToType.Message); + } +} diff --git a/ts/test/test-utils/testUtils.ts b/ts/test/test-utils/testUtils.ts index fc7732e29..821e655ff 100644 --- a/ts/test/test-utils/testUtils.ts +++ b/ts/test/test-utils/testUtils.ts @@ -67,4 +67,4 @@ export function generateUniqueChatMessage(): ChatMessage { lokiProfile: undefined, preview: undefined, }); -} \ No newline at end of file +}