Session v1.0 changes (#802)
* correct typo in readme
* include log
* decrypt file server response, remove debug, handle crypt before _sendToProxy, improve json parsing failure logging
* support file uploads on file proxy, fix _sendToProxy calling
* bump form-data to 3.0
* initial refactor of feaure flag detection statements in serverRequest()
* fix send-message line-height with multiple lines
* fix lint
* fix position of delete account modal
* Profile picture upload, fixes and copy
* Various changes suggested by redesign overview
* Scrolling button updated and animations to modals
* Display subscriber count for open chats
* Prevent illegal username and passwords
* Delete channel / group merge
* Solidification of minor changes w appview injections
* hide description field in group panel for now
* fix join publicgroups pulls
* increase min height respecting ratio
* allow space inside a display name but not at start or end
* fix height of leftpane overlay view
* add back typing indicator and read receipt setting under privacy
* Auto-focus new open chat input box
* Password lock screen and delete data screen
* touchups
* Resolving Bilb revisions
* Disable link previews as default per Kee on signup
* remove date, we have git
* add missing semicolon
* _sendToProxy pass headers/handle response refactor, lint
* fix my yarn conflict/resolve
* include IV in server response
* Sealed sender support
* Support sealed sender for friend requests
* fix lint
* Remove unused destinationRegistrationId; lint
* Update messages.json
* pull RSS through file proxy
* fix unit tests: remove not used count in scrolldown view and assert svg
present
* Disable auto-joining default loki open groups
* session-id-editable-textarea
* fix the textscramble for sessionID on registration
* speed up lint, add lint-full/format-full, make sure use lint-full
* add skipToken to establishConnection options, smuggle out secureRpcPubKey
* get latest version through snode proxy, remove clearfix from ExpiredAlertBanner
* expose semver and LokiAppDotNetServerAPI because we can't get ourKey from storage early enough
* update note
* fix upgrade link, wrap expiredWarning in span for styling, use br to clear the float, trim trailing whitespace
* designalify
* designalify
* designalify user agent
* continue designalification
* make expired banner legible
* remove ugly TLS hack
* disable unauthorization rejection when making https requests limited to lokiRpc
* Update main.js
Aspect ratio amendment
* Constants rework
* local commit
* event listeners
* address missing comma for lint
* fix header sessions message section
* fix profile image size conversation list with pending friend request
* textarea centering
* refresh files in group in group panel
* Looking into keyboard navigation
* Remove P2P
* cache eslint on `lint` but not `ready`
* Cleanup media view formatting
* force locale to be EN until our files are updated and translated
* Simplification of keyup
* Updated all icon references
* SASS fixup
* fix disabled state of message input on sent friendrequest
* trim pubkey when user can enter one to remove whitespaces
* remove lZ in path which fixes errors on svg and does not alter rendering
* fix text scramble animation on registration
* reload app on ctrl-r or f5 from anywhere
* add back file which should have not been deleted
* fix lint and clean code
* fix lint
* add .loki to have a self-signed cert
* Remove mixpanel
* use local shortcut instead of global shortcut
otherwise, ctrl+r is only caught bu the last loaded instance
* open the conversation when accepting a friend request
also, it does what is needed to show the new friend in the friend list
* make sure token comms are done over fileProxy, other notes, logging adjustment
* leftpane sections titles are Wasa bold
* minor refactor
* onboarding messageview
* linter
* fix padding buttons overlay
* do not render session-id-editable border when textarea disabled
* textarea sessionID SpaceMono font
* various touchups
* fix font of description to sfprodisplay
* reduce triple dots conversation header icon size
* reduce size of conversationHeader title font size
* fix font for session-search-input
* make conversationlistitem title font wasa
* fix green and white border under title in leftpane
* fix panel-text-divider font-size and family
* disable completely borders for profile images
* make profile image which where 48pixels big 36 noew, as no more border
* Complete conditional message onboarding
* cache file deletions
* Link preview warning on setting toggle
* Messages.json amendments
* Join channel generalisation
* Localise global vars
* remove eslintcache
* rm global launchcount
* Remove source field from envelope
* Session public chat icon
* CLosed groups ui initial listprops
* Desktop: enable useSnodeProxy feature flag
* file proxy needs to be able to talk to snode
- disable TLS check for fileProxy
- lokiHttpsAgent => snodeHttpsAgent (since we use for two different things now)
* enable useSealedSender too per Maxim
* lint
* lint
* window.extension.expiredPromise version
* better error checking
* use promise version to see if we're expired
* fix typo
* lint
* put back seemingly now required process.env.NODE_TLS_REJECT_UNAUTHORIZED
* fix querystring in file-proxy
* lint
* fix typo
* Remove more references to signal.org
* make sure TLS is forced on open groups, improve serverRequest error message
* Closed groups UI
* function params changes
* turn off snode proxy logging
* include useful info on error
* actually validate URL before starting up a bunch of timers
* Closed groups overlay integration
* move comments from connecting_to_server_dialog_view
* use attempt from window object to reduce code duplication
* refactor out validServer()
* lint
* lint caught typo
* Rename BACKGROUND_FRIEND_REQUEST to SESSION_REQUEST.
Don't trigger friend request logic if a message is aimed at a group.
* Linting
* Closed group joining completed w/o backend
* Fix friend request messages being sent to users you don't have a session in closed groups.
Disable typing messages and read receipts in groups.
Send out session request messages if you don't have a session with a member in the group.
* Remove unneeded boolean condition.
* Closed group update message stylgin
* constants renaming
* Message deletion fix
* gruntify
* fix grunt error
* expose isRss, don't close uncloseable Rss conversation on deleteMessages
* remove copyId and block user on RSS feeds
* remove options from RSS feed that don't make any sense and don't work
* fix grunt error
* squelch RSS duplicate messages
* extension.expiredStatus(), adjustable timers, improve guards
* allowing sending of messages if we're still waiting to hear back
* markRandomNodeUnreachable() refactor, notes/logging
* improve logging
* improve logging
* no need to validate empty token, support lokinet/getession file domains, mark broken snodes as bad, improve logging
* try to address travis-osx lint complaints
* not designed to have a period at the end of titleIsNow
* put period back at the end
* Catch a stray loki messenger
* fix stray loki messenger
* loki messenger isnt a thing
* lint
* Fix open group joining.
* guards incase there are no members yet, fixes dialog not showing up
* fixed file server holding up message sender init.
fix joining closed groups.
* Clean
* Don't wait for file server to return tokens when establishing home connection.
* Disable join public chat prompt
Co-authored-by: Audric Ackermann <audric.bilb@gmail.com>
Co-authored-by: Ryan Tharp <neuro@interx.net>
Co-authored-by: Vince <vincent@loki.network>
Co-authored-by: Maxim Shishmarev <msgmaxim@gmail.com>
5 years ago
|
|
|
|
import React from 'react';
|
|
|
|
|
import { SessionIconButton, SessionIconSize, SessionIconType } from './icon';
|
|
|
|
|
import { Avatar } from '../Avatar';
|
|
|
|
|
import {
|
|
|
|
|
SessionButton,
|
|
|
|
|
SessionButtonColor,
|
|
|
|
|
SessionButtonType,
|
|
|
|
|
} from './SessionButton';
|
|
|
|
|
import { MediaGallery } from '../conversation/media-gallery/MediaGallery';
|
|
|
|
|
import _ from 'lodash';
|
|
|
|
|
import { TimerOption } from '../conversation/ConversationHeader';
|
|
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
memberCount: number;
|
|
|
|
|
description: string;
|
|
|
|
|
avatarPath: string;
|
|
|
|
|
timerOptions: Array<TimerOption>;
|
|
|
|
|
isPublic: boolean;
|
|
|
|
|
|
|
|
|
|
onGoBack: () => void;
|
|
|
|
|
onInviteFriends: () => void;
|
|
|
|
|
onLeaveGroup: () => void;
|
|
|
|
|
onShowLightBox: (options: any) => void;
|
|
|
|
|
onSetDisappearingMessages: (seconds: number) => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class SessionChannelSettings extends React.Component<Props, any> {
|
|
|
|
|
public constructor(props: Props) {
|
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
|
|
this.state = {
|
|
|
|
|
documents: Array<any>(),
|
|
|
|
|
media: Array<any>(),
|
|
|
|
|
onItemClick: undefined,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public componentWillMount() {
|
|
|
|
|
this.getMediaGalleryProps()
|
|
|
|
|
.then(({ documents, media, onItemClick }) => {
|
|
|
|
|
this.setState({
|
|
|
|
|
documents,
|
|
|
|
|
media,
|
|
|
|
|
onItemClick,
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
.ignore();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public componentDidUpdate() {
|
|
|
|
|
this.getMediaGalleryProps()
|
|
|
|
|
.then(({ documents, media, onItemClick }) => {
|
|
|
|
|
this.setState({
|
|
|
|
|
documents,
|
|
|
|
|
media,
|
|
|
|
|
onItemClick,
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
.ignore();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async getMediaGalleryProps() {
|
|
|
|
|
// We fetch more documents than media as they don’t require to be loaded
|
|
|
|
|
// into memory right away. Revisit this once we have infinite scrolling:
|
|
|
|
|
const DEFAULT_MEDIA_FETCH_COUNT = 50;
|
|
|
|
|
const DEFAULT_DOCUMENTS_FETCH_COUNT = 150;
|
|
|
|
|
const conversationId = this.props.id;
|
|
|
|
|
const rawMedia = await window.Signal.Data.getMessagesWithVisualMediaAttachments(
|
|
|
|
|
conversationId,
|
|
|
|
|
{
|
|
|
|
|
limit: DEFAULT_MEDIA_FETCH_COUNT,
|
|
|
|
|
MessageCollection: window.Whisper.MessageCollection,
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
const rawDocuments = await window.Signal.Data.getMessagesWithFileAttachments(
|
|
|
|
|
conversationId,
|
|
|
|
|
{
|
|
|
|
|
limit: DEFAULT_DOCUMENTS_FETCH_COUNT,
|
|
|
|
|
MessageCollection: window.Whisper.MessageCollection,
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// First we upgrade these messages to ensure that they have thumbnails
|
|
|
|
|
const max = rawMedia.length;
|
|
|
|
|
for (let i = 0; i < max; i += 1) {
|
|
|
|
|
const message = rawMedia[i];
|
|
|
|
|
const { schemaVersion } = message;
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
);
|
|
|
|
|
// eslint-disable-next-line no-await-in-loop
|
|
|
|
|
await window.Signal.Data.saveMessage(rawMedia[i], {
|
|
|
|
|
Message: window.Whisper.Message,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// tslint:disable-next-line: underscore-consistent-invocation
|
|
|
|
|
const media = _.flatten(
|
|
|
|
|
rawMedia.map((message: { attachments: any }) => {
|
|
|
|
|
const { attachments } = message;
|
|
|
|
|
|
|
|
|
|
return (attachments || [])
|
|
|
|
|
.filter(
|
|
|
|
|
(attachment: { thumbnail: any; pending: any; error: any }) =>
|
|
|
|
|
attachment.thumbnail && !attachment.pending && !attachment.error
|
|
|
|
|
)
|
|
|
|
|
.map(
|
|
|
|
|
(
|
|
|
|
|
attachment: { path?: any; contentType?: any; thumbnail?: any },
|
|
|
|
|
index: any
|
|
|
|
|
) => {
|
|
|
|
|
const { thumbnail } = attachment;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
objectURL: window.Signal.Migrations.getAbsoluteAttachmentPath(
|
|
|
|
|
attachment.path
|
|
|
|
|
),
|
|
|
|
|
thumbnailObjectUrl: thumbnail
|
|
|
|
|
? 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 attachments = message.attachments || [];
|
|
|
|
|
const attachment = attachments[0];
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
contentType: attachment.contentType,
|
|
|
|
|
index: 0,
|
|
|
|
|
attachment,
|
|
|
|
|
message,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const saveAttachment = async ({ attachment, message }: any = {}) => {
|
|
|
|
|
const timestamp = message.received_at;
|
|
|
|
|
window.Signal.Types.Attachment.save({
|
|
|
|
|
attachment,
|
|
|
|
|
document,
|
|
|
|
|
getAbsolutePath: window.Signal.Migrations.getAbsoluteAttachmentPath,
|
|
|
|
|
timestamp,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onItemClick = async ({ message, attachment, type }: any) => {
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 'documents': {
|
|
|
|
|
saveAttachment({ message, attachment }).ignore();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 'media': {
|
|
|
|
|
const lightBoxOptions = {
|
|
|
|
|
media,
|
|
|
|
|
attachment,
|
|
|
|
|
message,
|
|
|
|
|
};
|
|
|
|
|
this.onShowLightBox(lightBoxOptions);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw new TypeError(`Unknown attachment type: '${type}'`);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
media,
|
|
|
|
|
documents,
|
|
|
|
|
onItemClick,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public onShowLightBox(options: any) {
|
|
|
|
|
this.props.onShowLightBox(options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public render() {
|
|
|
|
|
const { memberCount, name, onLeaveGroup, isPublic } = this.props;
|
|
|
|
|
const { documents, media, onItemClick } = this.state;
|
|
|
|
|
const showMemberCount = !!(memberCount && memberCount > 0);
|
|
|
|
|
const leaveGroupString = isPublic
|
|
|
|
|
? window.i18n('leaveOpenGroup')
|
|
|
|
|
: window.i18n('leaveClosedGroup');
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="group-settings">
|
|
|
|
|
{this.renderHeader()}
|
|
|
|
|
<h2>{name}</h2>
|
|
|
|
|
{showMemberCount && (
|
|
|
|
|
<>
|
|
|
|
|
<div className="spacer-lg" />
|
|
|
|
|
<div className="text-subtle">
|
|
|
|
|
{window.i18n('members', memberCount)}
|
|
|
|
|
</div>
|
|
|
|
|
<div className="spacer-lg" />
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
<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={leaveGroupString}
|
|
|
|
|
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}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|