Fixed a minor channel tree select bug.
parent
2019cfe549
commit
f18957e75e
|
@ -32,7 +32,6 @@ import * as dns from "tc-backend/dns";
|
|||
import * as top_menu from "tc-shared/ui/frames/MenuBar";
|
||||
import {EventHandler, Registry} from "tc-shared/events";
|
||||
import {ServerLog} from "tc-shared/ui/frames/server_log";
|
||||
import {server} from "websocket";
|
||||
|
||||
export enum DisconnectReason {
|
||||
HANDLER_DESTROYED,
|
||||
|
@ -639,6 +638,7 @@ export class ConnectionHandler {
|
|||
this.serverConnection.disconnect();
|
||||
|
||||
this.side_bar.private_conversations().clear_client_ids();
|
||||
this.side_bar.channel_conversations().set_current_channel(0);
|
||||
this.hostbanner.update();
|
||||
|
||||
if(auto_reconnect) {
|
||||
|
|
|
@ -50,6 +50,8 @@ export abstract class AbstractServerConnection {
|
|||
|
||||
//FIXME: Remove this this is currently only some kind of hack
|
||||
updateConnectionState(state: ConnectionState) {
|
||||
if(state === this.connection_state_) return;
|
||||
|
||||
const old_state = this.connection_state_;
|
||||
this.connection_state_ = state;
|
||||
if(this.onconnectionstatechanged)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {ClientEvents, MusicClientEntry, SongInfo} from "tc-shared/ui/client";
|
||||
import {PlaylistSong} from "tc-shared/connection/ServerConnectionDeclaration";
|
||||
import {guid} from "tc-shared/crypto/uid";
|
||||
import * as React from "react";
|
||||
|
||||
|
@ -232,7 +231,11 @@ export function ReactEventHandler<ObjectClass = React.Component<any, any>, Event
|
|||
constructor.prototype.componentWillUnmount = function () {
|
||||
const registry = registry_callback(this);
|
||||
if(!registry) throw "Event registry returned for an event object is invalid";
|
||||
registry.unregister_handler(this);
|
||||
try {
|
||||
registry.unregister_handler(this);
|
||||
} catch (error) {
|
||||
console.warn("Failed to unregister event handler: %o", error);
|
||||
}
|
||||
|
||||
if(typeof willUnmount === "function")
|
||||
willUnmount.call(this, arguments);
|
||||
|
|
|
@ -29,8 +29,7 @@ import * as React from "react";
|
|||
import * as ReactDOM from "react-dom";
|
||||
import * as cbar from "./ui/frames/control-bar";
|
||||
import * as global_ev_handler from "./events/ClientGlobalControlHandler";
|
||||
import {ClientGlobalControlEvents, global_client_actions} from "tc-shared/events/GlobalEvents";
|
||||
import {spawnSettingsModal} from "tc-shared/ui/modal/ModalSettings";
|
||||
import {global_client_actions} from "tc-shared/events/GlobalEvents";
|
||||
|
||||
/* required import for init */
|
||||
require("./proto").initialize();
|
||||
|
|
|
@ -38,7 +38,9 @@ export class LocalIconRenderer extends React.Component<LoadedIconRenderer, {}> {
|
|||
|
||||
render() {
|
||||
const icon = this.props.icon;
|
||||
if(icon.status === "loaded") {
|
||||
if(!icon || icon.status === "empty" || icon.status === "destroyed")
|
||||
return <div className={"icon-container icon-empty"} title={this.props.title} />;
|
||||
else if(icon.status === "loaded") {
|
||||
if(icon.icon_id >= 0 && icon.icon_id <= 1000) {
|
||||
if(icon.icon_id === 0)
|
||||
return <div className={"icon-container icon-empty"} title={this.props.title} />;
|
||||
|
@ -49,15 +51,13 @@ export class LocalIconRenderer extends React.Component<LoadedIconRenderer, {}> {
|
|||
return <div key={"loading"} className={"icon-container"} title={this.props.title}><div className={"icon_loading"} /></div>;
|
||||
else if(icon.status === "error")
|
||||
return <div key={"error"} className={"icon client-warning"} title={icon.error_message || tr("Failed to load icon")} />;
|
||||
else if(icon.status === "empty" || icon.status === "destroyed")
|
||||
return <div className={"icon-container icon-empty"} title={this.props.title} />;
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this.props.icon.status_change_callbacks.push(this.callback_state_update);
|
||||
this.props.icon?.status_change_callbacks.push(this.callback_state_update);
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
this.props.icon.status_change_callbacks.remove(this.callback_state_update);
|
||||
this.props.icon?.status_change_callbacks.remove(this.callback_state_update);
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ let update_batches: {[key: number]:UpdateBatch} = {
|
|||
0: generate_batch(),
|
||||
1: generate_batch()
|
||||
};
|
||||
(window as any).update_batches = update_batches;
|
||||
|
||||
export function BatchUpdateAssignment(type: BatchUpdateType) {
|
||||
return function (constructor: Function) {
|
||||
|
|
|
@ -31,6 +31,8 @@ export interface ChannelTreeViewState {
|
|||
element_scroll_offset?: number; /* in px */
|
||||
scroll_offset: number; /* in px */
|
||||
view_height: number; /* in px */
|
||||
|
||||
tree_version: number;
|
||||
}
|
||||
|
||||
type TreeEntry = ChannelEntry | ServerEntry | ClientEntry;
|
||||
|
@ -67,6 +69,7 @@ export class ChannelTreeView extends ReactComponentBase<ChannelTreeViewPropertie
|
|||
return {
|
||||
scroll_offset: 0,
|
||||
view_height: 0,
|
||||
tree_version: 0
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -238,6 +241,14 @@ export class ChannelTreeView extends ReactComponentBase<ChannelTreeViewPropertie
|
|||
this.handleTreeUpdate();
|
||||
}
|
||||
|
||||
@EventHandler<ChannelTreeEvents>("notify_tree_reset")
|
||||
private handleTreeReset() {
|
||||
this.rebuild_tree();
|
||||
this.setState({
|
||||
tree_version: this.state.tree_version + 1
|
||||
});
|
||||
}
|
||||
|
||||
private onScroll() {
|
||||
this.setState({
|
||||
scroll_offset: this.ref_container.current.scrollTop
|
||||
|
|
|
@ -42,6 +42,7 @@ export interface ChannelTreeEvents {
|
|||
|
||||
notify_selection_changed: {},
|
||||
notify_root_channel_changed: {},
|
||||
notify_tree_reset: {},
|
||||
notify_query_view_state_changed: { queries_shown: boolean },
|
||||
|
||||
notify_entry_move_begin: {},
|
||||
|
@ -283,37 +284,6 @@ export class ChannelTree {
|
|||
this.events.destroy();
|
||||
}
|
||||
|
||||
showContextMenu(x: number, y: number, on_close: () => void = undefined) {
|
||||
let channelCreate =
|
||||
this.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_TEMPORARY).granted(1) ||
|
||||
this.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_SEMI_PERMANENT).granted(1) ||
|
||||
this.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_PERMANENT).granted(1);
|
||||
|
||||
contextmenu.spawn_context_menu(x, y,
|
||||
{
|
||||
type: contextmenu.MenuEntryType.ENTRY,
|
||||
icon_class: "client-channel_create",
|
||||
name: tr("Create channel"),
|
||||
invalidPermission: !channelCreate,
|
||||
callback: () => this.spawnCreateChannel()
|
||||
},
|
||||
contextmenu.Entry.HR(),
|
||||
{
|
||||
type: contextmenu.MenuEntryType.ENTRY,
|
||||
icon_class: "client-channel_collapse_all",
|
||||
name: tr("Collapse all channels"),
|
||||
callback: () => this.collapse_channels()
|
||||
},
|
||||
{
|
||||
type: contextmenu.MenuEntryType.ENTRY,
|
||||
icon_class: "client-channel_expand_all",
|
||||
name: tr("Expend all channels"),
|
||||
callback: () => this.expand_channels()
|
||||
},
|
||||
contextmenu.Entry.CLOSE(on_close)
|
||||
);
|
||||
}
|
||||
|
||||
initialiseHead(serverName: string, address: ServerAddress) {
|
||||
this.server.reset();
|
||||
this.server.remote_address = Object.assign({}, address);
|
||||
|
@ -572,6 +542,36 @@ export class ChannelTree {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
showContextMenu(x: number, y: number, on_close: () => void = undefined) {
|
||||
let channelCreate =
|
||||
this.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_TEMPORARY).granted(1) ||
|
||||
this.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_SEMI_PERMANENT).granted(1) ||
|
||||
this.client.permissions.neededPermission(PermissionType.B_CHANNEL_CREATE_PERMANENT).granted(1);
|
||||
|
||||
contextmenu.spawn_context_menu(x, y,
|
||||
{
|
||||
type: contextmenu.MenuEntryType.ENTRY,
|
||||
icon_class: "client-channel_create",
|
||||
name: tr("Create channel"),
|
||||
invalidPermission: !channelCreate,
|
||||
callback: () => this.spawnCreateChannel()
|
||||
},
|
||||
contextmenu.Entry.HR(),
|
||||
{
|
||||
type: contextmenu.MenuEntryType.ENTRY,
|
||||
icon_class: "client-channel_collapse_all",
|
||||
name: tr("Collapse all channels"),
|
||||
callback: () => this.collapse_channels()
|
||||
},
|
||||
{
|
||||
type: contextmenu.MenuEntryType.ENTRY,
|
||||
icon_class: "client-channel_expand_all",
|
||||
name: tr("Expend all channels"),
|
||||
callback: () => this.expand_channels()
|
||||
},
|
||||
contextmenu.Entry.CLOSE(on_close)
|
||||
);
|
||||
}
|
||||
private open_multiselect_context_menu(entries: ChannelTreeEntry<any>[], x: number, y: number) {
|
||||
const clients = entries.filter(e => e instanceof ClientEntry) as ClientEntry[];
|
||||
const channels = entries.filter(e => e instanceof ChannelEntry) as ChannelEntry[];
|
||||
|
@ -811,13 +811,9 @@ export class ChannelTree {
|
|||
this.channels = [];
|
||||
this.channel_last = undefined;
|
||||
this.channel_first = undefined;
|
||||
this.events.fire("notify_tree_reset");
|
||||
} finally {
|
||||
try {
|
||||
this.events.fire_async("notify_root_channel_changed", undefined, () => flush_batched_updates(BatchUpdateType.CHANNEL_TREE));
|
||||
} catch (e) {
|
||||
flush_batched_updates(BatchUpdateType.CHANNEL_TREE);
|
||||
throw e;
|
||||
}
|
||||
flush_batched_updates(BatchUpdateType.CHANNEL_TREE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue