Removed the notify visibility event which hasn't been used any more

This commit is contained in:
WolverinDEV 2021-04-05 20:06:44 +02:00
parent 1dfa10b09b
commit ae39685a40
15 changed files with 148 additions and 114 deletions

View file

@ -8,7 +8,6 @@ import {LogCategory, logError, logInfo, logTrace, logWarn} from "./log";
import {createErrorModal, createInputModal, Modal} from "./ui/elements/Modal"; import {createErrorModal, createInputModal, Modal} from "./ui/elements/Modal";
import {hashPassword} from "./utils/helpers"; import {hashPassword} from "./utils/helpers";
import {HandshakeHandler} from "./connection/HandshakeHandler"; import {HandshakeHandler} from "./connection/HandshakeHandler";
import * as htmltags from "./ui/htmltags";
import {FilterMode, InputStartError, InputState} from "./voice/RecorderBase"; import {FilterMode, InputStartError, InputState} from "./voice/RecorderBase";
import {defaultRecorder, RecorderProfile} from "./voice/RecorderProfile"; import {defaultRecorder, RecorderProfile} from "./voice/RecorderProfile";
import {Regex} from "./ui/modal/ModalConnect"; 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 {assertMainApplication} from "tc-shared/ui/utils";
import {getDNSProvider} from "tc-shared/dns"; import {getDNSProvider} from "tc-shared/dns";
import {W2GPluginCmdHandler} from "tc-shared/ui/modal/video-viewer/W2GPlugin"; import {W2GPluginCmdHandler} from "tc-shared/ui/modal/video-viewer/W2GPlugin";
import * as htmltags from "./ui/htmltags";
assertMainApplication(); assertMainApplication();
@ -1249,11 +1249,6 @@ export interface ConnectionEvents {
newState: ConnectionState 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 */ /* fill only trigger once, after everything has been constructed */
notify_handler_initialized: {} notify_handler_initialized: {}
} }

View file

@ -102,8 +102,6 @@ export class ConnectionManager {
oldHandlerId: oldHandler?.handlerId, oldHandlerId: oldHandler?.handlerId,
newHandlerId: handler?.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) { swapHandlerOrder(handlerA: ConnectionHandler, handlerB: ConnectionHandler) {

View file

@ -19,6 +19,7 @@ import {AppUiEvents} from "tc-shared/ui/AppDefinitions";
import {ChannelTreeRenderer} from "tc-shared/ui/tree/Renderer"; import {ChannelTreeRenderer} from "tc-shared/ui/tree/Renderer";
import {ChannelTreeUIEvents} from "tc-shared/ui/tree/Definitions"; import {ChannelTreeUIEvents} from "tc-shared/ui/tree/Definitions";
import {ImagePreviewHook} from "tc-shared/ui/frames/ImagePreview"; import {ImagePreviewHook} from "tc-shared/ui/frames/ImagePreview";
import {InternalModalHook} from "tc-shared/ui/react-elements/modal/internal";
const cssStyle = require("./AppRenderer.scss"); const cssStyle = require("./AppRenderer.scss");
const VideoFrame = React.memo((props: { events: Registry<AppUiEvents> }) => { const VideoFrame = React.memo((props: { events: Registry<AppUiEvents> }) => {
@ -105,6 +106,10 @@ export const TeaAppMainView = (props: {
<ErrorBoundary> <ErrorBoundary>
<ImagePreviewHook /> <ImagePreviewHook />
</ErrorBoundary> </ErrorBoundary>
<ErrorBoundary>
<InternalModalHook />
</ErrorBoundary>
</div> </div>
); );
} }

View file

@ -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>) { protected reportStateToUI(conversation: AbstractChat<any>) {
let historyState: ChatHistoryState; let historyState: ChatHistoryState;
const localHistoryState = this.conversationManager.historyUiStates[conversation.getChatId()]; const localHistoryState = this.conversationManager.historyUiStates[conversation.getChatId()];

View file

@ -139,7 +139,6 @@ export interface AbstractConversationUiEvents {
} }
notify_selected_chat: { chatId: "unselected" | string }, notify_selected_chat: { chatId: "unselected" | string },
notify_panel_show: {},
notify_chat_event: { notify_chat_event: {
chatId: string, chatId: string,
triggerUnread: boolean, triggerUnread: boolean,

View file

@ -824,11 +824,6 @@ class ConversationMessages extends React.PureComponent<ConversationMessagesPrope
} }
} }
@EventHandler<AbstractConversationUiEvents>("notify_panel_show")
private handlePanelShow() {
this.fixScroll();
}
@EventHandler<AbstractConversationUiEvents>("query_conversation_history") @EventHandler<AbstractConversationUiEvents>("query_conversation_history")
private handleQueryConversationHistory(event: AbstractConversationUiEvents["query_conversation_history"]) { private handleQueryConversationHistory(event: AbstractConversationUiEvents["query_conversation_history"]) {
if (event.chatId !== this.currentChatId) if (event.chatId !== this.currentChatId)

View file

@ -57,7 +57,6 @@ export class ChannelConversationController extends AbstractConversationControlle
this.connection = connection; this.connection = connection;
if(connection) { if(connection) {
this.initializeConnectionListener(connection);
/* FIXME: Update cross channel talk state! */ /* FIXME: Update cross channel talk state! */
this.setConversationManager(connection.getChannelConversations()); this.setConversationManager(connection.getChannelConversations());
} else { } 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") @EventHandler<AbstractConversationUiEvents>("action_delete_message")
private handleMessageDelete(event: AbstractConversationUiEvents["action_delete_message"]) { private handleMessageDelete(event: AbstractConversationUiEvents["action_delete_message"]) {
const conversation = this.conversationManager?.findConversationById(event.chatId); const conversation = this.conversationManager?.findConversationById(event.chatId);

View file

@ -73,7 +73,6 @@ export class PrivateConversationController extends AbstractConversationControlle
this.connection = connection; this.connection = connection;
if(connection) { if(connection) {
this.initializeConnectionListener(connection);
this.setConversationManager(connection.getPrivateConversations()); this.setConversationManager(connection.getPrivateConversations());
} else { } else {
this.setConversationManager(undefined); this.setConversationManager(undefined);
@ -81,15 +80,6 @@ export class PrivateConversationController extends AbstractConversationControlle
this.reportConversationList(); 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) { protected registerConversationManagerEvents(manager: PrivateConversationManager) {
super.registerConversationManagerEvents(manager); super.registerConversationManagerEvents(manager);

View file

@ -13,6 +13,7 @@ import {findRegisteredModal, RegisteredModal} from "tc-shared/ui/react-elements/
import {assertMainApplication} from "tc-shared/ui/utils"; import {assertMainApplication} from "tc-shared/ui/utils";
import {InternalModalInstance} from "./internal"; import {InternalModalInstance} from "./internal";
import {ExternalModalController} from "./external/Controller"; import {ExternalModalController} from "./external/Controller";
import {LogCategory, logError} from "tc-shared/log";
assertMainApplication(); assertMainApplication();
export class GenericModalController<T extends keyof ModalConstructorArguments> implements ModalController { 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_minimize", () => this.instance.minimize());
events.on("action_popout", () => { events.on("action_popout", () => {

View file

@ -116,7 +116,9 @@ export class ModalBodyRenderer extends React.PureComponent<{
this.props.className, this.props.className,
cssStyle["color-" + this.props.modalInstance.color()] cssStyle["color-" + this.props.modalInstance.color()]
)}> )}>
<ErrorBoundary>
{this.props.modalInstance.renderBody()} {this.props.modalInstance.renderBody()}
</ErrorBoundary>
</div> </div>
) )
} }
@ -139,8 +141,8 @@ export class ModalFrameRenderer extends React.PureComponent<{
export class PageModalRenderer extends React.PureComponent<{ export class PageModalRenderer extends React.PureComponent<{
modalInstance: AbstractModal, modalInstance: AbstractModal,
onBackdropClicked: () => void, onBackdropClicked: () => void,
children: React.ReactElement<ModalFrameRenderer> children: React.ReactElement<ModalFrameRenderer>,
}, {
shown: boolean shown: boolean
}> { }> {
constructor(props) { constructor(props) {
@ -157,7 +159,7 @@ export class PageModalRenderer extends React.PureComponent<{
className={joinClassList( className={joinClassList(
cssStyle.modalPageContainer, cssStyle.modalPageContainer,
cssStyle["align-" + this.props.modalInstance.verticalAlignment()], cssStyle["align-" + this.props.modalInstance.verticalAlignment()],
this.state.shown ? cssStyle.shown : undefined this.props.shown ? cssStyle.shown : undefined
)} )}
tabIndex={-1} tabIndex={-1}
role={"dialog"} role={"dialog"}

View file

@ -1,11 +1,12 @@
import { import {
AbstractModal, AbstractModal,
constructAbstractModalClass, ModalInstanceController, ModalInstanceEvents, constructAbstractModalClass,
ModalInstanceController,
ModalInstanceEvents,
ModalOptions, ModalOptions,
ModalState ModalState
} from "tc-shared/ui/react-elements/modal/Definitions"; } from "tc-shared/ui/react-elements/modal/Definitions";
import * as React from "react"; import * as React from "react";
import * as ReactDOM from "react-dom";
import { import {
ModalBodyRenderer, ModalBodyRenderer,
ModalFrameRenderer, ModalFrameRenderer,
@ -15,36 +16,79 @@ import {
import {RegisteredModal} from "tc-shared/ui/react-elements/modal/Registry"; import {RegisteredModal} from "tc-shared/ui/react-elements/modal/Registry";
import {LogCategory, logError} from "tc-shared/log"; import {LogCategory, logError} from "tc-shared/log";
import {Registry} from "tc-events"; 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 { export class InternalModalInstance implements ModalInstanceController {
readonly instanceUniqueId: string;
readonly events: Registry<ModalInstanceEvents>; readonly events: Registry<ModalInstanceEvents>;
readonly refRendererInstance: React.RefObject<InternalRendererInstance>;
private readonly modalKlass: RegisteredModal<any>; private readonly modalKlass: RegisteredModal<any>;
private readonly constructorArguments: any[]; private readonly constructorArguments: any[];
private readonly rendererInstance: React.RefObject<PageModalRenderer>;
private readonly modalOptions: ModalOptions; private readonly modalOptions: ModalOptions;
private state: ModalState; private state: ModalState;
private modalInstance: AbstractModal; public modalInstance: AbstractModal;
private htmlContainer: HTMLDivElement;
private modalInitializePromise: Promise<void>; private modalInitializePromise: Promise<void>;
constructor(modalType: RegisteredModal<any>, constructorArguments: any[], modalOptions: ModalOptions) { constructor(modalType: RegisteredModal<any>, constructorArguments: any[], modalOptions: ModalOptions) {
this.instanceUniqueId = guid();
this.events = new Registry<ModalInstanceEvents>(); this.events = new Registry<ModalInstanceEvents>();
this.modalKlass = modalType; this.modalKlass = modalType;
this.modalOptions = modalOptions; this.modalOptions = modalOptions;
this.constructorArguments = constructorArguments; this.constructorArguments = constructorArguments;
this.rendererInstance = React.createRef(); this.refRendererInstance = React.createRef();
this.state = ModalState.DESTROYED; this.state = ModalState.DESTROYED;
} }
private async constructModal() { private async constructModal() {
if(this.htmlContainer || this.modalInstance) { if(this.modalInstance) {
throw tr("internal modal has already been constructed"); 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 = constructAbstractModalClass(modalClass.default, { windowed: false }, this.constructorArguments);
this.modalInstance["onInitialize"](); this.modalInstance["onInitialize"]();
} catch (error) { } catch (error) {
this.destructModalInstance();
logError(LogCategory.GENERAL, tr("Failed to create new modal of instance type %s: %o"), this.modalKlass.modalId, error); 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"); throw tr("failed to create new modal instance");
} }
this.htmlContainer = document.createElement("div"); if(!internalModalContainer.current) {
document.body.appendChild(this.htmlContainer); this.destructModalInstance();
throw tr("missing modal hanging container");
}
await new Promise(resolve => { await new Promise(resolve => internalModalContainer.current.addModalInstance(this, resolve));
ReactDOM.render( if(!this.refRendererInstance.current) {
<PageModalRenderer modalInstance={this.modalInstance} onBackdropClicked={this.getCloseCallback()} ref={this.rendererInstance}> this.destructModalInstance();
<ModalFrameRenderer windowed={false}> throw tr("missing rendered modal reference");
<ModalFrameTopRenderer }
replacePageTitle={false}
modalInstance={this.modalInstance}
onClose={this.getCloseCallback()}
onPopout={this.getPopoutCallback()}
onMinimize={this.getMinimizeCallback()}
/>
<ModalBodyRenderer modalInstance={this.modalInstance} />
</ModalFrameRenderer>
</PageModalRenderer>,
this.htmlContainer,
resolve
);
});
} }
private destructModal() { private destructModal() {
this.state = ModalState.DESTROYED; this.state = ModalState.DESTROYED;
if(this.htmlContainer) { this.destructModalInstance();
ReactDOM.unmountComponentAtNode(this.htmlContainer); this.events.fire("notify_destroy");
this.htmlContainer.remove();
this.htmlContainer = undefined;
} }
if(this.modalInstance) { private destructModalInstance() {
this.modalInstance["onDestroy"](); internalModalContainer.current?.removeModalInstance(this);
this.modalInstance = undefined; if(!this.modalInstance) {
return;
} }
this.events.fire("notify_destroy");
try {
this.modalInstance["onDestroy"]();
} catch (error) {
logError(LogCategory.GENERAL, tr("Failed to invoke the destroy callback on the created modal instance: %o"), error);
}
this.modalInstance = undefined;
} }
getState(): ModalState { getState(): ModalState {
@ -118,13 +156,13 @@ export class InternalModalInstance implements ModalInstanceController {
await this.modalInitializePromise; await this.modalInitializePromise;
} }
if(!this.rendererInstance.current) { if(!this.refRendererInstance.current) {
return; return;
} }
this.state = ModalState.SHOWN;
this.modalInstance["onOpen"](); 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"); this.events.fire("notify_open");
} }
@ -133,13 +171,13 @@ export class InternalModalInstance implements ModalInstanceController {
await this.modalInitializePromise; await this.modalInitializePromise;
} }
if(!this.rendererInstance.current) { if(!this.refRendererInstance.current) {
return; return;
} }
this.state = ModalState.HIDDEN; this.state = ModalState.HIDDEN;
this.modalInstance["onClose"](); 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? */ /* TODO: Somehow get the real animation finish signal? */
await new Promise(resolve => setTimeout(resolve, 500)); await new Promise(resolve => setTimeout(resolve, 500));
@ -154,11 +192,11 @@ export class InternalModalInstance implements ModalInstanceController {
this.events.destroy(); this.events.destroy();
} }
protected getCloseCallback() { public getCloseCallback() {
return () => this.events.fire("action_close"); return () => this.events.fire("action_close");
} }
protected getPopoutCallback() { public getPopoutCallback() {
if(!this.modalKlass.popoutSupported) { if(!this.modalKlass.popoutSupported) {
return undefined; return undefined;
} }
@ -170,8 +208,48 @@ export class InternalModalInstance implements ModalInstanceController {
return () => this.events.fire("action_popout"); return () => this.events.fire("action_popout");
} }
protected getMinimizeCallback() { public getMinimizeCallback() {
/* We can't minimize any windows */ /* We can't minimize any windows */
return undefined; 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} />
));

View file

@ -680,8 +680,6 @@ export function initializeChannelTreeController(events: Registry<ChannelTreeUIEv
events.fire_react("notify_unread_state", { treeEntryId: event.treeEntryId, unread: entry.isUnread() }); 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_tree_entries", event => controller.sendChannelTreeEntriesFull(event.fullInfo ? undefined : []));
events.on("query_selected_entry", () => controller.sendSelectedEntry()); events.on("query_selected_entry", () => controller.sendSelectedEntry());
events.on("query_channel_info", event => { events.on("query_channel_info", event => {

View file

@ -103,7 +103,6 @@ export interface ChannelTreeUIEvents {
notify_unread_state: { treeEntryId: number, unread: boolean }, notify_unread_state: { treeEntryId: number, unread: boolean },
notify_visibility_changed: { visible: boolean },
notify_destroy: {} notify_destroy: {}
} }

View file

@ -110,25 +110,6 @@ export class ChannelTreeView extends ReactComponentBase<ChannelTreeViewPropertie
this.resizeObserver = undefined; 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() { private visibleEntries() {
const entryHeight = ChannelTreeView.EntryHeightEm * this.state.fontSize; const entryHeight = ChannelTreeView.EntryHeightEm * this.state.fontSize;
let viewEntryCount = Math.ceil(this.state.viewHeight / entryHeight); let viewEntryCount = Math.ceil(this.state.viewHeight / entryHeight);

File diff suppressed because one or more lines are too long