Removed the notify visibility event which hasn't been used any more
parent
1dfa10b09b
commit
ae39685a40
|
@ -8,7 +8,6 @@ import {LogCategory, logError, logInfo, logTrace, logWarn} from "./log";
|
|||
import {createErrorModal, createInputModal, Modal} from "./ui/elements/Modal";
|
||||
import {hashPassword} from "./utils/helpers";
|
||||
import {HandshakeHandler} from "./connection/HandshakeHandler";
|
||||
import * as htmltags from "./ui/htmltags";
|
||||
import {FilterMode, InputStartError, InputState} from "./voice/RecorderBase";
|
||||
import {defaultRecorder, RecorderProfile} from "./voice/RecorderProfile";
|
||||
import {Regex} from "./ui/modal/ModalConnect";
|
||||
|
@ -38,6 +37,7 @@ import {ConnectParameters} from "tc-shared/ui/modal/connect/Controller";
|
|||
import {assertMainApplication} from "tc-shared/ui/utils";
|
||||
import {getDNSProvider} from "tc-shared/dns";
|
||||
import {W2GPluginCmdHandler} from "tc-shared/ui/modal/video-viewer/W2GPlugin";
|
||||
import * as htmltags from "./ui/htmltags";
|
||||
|
||||
assertMainApplication();
|
||||
|
||||
|
@ -1249,11 +1249,6 @@ export interface ConnectionEvents {
|
|||
newState: ConnectionState
|
||||
},
|
||||
|
||||
/* the handler has become visible/invisible for the client */
|
||||
notify_visibility_changed: {
|
||||
visible: boolean
|
||||
},
|
||||
|
||||
/* fill only trigger once, after everything has been constructed */
|
||||
notify_handler_initialized: {}
|
||||
}
|
|
@ -102,8 +102,6 @@ export class ConnectionManager {
|
|||
oldHandlerId: oldHandler?.handlerId,
|
||||
newHandlerId: handler?.handlerId
|
||||
});
|
||||
oldHandler?.events().fire("notify_visibility_changed", { visible: false });
|
||||
handler?.events().fire("notify_visibility_changed", { visible: true });
|
||||
}
|
||||
|
||||
swapHandlerOrder(handlerA: ConnectionHandler, handlerB: ConnectionHandler) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import {AppUiEvents} from "tc-shared/ui/AppDefinitions";
|
|||
import {ChannelTreeRenderer} from "tc-shared/ui/tree/Renderer";
|
||||
import {ChannelTreeUIEvents} from "tc-shared/ui/tree/Definitions";
|
||||
import {ImagePreviewHook} from "tc-shared/ui/frames/ImagePreview";
|
||||
import {InternalModalHook} from "tc-shared/ui/react-elements/modal/internal";
|
||||
|
||||
const cssStyle = require("./AppRenderer.scss");
|
||||
const VideoFrame = React.memo((props: { events: Registry<AppUiEvents> }) => {
|
||||
|
@ -105,6 +106,10 @@ export const TeaAppMainView = (props: {
|
|||
<ErrorBoundary>
|
||||
<ImagePreviewHook />
|
||||
</ErrorBoundary>
|
||||
|
||||
<ErrorBoundary>
|
||||
<InternalModalHook />
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -110,11 +110,6 @@ export abstract class AbstractConversationController<
|
|||
}
|
||||
}
|
||||
|
||||
/* TODO: Is this even a thing? */
|
||||
handlePanelShow() {
|
||||
this.uiEvents.fire_react("notify_panel_show");
|
||||
}
|
||||
|
||||
protected reportStateToUI(conversation: AbstractChat<any>) {
|
||||
let historyState: ChatHistoryState;
|
||||
const localHistoryState = this.conversationManager.historyUiStates[conversation.getChatId()];
|
||||
|
|
|
@ -139,7 +139,6 @@ export interface AbstractConversationUiEvents {
|
|||
}
|
||||
|
||||
notify_selected_chat: { chatId: "unselected" | string },
|
||||
notify_panel_show: {},
|
||||
notify_chat_event: {
|
||||
chatId: string,
|
||||
triggerUnread: boolean,
|
||||
|
|
|
@ -824,11 +824,6 @@ class ConversationMessages extends React.PureComponent<ConversationMessagesPrope
|
|||
}
|
||||
}
|
||||
|
||||
@EventHandler<AbstractConversationUiEvents>("notify_panel_show")
|
||||
private handlePanelShow() {
|
||||
this.fixScroll();
|
||||
}
|
||||
|
||||
@EventHandler<AbstractConversationUiEvents>("query_conversation_history")
|
||||
private handleQueryConversationHistory(event: AbstractConversationUiEvents["query_conversation_history"]) {
|
||||
if (event.chatId !== this.currentChatId)
|
||||
|
|
|
@ -57,7 +57,6 @@ export class ChannelConversationController extends AbstractConversationControlle
|
|||
|
||||
this.connection = connection;
|
||||
if(connection) {
|
||||
this.initializeConnectionListener(connection);
|
||||
/* FIXME: Update cross channel talk state! */
|
||||
this.setConversationManager(connection.getChannelConversations());
|
||||
} else {
|
||||
|
@ -65,16 +64,6 @@ export class ChannelConversationController extends AbstractConversationControlle
|
|||
}
|
||||
}
|
||||
|
||||
private initializeConnectionListener(connection: ConnectionHandler) {
|
||||
this.connectionListener.push(connection.events().on("notify_visibility_changed", event => {
|
||||
if(!event.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.handlePanelShow();
|
||||
}));
|
||||
}
|
||||
|
||||
@EventHandler<AbstractConversationUiEvents>("action_delete_message")
|
||||
private handleMessageDelete(event: AbstractConversationUiEvents["action_delete_message"]) {
|
||||
const conversation = this.conversationManager?.findConversationById(event.chatId);
|
||||
|
|
|
@ -73,7 +73,6 @@ export class PrivateConversationController extends AbstractConversationControlle
|
|||
|
||||
this.connection = connection;
|
||||
if(connection) {
|
||||
this.initializeConnectionListener(connection);
|
||||
this.setConversationManager(connection.getPrivateConversations());
|
||||
} else {
|
||||
this.setConversationManager(undefined);
|
||||
|
@ -81,15 +80,6 @@ export class PrivateConversationController extends AbstractConversationControlle
|
|||
this.reportConversationList();
|
||||
}
|
||||
|
||||
private initializeConnectionListener(connection: ConnectionHandler) {
|
||||
this.connectionListener.push(connection.events().on("notify_visibility_changed", event => {
|
||||
if(!event.visible)
|
||||
return;
|
||||
|
||||
this.handlePanelShow();
|
||||
}));
|
||||
}
|
||||
|
||||
protected registerConversationManagerEvents(manager: PrivateConversationManager) {
|
||||
super.registerConversationManagerEvents(manager);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import {findRegisteredModal, RegisteredModal} from "tc-shared/ui/react-elements/
|
|||
import {assertMainApplication} from "tc-shared/ui/utils";
|
||||
import {InternalModalInstance} from "./internal";
|
||||
import {ExternalModalController} from "./external/Controller";
|
||||
import {LogCategory, logError} from "tc-shared/log";
|
||||
|
||||
assertMainApplication();
|
||||
export class GenericModalController<T extends keyof ModalConstructorArguments> implements ModalController {
|
||||
|
@ -82,7 +83,15 @@ export class GenericModalController<T extends keyof ModalConstructorArguments> i
|
|||
}
|
||||
});
|
||||
|
||||
events.on("action_close", () => this.destroy());
|
||||
events.on("action_close", () => {
|
||||
if(this.popedOut) {
|
||||
this.destroy();
|
||||
} else {
|
||||
this.hide().catch(error => {
|
||||
logError(LogCategory.GENERAL, tr("Failed to hide modal: %o"), error);
|
||||
}).then(() => this.destroy());
|
||||
}
|
||||
});
|
||||
events.on("action_minimize", () => this.instance.minimize());
|
||||
|
||||
events.on("action_popout", () => {
|
||||
|
|
|
@ -116,7 +116,9 @@ export class ModalBodyRenderer extends React.PureComponent<{
|
|||
this.props.className,
|
||||
cssStyle["color-" + this.props.modalInstance.color()]
|
||||
)}>
|
||||
{this.props.modalInstance.renderBody()}
|
||||
<ErrorBoundary>
|
||||
{this.props.modalInstance.renderBody()}
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -139,8 +141,8 @@ export class ModalFrameRenderer extends React.PureComponent<{
|
|||
export class PageModalRenderer extends React.PureComponent<{
|
||||
modalInstance: AbstractModal,
|
||||
onBackdropClicked: () => void,
|
||||
children: React.ReactElement<ModalFrameRenderer>
|
||||
}, {
|
||||
children: React.ReactElement<ModalFrameRenderer>,
|
||||
|
||||
shown: boolean
|
||||
}> {
|
||||
constructor(props) {
|
||||
|
@ -157,7 +159,7 @@ export class PageModalRenderer extends React.PureComponent<{
|
|||
className={joinClassList(
|
||||
cssStyle.modalPageContainer,
|
||||
cssStyle["align-" + this.props.modalInstance.verticalAlignment()],
|
||||
this.state.shown ? cssStyle.shown : undefined
|
||||
this.props.shown ? cssStyle.shown : undefined
|
||||
)}
|
||||
tabIndex={-1}
|
||||
role={"dialog"}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import {
|
||||
AbstractModal,
|
||||
constructAbstractModalClass, ModalInstanceController, ModalInstanceEvents,
|
||||
constructAbstractModalClass,
|
||||
ModalInstanceController,
|
||||
ModalInstanceEvents,
|
||||
ModalOptions,
|
||||
ModalState
|
||||
} from "tc-shared/ui/react-elements/modal/Definitions";
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import {
|
||||
ModalBodyRenderer,
|
||||
ModalFrameRenderer,
|
||||
|
@ -15,36 +16,79 @@ import {
|
|||
import {RegisteredModal} from "tc-shared/ui/react-elements/modal/Registry";
|
||||
import {LogCategory, logError} from "tc-shared/log";
|
||||
import {Registry} from "tc-events";
|
||||
import {guid} from "tc-shared/crypto/uid";
|
||||
import {ErrorBoundary} from "tc-shared/ui/react-elements/ErrorBoundary";
|
||||
|
||||
class InternalRendererInstance extends React.PureComponent<{
|
||||
instance: InternalModalInstance,
|
||||
}, {
|
||||
shown: boolean
|
||||
}> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
shown: false
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const instance = this.props.instance;
|
||||
if(!instance?.modalInstance) {
|
||||
throw tr("missing modal instance");
|
||||
}
|
||||
|
||||
return (
|
||||
<PageModalRenderer modalInstance={instance.modalInstance} onBackdropClicked={instance.getCloseCallback()} shown={this.state.shown}>
|
||||
<ModalFrameRenderer windowed={false}>
|
||||
<ModalFrameTopRenderer
|
||||
replacePageTitle={false}
|
||||
modalInstance={instance.modalInstance}
|
||||
|
||||
onClose={instance.getCloseCallback()}
|
||||
onPopout={instance.getPopoutCallback()}
|
||||
onMinimize={instance.getMinimizeCallback()}
|
||||
/>
|
||||
<ModalBodyRenderer modalInstance={instance.modalInstance} />
|
||||
</ModalFrameRenderer>
|
||||
</PageModalRenderer>
|
||||
);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
/* TODO: May notify the instance about this if this wasn't planned */
|
||||
}
|
||||
}
|
||||
|
||||
export class InternalModalInstance implements ModalInstanceController {
|
||||
readonly instanceUniqueId: string;
|
||||
readonly events: Registry<ModalInstanceEvents>;
|
||||
readonly refRendererInstance: React.RefObject<InternalRendererInstance>;
|
||||
|
||||
private readonly modalKlass: RegisteredModal<any>;
|
||||
private readonly constructorArguments: any[];
|
||||
private readonly rendererInstance: React.RefObject<PageModalRenderer>;
|
||||
|
||||
private readonly modalOptions: ModalOptions;
|
||||
|
||||
private state: ModalState;
|
||||
|
||||
private modalInstance: AbstractModal;
|
||||
private htmlContainer: HTMLDivElement;
|
||||
|
||||
public modalInstance: AbstractModal;
|
||||
private modalInitializePromise: Promise<void>;
|
||||
|
||||
constructor(modalType: RegisteredModal<any>, constructorArguments: any[], modalOptions: ModalOptions) {
|
||||
this.instanceUniqueId = guid();
|
||||
this.events = new Registry<ModalInstanceEvents>();
|
||||
|
||||
this.modalKlass = modalType;
|
||||
this.modalOptions = modalOptions;
|
||||
this.constructorArguments = constructorArguments;
|
||||
|
||||
this.rendererInstance = React.createRef();
|
||||
this.refRendererInstance = React.createRef();
|
||||
this.state = ModalState.DESTROYED;
|
||||
}
|
||||
|
||||
private async constructModal() {
|
||||
if(this.htmlContainer || this.modalInstance) {
|
||||
if(this.modalInstance) {
|
||||
throw tr("internal modal has already been constructed");
|
||||
}
|
||||
|
||||
|
@ -57,47 +101,41 @@ export class InternalModalInstance implements ModalInstanceController {
|
|||
this.modalInstance = constructAbstractModalClass(modalClass.default, { windowed: false }, this.constructorArguments);
|
||||
this.modalInstance["onInitialize"]();
|
||||
} catch (error) {
|
||||
this.destructModalInstance();
|
||||
logError(LogCategory.GENERAL, tr("Failed to create new modal of instance type %s: %o"), this.modalKlass.modalId, error);
|
||||
throw tr("failed to create new modal instance");
|
||||
}
|
||||
|
||||
this.htmlContainer = document.createElement("div");
|
||||
document.body.appendChild(this.htmlContainer);
|
||||
if(!internalModalContainer.current) {
|
||||
this.destructModalInstance();
|
||||
throw tr("missing modal hanging container");
|
||||
}
|
||||
|
||||
await new Promise(resolve => {
|
||||
ReactDOM.render(
|
||||
<PageModalRenderer modalInstance={this.modalInstance} onBackdropClicked={this.getCloseCallback()} ref={this.rendererInstance}>
|
||||
<ModalFrameRenderer windowed={false}>
|
||||
<ModalFrameTopRenderer
|
||||
replacePageTitle={false}
|
||||
modalInstance={this.modalInstance}
|
||||
|
||||
onClose={this.getCloseCallback()}
|
||||
onPopout={this.getPopoutCallback()}
|
||||
onMinimize={this.getMinimizeCallback()}
|
||||
/>
|
||||
<ModalBodyRenderer modalInstance={this.modalInstance} />
|
||||
</ModalFrameRenderer>
|
||||
</PageModalRenderer>,
|
||||
this.htmlContainer,
|
||||
resolve
|
||||
);
|
||||
});
|
||||
await new Promise(resolve => internalModalContainer.current.addModalInstance(this, resolve));
|
||||
if(!this.refRendererInstance.current) {
|
||||
this.destructModalInstance();
|
||||
throw tr("missing rendered modal reference");
|
||||
}
|
||||
}
|
||||
|
||||
private destructModal() {
|
||||
this.state = ModalState.DESTROYED;
|
||||
if(this.htmlContainer) {
|
||||
ReactDOM.unmountComponentAtNode(this.htmlContainer);
|
||||
this.htmlContainer.remove();
|
||||
this.htmlContainer = undefined;
|
||||
this.destructModalInstance();
|
||||
this.events.fire("notify_destroy");
|
||||
}
|
||||
|
||||
private destructModalInstance() {
|
||||
internalModalContainer.current?.removeModalInstance(this);
|
||||
if(!this.modalInstance) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.modalInstance) {
|
||||
try {
|
||||
this.modalInstance["onDestroy"]();
|
||||
this.modalInstance = undefined;
|
||||
} catch (error) {
|
||||
logError(LogCategory.GENERAL, tr("Failed to invoke the destroy callback on the created modal instance: %o"), error);
|
||||
}
|
||||
this.events.fire("notify_destroy");
|
||||
this.modalInstance = undefined;
|
||||
}
|
||||
|
||||
getState(): ModalState {
|
||||
|
@ -118,13 +156,13 @@ export class InternalModalInstance implements ModalInstanceController {
|
|||
await this.modalInitializePromise;
|
||||
}
|
||||
|
||||
if(!this.rendererInstance.current) {
|
||||
if(!this.refRendererInstance.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.state = ModalState.SHOWN;
|
||||
this.modalInstance["onOpen"]();
|
||||
await new Promise(resolve => this.rendererInstance.current.setState({ shown: true }, resolve));
|
||||
this.state = ModalState.SHOWN;
|
||||
await new Promise(resolve => this.refRendererInstance.current.setState({ shown: true }, resolve));
|
||||
this.events.fire("notify_open");
|
||||
}
|
||||
|
||||
|
@ -133,13 +171,13 @@ export class InternalModalInstance implements ModalInstanceController {
|
|||
await this.modalInitializePromise;
|
||||
}
|
||||
|
||||
if(!this.rendererInstance.current) {
|
||||
if(!this.refRendererInstance.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.state = ModalState.HIDDEN;
|
||||
this.modalInstance["onClose"]();
|
||||
await new Promise(resolve => this.rendererInstance.current.setState({ shown: false }, resolve));
|
||||
await new Promise(resolve => this.refRendererInstance.current.setState({ shown: false }, resolve));
|
||||
|
||||
/* TODO: Somehow get the real animation finish signal? */
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
|
@ -154,11 +192,11 @@ export class InternalModalInstance implements ModalInstanceController {
|
|||
this.events.destroy();
|
||||
}
|
||||
|
||||
protected getCloseCallback() {
|
||||
public getCloseCallback() {
|
||||
return () => this.events.fire("action_close");
|
||||
}
|
||||
|
||||
protected getPopoutCallback() {
|
||||
public getPopoutCallback() {
|
||||
if(!this.modalKlass.popoutSupported) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -170,8 +208,48 @@ export class InternalModalInstance implements ModalInstanceController {
|
|||
return () => this.events.fire("action_popout");
|
||||
}
|
||||
|
||||
protected getMinimizeCallback() {
|
||||
public getMinimizeCallback() {
|
||||
/* We can't minimize any windows */
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const internalModalContainer: React.RefObject<InternalModalHookInner> = React.createRef();
|
||||
class InternalModalHookInner extends React.PureComponent<{}, {
|
||||
revision: number
|
||||
}> {
|
||||
private modalStack: InternalModalInstance[];
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.modalStack = [];
|
||||
this.state = { revision: 0 };
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
this.modalStack.map(modal => (
|
||||
<ErrorBoundary key={modal.instanceUniqueId}>
|
||||
<InternalRendererInstance instance={modal} ref={modal.refRendererInstance} />
|
||||
</ErrorBoundary>
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
addModalInstance(modal: InternalModalInstance, callbackRendered?: () => void) {
|
||||
this.modalStack.push(modal);
|
||||
this.setState({ revision: performance.now() }, callbackRendered);
|
||||
}
|
||||
|
||||
removeModalInstance(modal: InternalModalInstance) {
|
||||
if(!this.modalStack.remove(modal)) {
|
||||
return;
|
||||
}
|
||||
this.setState({ revision: performance.now() });
|
||||
}
|
||||
}
|
||||
|
||||
export const InternalModalHook = React.memo(() => (
|
||||
<InternalModalHookInner ref={internalModalContainer} />
|
||||
));
|
|
@ -680,8 +680,6 @@ export function initializeChannelTreeController(events: Registry<ChannelTreeUIEv
|
|||
events.fire_react("notify_unread_state", { treeEntryId: event.treeEntryId, unread: entry.isUnread() });
|
||||
});
|
||||
|
||||
events.on("notify_destroy", channelTree.client.events().on("notify_visibility_changed", event => events.fire_react("notify_visibility_changed", event)));
|
||||
|
||||
events.on("query_tree_entries", event => controller.sendChannelTreeEntriesFull(event.fullInfo ? undefined : []));
|
||||
events.on("query_selected_entry", () => controller.sendSelectedEntry());
|
||||
events.on("query_channel_info", event => {
|
||||
|
|
|
@ -103,7 +103,6 @@ export interface ChannelTreeUIEvents {
|
|||
|
||||
notify_unread_state: { treeEntryId: number, unread: boolean },
|
||||
|
||||
notify_visibility_changed: { visible: boolean },
|
||||
notify_destroy: {}
|
||||
}
|
||||
|
||||
|
|
|
@ -110,25 +110,6 @@ export class ChannelTreeView extends ReactComponentBase<ChannelTreeViewPropertie
|
|||
this.resizeObserver = undefined;
|
||||
}
|
||||
|
||||
@EventHandler<ChannelTreeUIEvents>("notify_visibility_changed")
|
||||
private handleVisibilityChanged(event: ChannelTreeUIEvents["notify_visibility_changed"]) {
|
||||
if (!event.visible) {
|
||||
this.setState({smoothScroll: false});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.scrollFixRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.scrollFixRequested = true;
|
||||
requestAnimationFrame(() => {
|
||||
this.scrollFixRequested = false;
|
||||
this.refContainer.current.scrollTop = this.state.scrollOffset;
|
||||
this.setState({smoothScroll: true});
|
||||
});
|
||||
}
|
||||
|
||||
private visibleEntries() {
|
||||
const entryHeight = ChannelTreeView.EntryHeightEm * this.state.fontSize;
|
||||
let viewEntryCount = Math.ceil(this.state.viewHeight / entryHeight);
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue