mirror of
https://github.com/oxen-io/session-desktop.git
synced 2023-12-14 02:12:57 +01:00
Merge branch 'clearnet' into audio-messages-play-all
This commit is contained in:
commit
397b0d09dc
|
@ -32,4 +32,3 @@ ts/**/*.js
|
|||
# Libloki specific files
|
||||
libloki/test/components.js
|
||||
libloki/modules/mnemonic.js
|
||||
session-file-server/**
|
||||
|
|
3
.github/workflows/build-binaries.yml
vendored
3
.github/workflows/build-binaries.yml
vendored
|
@ -20,9 +20,6 @@ jobs:
|
|||
- name: Checkout git repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Pull git submodules
|
||||
run: git submodule update --init
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
|
|
3
.github/workflows/pull-request.yml
vendored
3
.github/workflows/pull-request.yml
vendored
|
@ -22,9 +22,6 @@ jobs:
|
|||
- name: Checkout git repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Pull git submodules
|
||||
run: git submodule update --init
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
|
|
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
|
@ -20,9 +20,6 @@ jobs:
|
|||
- name: Checkout git repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Pull git submodules
|
||||
run: git submodule update --init
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
|
|
4
.gitmodules
vendored
4
.gitmodules
vendored
|
@ -1,4 +0,0 @@
|
|||
[submodule "session-file-server"]
|
||||
path = session-file-server
|
||||
url = https://github.com/loki-project/session-file-server/
|
||||
branch = session
|
|
@ -49,5 +49,4 @@ stylesheets/_intlTelInput.scss
|
|||
# Coverage
|
||||
coverage/**
|
||||
.nyc_output/**
|
||||
session-file-server/**
|
||||
release/**
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "session-desktop",
|
||||
"productName": "Session",
|
||||
"description": "Private messaging from your desktop",
|
||||
"version": "1.6.5",
|
||||
"version": "1.6.6",
|
||||
"license": "GPL-3.0",
|
||||
"author": {
|
||||
"name": "Loki Project",
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
word-break: break-all;
|
||||
}
|
||||
|
||||
.session-icon-button svg path {
|
||||
transition: fill 0.3s ease;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
caret-color: $session-color-green !important;
|
||||
|
|
|
@ -13,8 +13,8 @@ files = [y for x in os.walk(dir_path) for y in glob(os.path.join(x[0], '*.js'))]
|
|||
files += [y for x in os.walk(dir_path) for y in glob(os.path.join(x[0], '*.ts'))]
|
||||
files += [y for x in os.walk(dir_path) for y in glob(os.path.join(x[0], '*.tsx'))]
|
||||
|
||||
# exclude node_modules and session-file-server directories
|
||||
filtered_files = [f for f in files if "node_modules" not in f and "session-file-server" not in f]
|
||||
# exclude node_modules directories
|
||||
filtered_files = [f for f in files if "node_modules" not in f]
|
||||
|
||||
# search for this pattern in _locales/en/messages.json: it is a defined localized string
|
||||
patternLocalizedString = re.compile("^ \".*\"\: {")
|
||||
|
|
|
@ -11,7 +11,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
|||
import { StateType } from '../state/reducer';
|
||||
import { SessionIcon, SessionIconButton, SessionIconSize, SessionIconType } from './session/icon';
|
||||
|
||||
import { SessionWrapperModal } from '../components/session/SessionWrapperModal';
|
||||
import { SessionWrapperModal } from './session/SessionWrapperModal';
|
||||
|
||||
import ip2country from 'ip2country';
|
||||
import countryLookup from 'country-code-lookup';
|
||||
|
@ -26,6 +26,7 @@ import {
|
|||
|
||||
// tslint:disable-next-line: no-submodule-imports
|
||||
import useNetworkState from 'react-use/lib/useNetworkState';
|
||||
import { SessionSpinner } from './session/SessionSpinner';
|
||||
|
||||
export type StatusLightType = {
|
||||
glowStartDelay: number;
|
||||
|
@ -37,6 +38,10 @@ const OnionPathModalInner = () => {
|
|||
const onionPath = useSelector(getFirstOnionPath);
|
||||
// including the device and destination in calculation
|
||||
const glowDuration = onionPath.length + 2;
|
||||
console.warn('onionPath', onionPath);
|
||||
if (!onionPath || onionPath.length === 0) {
|
||||
return <SessionSpinner loading={true} />;
|
||||
}
|
||||
|
||||
const nodes = [
|
||||
{
|
||||
|
@ -116,7 +121,7 @@ export const ModalStatusLight = (props: StatusLightType) => {
|
|||
glowDuration={glowDuration}
|
||||
glowStartDelay={glowStartDelay}
|
||||
iconType={SessionIconType.Circle}
|
||||
iconSize={SessionIconSize.Medium}
|
||||
iconSize={SessionIconSize.Small}
|
||||
theme={theme}
|
||||
/>
|
||||
);
|
|
@ -41,8 +41,6 @@ const InviteContactsDialogInner = (props: Props) => {
|
|||
}
|
||||
|
||||
const chatName = convo.get('name');
|
||||
// const chatServer = convo.get('server');
|
||||
// const channelId = convo.get('channelId');
|
||||
const isPublicConvo = convo.isPublic();
|
||||
|
||||
const [contactList, setContactList] = useState(
|
||||
|
|
|
@ -78,7 +78,7 @@ export class UpdateGroupNameDialog extends React.Component<Props, State> {
|
|||
);
|
||||
|
||||
const isAdmin = this.convo.isPublic()
|
||||
? this.convo.isAdmin(window.storage.get('primaryDevicePubKey'))
|
||||
? false // disable editing of opengroup rooms as we don't handle them for now
|
||||
: true;
|
||||
|
||||
return (
|
||||
|
|
|
@ -45,7 +45,7 @@ import { FSv2 } from '../../fileserver';
|
|||
import { debounce } from 'lodash';
|
||||
import { DURATION } from '../../session/constants';
|
||||
import { actions as conversationActions } from '../../state/ducks/conversations';
|
||||
import { ActionPanelOnionStatusLight, OnionPathModal } from '../OnionStatusDialog';
|
||||
import { ActionPanelOnionStatusLight, OnionPathModal } from '../OnionStatusPathDialog';
|
||||
import { EditProfileDialog } from '../EditProfileDialog';
|
||||
import { SessionConfirm } from './SessionConfirm';
|
||||
import {
|
||||
|
@ -73,6 +73,7 @@ import { editProfileModal, onionPathModal } from '../../state/ducks/modalDialog'
|
|||
import { SessionSeedModal } from './SessionSeedModal';
|
||||
import { AdminLeaveClosedGroupDialog } from '../conversation/AdminLeaveClosedGroupDialog';
|
||||
import { uploadOurAvatar } from '../../interactions/conversationInteractions';
|
||||
import { ModalContainer } from './ModalContainer';
|
||||
|
||||
// tslint:disable-next-line: no-import-side-effect no-submodule-imports
|
||||
|
||||
|
@ -279,42 +280,6 @@ const doAppStartUp = () => {
|
|||
SwarmPolling.getInstance().start();
|
||||
};
|
||||
|
||||
const ModalContainer = () => {
|
||||
const confirmModalState = useSelector(getConfirmModal);
|
||||
const inviteModalState = useSelector(getInviteContactModal);
|
||||
const addModeratorsModalState = useSelector(getAddModeratorsModal);
|
||||
const removeModeratorsModalState = useSelector(getRemoveModeratorsModal);
|
||||
const updateGroupMembersModalState = useSelector(getUpdateGroupMembersModal);
|
||||
const updateGroupNameModalState = useSelector(getUpdateGroupNameModal);
|
||||
const userDetailsModalState = useSelector(getUserDetailsModal);
|
||||
const changeNicknameModal = useSelector(getChangeNickNameDialog);
|
||||
const editProfileModalState = useSelector(getEditProfileDialog);
|
||||
const onionPathModalState = useSelector(getOnionPathDialog);
|
||||
const recoveryPhraseModalState = useSelector(getRecoveryPhraseDialog);
|
||||
const adminLeaveClosedGroupModalState = useSelector(getAdminLeaveClosedGroupDialog);
|
||||
|
||||
return (
|
||||
<>
|
||||
{confirmModalState && <SessionConfirm {...confirmModalState} />}
|
||||
{inviteModalState && <InviteContactsDialog {...inviteModalState} />}
|
||||
{addModeratorsModalState && <AddModeratorsDialog {...addModeratorsModalState} />}
|
||||
{removeModeratorsModalState && <RemoveModeratorsDialog {...removeModeratorsModalState} />}
|
||||
{updateGroupMembersModalState && (
|
||||
<UpdateGroupMembersDialog {...updateGroupMembersModalState} />
|
||||
)}
|
||||
{updateGroupNameModalState && <UpdateGroupNameDialog {...updateGroupNameModalState} />}
|
||||
{userDetailsModalState && <UserDetailsDialog {...userDetailsModalState} />}
|
||||
{changeNicknameModal && <SessionNicknameDialog {...changeNicknameModal} />}
|
||||
{editProfileModalState && <EditProfileDialog {...editProfileModalState} />}
|
||||
{onionPathModalState && <OnionPathModal {...onionPathModalState} />}
|
||||
{recoveryPhraseModalState && <SessionSeedModal {...recoveryPhraseModalState} />}
|
||||
{adminLeaveClosedGroupModalState && (
|
||||
<AdminLeaveClosedGroupDialog {...adminLeaveClosedGroupModalState} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* ActionsPanel is the far left banner (not the left pane).
|
||||
* The panel with buttons to switch between the message/contact/settings/theme views
|
||||
|
|
68
ts/components/session/ModalContainer.tsx
Normal file
68
ts/components/session/ModalContainer.tsx
Normal file
|
@ -0,0 +1,68 @@
|
|||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import {
|
||||
getAddModeratorsModal,
|
||||
getAdminLeaveClosedGroupDialog,
|
||||
getChangeNickNameDialog,
|
||||
getConfirmModal,
|
||||
getEditProfileDialog,
|
||||
getInviteContactModal,
|
||||
getOnionPathDialog,
|
||||
getRecoveryPhraseDialog,
|
||||
getRemoveModeratorsModal,
|
||||
getSessionPasswordDialog,
|
||||
getUpdateGroupMembersModal,
|
||||
getUpdateGroupNameModal,
|
||||
getUserDetailsModal,
|
||||
} from '../../state/selectors/modal';
|
||||
import { AdminLeaveClosedGroupDialog } from '../conversation/AdminLeaveClosedGroupDialog';
|
||||
import { InviteContactsDialog } from '../conversation/InviteContactsDialog';
|
||||
import { AddModeratorsDialog } from '../conversation/ModeratorsAddDialog';
|
||||
import { RemoveModeratorsDialog } from '../conversation/ModeratorsRemoveDialog';
|
||||
import { UpdateGroupMembersDialog } from '../conversation/UpdateGroupMembersDialog';
|
||||
import { UpdateGroupNameDialog } from '../conversation/UpdateGroupNameDialog';
|
||||
import { EditProfileDialog } from '../EditProfileDialog';
|
||||
import { OnionPathModal } from '../OnionStatusPathDialog';
|
||||
import { UserDetailsDialog } from '../UserDetailsDialog';
|
||||
import { SessionConfirm } from './SessionConfirm';
|
||||
import { SessionNicknameDialog } from './SessionNicknameDialog';
|
||||
import { SessionPasswordModal } from './SessionPasswordModal';
|
||||
import { SessionSeedModal } from './SessionSeedModal';
|
||||
|
||||
export const ModalContainer = () => {
|
||||
const confirmModalState = useSelector(getConfirmModal);
|
||||
const inviteModalState = useSelector(getInviteContactModal);
|
||||
const addModeratorsModalState = useSelector(getAddModeratorsModal);
|
||||
const removeModeratorsModalState = useSelector(getRemoveModeratorsModal);
|
||||
const updateGroupMembersModalState = useSelector(getUpdateGroupMembersModal);
|
||||
const updateGroupNameModalState = useSelector(getUpdateGroupNameModal);
|
||||
const userDetailsModalState = useSelector(getUserDetailsModal);
|
||||
const changeNicknameModal = useSelector(getChangeNickNameDialog);
|
||||
const editProfileModalState = useSelector(getEditProfileDialog);
|
||||
const onionPathModalState = useSelector(getOnionPathDialog);
|
||||
const recoveryPhraseModalState = useSelector(getRecoveryPhraseDialog);
|
||||
const adminLeaveClosedGroupModalState = useSelector(getAdminLeaveClosedGroupDialog);
|
||||
const sessionPasswordModalState = useSelector(getSessionPasswordDialog);
|
||||
|
||||
return (
|
||||
<>
|
||||
{confirmModalState && <SessionConfirm {...confirmModalState} />}
|
||||
{inviteModalState && <InviteContactsDialog {...inviteModalState} />}
|
||||
{addModeratorsModalState && <AddModeratorsDialog {...addModeratorsModalState} />}
|
||||
{removeModeratorsModalState && <RemoveModeratorsDialog {...removeModeratorsModalState} />}
|
||||
{updateGroupMembersModalState && (
|
||||
<UpdateGroupMembersDialog {...updateGroupMembersModalState} />
|
||||
)}
|
||||
{updateGroupNameModalState && <UpdateGroupNameDialog {...updateGroupNameModalState} />}
|
||||
{userDetailsModalState && <UserDetailsDialog {...userDetailsModalState} />}
|
||||
{changeNicknameModal && <SessionNicknameDialog {...changeNicknameModal} />}
|
||||
{editProfileModalState && <EditProfileDialog {...editProfileModalState} />}
|
||||
{onionPathModalState && <OnionPathModal {...onionPathModalState} />}
|
||||
{recoveryPhraseModalState && <SessionSeedModal {...recoveryPhraseModalState} />}
|
||||
{adminLeaveClosedGroupModalState && (
|
||||
<AdminLeaveClosedGroupDialog {...adminLeaveClosedGroupModalState} />
|
||||
)}
|
||||
{sessionPasswordModalState && <SessionPasswordModal {...sessionPasswordModalState} />}
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -1,25 +1,19 @@
|
|||
import React from 'react';
|
||||
|
||||
import { SessionModal } from './SessionModal';
|
||||
import { SessionButton, SessionButtonColor } from './SessionButton';
|
||||
import { missingCaseError, PasswordUtil } from '../../util/';
|
||||
import { ToastUtils } from '../../session/utils';
|
||||
import { SessionIconType } from './icon';
|
||||
import { DefaultTheme, withTheme } from 'styled-components';
|
||||
import { getPasswordHash } from '../../data/data';
|
||||
import { SessionWrapperModal } from './SessionWrapperModal';
|
||||
import { SpacerLG, SpacerSM } from '../basic/Text';
|
||||
export enum PasswordAction {
|
||||
Set = 'set',
|
||||
Change = 'change',
|
||||
Remove = 'remove',
|
||||
}
|
||||
import autoBind from 'auto-bind';
|
||||
import { sessionPassword } from '../../state/ducks/modalDialog';
|
||||
export type PasswordAction = 'set' | 'change' | 'remove';
|
||||
|
||||
interface Props {
|
||||
action: PasswordAction;
|
||||
onOk: any;
|
||||
onClose: any;
|
||||
theme: DefaultTheme;
|
||||
passwordAction: PasswordAction;
|
||||
onOk: () => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -29,7 +23,7 @@ interface State {
|
|||
currentPasswordRetypeEntered: string | null;
|
||||
}
|
||||
|
||||
class SessionPasswordModalInner extends React.Component<Props, State> {
|
||||
export class SessionPasswordModal extends React.Component<Props, State> {
|
||||
private passportInput: HTMLInputElement | null = null;
|
||||
|
||||
constructor(props: any) {
|
||||
|
@ -42,14 +36,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
|
|||
currentPasswordRetypeEntered: null,
|
||||
};
|
||||
|
||||
this.showError = this.showError.bind(this);
|
||||
|
||||
this.setPassword = this.setPassword.bind(this);
|
||||
this.closeDialog = this.closeDialog.bind(this);
|
||||
|
||||
this.onPasswordInput = this.onPasswordInput.bind(this);
|
||||
this.onPasswordConfirmInput = this.onPasswordConfirmInput.bind(this);
|
||||
this.onPasswordRetypeInput = this.onPasswordRetypeInput.bind(this);
|
||||
autoBind(this);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
|
@ -60,9 +47,9 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
const { action, onOk } = this.props;
|
||||
const { passwordAction } = this.props;
|
||||
const placeholders =
|
||||
action === PasswordAction.Change
|
||||
passwordAction === 'change'
|
||||
? [
|
||||
window.i18n('typeInOldPassword'),
|
||||
window.i18n('enterPassword'),
|
||||
|
@ -71,10 +58,13 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
|
|||
: [window.i18n('enterPassword'), window.i18n('confirmPassword')];
|
||||
|
||||
const confirmButtonColor =
|
||||
action === PasswordAction.Remove ? SessionButtonColor.Danger : SessionButtonColor.Primary;
|
||||
passwordAction === 'remove' ? SessionButtonColor.Danger : SessionButtonColor.Primary;
|
||||
|
||||
return (
|
||||
<SessionWrapperModal title={window.i18n(`${action}Password`)} onClose={this.closeDialog}>
|
||||
<SessionWrapperModal
|
||||
title={window.i18n(`${passwordAction}Password`)}
|
||||
onClose={this.closeDialog}
|
||||
>
|
||||
<SpacerSM />
|
||||
|
||||
<div className="session-modal__input-group">
|
||||
|
@ -87,7 +77,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
|
|||
placeholder={placeholders[0]}
|
||||
onKeyUp={this.onPasswordInput}
|
||||
/>
|
||||
{action !== PasswordAction.Remove && (
|
||||
{passwordAction !== 'remove' && (
|
||||
<input
|
||||
type="password"
|
||||
id="password-modal-input-confirm"
|
||||
|
@ -95,7 +85,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
|
|||
onKeyUp={this.onPasswordConfirmInput}
|
||||
/>
|
||||
)}
|
||||
{action === PasswordAction.Change && (
|
||||
{passwordAction === 'change' && (
|
||||
<input
|
||||
type="password"
|
||||
id="password-modal-input-reconfirm"
|
||||
|
@ -183,7 +173,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
|
|||
SessionIconType.Lock
|
||||
);
|
||||
|
||||
this.props.onOk(this.props.action);
|
||||
this.props.onOk();
|
||||
this.closeDialog();
|
||||
}
|
||||
|
||||
|
@ -222,7 +212,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
|
|||
SessionIconType.Lock
|
||||
);
|
||||
|
||||
this.props.onOk(this.props.action);
|
||||
this.props.onOk();
|
||||
this.closeDialog();
|
||||
}
|
||||
|
||||
|
@ -243,31 +233,30 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
|
|||
window.i18n('removePasswordToastDescription')
|
||||
);
|
||||
|
||||
this.props.onOk(this.props.action);
|
||||
this.props.onOk();
|
||||
this.closeDialog();
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: cyclomatic-complexity
|
||||
private async setPassword() {
|
||||
const { action } = this.props;
|
||||
const { passwordAction } = this.props;
|
||||
const {
|
||||
currentPasswordEntered,
|
||||
currentPasswordConfirmEntered,
|
||||
currentPasswordRetypeEntered,
|
||||
} = this.state;
|
||||
const { Set, Remove, Change } = PasswordAction;
|
||||
|
||||
// Trim leading / trailing whitespace for UX
|
||||
const firstPasswordEntered = (currentPasswordEntered || '').trim();
|
||||
const secondPasswordEntered = (currentPasswordConfirmEntered || '').trim();
|
||||
const thirdPasswordEntered = (currentPasswordRetypeEntered || '').trim();
|
||||
|
||||
switch (action) {
|
||||
case Set: {
|
||||
switch (passwordAction) {
|
||||
case 'set': {
|
||||
await this.handleActionSet(firstPasswordEntered, secondPasswordEntered);
|
||||
return;
|
||||
}
|
||||
case Change: {
|
||||
case 'change': {
|
||||
await this.handleActionChange(
|
||||
firstPasswordEntered,
|
||||
secondPasswordEntered,
|
||||
|
@ -275,19 +264,17 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
|
|||
);
|
||||
return;
|
||||
}
|
||||
case Remove: {
|
||||
case 'remove': {
|
||||
await this.handleActionRemove(firstPasswordEntered);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
throw missingCaseError(action);
|
||||
throw missingCaseError(passwordAction);
|
||||
}
|
||||
}
|
||||
|
||||
private closeDialog() {
|
||||
if (this.props.onClose) {
|
||||
this.props.onClose();
|
||||
}
|
||||
window.inboxStore?.dispatch(sessionPassword(null));
|
||||
}
|
||||
|
||||
private async onPasswordInput(event: any) {
|
||||
|
@ -317,5 +304,3 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
|
|||
this.setState({ currentPasswordRetypeEntered });
|
||||
}
|
||||
}
|
||||
|
||||
export const SessionPasswordModal = withTheme(SessionPasswordModalInner);
|
||||
|
|
|
@ -33,15 +33,9 @@ import { SessionMemberListItem } from '../SessionMemberListItem';
|
|||
import autoBind from 'auto-bind';
|
||||
import { SectionType } from '../ActionsPanel';
|
||||
import { SessionSettingCategory } from '../settings/SessionSettings';
|
||||
import {
|
||||
defaultMentionsInputReducer,
|
||||
updateMentionsMembers,
|
||||
} from '../../../state/ducks/mentionsInput';
|
||||
import { getMentionsInput } from '../../../state/selectors/mentionsInput';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { updateConfirmModal } from '../../../state/ducks/modalDialog';
|
||||
import { SessionButtonColor } from '../SessionButton';
|
||||
import { any } from 'underscore';
|
||||
import { SessionConfirmDialogProps } from '../SessionConfirm';
|
||||
|
||||
export interface ReplyingToMessageProps {
|
||||
|
@ -93,7 +87,6 @@ interface Props {
|
|||
showLeftPaneSection: (section: SectionType) => void;
|
||||
showSettingsSection: (category: SessionSettingCategory) => void;
|
||||
theme: DefaultTheme;
|
||||
updateConfirmModal: (props: SessionConfirmDialogProps) => any;
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -247,15 +240,17 @@ export class SessionCompositionBox extends React.Component<Props, State> {
|
|||
private showLinkSharingConfirmationModalDialog(e: any) {
|
||||
const pastedText = e.clipboardData.getData('text');
|
||||
if (this.isURL(pastedText)) {
|
||||
this.props.updateConfirmModal({
|
||||
shouldShowConfirm: () => !window.getSettingValue('link-preview-setting'),
|
||||
title: window.i18n('linkPreviewsTitle'),
|
||||
message: window.i18n('linkPreviewsConfirmMessage'),
|
||||
okTheme: SessionButtonColor.Danger,
|
||||
onClickOk: () => {
|
||||
window.setSettingValue('link-preview-setting', true);
|
||||
},
|
||||
});
|
||||
window.inboxStore?.dispatch(
|
||||
updateConfirmModal({
|
||||
shouldShowConfirm: () => !window.getSettingValue('link-preview-setting'),
|
||||
title: window.i18n('linkPreviewsTitle'),
|
||||
message: window.i18n('linkPreviewsConfirmMessage'),
|
||||
okTheme: SessionButtonColor.Danger,
|
||||
onClickOk: () => {
|
||||
window.setSettingValue('link-preview-setting', true);
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -304,7 +304,6 @@ export class SessionConversation extends React.Component<Props, State> {
|
|||
removeAttachment={this.removeAttachment}
|
||||
onChoseAttachments={this.onChoseAttachments}
|
||||
theme={this.props.theme}
|
||||
updateConfirmModal={actions.updateConfirmModal}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -62,43 +62,51 @@ const rotate = keyframes`
|
|||
* Creates a glow animation made for multiple element sequentially
|
||||
*/
|
||||
const glow = (color: string, glowDuration: number, glowStartDelay: number) => {
|
||||
const dropShadowType = `drop-shadow(0px 0px 4px ${color}) `;
|
||||
|
||||
//increase shadow intensity by 3
|
||||
const dropShadow = `${dropShadowType.repeat(1)};`;
|
||||
const dropShadow = `drop-shadow(0px 0px 6px ${color});`;
|
||||
|
||||
// creating keyframe for sequential animations
|
||||
let kf = '';
|
||||
for (let i = 0; i <= glowDuration; i++) {
|
||||
// const percent = (100 / glowDuration) * i;
|
||||
const percent = (100 / glowDuration) * i;
|
||||
if (i === glowStartDelay) {
|
||||
const durationWithLoop = glowDuration + 1;
|
||||
for (let i = 0; i <= durationWithLoop; i++) {
|
||||
const percent = (100 / durationWithLoop) * i;
|
||||
|
||||
if (i === glowStartDelay + 1) {
|
||||
kf += `${percent}% {
|
||||
filter: ${dropShadow}
|
||||
transform: scale(1.5);
|
||||
transform: scale(1.1);
|
||||
}`;
|
||||
} else {
|
||||
kf += `${percent}% {
|
||||
filter: none;
|
||||
transform: scale(0.8);
|
||||
transform: scale(0.9);
|
||||
}`;
|
||||
}
|
||||
}
|
||||
return keyframes`${kf}`;
|
||||
};
|
||||
|
||||
const animation = (props: any) => {
|
||||
const animation = (props: {
|
||||
rotateDuration?: number;
|
||||
glowDuration?: number;
|
||||
glowStartDelay?: number;
|
||||
iconColor?: string;
|
||||
}) => {
|
||||
if (props.rotateDuration) {
|
||||
return css`
|
||||
${rotate} ${props.rotateDuration}s infinite linear;
|
||||
`;
|
||||
} else if (props.glowDuration !== undefined && props.glowStartDelay !== undefined) {
|
||||
} else if (
|
||||
props.glowDuration !== undefined &&
|
||||
props.glowStartDelay !== undefined &&
|
||||
props.iconColor
|
||||
) {
|
||||
return css`
|
||||
${glow(
|
||||
props.iconColor,
|
||||
props.glowDuration,
|
||||
props.glowStartDelay
|
||||
)} ${props.glowDuration}s ease-in infinite;
|
||||
)} ${props.glowDuration}s ease infinite;
|
||||
`;
|
||||
} else {
|
||||
return;
|
||||
|
|
|
@ -10,7 +10,6 @@ import {
|
|||
updateConfirmModal,
|
||||
} from '../../../state/ducks/modalDialog';
|
||||
import { ConversationController } from '../../../session/conversations';
|
||||
import { UserUtils } from '../../../session/utils';
|
||||
import {
|
||||
blockConvoById,
|
||||
clearNickNameByConvoId,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import React from 'react';
|
||||
|
||||
// tslint:disable-next-line: no-submodule-imports
|
||||
import useNetworkState from 'react-use/lib/useNetworkState';
|
||||
import styled from 'styled-components';
|
||||
import { useNetwork } from '../../../hooks/useNetwork';
|
||||
|
||||
type ContainerProps = {
|
||||
show: boolean;
|
||||
|
@ -24,8 +26,7 @@ const OfflineTitle = styled.h3`
|
|||
const OfflineMessage = styled.div``;
|
||||
|
||||
export const SessionOffline = () => {
|
||||
const isOnline = useNetwork();
|
||||
|
||||
const isOnline = useNetworkState().online;
|
||||
return (
|
||||
<OfflineContainer show={!isOnline}>
|
||||
<OfflineTitle>{window.i18n('offline')}</OfflineTitle>
|
||||
|
|
|
@ -12,11 +12,12 @@ import { connect, useSelector } from 'react-redux';
|
|||
import { getPasswordHash } from '../../../../ts/data/data';
|
||||
import { SpacerLG, SpacerXS } from '../../basic/Text';
|
||||
import { shell } from 'electron';
|
||||
import { PasswordAction, SessionPasswordModal } from '../SessionPasswordModal';
|
||||
import { SessionConfirmDialogProps } from '../SessionConfirm';
|
||||
import { mapDispatchToProps } from '../../../state/actions';
|
||||
import { unblockConvoById } from '../../../interactions/conversationInteractions';
|
||||
import { toggleAudioAutoplay } from '../../../state/ducks/userConfig';
|
||||
import { sessionPassword } from '../../../state/ducks/modalDialog';
|
||||
import { PasswordAction } from '../SessionPasswordModal';
|
||||
|
||||
export enum SessionSettingCategory {
|
||||
Appearance = 'appearance',
|
||||
|
@ -47,7 +48,6 @@ interface State {
|
|||
pwdLockError: string | null;
|
||||
mediaSetting: boolean | null;
|
||||
shouldLockSettings: boolean | null;
|
||||
modal: JSX.Element | null;
|
||||
}
|
||||
|
||||
interface ConfirmationDialogParams extends SessionConfirmDialogProps {
|
||||
|
@ -80,7 +80,6 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
|
|||
pwdLockError: null,
|
||||
mediaSetting: null,
|
||||
shouldLockSettings: true,
|
||||
modal: null,
|
||||
};
|
||||
|
||||
this.settingsViewRef = React.createRef();
|
||||
|
@ -174,12 +173,8 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
|
|||
<h3>{window.i18n('password')}</h3>
|
||||
<input type="password" id="password-lock-input" defaultValue="" placeholder="Password" />
|
||||
|
||||
<SpacerXS />
|
||||
{this.state.pwdLockError && (
|
||||
<>
|
||||
<div className="session-label warning">{this.state.pwdLockError}</div>
|
||||
<SpacerLG />
|
||||
</>
|
||||
<div className="session-label warning">{this.state.pwdLockError}</div>
|
||||
)}
|
||||
|
||||
<SessionButton
|
||||
|
@ -234,8 +229,6 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
|
|||
categoryTitle={window.i18n(`${category}SettingsTitle`)}
|
||||
/>
|
||||
|
||||
{this.state.modal ? this.state.modal : null}
|
||||
|
||||
<div className="session-settings-view">
|
||||
{shouldRenderPasswordLock ? (
|
||||
this.renderPasswordLock()
|
||||
|
@ -529,7 +522,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
|
|||
buttonColor: SessionButtonColor.Primary,
|
||||
},
|
||||
onClick: () => {
|
||||
this.displayPasswordModal(PasswordAction.Set);
|
||||
this.displayPasswordModal('set');
|
||||
},
|
||||
confirmationDialogParams: undefined,
|
||||
},
|
||||
|
@ -547,7 +540,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
|
|||
buttonColor: SessionButtonColor.Primary,
|
||||
},
|
||||
onClick: () => {
|
||||
this.displayPasswordModal(PasswordAction.Change);
|
||||
this.displayPasswordModal('change');
|
||||
},
|
||||
confirmationDialogParams: undefined,
|
||||
},
|
||||
|
@ -565,7 +558,7 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
|
|||
buttonColor: SessionButtonColor.Danger,
|
||||
},
|
||||
onClick: () => {
|
||||
this.displayPasswordModal(PasswordAction.Remove);
|
||||
this.displayPasswordModal('remove');
|
||||
},
|
||||
confirmationDialogParams: undefined,
|
||||
},
|
||||
|
@ -573,25 +566,14 @@ class SettingsViewInner extends React.Component<SettingsViewProps, State> {
|
|||
}
|
||||
|
||||
private displayPasswordModal(passwordAction: PasswordAction) {
|
||||
this.setState({
|
||||
...this.state,
|
||||
modal: (
|
||||
<SessionPasswordModal
|
||||
onClose={() => {
|
||||
this.clearModal();
|
||||
}}
|
||||
onOk={this.onPasswordUpdated}
|
||||
action={passwordAction}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
private clearModal(): void {
|
||||
this.setState({
|
||||
...this.state,
|
||||
modal: null,
|
||||
});
|
||||
window.inboxStore?.dispatch(
|
||||
sessionPassword({
|
||||
passwordAction,
|
||||
onOk: () => {
|
||||
this.onPasswordUpdated(passwordAction);
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private getBlockedUserSettings(): Array<LocalSettingType> {
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
|
||||
export function useNetwork() {
|
||||
const [isOnline, setNetwork] = useState(window.navigator.onLine);
|
||||
const updateNetwork = () => {
|
||||
setNetwork(window.navigator.onLine);
|
||||
};
|
||||
|
||||
// there are some weird behavior with this api.
|
||||
// basically, online events might not be called if the pc has a virtual machine running
|
||||
// https://github.com/electron/electron/issues/11290#issuecomment-348598311
|
||||
useEffect(() => {
|
||||
window.addEventListener('offline', updateNetwork);
|
||||
window.addEventListener('online', updateNetwork);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('offline', updateNetwork);
|
||||
window.removeEventListener('online', updateNetwork);
|
||||
};
|
||||
});
|
||||
return isOnline;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { SessionConfirmDialogProps } from '../../components/session/SessionConfirm';
|
||||
import { PasswordAction } from '../../components/session/SessionPasswordModal';
|
||||
|
||||
export type ConfirmModalState = SessionConfirmDialogProps | null;
|
||||
export type InviteContactModalState = { conversationId: string } | null;
|
||||
|
@ -13,6 +14,8 @@ export type EditProfileModalState = {} | null;
|
|||
export type OnionPathModalState = EditProfileModalState;
|
||||
export type RecoveryPhraseModalState = EditProfileModalState;
|
||||
|
||||
export type SessionPasswordModalState = { passwordAction: PasswordAction; onOk: () => void } | null;
|
||||
|
||||
export type UserDetailsModalState = {
|
||||
conversationId: string;
|
||||
authorAvatarPath?: string;
|
||||
|
@ -32,6 +35,7 @@ export type ModalState = {
|
|||
onionPathModal: OnionPathModalState;
|
||||
recoveryPhraseModal: RecoveryPhraseModalState;
|
||||
adminLeaveClosedGroup: AdminLeaveClosedGroupModalState;
|
||||
sessionPasswordModal: SessionPasswordModalState;
|
||||
};
|
||||
|
||||
export const initialModalState: ModalState = {
|
||||
|
@ -47,6 +51,7 @@ export const initialModalState: ModalState = {
|
|||
onionPathModal: null,
|
||||
recoveryPhraseModal: null,
|
||||
adminLeaveClosedGroup: null,
|
||||
sessionPasswordModal: null,
|
||||
};
|
||||
|
||||
const ModalSlice = createSlice({
|
||||
|
@ -89,6 +94,9 @@ const ModalSlice = createSlice({
|
|||
adminLeaveClosedGroup(state, action: PayloadAction<AdminLeaveClosedGroupModalState | null>) {
|
||||
return { ...state, adminLeaveClosedGroup: action.payload };
|
||||
},
|
||||
sessionPassword(state, action: PayloadAction<SessionPasswordModalState>) {
|
||||
return { ...state, sessionPasswordModal: action.payload };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -106,5 +114,6 @@ export const {
|
|||
onionPathModal,
|
||||
recoveryPhraseModal,
|
||||
adminLeaveClosedGroup,
|
||||
sessionPassword,
|
||||
} = actions;
|
||||
export const modalReducer = reducer;
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
OnionPathModalState,
|
||||
RecoveryPhraseModalState,
|
||||
RemoveModeratorsModalState,
|
||||
SessionPasswordModalState,
|
||||
UpdateGroupMembersModalState,
|
||||
UpdateGroupNameModalState,
|
||||
UserDetailsModalState,
|
||||
|
@ -80,3 +81,8 @@ export const getAdminLeaveClosedGroupDialog = createSelector(
|
|||
getModal,
|
||||
(state: ModalState): AdminLeaveClosedGroupModalState => state.adminLeaveClosedGroup
|
||||
);
|
||||
|
||||
export const getSessionPasswordDialog = createSelector(
|
||||
getModal,
|
||||
(state: ModalState): SessionPasswordModalState => state.sessionPasswordModal
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue