|
|
|
@ -1,11 +1,14 @@
|
|
|
|
|
import React from 'react';
|
|
|
|
|
import { SessionIconButton, SessionIconSize, SessionIconType } from './icon';
|
|
|
|
|
import { Avatar } from '../Avatar';
|
|
|
|
|
import { SessionButton, SessionButtonColor, SessionButtonType } from './SessionButton';
|
|
|
|
|
import {
|
|
|
|
|
SessionButton,
|
|
|
|
|
SessionButtonColor,
|
|
|
|
|
SessionButtonType,
|
|
|
|
|
} from './SessionButton';
|
|
|
|
|
import { MediaGallery } from '../conversation/media-gallery/MediaGallery';
|
|
|
|
|
import _ from 'lodash';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
@ -19,7 +22,6 @@ interface Props {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class SessionChannelSettings extends React.Component<Props, any> {
|
|
|
|
|
|
|
|
|
|
public constructor(props: Props) {
|
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
|
@ -31,13 +33,15 @@ export class SessionChannelSettings extends React.Component<Props, any> {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public componentWillMount() {
|
|
|
|
|
this.getMediaGalleryProps().then(({ documents, media, onItemClick }) => {
|
|
|
|
|
this.getMediaGalleryProps()
|
|
|
|
|
.then(({ documents, media, onItemClick }) => {
|
|
|
|
|
this.setState({
|
|
|
|
|
documents,
|
|
|
|
|
media,
|
|
|
|
|
onItemClick,
|
|
|
|
|
});
|
|
|
|
|
}).ignore();
|
|
|
|
|
})
|
|
|
|
|
.ignore();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async getMediaGalleryProps() {
|
|
|
|
@ -70,7 +74,9 @@ export class SessionChannelSettings extends React.Component<Props, any> {
|
|
|
|
|
if (schemaVersion < message.VERSION_NEEDED_FOR_DISPLAY) {
|
|
|
|
|
// Yep, we really do want to wait for each of these
|
|
|
|
|
// eslint-disable-next-line no-await-in-loop
|
|
|
|
|
rawMedia[i] = await window.Signal.Migrations.upgradeMessageSchema(message);
|
|
|
|
|
rawMedia[i] = await window.Signal.Migrations.upgradeMessageSchema(
|
|
|
|
|
message
|
|
|
|
|
);
|
|
|
|
|
// eslint-disable-next-line no-await-in-loop
|
|
|
|
|
await window.Signal.Data.saveMessage(rawMedia[i], {
|
|
|
|
|
Message: window.Whisper.Message,
|
|
|
|
@ -86,30 +92,37 @@ export class SessionChannelSettings extends React.Component<Props, any> {
|
|
|
|
|
return (attachments || [])
|
|
|
|
|
.filter(
|
|
|
|
|
(attachment: { thumbnail: any; pending: any; error: any }) =>
|
|
|
|
|
attachment.thumbnail &&
|
|
|
|
|
!attachment.pending &&
|
|
|
|
|
!attachment.error
|
|
|
|
|
attachment.thumbnail && !attachment.pending && !attachment.error
|
|
|
|
|
)
|
|
|
|
|
.map((attachment: { path?: any; contentType?: any; thumbnail?: any }, index: any) => {
|
|
|
|
|
.map(
|
|
|
|
|
(
|
|
|
|
|
attachment: { path?: any; contentType?: any; thumbnail?: any },
|
|
|
|
|
index: any
|
|
|
|
|
) => {
|
|
|
|
|
const { thumbnail } = attachment;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
objectURL: window.Signal.Migrations.getAbsoluteAttachmentPath(attachment.path),
|
|
|
|
|
objectURL: window.Signal.Migrations.getAbsoluteAttachmentPath(
|
|
|
|
|
attachment.path
|
|
|
|
|
),
|
|
|
|
|
thumbnailObjectUrl: thumbnail
|
|
|
|
|
? window.Signal.Migrations.getAbsoluteAttachmentPath(thumbnail.path)
|
|
|
|
|
? window.Signal.Migrations.getAbsoluteAttachmentPath(
|
|
|
|
|
thumbnail.path
|
|
|
|
|
)
|
|
|
|
|
: null,
|
|
|
|
|
contentType: attachment.contentType,
|
|
|
|
|
index,
|
|
|
|
|
attachment,
|
|
|
|
|
message,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Unlike visual media, only one non-image attachment is supported
|
|
|
|
|
const documents = rawDocuments.map((message: { attachments: Array<any> }) => {
|
|
|
|
|
const documents = rawDocuments.map(
|
|
|
|
|
(message: { attachments: Array<any> }) => {
|
|
|
|
|
const attachments = message.attachments || [];
|
|
|
|
|
const attachment = attachments[0];
|
|
|
|
|
|
|
|
|
@ -119,7 +132,8 @@ export class SessionChannelSettings extends React.Component<Props, any> {
|
|
|
|
|
attachment,
|
|
|
|
|
message,
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const saveAttachment = async ({ attachment, message }: any = {}) => {
|
|
|
|
|
const timestamp = message.received_at;
|
|
|
|
@ -131,7 +145,7 @@ export class SessionChannelSettings extends React.Component<Props, any> {
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onItemClick = async ({ message, attachment, type } : any) => {
|
|
|
|
|
const onItemClick = async ({ message, attachment, type }: any) => {
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 'documents':
|
|
|
|
|
case 'media': {
|
|
|
|
@ -169,7 +183,6 @@ export class SessionChannelSettings extends React.Component<Props, any> {
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public render() {
|
|
|
|
|
const { memberCount, name, onLeaveGroup } = this.props;
|
|
|
|
|
const { documents, media, onItemClick } = this.state;
|
|
|
|
@ -178,25 +191,59 @@ export class SessionChannelSettings extends React.Component<Props, any> {
|
|
|
|
|
<div className="group-settings">
|
|
|
|
|
{this.renderHeader()}
|
|
|
|
|
<h2>{name}</h2>
|
|
|
|
|
{memberCount && <div className="text-subtle">{window.i18n('members', memberCount)}</div>}
|
|
|
|
|
<input className="description" placeholder={window.i18n('description')} />
|
|
|
|
|
|
|
|
|
|
<div className="group-settings-item" >{window.i18n('notifications')}</div>
|
|
|
|
|
<div className="group-settings-item" >{window.i18n('disappearingMessages')}</div>
|
|
|
|
|
<MediaGallery documents={documents} media={media} onItemClick={onItemClick} />
|
|
|
|
|
<SessionButton text={window.i18n('leaveGroup')} buttonColor={SessionButtonColor.Danger} buttonType={SessionButtonType.SquareOutline} onClick={onLeaveGroup}/>
|
|
|
|
|
</div>);
|
|
|
|
|
{memberCount && (
|
|
|
|
|
<div className="text-subtle">
|
|
|
|
|
{window.i18n('members', memberCount)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
<input
|
|
|
|
|
className="description"
|
|
|
|
|
placeholder={window.i18n('description')}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<div className="group-settings-item">
|
|
|
|
|
{window.i18n('notifications')}
|
|
|
|
|
</div>
|
|
|
|
|
<div className="group-settings-item">
|
|
|
|
|
{window.i18n('disappearingMessages')}
|
|
|
|
|
</div>
|
|
|
|
|
<MediaGallery
|
|
|
|
|
documents={documents}
|
|
|
|
|
media={media}
|
|
|
|
|
onItemClick={onItemClick}
|
|
|
|
|
/>
|
|
|
|
|
<SessionButton
|
|
|
|
|
text={window.i18n('leaveGroup')}
|
|
|
|
|
buttonColor={SessionButtonColor.Danger}
|
|
|
|
|
buttonType={SessionButtonType.SquareOutline}
|
|
|
|
|
onClick={onLeaveGroup}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private renderHeader() {
|
|
|
|
|
const { id, onGoBack, onInviteFriends, avatarPath } = this.props;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="group-settings-header">
|
|
|
|
|
<SessionIconButton iconType={SessionIconType.Chevron} iconSize={SessionIconSize.Medium} iconRotation={90} onClick={onGoBack} />
|
|
|
|
|
<Avatar avatarPath={avatarPath} phoneNumber={id} conversationType="group" size={80} />
|
|
|
|
|
<SessionIconButton iconType={SessionIconType.AddUser} iconSize={SessionIconSize.Medium} onClick={onInviteFriends} />
|
|
|
|
|
<SessionIconButton
|
|
|
|
|
iconType={SessionIconType.Chevron}
|
|
|
|
|
iconSize={SessionIconSize.Medium}
|
|
|
|
|
iconRotation={90}
|
|
|
|
|
onClick={onGoBack}
|
|
|
|
|
/>
|
|
|
|
|
<Avatar
|
|
|
|
|
avatarPath={avatarPath}
|
|
|
|
|
phoneNumber={id}
|
|
|
|
|
conversationType="group"
|
|
|
|
|
size={80}
|
|
|
|
|
/>
|
|
|
|
|
<SessionIconButton
|
|
|
|
|
iconType={SessionIconType.AddUser}
|
|
|
|
|
iconSize={SessionIconSize.Medium}
|
|
|
|
|
onClick={onInviteFriends}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|