Finishing up some modals

This commit is contained in:
Vincent 2019-12-30 17:38:28 +11:00
parent 66911d6f06
commit 6ee5d041fb
11 changed files with 217 additions and 51 deletions

View File

@ -1127,7 +1127,7 @@
"Shown on the drop-down menu for an individual message, deletes single message"
},
"deleteMessages": {
"message": "Delete messages",
"message": "Delete Messages",
"description": "Menu item for deleting messages, title case."
},
"deletePublicConversationConfirmation": {
@ -1152,7 +1152,7 @@
"Confirmation dialog text that tells the user what will happen if they leave the public channel."
},
"deleteContact": {
"message": "Delete contact",
"message": "Delete Contact",
"description":
"Confirmation dialog title that asks the user if they really wish to delete the contact. Answer buttons use the strings 'ok' and 'cancel'. The deletion is permanent, i.e. it cannot be undone."
},

View File

@ -52,6 +52,7 @@
<script type='text/x-tmpl-mustache' id='two-column'>
<div id='session-toast-container'></div>
<div id='session-confirm-container'></div>
<div class='gutter'>
<div class='network-status-container'></div>
<div class='left-pane-placeholder'></div>
@ -704,6 +705,7 @@
<script type='text/javascript' src='js/views/session_toggle_view.js'></script>
<script type='text/javascript' src='js/views/session_modal_view.js'></script>
<script type='text/javascript' src='js/views/session_dropdown_view.js'></script>
<script type='text/javascript' src='js/views/session_confirm_view.js'></script>
<script type='text/javascript' src='js/views/file_input_view.js'></script>
<script type='text/javascript' src='js/views/list_view.js'></script>
<script type='text/javascript' src='js/views/contact_list_view.js'></script>

View File

@ -802,12 +802,21 @@
appView.openConversation(groupId, {});
};
// $(document).ready(() => {
// window.settingsView = new Whisper.SessionSettingsView({
// el: $('#settings-container'),
// });
// window.settingsView.render();
// });
window.confirmationDialog = params => {
const confirmDialog = new Whisper.SessionConfirmView({
el: $('#session-confirm-container'),
title: params.title,
message: params.message,
resolve: params.resolve || undefined,
reject: params.reject || undefined,
okText: params.okText || undefined,
cancelText: params.cancelText || undefined,
hideCancel: params.hideCancel || false,
});
confirmDialog.render();
}
window.generateID = () =>
Math.random()

View File

@ -2665,13 +2665,18 @@
},
deleteContact() {
const title = this.isPublic()
? i18n('deletePublicChannel')
: i18n('deleteContact');
const message = this.isPublic()
? i18n('deletePublicChannelConfirmation')
: i18n('deleteContactConfirmation');
Whisper.events.trigger('showConfirmationDialog', {
window.confirmationDialog({
title,
message,
onOk: () => ConversationController.deleteContact(this.id),
resolve: () => ConversationController.deleteContact(this.id),
});
},
@ -2721,17 +2726,23 @@
deleteMessages() {
this.resetMessageSelection();
let params;
if (this.isPublic()) {
Whisper.events.trigger('showConfirmationDialog', {
params = {
title: i18n('deleteMessages'),
message: i18n('deletePublicConversationConfirmation'),
onOk: () => ConversationController.deleteContact(this.id),
});
resolve: () => ConversationController.deleteContact(this.id),
};
} else {
Whisper.events.trigger('showConfirmationDialog', {
params = {
title: i18n('deleteMessages'),
message: i18n('deleteConversationConfirmation'),
onOk: () => this.destroyMessages(),
});
resolve: () => this.destroyMessages(),
};
}
window.confirmationDialog(params);
},
async destroyMessages() {

View File

@ -61,6 +61,7 @@ const {
const { SessionToast } = require('../../ts/components/session/SessionToast');
const { SessionToggle } = require('../../ts/components/session/SessionToggle');
const { SessionModal } = require('../../ts/components/session/SessionModal');
const { SessionConfirm } = require('../../ts/components/session/SessionConfirm');
const {
SessionDropdown,
} = require('../../ts/components/session/SessionDropdown');
@ -267,6 +268,7 @@ exports.setup = (options = {}) => {
SessionSettings,
SessionToast,
SessionToggle,
SessionConfirm,
SessionModal,
SessionDropdown,
MediaGallery,

View File

@ -8,11 +8,8 @@ $(document).on('keyup', e => {
}
});
const $body = $(document.body);
$body.addClass(`${window.theme}-theme`);
window.view = new Whisper.ConfirmationDialogView({
message: i18n('audioPermissionNeeded'),
const dialogParams = {
title: i18n('audioPermissionNeeded'),
okText: i18n('allowAccess'),
resolve: () => {
'use strict';
@ -20,7 +17,7 @@ window.view = new Whisper.ConfirmationDialogView({
window.setMediaPermissions(true);
window.closePermissionsPopup();
},
reject: window.closePermissionsPopup,
});
onClose: window.closePermissionsPopup,
};
window.confirmationDialog(dialogParams);
window.view.$el.appendTo($body);

View File

@ -1328,6 +1328,7 @@
message.resend(contact.id);
},
});
this.$el.prepend(dialog.el);

View File

@ -0,0 +1,55 @@
/* global Whisper */
// eslint-disable-next-line func-names
(function() {
'use strict';
window.Whisper = window.Whisper || {};
Whisper.SessionConfirmView = Whisper.View.extend({
initialize(options) {
this.props = {
title: options.title,
message: options.message,
onClickOk: this.ok.bind(this),
onClickClose: this.cancel.bind(this),
resolve: options.resolve,
reject: options.reject,
okText: options.okText,
cancelText: options.cancelText,
hideCancel: options.hideCancel,
};
},
render() {
this.$('.session-confirm-wrapper').remove();
this.confirmView = new Whisper.ReactWrapperView({
className: 'session-confirm-wrapper',
Component: window.Signal.Components.SessionConfirm,
props: this.props,
});
this.$el.append(this.confirmView.el);
},
ok() {
this.$('.session-confirm-wrapper').remove();
if (this.props.resolve){
this.props.resolve()
}
},
cancel() {
this.$('.session-confirm-wrapper').remove();
if (this.props.reject) {
this.props.reject()
}
},
onKeyup(event) {
if (event.key === 'Escape' || event.key === 'Esc') {
this.cancel();
}
},
});
})();

View File

@ -7,6 +7,7 @@ import {
SessionButtonColor,
SessionButtonType,
} from './session/SessionButton';
import { SessionConfirm } from './session/SessionConfirm';
interface Props {
i18n: any;

View File

@ -0,0 +1,76 @@
import React from 'react';
import { SessionModal } from './SessionModal';
import { SessionButton } from './SessionButton';
interface Props {
message: string;
title: string;
onOk?: any;
onClose?: any;
onClickOk: any,
onClickClose: any,
okText?: string;
cancelText?: string;
hideCancel: boolean;
}
export class SessionConfirm extends React.Component<Props> {
public static defaultProps = {
title: '',
hideCancel: false,
}
constructor(props: any) {
super(props);
}
public render() {
const { title,
message,
onClickOk,
onClickClose,
hideCancel,
} = this.props;
const okText = this.props.okText || window.i18n('ok');
const cancelText = this.props.cancelText || window.i18n('cancel');
const showHeader = !! this.props.title;
return (
<SessionModal
title={title}
onClose={() => null}
onOk={() => null}
showExitIcon={false}
showHeader={showHeader}
>
{ showHeader ? null : (
<div className="spacer-lg"></div>
)}
<div className="session-modal__centered">
<span className="text-subtle">
{message}
</span>
</div>
<div className="spacer-lg"></div>
<div className="session-modal__button-group">
<SessionButton
text={okText}
onClick={onClickOk}
/>
{ hideCancel ? null : (
<SessionButton
text={cancelText}
onClick={onClickClose}
/>
)}
</div>
</SessionModal>
);
}
}

View File

@ -1,5 +1,4 @@
import React from 'react';
import classNames from 'classnames';
import { SessionIconButton, SessionIconSize, SessionIconType } from './icon/';
@ -7,6 +6,8 @@ interface Props {
title: string;
onClose: any;
onOk: any;
showExitIcon?: boolean;
showHeader?: boolean;
//Maximum of two icons in header
headerIconButtons?: Array<{
type: SessionIconType;
@ -18,7 +19,12 @@ interface State {
isVisible: boolean;
}
export class SessionModal extends React.PureComponent<Props, State> {
export class SessionModal extends React.PureComponent<Props, State> {
public static defaultProps = {
showExitIcon: true,
showHeader: true,
};
constructor(props: any) {
super(props);
this.state = {
@ -32,34 +38,40 @@ export class SessionModal extends React.PureComponent<Props, State> {
}
public render() {
const { title, headerIconButtons } = this.props;
const { title, headerIconButtons, showExitIcon, showHeader } = this.props;
const { isVisible } = this.state;
return isVisible ? (
<div className={classNames('session-modal')}>
<div className="session-modal__header">
<div className="session-modal__header__close">
<SessionIconButton
iconType={SessionIconType.Exit}
iconSize={SessionIconSize.Small}
onClick={this.close}
/>
</div>
<div className="session-modal__header__title">{title}</div>
<div className="session-modal__header__icons">
{headerIconButtons
? headerIconButtons.map((iconItem: any) => {
return (
<SessionIconButton
key={iconItem.type}
iconType={iconItem.type}
iconSize={SessionIconSize.Medium}
/>
);
})
: null}
</div>
</div>
<div className={'session-modal'}>
{ showHeader ? (
<>
<div className="session-modal__header">
<div className="session-modal__header__close">
{showExitIcon ? (
<SessionIconButton
iconType={SessionIconType.Exit}
iconSize={SessionIconSize.Small}
onClick={this.close}
/>
) : null }
</div>
<div className="session-modal__header__title">{title}</div>
<div className="session-modal__header__icons">
{headerIconButtons
? headerIconButtons.map((iconItem: any) => {
return (
<SessionIconButton
key={iconItem.type}
iconType={iconItem.type}
iconSize={SessionIconSize.Medium}
/>
);
})
: null}
</div>
</div>
</>
) : null }
<div className="session-modal__body">{this.props.children}</div>
</div>