diff --git a/stylesheets/_modules.scss b/stylesheets/_modules.scss index 75f87afbcf..8b5c30faaa 100644 --- a/stylesheets/_modules.scss +++ b/stylesheets/_modules.scss @@ -2100,7 +2100,10 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05', .module-about { &__container { margin-bottom: 8px; + margin-left: auto; + margin-right: auto; max-width: 248px; + text-align: center; } &__text { @@ -2113,6 +2116,13 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05', } max-width: 400px; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + display: -webkit-box; + overflow: hidden; + text-align: left; + text-overflow: ellipsis; + img.emoji { height: 1em; margin-right: 3px; @@ -2740,6 +2750,11 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05', flex-direction: row; flex-grow: 1; + justify-content: space-between; +} + +.module-contact-list-item__left { + flex: 1; } .module-contact-list-item__text__name { @@ -2780,7 +2795,6 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05', } .module-contact-list-item__admin { - flex-grow: 1; text-align: right; height: 100%; @@ -2897,6 +2911,10 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05', max-width: 100%; } +.module-conversation-header__title-clickable { + cursor: pointer; +} + .module-conversation-header__note-to-self { @include dark-theme { color: $color-gray-02; diff --git a/ts/Crypto.ts b/ts/Crypto.ts index 9c0e203c9e..db689a7c16 100644 --- a/ts/Crypto.ts +++ b/ts/Crypto.ts @@ -773,3 +773,17 @@ export function splitUuids(arrayBuffer: ArrayBuffer): Array { } return uuids; } + +export function trimForDisplay(arrayBuffer: ArrayBuffer): ArrayBuffer { + const padded = new Uint8Array(arrayBuffer); + + let paddingEnd = 0; + for (paddingEnd; paddingEnd < padded.length; paddingEnd += 1) { + if (padded[paddingEnd] === 0x00) { + break; + } + } + return window.dcodeIO.ByteBuffer.wrap(padded) + .slice(0, paddingEnd) + .toArrayBuffer(); +} diff --git a/ts/components/ContactListItem.stories.tsx b/ts/components/ContactListItem.stories.tsx index fb88015a2d..e3f106aa82 100644 --- a/ts/components/ContactListItem.stories.tsx +++ b/ts/components/ContactListItem.stories.tsx @@ -64,7 +64,7 @@ storiesOf('Components/ContactListItem', module) name="Someone πŸ”₯ Somewhere" phoneNumber="(202) 555-0011" profileName="πŸ”₯FlamesπŸ”₯" - about="πŸ‘ Free to chat" + about="πŸ‘ This is my really long status message that I have in order to test line breaking" avatarPath={gifUrl} onClick={onClick} /> diff --git a/ts/components/conversation/ConversationHeader.stories.tsx b/ts/components/conversation/ConversationHeader.stories.tsx index dca64fe929..157cf713e6 100644 --- a/ts/components/conversation/ConversationHeader.stories.tsx +++ b/ts/components/conversation/ConversationHeader.stories.tsx @@ -47,6 +47,7 @@ const commonProps = { onShowSafetyNumber: action('onShowSafetyNumber'), onShowAllMedia: action('onShowAllMedia'), + onShowContactModal: action('onShowContactModal'), onShowGroupMembers: action('onShowGroupMembers'), onGoBack: action('onGoBack'), diff --git a/ts/components/conversation/ConversationHeader.tsx b/ts/components/conversation/ConversationHeader.tsx index f7f4bef199..070bedd03f 100644 --- a/ts/components/conversation/ConversationHeader.tsx +++ b/ts/components/conversation/ConversationHeader.tsx @@ -63,6 +63,7 @@ export type PropsDataType = { export type PropsActionsType = { onSetMuteNotifications: (seconds: number) => void; onSetDisappearingMessages: (seconds: number) => void; + onShowContactModal: (contactId: string) => void; onDeleteMessages: () => void; onResetSession: () => void; onSearchInConversation: () => void; @@ -468,6 +469,42 @@ export class ConversationHeader extends React.Component { ); } + private renderHeader(): JSX.Element { + const { id, isMe, onShowContactModal, type } = this.props; + + if (type === 'group' || isMe) { + return ( +
+ {this.renderAvatar()} + {this.renderTitle()} +
+ ); + } + + const onContactClick = () => onShowContactModal(id); + const onKeyDown = (e: React.KeyboardEvent): void => { + if (e.key === 'Enter' || e.key === ' ') { + e.stopPropagation(); + e.preventDefault(); + + onShowContactModal(id); + } + }; + + return ( +
+ {this.renderAvatar()} + {this.renderTitle()} +
+ ); + } + public render(): JSX.Element { const { id } = this.props; const triggerId = `conversation-${id}`; @@ -476,10 +513,7 @@ export class ConversationHeader extends React.Component {
{this.renderBackButton()}
-
- {this.renderAvatar()} - {this.renderTitle()} -
+ {this.renderHeader()}
{this.renderExpirationLength()} {this.renderOutgoingCallButtons()} diff --git a/ts/components/conversation/ConversationHero.tsx b/ts/components/conversation/ConversationHero.tsx index f2bda07e53..a4e3b446f0 100644 --- a/ts/components/conversation/ConversationHero.tsx +++ b/ts/components/conversation/ConversationHero.tsx @@ -191,7 +191,7 @@ export const ConversationHero = ({ /> )} - {about && ( + {about && !isMe && (
diff --git a/ts/models/conversations.ts b/ts/models/conversations.ts index 3f06beecc9..d18911037c 100644 --- a/ts/models/conversations.ts +++ b/ts/models/conversations.ts @@ -29,6 +29,7 @@ import { fromEncodedBinaryToArrayBuffer, getRandomBytes, stringFromBytes, + trimForDisplay, verifyAccessKey, } from '../Crypto'; import { GroupChangeClass } from '../textsecure.d'; @@ -3768,26 +3769,26 @@ export class ConversationModel extends window.Backbone.Model< } if (profile.about) { - const key = this.get('profileKey'); + const key = c.get('profileKey'); if (key) { const keyBuffer = base64ToArrayBuffer(key); const decrypted = await window.textsecure.crypto.decryptProfile( base64ToArrayBuffer(profile.about), keyBuffer ); - this.set('about', stringFromBytes(decrypted)); + c.set('about', stringFromBytes(trimForDisplay(decrypted))); } } if (profile.aboutEmoji) { - const key = this.get('profileKey'); + const key = c.get('profileKey'); if (key) { const keyBuffer = base64ToArrayBuffer(key); const decrypted = await window.textsecure.crypto.decryptProfile( base64ToArrayBuffer(profile.aboutEmoji), keyBuffer ); - this.set('aboutEmoji', stringFromBytes(decrypted)); + c.set('aboutEmoji', stringFromBytes(trimForDisplay(decrypted))); } } diff --git a/ts/state/smart/ConversationHeader.tsx b/ts/state/smart/ConversationHeader.tsx index 6cf642238f..2eaf3067e3 100644 --- a/ts/state/smart/ConversationHeader.tsx +++ b/ts/state/smart/ConversationHeader.tsx @@ -33,6 +33,7 @@ export type OwnProps = { onSetMuteNotifications: (seconds: number) => void; onSetPin: (value: boolean) => void; onShowAllMedia: () => void; + onShowContactModal: (contactId: string) => void; onShowGroupMembers: () => void; onArchive: () => void; diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index b072463d35..e4fb2588a2 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -14770,7 +14770,7 @@ "rule": "React-createRef", "path": "ts/components/conversation/ConversationHeader.tsx", "line": " this.menuTriggerRef = React.createRef();", - "lineNumber": 101, + "lineNumber": 102, "reasonCategory": "usageTrusted", "updated": "2020-05-20T20:10:43.540Z", "reasonDetail": "Used to reference popup menu" diff --git a/ts/views/conversation_view.ts b/ts/views/conversation_view.ts index e6cdf668ca..cfe642a6d3 100644 --- a/ts/views/conversation_view.ts +++ b/ts/views/conversation_view.ts @@ -458,6 +458,7 @@ Whisper.ConversationView = Whisper.View.extend({ { id: this.model.id, + onShowContactModal: this.showContactModal.bind(this), onSetDisappearingMessages: (seconds: number) => this.setDisappearingMessages(seconds), onDeleteMessages: () => this.destroyMessages(),