diff --git a/native/account/logged-out-modal.react.js b/native/account/logged-out-modal.react.js --- a/native/account/logged-out-modal.react.js +++ b/native/account/logged-out-modal.react.js @@ -92,6 +92,7 @@ max, stopClock, clockRunning, + useValue, } = Animated; export type LoggedOutMode = @@ -233,6 +234,12 @@ +mode: Mode, +setMode: (Partial) => void, +nextModeRef: { current: LoggedOutMode }, + +contentHeight: Value, + +keyboardHeightValue: Value, + +modeValue: Value, + +buttonOpacity: Value, + +panelPaddingTop: Node, + +panelOpacity: Node, // Navigation state +isForeground: boolean, // Redux state @@ -252,35 +259,12 @@ activeAlert = false; - contentHeight: Value; - keyboardHeightValue: Value = new Value(0); - modeValue: Value; - - buttonOpacity: Value; - panelPaddingTopValue: Node; - panelOpacityValue: Node; - - constructor(props: Props) { - super(props); - - this.contentHeight = new Value(props.dimensions.safeAreaHeight); - this.modeValue = new Value(modeNumbers[this.props.mode.curMode]); - - this.buttonOpacity = new Value(props.persistedStateLoaded ? 1 : 0); - this.panelPaddingTopValue = this.panelPaddingTop(); - this.panelOpacityValue = this.panelOpacity(); - } - setMode(newMode: LoggedOutMode) { this.props.nextModeRef.current = newMode; this.props.setMode({ curMode: newMode, nextMode: newMode }); - this.modeValue.setValue(modeNumbers[newMode]); + this.props.modeValue.setValue(modeNumbers[newMode]); } - proceedToNextMode = () => { - this.props.setMode({ curMode: this.props.nextModeRef.current }); - }; - componentDidMount() { if (this.props.rehydrateConcluded) { this.onInitialAppLoad(); @@ -313,8 +297,8 @@ this.props.mode.curMode === 'prompt' && prevProps.mode.curMode !== 'prompt' ) { - this.buttonOpacity.setValue(0); - Animated.timing(this.buttonOpacity, { + this.props.buttonOpacity.setValue(0); + Animated.timing(this.props.buttonOpacity, { easing: EasingNode.out(EasingNode.ease), duration: 250, toValue: 1.0, @@ -324,7 +308,7 @@ const newContentHeight = this.props.dimensions.safeAreaHeight; const oldContentHeight = prevProps.dimensions.safeAreaHeight; if (newContentHeight !== oldContentHeight) { - this.contentHeight.setValue(newContentHeight); + this.props.contentHeight.setValue(newContentHeight); } } @@ -384,109 +368,6 @@ return false; }; - panelPaddingTop(): Node { - const headerHeight = Platform.OS === 'ios' ? 62.33 : 58.54; - const promptButtonsSize = Platform.OS === 'ios' ? 40 : 61; - const logInContainerSize = 140; - const registerPanelSize = Platform.OS === 'ios' ? 181 : 180; - const siwePanelSize = 250; - - const containerSize = add( - headerHeight, - cond(not(isPastPrompt(this.modeValue)), promptButtonsSize, 0), - cond(eq(this.modeValue, modeNumbers['log-in']), logInContainerSize, 0), - cond(eq(this.modeValue, modeNumbers['register']), registerPanelSize, 0), - cond(eq(this.modeValue, modeNumbers['siwe']), siwePanelSize, 0), - ); - const potentialPanelPaddingTop = divide( - max(sub(this.contentHeight, this.keyboardHeightValue, containerSize), 0), - 2, - ); - - const panelPaddingTop = new Value(-1); - const targetPanelPaddingTop = new Value(-1); - const prevModeValue = new Value( - modeNumbers[this.props.nextModeRef.current], - ); - const clock = new Clock(); - const keyboardTimeoutClock = new Clock(); - return block([ - cond(lessThan(panelPaddingTop, 0), [ - set(panelPaddingTop, potentialPanelPaddingTop), - set(targetPanelPaddingTop, potentialPanelPaddingTop), - ]), - cond( - lessThan(this.keyboardHeightValue, 0), - [ - runTiming(keyboardTimeoutClock, 0, 1, true, { duration: 500 }), - cond( - not(clockRunning(keyboardTimeoutClock)), - set(this.keyboardHeightValue, 0), - ), - ], - stopClock(keyboardTimeoutClock), - ), - cond( - and( - greaterOrEq(this.keyboardHeightValue, 0), - neq(prevModeValue, this.modeValue), - ), - [ - stopClock(clock), - cond( - neq(isPastPrompt(prevModeValue), isPastPrompt(this.modeValue)), - set(targetPanelPaddingTop, potentialPanelPaddingTop), - ), - set(prevModeValue, this.modeValue), - ], - ), - ratchetAlongWithKeyboardHeight(this.keyboardHeightValue, [ - stopClock(clock), - set(targetPanelPaddingTop, potentialPanelPaddingTop), - ]), - cond( - neq(panelPaddingTop, targetPanelPaddingTop), - set( - panelPaddingTop, - runTiming(clock, panelPaddingTop, targetPanelPaddingTop), - ), - ), - panelPaddingTop, - ]); - } - - panelOpacity(): Node { - const targetPanelOpacity = isPastPrompt(this.modeValue); - - const panelOpacity = new Value(-1); - const prevPanelOpacity = new Value(-1); - const prevTargetPanelOpacity = new Value(-1); - const clock = new Clock(); - return block([ - cond(lessThan(panelOpacity, 0), [ - set(panelOpacity, targetPanelOpacity), - set(prevPanelOpacity, targetPanelOpacity), - set(prevTargetPanelOpacity, targetPanelOpacity), - ]), - cond(greaterOrEq(this.keyboardHeightValue, 0), [ - cond(neq(targetPanelOpacity, prevTargetPanelOpacity), [ - stopClock(clock), - set(prevTargetPanelOpacity, targetPanelOpacity), - ]), - cond( - neq(panelOpacity, targetPanelOpacity), - set(panelOpacity, runTiming(clock, panelOpacity, targetPanelOpacity)), - ), - ]), - cond( - and(eq(panelOpacity, 0), neq(prevPanelOpacity, 0)), - call([], this.proceedToNextMode), - ), - set(prevPanelOpacity, panelOpacity), - panelOpacity, - ]); - } - keyboardShow = (event: KeyboardEvent) => { if ( event.startCoordinates && @@ -502,12 +383,12 @@ 0, ), }); - this.keyboardHeightValue.setValue(keyboardHeight); + this.props.keyboardHeightValue.setValue(keyboardHeight); }; keyboardHide = () => { if (!this.activeAlert) { - this.keyboardHeightValue.setValue(0); + this.props.keyboardHeightValue.setValue(0); } }; @@ -518,8 +399,8 @@ goBackToPrompt = () => { this.props.nextModeRef.current = 'prompt'; this.props.setMode({ nextMode: 'prompt' }); - this.keyboardHeightValue.setValue(0); - this.modeValue.setValue(modeNumbers['prompt']); + this.props.keyboardHeightValue.setValue(0); + this.props.modeValue.setValue(modeNumbers['prompt']); Keyboard.dismiss(); }; @@ -554,7 +435,7 @@ panel = ( ); @@ -562,12 +443,12 @@ panel = ( ); } else if (this.props.mode.curMode === 'prompt') { - const opacityStyle = { opacity: this.buttonOpacity }; + const opacityStyle = { opacity: this.props.buttonOpacity }; const registerButtons = []; registerButtons.push( @@ -645,10 +526,10 @@ const windowWidth = this.props.dimensions.width; const buttonStyle = { - opacity: this.panelOpacityValue, + opacity: this.props.panelOpacity, left: windowWidth < 360 ? 28 : 40, }; - const padding = { paddingTop: this.panelPaddingTopValue }; + const padding = { paddingTop: this.props.panelPaddingTop }; const animatedContent = ( @@ -708,7 +589,7 @@ // keyboard appears before showing LogInPanel. Since we need LogInPanel // to appear before the username field is focused, we need to avoid this // behavior on iOS. - this.keyboardHeightValue.setValue(-1); + this.props.keyboardHeightValue.setValue(-1); } this.setMode('log-in'); }; @@ -718,7 +599,7 @@ }; onPressRegister = () => { - this.keyboardHeightValue.setValue(-1); + this.props.keyboardHeightValue.setValue(-1); this.setMode('register'); }; @@ -818,6 +699,119 @@ const nextModeRef = React.useRef(initialMode); + const dimensions = useSelector(derivedDimensionsInfoSelector); + const contentHeight = useValue(dimensions.safeAreaHeight); + const keyboardHeightValue = useValue(0); + const modeValue = useValue(modeNumbers[initialMode]); + const buttonOpacity = useValue(persistedStateLoaded ? 1 : 0); + + const prevModeValue = useValue(modeNumbers[initialMode]); + const panelPaddingTop = React.useMemo(() => { + const headerHeight = Platform.OS === 'ios' ? 62.33 : 58.54; + const promptButtonsSize = Platform.OS === 'ios' ? 40 : 61; + const logInContainerSize = 140; + const registerPanelSize = Platform.OS === 'ios' ? 181 : 180; + const siwePanelSize = 250; + + const containerSize = add( + headerHeight, + cond(not(isPastPrompt(modeValue)), promptButtonsSize, 0), + cond(eq(modeValue, modeNumbers['log-in']), logInContainerSize, 0), + cond(eq(modeValue, modeNumbers['register']), registerPanelSize, 0), + cond(eq(modeValue, modeNumbers['siwe']), siwePanelSize, 0), + ); + const potentialPanelPaddingTop = divide( + max(sub(contentHeight, keyboardHeightValue, containerSize), 0), + 2, + ); + + const panelPaddingTopValue = new Value(-1); + const targetPanelPaddingTop = new Value(-1); + const clock = new Clock(); + const keyboardTimeoutClock = new Clock(); + return block([ + cond(lessThan(panelPaddingTopValue, 0), [ + set(panelPaddingTopValue, potentialPanelPaddingTop), + set(targetPanelPaddingTop, potentialPanelPaddingTop), + ]), + cond( + lessThan(keyboardHeightValue, 0), + [ + runTiming(keyboardTimeoutClock, 0, 1, true, { duration: 500 }), + cond( + not(clockRunning(keyboardTimeoutClock)), + set(keyboardHeightValue, 0), + ), + ], + stopClock(keyboardTimeoutClock), + ), + cond( + and( + greaterOrEq(keyboardHeightValue, 0), + neq(prevModeValue, modeValue), + ), + [ + stopClock(clock), + cond( + neq(isPastPrompt(prevModeValue), isPastPrompt(modeValue)), + set(targetPanelPaddingTop, potentialPanelPaddingTop), + ), + set(prevModeValue, modeValue), + ], + ), + ratchetAlongWithKeyboardHeight(keyboardHeightValue, [ + stopClock(clock), + set(targetPanelPaddingTop, potentialPanelPaddingTop), + ]), + cond( + neq(panelPaddingTopValue, targetPanelPaddingTop), + set( + panelPaddingTopValue, + runTiming(clock, panelPaddingTopValue, targetPanelPaddingTop), + ), + ), + panelPaddingTopValue, + ]); + }, [modeValue, contentHeight, keyboardHeightValue, prevModeValue]); + + const proceedToNextMode = React.useCallback(() => { + setMode({ curMode: nextModeRef.current }); + }, [setMode]); + const panelOpacity = React.useMemo(() => { + const targetPanelOpacity = isPastPrompt(modeValue); + + const panelOpacityValue = new Value(-1); + const prevPanelOpacity = new Value(-1); + const prevTargetPanelOpacity = new Value(-1); + const clock = new Clock(); + return block([ + cond(lessThan(panelOpacityValue, 0), [ + set(panelOpacityValue, targetPanelOpacity), + set(prevPanelOpacity, targetPanelOpacity), + set(prevTargetPanelOpacity, targetPanelOpacity), + ]), + cond(greaterOrEq(keyboardHeightValue, 0), [ + cond(neq(targetPanelOpacity, prevTargetPanelOpacity), [ + stopClock(clock), + set(prevTargetPanelOpacity, targetPanelOpacity), + ]), + cond( + neq(panelOpacityValue, targetPanelOpacity), + set( + panelOpacityValue, + runTiming(clock, panelOpacityValue, targetPanelOpacity), + ), + ), + ]), + cond( + and(eq(panelOpacityValue, 0), neq(prevPanelOpacity, 0)), + call([], proceedToNextMode), + ), + set(prevPanelOpacity, panelOpacityValue), + panelOpacityValue, + ]); + }, [modeValue, keyboardHeightValue, proceedToNextMode]); + const navContext = React.useContext(NavContext); const isForeground = isForegroundSelector(navContext); @@ -826,7 +820,6 @@ ); const cookie = useSelector(cookieSelector(authoritativeKeyserverID)); const loggedIn = useSelector(isLoggedIn); - const dimensions = useSelector(derivedDimensionsInfoSelector); const splashStyle = useSelector(splashStyleSelector); const styles = useStyles(unboundStyles); @@ -839,6 +832,12 @@ mode={mode} setMode={setMode} nextModeRef={nextModeRef} + contentHeight={contentHeight} + keyboardHeightValue={keyboardHeightValue} + modeValue={modeValue} + buttonOpacity={buttonOpacity} + panelPaddingTop={panelPaddingTop} + panelOpacity={panelOpacity} isForeground={isForeground} persistedStateLoaded={persistedStateLoaded} rehydrateConcluded={rehydrateConcluded}