Merge branch 'unstable' into feat/ses-50/onboarding

pull/3056/head
William Grant 2 years ago
commit 208d9cc0eb

@ -2,7 +2,7 @@
"name": "session-desktop", "name": "session-desktop",
"productName": "Session", "productName": "Session",
"description": "Private messaging from your desktop", "description": "Private messaging from your desktop",
"version": "1.12.1", "version": "1.12.2",
"license": "GPL-3.0", "license": "GPL-3.0",
"author": { "author": {
"name": "Oxen Labs", "name": "Oxen Labs",

@ -29,7 +29,7 @@ window.getNodeVersion = () => configAny.node_version;
window.sessionFeatureFlags = { window.sessionFeatureFlags = {
useOnionRequests: true, useOnionRequests: true,
useTestNet: isTestNet(), useTestNet: isTestNet() || isTestIntegration(),
integrationTestEnv: isTestIntegration(), integrationTestEnv: isTestIntegration(),
useClosedGroupV3: false, useClosedGroupV3: false,
debug: { debug: {

@ -153,7 +153,6 @@ $session-margin-md: 15px;
$session-margin-lg: 20px; $session-margin-lg: 20px;
// Animations // Animations
$session-transition-duration: 0.25s;
@keyframes fadein { @keyframes fadein {
from { from {

@ -172,13 +172,13 @@
} }
.rc-slider-tooltip-zoom-down-enter, .rc-slider-tooltip-zoom-down-enter,
.rc-slider-tooltip-zoom-down-appear { .rc-slider-tooltip-zoom-down-appear {
animation-duration: 0.3s; animation-duration: var(--default-duration);
animation-fill-mode: both; animation-fill-mode: both;
display: block !important; display: block !important;
animation-play-state: paused; animation-play-state: paused;
} }
.rc-slider-tooltip-zoom-down-leave { .rc-slider-tooltip-zoom-down-leave {
animation-duration: 0.3s; animation-duration: var(--default-duration);
animation-fill-mode: both; animation-fill-mode: both;
display: block !important; display: block !important;
animation-play-state: paused; animation-play-state: paused;

@ -0,0 +1,21 @@
import FocusTrap from 'focus-trap-react';
import { ReactNode, useState } from 'react';
import { useMount } from 'react-use';
/**
* Focus trap which activates on mount.
*/
export function SessionFocusTrap(props: { children: ReactNode }) {
const [active, setActive] = useState(false);
// Activate the trap on mount so we **should** have a button to tab through. focus-trap-react will throw if we don't have a button when the trap becomes active.
// We might still have an issue for dialogs which have buttons added with a useEffect, or asynchronously but have no buttons on mount.
// If that happens we will need to force those dialogs to have at least one button so focus-trap-react does not throw.
useMount(() => setActive(true));
return (
<FocusTrap active={active} focusTrapOptions={{ initialFocus: false, allowOutsideClick: true }}>
{props.children}
</FocusTrap>
);
}

@ -1,11 +1,11 @@
import classNames from 'classnames'; import classNames from 'classnames';
import FocusTrap from 'focus-trap-react'; import { ReactNode, useRef } from 'react';
import { useRef } from 'react';
import useKey from 'react-use/lib/useKey'; import useKey from 'react-use/lib/useKey';
import { SessionIconButton } from './icon'; import { SessionIconButton } from './icon';
import { SessionButton, SessionButtonColor, SessionButtonType } from './basic/SessionButton'; import { SessionButton, SessionButtonColor, SessionButtonType } from './basic/SessionButton';
import { SessionFocusTrap } from './SessionFocusTrap';
export type SessionWrapperModalType = { export type SessionWrapperModalType = {
title?: string; title?: string;
@ -17,7 +17,7 @@ export type SessionWrapperModalType = {
cancelText?: string; cancelText?: string;
showExitIcon?: boolean; showExitIcon?: boolean;
headerIconButtons?: Array<any>; headerIconButtons?: Array<any>;
children: any; children: ReactNode;
headerReverse?: boolean; headerReverse?: boolean;
additionalClassName?: string; additionalClassName?: string;
}; };
@ -64,7 +64,7 @@ export const SessionWrapperModal = (props: SessionWrapperModalType) => {
}; };
return ( return (
<FocusTrap focusTrapOptions={{ initialFocus: false, allowOutsideClick: true }}> <SessionFocusTrap>
<div <div
className={classNames('loki-dialog modal', additionalClassName || null)} className={classNames('loki-dialog modal', additionalClassName || null)}
onClick={handleClick} onClick={handleClick}
@ -128,6 +128,6 @@ export const SessionWrapperModal = (props: SessionWrapperModalType) => {
</div> </div>
</div> </div>
</div> </div>
</FocusTrap> </SessionFocusTrap>
); );
}; };

@ -355,7 +355,7 @@ const StyledCallWindowControls = styled.div<{ isFullScreen: boolean; makeVisible
margin-right: auto; margin-right: auto;
left: 0; left: 0;
right: 0; right: 0;
transition: all 0.25s ease-in-out; transition: all var(--default-duration) ease-in-out;
display: flex; display: flex;
justify-content: center; justify-content: center;

@ -20,7 +20,7 @@ export const styleForCompositionBoxSuggestions = (dir: HTMLDirection = 'ltr') =>
paddingBottom: '5px', paddingBottom: '5px',
backgroundColor: 'var(--suggestions-background-color)', backgroundColor: 'var(--suggestions-background-color)',
color: 'var(--suggestions-text-color)', color: 'var(--suggestions-text-color)',
transition: '0.25s', transition: 'var(--default-duration)',
'&focused': { '&focused': {
backgroundColor: 'var(--suggestions-background-hover-color)', backgroundColor: 'var(--suggestions-background-hover-color)',

@ -1,4 +1,3 @@
import FocusTrap from 'focus-trap-react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import useKey from 'react-use/lib/useKey'; import useKey from 'react-use/lib/useKey';
@ -16,6 +15,7 @@ import {
SessionButtonType, SessionButtonType,
} from '../../basic/SessionButton'; } from '../../basic/SessionButton';
import { SessionIconButton } from '../../icon'; import { SessionIconButton } from '../../icon';
import { SessionFocusTrap } from '../../SessionFocusTrap';
export const SelectionOverlay = () => { export const SelectionOverlay = () => {
const selectedMessageIds = useSelector(getSelectedMessageIds); const selectedMessageIds = useSelector(getSelectedMessageIds);
@ -68,7 +68,7 @@ export const SelectionOverlay = () => {
const classNameAndId = 'message-selection-overlay'; const classNameAndId = 'message-selection-overlay';
return ( return (
<FocusTrap focusTrapOptions={{ initialFocus: false, allowOutsideClick: true }}> <SessionFocusTrap>
<div className={classNameAndId} id={classNameAndId}> <div className={classNameAndId} id={classNameAndId}>
<div className="close-button"> <div className="close-button">
<SessionIconButton iconType="exit" iconSize="medium" onClick={onCloseOverlay} /> <SessionIconButton iconType="exit" iconSize="medium" onClick={onCloseOverlay} />
@ -92,6 +92,6 @@ export const SelectionOverlay = () => {
/> />
</div> </div>
</div> </div>
</FocusTrap> </SessionFocusTrap>
); );
}; };

@ -62,6 +62,7 @@ const Password = (props: PasswordProps) => {
<input <input
type="password" type="password"
id="seed-input-password" id="seed-input-password"
data-testid="password-input"
placeholder={i18n('enterPassword')} placeholder={i18n('enterPassword')}
onKeyUp={onEnter} onKeyUp={onEnter}
/> />
@ -77,12 +78,14 @@ const Password = (props: PasswordProps) => {
text={i18n('done')} text={i18n('done')}
buttonType={SessionButtonType.Simple} buttonType={SessionButtonType.Simple}
onClick={confirmPassword} onClick={confirmPassword}
dataTestId="session-confirm-ok-button"
/> />
<SessionButton <SessionButton
text={i18n('cancel')} text={i18n('cancel')}
buttonType={SessionButtonType.Simple} buttonType={SessionButtonType.Simple}
buttonColor={SessionButtonColor.Danger} buttonColor={SessionButtonColor.Danger}
onClick={onClose} onClick={onClose}
dataTestId="session-confirm-cancel-button"
/> />
</div> </div>
</> </>

@ -29,7 +29,7 @@ const StyledProgressBarContainer = styled.div`
const StyledProgressBarInner = styled.div` const StyledProgressBarInner = styled.div`
background: var(--primary-color); background: var(--primary-color);
width: 100%; width: 100%;
transition: width 0.5s ease-in; transition: width var(--default-duration) ease-in;
height: 100%; height: 100%;
`; `;

@ -1,4 +1,4 @@
import { MouseEvent } from 'react'; import { MouseEvent, ReactNode } from 'react';
import { contextMenu } from 'react-contexify'; import { contextMenu } from 'react-contexify';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
@ -137,6 +137,6 @@ export const MessageRequestsBanner = (props: { handleOnClick: () => any }) => {
); );
}; };
const Portal = ({ children }: { children: any }) => { const Portal = ({ children }: { children: ReactNode }) => {
return createPortal(children, document.querySelector('.inbox.index') as Element); return createPortal(children, document.querySelector('.inbox.index') as Element);
}; };

@ -1,6 +1,6 @@
import classNames from 'classnames'; import classNames from 'classnames';
import { isNil } from 'lodash'; import { isNil } from 'lodash';
import { MouseEvent, useCallback } from 'react'; import { MouseEvent, ReactNode, useCallback } from 'react';
import { contextMenu } from 'react-contexify'; import { contextMenu } from 'react-contexify';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
@ -34,7 +34,7 @@ type PropsHousekeeping = {
type Props = { conversationId: string } & PropsHousekeeping; type Props = { conversationId: string } & PropsHousekeeping;
const Portal = ({ children }: { children: any }) => { const Portal = ({ children }: { children: ReactNode }) => {
return createPortal(children, document.querySelector('.inbox.index') as Element); return createPortal(children, document.querySelector('.inbox.index') as Element);
}; };

@ -14,7 +14,7 @@ const StyledActionRow = styled.button`
display: flex; display: flex;
align-items: center; align-items: center;
border-bottom: 1px var(--border-color) solid; border-bottom: 1px var(--border-color) solid;
transition-duration: 0.25s; transition-duration: var(--default-duration);
width: 100%; width: 100%;
&:first-child { &:first-child {

@ -15,7 +15,7 @@ import {
} from '../../state/onboarding/selectors/registration'; } from '../../state/onboarding/selectors/registration';
import { Storage } from '../../util/storage'; import { Storage } from '../../util/storage';
import { Flex } from '../basic/Flex'; import { Flex } from '../basic/Flex';
import { SpacerLG, SpacerSM, SpacerXS } from '../basic/Text'; import { SpacerSM, SpacerXL, SpacerXS } from '../basic/Text';
import { SessionIcon, SessionIconButton } from '../icon'; import { SessionIcon, SessionIconButton } from '../icon';
import { OnboardContainer } from './components'; import { OnboardContainer } from './components';
import { CreateAccount, RestoreAccount, Start } from './stages'; import { CreateAccount, RestoreAccount, Start } from './stages';
@ -44,7 +44,7 @@ export const RegistrationStages = () => {
return ( return (
<AnimatePresence> <AnimatePresence>
<StyledRegistrationContainer container={true} flexDirection="column"> <StyledRegistrationContainer container={true} flexDirection="column">
<Flex container={true} alignItems="center"> <Flex container={true} alignItems="center" height={'30px'}>
<SessionIcon iconColor="var(--primary-color)" iconSize={'huge'} iconType="brand" /> <SessionIcon iconColor="var(--primary-color)" iconSize={'huge'} iconType="brand" />
<SpacerXS /> <SpacerXS />
<div style={{ flexGrow: 1 }}> <div style={{ flexGrow: 1 }}>
@ -82,7 +82,7 @@ export const RegistrationStages = () => {
</Flex> </Flex>
<Flex container={true} flexDirection="column" alignItems="center"> <Flex container={true} flexDirection="column" alignItems="center">
<SpacerLG /> <SpacerXL />
<OnboardContainer <OnboardContainer
key={`${Onboarding[step]}-${step === Onboarding.CreateAccount ? AccountCreation[creationStep] : AccountRestoration[restorationStep]}`} key={`${Onboarding[step]}-${step === Onboarding.CreateAccount ? AccountCreation[creationStep] : AccountRestoration[restorationStep]}`}
animate={ animate={

@ -428,7 +428,7 @@ async function createWindow() {
}, 5000); }, 5000);
} }
if (isDevProd()) { if (isDevProd() && !isTestIntegration()) {
// Open the DevTools. // Open the DevTools.
mainWindow.webContents.openDevTools({ mainWindow.webContents.openDevTools({
mode: 'bottom', mode: 'bottom',

@ -69,6 +69,8 @@ export function extractWebSocketContent(
} }
let instance: SwarmPolling | undefined; let instance: SwarmPolling | undefined;
const timeouts: Array<NodeJS.Timeout> = [];
export const getSwarmPollingInstance = () => { export const getSwarmPollingInstance = () => {
if (!instance) { if (!instance) {
instance = new SwarmPolling(); instance = new SwarmPolling();
@ -96,9 +98,11 @@ export class SwarmPolling {
if (waitForFirstPoll) { if (waitForFirstPoll) {
await this.pollForAllKeys(); await this.pollForAllKeys();
} else { } else {
setTimeout(() => { timeouts.push(
void this.pollForAllKeys(); setTimeout(() => {
}, 4000); void this.pollForAllKeys();
}, 4000)
);
} }
} }
@ -110,6 +114,15 @@ export class SwarmPolling {
this.hasStarted = false; this.hasStarted = false;
} }
public stop(e?: Error) {
window.log.info('[swarmPolling] stopped swarm polling', e?.message || e || '');
for (let i = 0; i < timeouts.length; i++) {
clearTimeout(timeouts[i]);
}
this.resetSwarmPolling();
}
public forcePolledTimestamp(pubkey: PubKey, lastPoll: number) { public forcePolledTimestamp(pubkey: PubKey, lastPoll: number) {
this.groupPolling = this.groupPolling.map(group => { this.groupPolling = this.groupPolling.map(group => {
if (PubKey.isEqual(pubkey, group.pubkey)) { if (PubKey.isEqual(pubkey, group.pubkey)) {
@ -175,7 +188,7 @@ export class SwarmPolling {
if (!window.getGlobalOnlineStatus()) { if (!window.getGlobalOnlineStatus()) {
window?.log?.error('pollForAllKeys: offline'); window?.log?.error('pollForAllKeys: offline');
// Very important to set up a new polling call so we do retry at some point // Very important to set up a new polling call so we do retry at some point
setTimeout(this.pollForAllKeys.bind(this), SWARM_POLLING_TIMEOUT.ACTIVE); timeouts.push(setTimeout(this.pollForAllKeys.bind(this), SWARM_POLLING_TIMEOUT.ACTIVE));
return; return;
} }
// we always poll as often as possible for our pubkey // we always poll as often as possible for our pubkey
@ -212,7 +225,7 @@ export class SwarmPolling {
window?.log?.warn('pollForAllKeys exception: ', e); window?.log?.warn('pollForAllKeys exception: ', e);
throw e; throw e;
} finally { } finally {
setTimeout(this.pollForAllKeys.bind(this), SWARM_POLLING_TIMEOUT.ACTIVE); timeouts.push(setTimeout(this.pollForAllKeys.bind(this), SWARM_POLLING_TIMEOUT.ACTIVE));
} }
} }

@ -1,5 +1,6 @@
import { ipcRenderer } from 'electron'; import { ipcRenderer } from 'electron';
import { ReactNode } from 'react';
import { createGlobalStyle } from 'styled-components'; import { createGlobalStyle } from 'styled-components';
import { getOppositeTheme, isThemeMismatched } from '../util/theme'; import { getOppositeTheme, isThemeMismatched } from '../util/theme';
import { classicDark } from './classicDark'; import { classicDark } from './classicDark';
@ -14,7 +15,7 @@ const SessionGlobalStyles = createGlobalStyle`
}; };
`; `;
export const SessionTheme = ({ children }: { children: any }) => ( export const SessionTheme = ({ children }: { children: ReactNode }) => (
<> <>
<SessionGlobalStyles /> <SessionGlobalStyles />
{children} {children}

@ -1,3 +1,4 @@
import { isTestIntegration } from '../shared/env_vars';
import { hexColorToRGB } from '../util/hexColorToRGB'; import { hexColorToRGB } from '../util/hexColorToRGB';
import { COLORS } from './constants/colors'; import { COLORS } from './constants/colors';
@ -129,8 +130,8 @@ export const THEME_GLOBALS: ThemeGlobals = {
'--composition-container-height': '60px', '--composition-container-height': '60px',
'--search-input-height': '34px', '--search-input-height': '34px',
'--default-duration': '0.25s', '--default-duration': isTestIntegration() ? '0s' : '0.25s',
'--default-duration-seconds': '0.25', // framer-motion requires a number '--default-duration-seconds': isTestIntegration() ? '0' : '0.25', // framer-motion requires a number
'--green-color': COLORS.PRIMARY.GREEN, '--green-color': COLORS.PRIMARY.GREEN,
'--blue-color': COLORS.PRIMARY.BLUE, '--blue-color': COLORS.PRIMARY.BLUE,

Loading…
Cancel
Save