Animate in-conversation panels on show/hide

This commit is contained in:
Ken Powers 2019-07-25 12:24:03 -04:00 committed by Scott Nonnenberg
parent c952d628c1
commit 464361b2eb
6 changed files with 112 additions and 37 deletions

View file

@ -16,6 +16,7 @@
initialize(options) { initialize(options) {
this.ourNumber = textsecure.storage.user.getNumber(); this.ourNumber = textsecure.storage.user.getNumber();
this.listenBack = options.listenBack; this.listenBack = options.listenBack;
this.loading = false;
this.listenTo(this.model, 'change', this.render); this.listenTo(this.model, 'change', this.render);
}, },
@ -39,19 +40,28 @@
profileName: this.model.getProfileName(), profileName: this.model.getProfileName(),
verified: this.model.isVerified(), verified: this.model.isVerified(),
onClick: this.showIdentity.bind(this), onClick: this.showIdentity.bind(this),
disabled: this.loading,
}, },
}); });
this.$el.append(this.contactView.el); this.$el.append(this.contactView.el);
return this; return this;
}, },
showIdentity() { showIdentity() {
if (this.model.id === this.ourNumber) { if (this.model.id === this.ourNumber || this.loading) {
return; return;
} }
this.loading = true;
this.render();
const view = new Whisper.KeyVerificationPanelView({ const view = new Whisper.KeyVerificationPanelView({
model: this.model, model: this.model,
onLoad: () => {
this.loading = false;
this.listenBack(view);
this.render();
},
}); });
this.listenBack(view);
}, },
}), }),
}); });

View file

@ -954,7 +954,7 @@
}; };
const view = new Whisper.ReactWrapperView({ const view = new Whisper.ReactWrapperView({
className: 'panel-wrapper', className: 'panel',
Component: Signal.Components.MediaGallery, Component: Signal.Components.MediaGallery,
props: await getProps(), props: await getProps(),
onClose: () => { onClose: () => {
@ -1537,7 +1537,7 @@
const props = message.getPropsForMessageDetail(); const props = message.getPropsForMessageDetail();
const view = new Whisper.ReactWrapperView({ const view = new Whisper.ReactWrapperView({
className: 'message-detail-wrapper', className: 'panel message-detail-wrapper',
Component: Signal.Components.MessageDetail, Component: Signal.Components.MessageDetail,
props, props,
onClose, onClose,
@ -1597,11 +1597,11 @@
listenBack(view) { listenBack(view) {
this.panels = this.panels || []; this.panels = this.panels || [];
if (this.panels.length > 0) {
this.panels[0].$el.hide();
}
this.panels.unshift(view); this.panels.unshift(view);
view.$el.insertBefore(this.$('.panel').first()); view.$el.insertAfter(this.$('.panel').last());
view.$el.one('animationend', () => {
view.$el.addClass('panel--static');
});
}, },
resetPanel() { resetPanel() {
if (!this.panels || !this.panels.length) { if (!this.panels || !this.panels.length) {
@ -1611,14 +1611,15 @@
const view = this.panels.shift(); const view = this.panels.shift();
if (this.panels.length > 0) { if (this.panels.length > 0) {
this.panels[0].$el.show(); this.panels[0].$el.fadeIn(250);
}
view.remove();
if (this.panels.length === 0) {
// Make sure poppers are positioned properly
window.dispatchEvent(new Event('resize'));
} }
view.$el.addClass('panel--remove').one('transitionend', () => {
view.remove();
if (this.panels.length === 0) {
// Make sure poppers are positioned properly
window.dispatchEvent(new Event('resize'));
}
});
}, },
endSession() { endSession() {

View file

@ -22,6 +22,9 @@
this.loadKeys().then(() => { this.loadKeys().then(() => {
this.listenTo(this.model, 'change', this.render); this.listenTo(this.model, 'change', this.render);
if (options.onLoad) {
options.onLoad();
}
}); });
}, },
loadKeys() { loadKeys() {

View file

@ -1,15 +1,56 @@
@import './mixins';
@keyframes panel--in {
from {
transform: translateX(500px);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
.conversation { .conversation {
background-color: $color-white; background-color: $color-white;
height: 100%; height: 100%;
position: relative; position: relative;
.panel, .panel {
.panel-wrapper {
height: calc(100% - #{$header-height}); height: calc(100% - #{$header-height});
overflow-y: scroll; overflow-y: scroll;
z-index: 1;
position: absolute;
left: 0;
top: 48px;
width: 100%;
height: calc(100% - 48px);
@include light-theme() {
background-color: $color-white;
}
@include dark-theme() {
background-color: $color-black;
}
} }
.panel { .panel {
&:not(.main) {
animation: panel--in 250ms ease-out;
}
&--static {
animation: none;
}
&--remove {
transform: translateX(500px);
opacity: 0;
transition: all 250ms ease-out;
}
.container { .container {
padding-top: 20px; padding-top: 20px;
max-width: 750px; max-width: 750px;
@ -18,8 +59,7 @@
} }
} }
.main.panel, .main.panel {
.panel-wrapper {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: initial; overflow: initial;

View file

@ -1512,7 +1512,17 @@
height: 35px; height: 35px;
min-width: 35px; min-width: 35px;
vertical-align: text-bottom; vertical-align: text-bottom;
cursor: pointer; border: none;
opacity: 0;
transition: opacity 250ms ease-out;
&:disabled {
cursor: default;
}
&--show {
opacity: 1;
}
} }
.module-conversation-header__title-container { .module-conversation-header__title-container {
@ -1595,7 +1605,17 @@
height: 20px; height: 20px;
width: 20px; width: 20px;
margin-left: 4px; margin-left: 4px;
cursor: pointer; border: none;
opacity: 0;
transition: opacity 250ms ease-out;
&:disabled {
cursor: default;
}
&--show {
opacity: 1;
}
} }
// Module: Message Detail // Module: Message Detail

View file

@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import classnames from 'classnames';
import { Emojify } from './Emojify'; import { Emojify } from './Emojify';
import { Avatar } from '../Avatar'; import { Avatar } from '../Avatar';
@ -49,7 +50,7 @@ interface Props {
} }
export class ConversationHeader extends React.Component<Props> { export class ConversationHeader extends React.Component<Props> {
public showMenuBound: (event: React.MouseEvent<HTMLDivElement>) => void; public showMenuBound: (event: React.MouseEvent<HTMLButtonElement>) => void;
public menuTriggerRef: React.RefObject<any>; public menuTriggerRef: React.RefObject<any>;
public constructor(props: Props) { public constructor(props: Props) {
@ -59,7 +60,7 @@ export class ConversationHeader extends React.Component<Props> {
this.showMenuBound = this.showMenu.bind(this); this.showMenuBound = this.showMenu.bind(this);
} }
public showMenu(event: React.MouseEvent<HTMLDivElement>) { public showMenu(event: React.MouseEvent<HTMLButtonElement>) {
if (this.menuTriggerRef.current) { if (this.menuTriggerRef.current) {
this.menuTriggerRef.current.handleContextClick(event); this.menuTriggerRef.current.handleContextClick(event);
} }
@ -68,15 +69,14 @@ export class ConversationHeader extends React.Component<Props> {
public renderBackButton() { public renderBackButton() {
const { onGoBack, showBackButton } = this.props; const { onGoBack, showBackButton } = this.props;
if (!showBackButton) {
return null;
}
return ( return (
<div <button
onClick={onGoBack} onClick={onGoBack}
role="button" className={classnames(
className="module-conversation-header__back-icon" 'module-conversation-header__back-icon',
showBackButton ? 'module-conversation-header__back-icon--show' : null
)}
disabled={!showBackButton}
/> />
); );
} }
@ -171,16 +171,17 @@ export class ConversationHeader extends React.Component<Props> {
public renderGear(triggerId: string) { public renderGear(triggerId: string) {
const { showBackButton } = this.props; const { showBackButton } = this.props;
if (showBackButton) {
return null;
}
return ( return (
<ContextMenuTrigger id={triggerId} ref={this.menuTriggerRef}> <ContextMenuTrigger id={triggerId} ref={this.menuTriggerRef}>
<div <button
role="button"
onClick={this.showMenuBound} onClick={this.showMenuBound}
className="module-conversation-header__gear-icon" className={classnames(
'module-conversation-header__gear-icon',
showBackButton
? null
: 'module-conversation-header__gear-icon--show'
)}
disabled={showBackButton}
/> />
</ContextMenuTrigger> </ContextMenuTrigger>
); );