Adjusted the client to the new webpack shared part

This commit is contained in:
WolverinDEV 2021-03-20 16:18:05 +01:00
parent 5d6f462b42
commit 84a82a8b27
129 changed files with 1279 additions and 779 deletions

67
imports/shared-app/Bookmarks.d.ts vendored Normal file
View File

@ -0,0 +1,67 @@
import { WritableKeys } from "tc-shared/proto";
import { Registry } from "tc-events";
declare type BookmarkBase = {
readonly uniqueId: string;
displayName: string;
previousEntry: string | undefined;
parentEntry: string | undefined;
};
export declare type BookmarkInfo = BookmarkBase & {
readonly type: "entry";
connectOnStartup: boolean;
connectProfile: string;
serverAddress: string;
serverPasswordHash: string | undefined;
defaultChannel: string | undefined;
defaultChannelPasswordHash: string | undefined;
};
export declare type BookmarkDirectory = BookmarkBase & {
readonly type: "directory";
};
export declare type BookmarkEntry = BookmarkInfo | BookmarkDirectory;
export interface BookmarkEvents {
notify_bookmark_created: {
bookmark: BookmarkEntry;
};
notify_bookmark_edited: {
bookmark: BookmarkEntry;
keys: (keyof BookmarkInfo | keyof BookmarkDirectory)[];
};
notify_bookmark_deleted: {
bookmark: BookmarkEntry;
children: BookmarkEntry[];
};
notify_bookmarks_imported: {
bookmarks: BookmarkEntry[];
};
}
export declare type OrderedBookmarkEntry = {
entry: BookmarkEntry;
depth: number;
childCount: number;
};
export declare class BookmarkManager {
readonly events: Registry<BookmarkEvents>;
private readonly registeredBookmarks;
private defaultBookmarkCreated;
constructor();
private loadBookmarks;
private importOldBookmarks;
private saveBookmarks;
getRegisteredBookmarks(): BookmarkEntry[];
getOrderedRegisteredBookmarks(): OrderedBookmarkEntry[];
findBookmark(uniqueId: string): BookmarkEntry | undefined;
createBookmark(properties: Pick<BookmarkInfo, WritableKeys<BookmarkInfo>>): BookmarkInfo;
editBookmark(uniqueId: string, newValues: Partial<Pick<BookmarkInfo, WritableKeys<BookmarkInfo>>>): void;
createDirectory(properties: Pick<BookmarkInfo, WritableKeys<BookmarkDirectory>>): BookmarkDirectory;
editDirectory(uniqueId: string, newValues: Partial<Pick<BookmarkDirectory, WritableKeys<BookmarkDirectory>>>): void;
deleteEntry(uniqueId: string): void;
executeConnect(uniqueId: string, newTab: boolean): void;
executeAutoConnect(): void;
exportBookmarks(): string;
importBookmarks(filePayload: string): number;
private doEditBookmark;
private validateHangInPoint;
}
export declare let bookmarks: BookmarkManager;
export {};

View File

@ -2,7 +2,7 @@ import { AbstractServerConnection } from "./connection/ConnectionBase";
import { PermissionManager } from "./permission/PermissionManager";
import { GroupManager } from "./permission/GroupManager";
import { ServerSettings } from "./settings";
import { SoundManager } from "./sound/Sounds";
import { SoundManager } from "./audio/Sounds";
import { ConnectionProfile } from "./profiles/ConnectionProfile";
import { RecorderProfile } from "./voice/RecorderProfile";
import { Registry } from "./events";

View File

@ -129,19 +129,45 @@ export declare enum SpecialKey {
ALT = 3
}
export interface KeyDescriptor {
key_code: string;
key_ctrl: boolean;
key_windows: boolean;
key_shift: boolean;
key_alt: boolean;
keyCode: string;
keyCtrl: boolean;
keyWindows: boolean;
keyShift: boolean;
keyAlt: boolean;
}
export interface KeyEvent extends KeyDescriptor {
readonly type: EventType;
readonly key: string;
}
export interface KeyHook extends KeyDescriptor {
cancel: boolean;
callback_press: () => any;
callback_release: () => any;
callbackPress: () => any;
callbackRelease: () => any;
}
export declare function key_description(key: KeyDescriptor): string;
export interface KeyBoardBackend {
registerListener(listener: (event: KeyEvent) => void): any;
unregisterListener(listener: (event: KeyEvent) => void): any;
registerHook(hook: KeyHook): any;
unregisterHook(hook: KeyHook): any;
isKeyPressed(key: string | SpecialKey): boolean;
}
export declare class AbstractKeyBoard implements KeyBoardBackend {
protected readonly registeredListener: ((event: KeyEvent) => void)[];
protected readonly activeSpecialKeys: {
[key: number]: boolean;
};
protected readonly activeKeys: any;
protected registeredKeyHooks: KeyHook[];
protected activeKeyHooks: KeyHook[];
constructor();
protected destroy(): void;
isKeyPressed(key: string | SpecialKey): boolean;
registerHook(hook: KeyHook): void;
unregisterHook(hook: KeyHook): void;
registerListener(listener: (event: KeyEvent) => void): void;
unregisterListener(listener: (event: KeyEvent) => void): void;
protected fireKeyEvent(event: KeyEvent): void;
protected resetKeyboardState(): void;
}
export declare function getKeyBoard(): KeyBoardBackend;
export declare function setKeyBoardBackend(newBackend: KeyBoardBackend): void;
export declare function getKeyDescription(key: KeyDescriptor): string;

27
imports/shared-app/audio/Player.d.ts vendored Normal file
View File

@ -0,0 +1,27 @@
export interface OutputDevice {
device_id: string;
driver: string;
name: string;
}
export interface AudioBackendEvents {
notify_initialized: {};
notify_volume_changed: {
oldVolume: number;
newVolume: number;
};
}
export interface AudioBackend {
isInitialized(): boolean;
getAudioContext(): AudioContext | undefined;
isDeviceRefreshAvailable(): boolean;
refreshDevices(): Promise<void>;
getAvailableDevices(): Promise<OutputDevice[]>;
getDefaultDeviceId(): string;
getCurrentDevice(): OutputDevice;
setCurrentDevice(targetId: string | undefined): Promise<void>;
getMasterVolume(): number;
setMasterVolume(volume: number): any;
executeWhenInitialized(callback: () => void): any;
}
export declare function getAudioBackend(): AudioBackend;
export declare function setAudioBackend(newBackend: AudioBackend): void;

View File

@ -1,9 +1,8 @@
import { AbstractInput, LevelMeter } from "../voice/RecorderBase";
import { Registry } from "../events";
export declare type DeviceQueryResult = {};
export interface AudioRecorderBacked {
createInput(): AbstractInput;
createLevelMeter(device: IDevice): Promise<LevelMeter>;
createLevelMeter(device: InputDevice): Promise<LevelMeter>;
getDeviceList(): DeviceList;
isRnNoiseSupported(): boolean;
toggleRnNoise(target: boolean): any;
@ -23,12 +22,12 @@ export interface DeviceListEvents {
};
}
export declare type DeviceListState = "healthy" | "uninitialized" | "no-permissions" | "error";
export interface IDevice {
export interface InputDevice {
deviceId: string;
driver: string;
name: string;
}
export declare namespace IDevice {
export declare namespace InputDevice {
const NoDeviceId = "none";
const DefaultDeviceId = "default";
}
@ -40,7 +39,7 @@ export interface DeviceList {
requestPermissions(): Promise<PermissionState>;
getPermissionState(): PermissionState;
getStatus(): DeviceListState;
getDevices(): IDevice[];
getDevices(): InputDevice[];
getDefaultDeviceId(): string;
awaitHealthy(): Promise<void>;
awaitInitialized(): Promise<void>;
@ -57,7 +56,7 @@ export declare abstract class AbstractDeviceList implements DeviceList {
awaitInitialized(): Promise<void>;
awaitHealthy(): Promise<void>;
abstract getDefaultDeviceId(): string;
abstract getDevices(): IDevice[];
abstract getDevices(): InputDevice[];
abstract getEvents(): Registry<DeviceListEvents>;
abstract isRefreshAvailable(): boolean;
abstract refresh(): Promise<void>;

View File

@ -80,3 +80,8 @@ export declare class SoundManager {
constructor(handle: ConnectionHandler);
play(_sound: Sound, options?: PlaybackOptions): void;
}
export interface SoundBackend {
playSound(sound: SoundFile): Promise<void>;
}
export declare function getSoundBackend(): SoundBackend;
export declare function setSoundBackend(newSoundBackend: SoundBackend): void;

View File

@ -1,5 +0,0 @@
export interface Device {
device_id: string;
driver: string;
name: string;
}

View File

@ -1,48 +0,0 @@
import { ConnectionHandler } from "./ConnectionHandler";
import { Registry } from "tc-shared/events";
export interface BookmarkEvents {
notify_bookmarks_updated: {};
}
export declare const bookmarkEvents: Registry<BookmarkEvents>;
export declare const boorkmak_connect: (mark: Bookmark, new_tab?: boolean) => void;
export interface ServerProperties {
server_address: string;
server_port: number;
server_password_hash?: string;
server_password?: string;
}
export declare enum BookmarkType {
ENTRY = 0,
DIRECTORY = 1
}
export interface Bookmark {
type: BookmarkType.ENTRY;
parent: DirectoryBookmark;
server_properties: ServerProperties;
display_name: string;
unique_id: string;
nickname: string;
default_channel?: number | string;
default_channel_password_hash?: string;
default_channel_password?: string;
connect_profile: string;
last_icon_id?: number;
last_icon_server_id?: string;
}
export interface DirectoryBookmark {
type: BookmarkType.DIRECTORY;
parent: DirectoryBookmark;
readonly content: (Bookmark | DirectoryBookmark)[];
unique_id: string;
display_name: string;
}
export declare function bookmarks(): DirectoryBookmark;
export declare function bookmarks_flat(): Bookmark[];
export declare function find_bookmark(uuid: string): Bookmark | DirectoryBookmark | undefined;
export declare function parent_bookmark(bookmark: Bookmark): DirectoryBookmark;
export declare function create_bookmark(display_name: string, directory: DirectoryBookmark, server_properties: ServerProperties, nickname: string): Bookmark;
export declare function create_bookmark_directory(parent: DirectoryBookmark, name: string): DirectoryBookmark;
export declare function change_directory(parent: DirectoryBookmark, bookmark: Bookmark | DirectoryBookmark): void;
export declare function save_bookmark(bookmark?: Bookmark | DirectoryBookmark): void;
export declare function delete_bookmark(bookmark: Bookmark | DirectoryBookmark): void;
export declare function add_server_to_bookmarks(server: ConnectionHandler): void;

View File

@ -129,6 +129,8 @@ export declare enum ErrorCode {
SERVER_CONNECT_BANNED = 3329,
BAN_FLOODING = 3331,
TOKEN_INVALID_ID = 3840,
TOKEN_EXPIRED = 3856,
TOKEN_USE_LIMIT_EXCEEDED = 3857,
WEB_HANDSHAKE_INVALID = 4096,
WEB_HANDSHAKE_UNSUPPORTED = 4097,
WEB_HANDSHAKE_IDENTITY_UNSUPPORTED = 4098,

View File

@ -19,6 +19,8 @@ export declare type ConnectionHistoryServerInfo = {
country: string;
clientsOnline: number | -1;
clientsMax: number | -1;
hostBannerUrl: string | undefined;
hostBannerMode: number;
passwordProtected: boolean;
};
export declare class ConnectionHistory {

View File

@ -1 +0,0 @@
import "./proto";

View File

@ -4,12 +4,42 @@ export interface AddressTarget {
}
export interface ResolveOptions {
timeout?: number;
allow_cache?: boolean;
max_depth?: number;
allow_srv?: boolean;
allow_cname?: boolean;
allow_any?: boolean;
allow_a?: boolean;
allow_aaaa?: boolean;
allowCache?: boolean;
maxDepth?: number;
allowSrv?: boolean;
allowCName?: boolean;
allowAny?: boolean;
allowA?: boolean;
allowAAAA?: boolean;
}
export declare const default_options: ResolveOptions;
export interface DNSResolveOptions {
timeout?: number;
allowCache?: boolean;
maxDepth?: number;
allowSrv?: boolean;
allowCName?: boolean;
allowAny?: boolean;
allowA?: boolean;
allowAAAA?: boolean;
}
export interface DNSAddress {
hostname: string;
port: number;
}
export declare type DNSResolveResult = {
status: "success";
originalAddress: DNSAddress;
resolvedAddress: DNSAddress;
} | {
status: "error";
message: string;
} | {
status: "empty-result";
};
export interface DNSProvider {
resolveAddress(address: DNSAddress, options: DNSResolveOptions): Promise<DNSResolveResult>;
resolveAddressIPv4(address: DNSAddress, options: DNSResolveOptions): Promise<DNSResolveResult>;
}
export declare function getDNSProvider(): DNSProvider;
export declare function setDNSProvider(newProvider: DNSProvider): void;

View File

@ -0,0 +1 @@
import "../main";

View File

@ -0,0 +1 @@
import "../ui/react-elements/modal/external/renderer/EntryPoint";

View File

@ -47,6 +47,7 @@ export declare abstract class RemoteIcon {
}
export declare abstract class AbstractIconManager {
protected static iconUniqueKey(iconId: number, serverUniqueId: string): string;
resolveIconInfo(icon: RemoteIconInfo): RemoteIcon;
/**
* @param iconId The requested icon
* @param serverUniqueId The server unique id for the icon

2
imports/shared-app/file/Utils.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
export declare const downloadTextAsFile: (text: string, name: string) => void;
export declare const requestFileAsText: () => Promise<string>;

View File

@ -62,7 +62,7 @@ export declare function registered_repositories(): TranslationRepository[];
export declare function delete_repository(repository: TranslationRepository): void;
export declare function iterate_repositories(callback_entry: (repository: TranslationRepository) => any): Promise<void>;
export declare function select_translation(repository: TranslationRepository, entry: RepositoryTranslation): void;
export declare function initialize(): Promise<void>;
export declare function initializeI18N(): Promise<void>;
declare global {
interface Window {
tr(message: string): string;

View File

@ -21,6 +21,7 @@ import "./ui/elements/ContextDivider";
import "./ui/elements/Tab";
import "./clientservice";
import "./text/bbcode/InviteController";
import "./text/bbcode/YoutubeController";
export declare function handleNativeConnectRequest(url: URL): void;
export declare function handleConnectRequest(serverAddress: string, serverUniqueId: string | undefined, parameters: UrlParameterParser): Promise<void>;
export declare function handle_connect_request(properties: ConnectRequestData, _connection: ConnectionHandler): void;

View File

@ -7,7 +7,17 @@ declare global {
remove(elem?: T): boolean;
last?(): T;
pop_front(): T | undefined;
/**
* @param entry The entry to toggle
* @returns `true` if the entry has been inserted and false if the entry has been deleted
*/
toggle(entry: T): boolean;
/**
* @param entry The entry to toggle
* @param insert Whatever the entry should be in the array or not
* @returns `true` if the array has been modified
*/
toggle(entry: T, insert: boolean): any;
}
interface JSON {
map_to<T>(object: T, json: any, variables?: string | string[], validator?: (map_field: string, map_value: string) => boolean, variable_direction?: number): number;
@ -47,5 +57,18 @@ declare global {
isSimilar(a: any, b: any): boolean;
}
}
declare const _default: {};
export = _default;
export declare type IfEquals<X, Y, A = X, B = never> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? A : B;
export declare type WritableKeys<T> = {
[P in keyof T]-?: IfEquals<{
[Q in P]: T[P];
}, {
-readonly [Q in P]: T[P];
}, P, never>;
}[keyof T];
export declare type ReadonlyKeys<T> = {
[P in keyof T]: IfEquals<{
[Q in P]: T[P];
}, {
-readonly [Q in P]: T[P];
}, never, P>;
}[keyof T];

View File

@ -50,8 +50,7 @@ export declare namespace AppParameters {
const KEY_CONNECT_CHANNEL_PASSWORD: RegistryKey<string>;
const KEY_IPC_APP_ADDRESS: RegistryKey<string>;
const KEY_IPC_CORE_PEER_ADDRESS: RegistryKey<string>;
const KEY_MODAL_IDENTITY_CODE: RegistryKey<string>;
const KEY_MODAL_TARGET: RegistryKey<string>;
const KEY_MODAL_IPC_CHANNEL: RegistryKey<string>;
const KEY_LOAD_DUMMY_ERROR: ValuedRegistryKey<boolean>;
}
export declare class StaticSettings {
@ -139,8 +138,13 @@ export declare class Settings {
static readonly KEY_VIDEO_DYNAMIC_QUALITY: ValuedRegistryKey<boolean>;
static readonly KEY_VIDEO_DYNAMIC_FRAME_RATE: ValuedRegistryKey<boolean>;
static readonly KEY_VIDEO_QUICK_SETUP: ValuedRegistryKey<boolean>;
static readonly KEY_VIDEO_SPOTLIGHT_MODE: ValuedRegistryKey<number>;
static readonly KEY_INVITE_SHORT_URL: ValuedRegistryKey<boolean>;
static readonly KEY_INVITE_ADVANCED_ENABLED: ValuedRegistryKey<boolean>;
static readonly KEY_MICROPHONE_LEVEL_INDICATOR: RegistryKey<boolean>;
static readonly KEY_MICROPHONE_THRESHOLD_ATTACK_SMOOTH: ValuedRegistryKey<number>;
static readonly KEY_MICROPHONE_THRESHOLD_RELEASE_SMOOTH: ValuedRegistryKey<number>;
static readonly KEY_MICROPHONE_THRESHOLD_RELEASE_DELAY: ValuedRegistryKey<number>;
static readonly FN_LOG_ENABLED: (category: string) => RegistryKey<boolean>;
static readonly FN_SEPARATOR_STATE: (separator: string) => RegistryKey<string>;
static readonly FN_LOG_LEVEL_ENABLED: (category: string) => RegistryKey<boolean>;

View File

@ -0,0 +1 @@
export {};

View File

@ -4,7 +4,7 @@ import ReactRenderer from "vendor/xbbcode/renderer/react";
import HTMLRenderer from "vendor/xbbcode/renderer/html";
import "./emoji";
import "./highlight";
import "./youtube";
import "./YoutubeRenderer";
import "./url";
import "./image";
export declare let BBCodeHandlerContext: Context<string>;

View File

@ -127,8 +127,7 @@ export declare class ChannelEntry extends ChannelTreeEntry<ChannelEvents> {
key: string;
value: string;
}[]): void;
generate_bbcode(): string;
generate_tag(braces?: boolean): JQuery;
generateBBCode(): string;
channelType(): ChannelType;
joinChannel(ignorePasswordFlag?: boolean): Promise<boolean>;
requestChannelPassword(ignorePermission: PermissionType): Promise<{

View File

@ -84,6 +84,7 @@ export interface ServerAddress {
port: number;
}
export declare function parseServerAddress(address: string): ServerAddress | undefined;
export declare function stringifyServerAddress(address: ServerAddress): string;
export interface ServerEvents extends ChannelTreeEntryEvents {
notify_properties_updated: {
updated_properties: Partial<ServerProperties>;

View File

@ -42,6 +42,7 @@ export declare class Modal {
export declare function createModal(data: ModalProperties | any): Modal;
export declare class InputModalProperties extends ModalProperties {
maxLength?: number;
defaultValue?: string;
field_title?: string;
field_label?: string;
field_placeholder?: string;

View File

@ -1,6 +1,10 @@
import { Registry } from "tc-shared/events";
import { HostBannerUiEvents } from "tc-shared/ui/frames/HostBannerDefinitions";
import { HostBannerInfoSet, HostBannerUiEvents } from "tc-shared/ui/frames/HostBannerDefinitions";
import * as React from "react";
export declare const HostBannerRenderer: React.MemoExoticComponent<(props: {
banner: HostBannerInfoSet;
className?: string;
}) => JSX.Element>;
export declare const HostBanner: React.MemoExoticComponent<(props: {
events: Registry<HostBannerUiEvents>;
}) => JSX.Element>;

View File

@ -0,0 +1,5 @@
import React from "react";
export declare const ImagePreviewHook: React.MemoExoticComponent<() => JSX.Element>;
export declare function showImagePreview(url: string, originalUrl: string): void;
export declare function isImagePreviewAvailable(): boolean;
export declare function closeImagePreview(): void;

View File

@ -23,7 +23,7 @@ declare class InfoController {
private unregisterCurrentHandlerEvents;
setConnectionHandler(handler: ConnectionHandler): void;
sendConnectionState(): void;
sendBookmarks(): void;
sendBookmarks(): Promise<void>;
sendAwayState(): void;
sendMicrophoneState(): void;
sendMicrophoneList(): void;

View File

@ -1,4 +0,0 @@
export declare function preview_image(url: string, original_url: string): void;
export declare function preview_image_tag(tag: JQuery): void;
export declare function current_url(): string;
export declare function close_preview(): void;

View File

@ -80,8 +80,9 @@ export interface ChannelVideoEvents {
action_video_scroll: {
direction: "left" | "right";
};
action_set_spotlight: {
videoId: string | undefined;
action_toggle_spotlight: {
videoIds: string[];
enabled: boolean;
expend: boolean;
};
action_focus_spotlight: {};
@ -143,7 +144,7 @@ export interface ChannelVideoEvents {
right: boolean;
};
notify_spotlight: {
videoId: string | undefined;
videoId: string[];
};
notify_video_statistics: {
videoId: string | undefined;

View File

@ -1,6 +1,11 @@
/// <reference types="react" />
import * as React from "react";
import { Registry } from "tc-shared/events";
import { ChannelVideoEvents } from "tc-shared/ui/frames/video/Definitions";
import { ChannelVideoEvents } from "./Definitions";
export declare const RendererVideoEventContext: React.Context<Registry<ChannelVideoEvents>>;
export declare const VideoContainer: React.MemoExoticComponent<(props: {
videoId: string;
isSpotlight: boolean;
}) => JSX.Element>;
export declare const ChannelVideoRenderer: (props: {
handlerId: string;
events: Registry<ChannelVideoEvents>;

View File

@ -0,0 +1,9 @@
import * as React from "react";
import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!react-resizable/css/styles.css";
import "!style-loader!css-loader?url=false!sass-loader?sourceMap=true!react-grid-layout/css/styles.css";
export declare type SpotlightDimensions = {
width: number;
height: number;
};
export declare const SpotlightDimensionsContext: React.Context<SpotlightDimensions>;
export declare const Spotlight: () => JSX.Element;

View File

@ -5,17 +5,8 @@ export interface ClientProperties {
add_braces?: boolean;
client_database_id?: number;
}
export interface ChannelProperties {
channel_id: number;
channel_name: string;
channel_display_name?: string;
add_braces?: boolean;
}
export declare function generate_client(properties: ClientProperties): string;
export declare function generate_client_object(properties: ClientProperties): JQuery;
export declare function generate_channel(properties: ChannelProperties): string;
export declare function generate_channel_object(properties: ChannelProperties): JQuery;
export declare namespace callbacks {
function callback_context_client(element: JQuery): boolean;
function callback_context_channel(element: JQuery): boolean;
}

View File

@ -18,5 +18,5 @@ export interface VolumeChangeEvents {
};
"close-modal": {};
}
export declare function spawnClientVolumeChange(client: ClientEntry): import("../react-elements/internal-modal/Controller").InternalModalController;
export declare function spawnMusicBotVolumeChange(client: MusicClientEntry, maxValue: number): import("../react-elements/internal-modal/Controller").InternalModalController;
export declare function spawnClientVolumeChange(client: ClientEntry): import("../react-elements/modal/Definitions").ModalController;
export declare function spawnMusicBotVolumeChange(client: MusicClientEntry, maxValue: number): import("../react-elements/modal/Definitions").ModalController;

View File

@ -1,2 +0,0 @@
import { ConnectionHandler } from "../../ConnectionHandler";
export declare function spawnInviteEditor(connection: ConnectionHandler): void;

View File

@ -1,11 +0,0 @@
import { ConnectionHandler } from "../../ConnectionHandler";
export interface ServerEntry {
source: ConnectionHandler;
add_message(invoker: PokeInvoker, message: string): any;
}
export declare type PokeInvoker = {
name: string;
id: number;
unique_id: string;
};
export declare function spawnPoke(source: ConnectionHandler, invoker: PokeInvoker, message: string): void;

View File

@ -0,0 +1,2 @@
import { ConnectionHandler } from "tc-shared/ConnectionHandler";
export declare function spawnModalAddCurrentServerToBookmarks(handler: ConnectionHandler): void;

View File

@ -0,0 +1,21 @@
export declare type TargetBookmarkInfo = {
type: "success";
handlerId: string;
serverName: string;
serverUniqueId: string;
currentChannelId: number;
currentChannelName: string;
} | {
type: "not-connected" | "loading";
};
export interface ModalBookmarksAddServerVariables {
readonly serverInfo: TargetBookmarkInfo;
bookmarkName: string;
bookmarkNameValid: boolean;
saveCurrentChannel: boolean;
}
export interface ModalBookmarksAddServerEvents {
action_add_bookmark: {};
action_cancel: {};
notify_bookmark_added: {};
}

View File

@ -0,0 +1,13 @@
import { AbstractModal } from "tc-shared/ui/react-elements/modal/Definitions";
import React from "react";
import { IpcRegistryDescription } from "tc-events";
import { ModalBookmarksAddServerEvents, ModalBookmarksAddServerVariables } from "tc-shared/ui/modal/bookmarks-add-server/Definitions";
import { IpcVariableDescriptor } from "tc-shared/ui/utils/IpcVariable";
declare class ModalBookmarksAddServer extends AbstractModal {
private readonly variables;
private readonly events;
constructor(events: IpcRegistryDescription<ModalBookmarksAddServerEvents>, variables: IpcVariableDescriptor<ModalBookmarksAddServerVariables>);
renderBody(): React.ReactElement;
renderTitle(): string | React.ReactElement;
}
export = ModalBookmarksAddServer;

View File

@ -0,0 +1,87 @@
import { RemoteIconInfo } from "tc-shared/file/Icons";
export declare type BookmarkListEntry = {
uniqueId: string;
type: "bookmark" | "directory";
displayName: string;
icon: RemoteIconInfo | undefined;
depth: number;
childCount: number;
};
export interface BookmarkConnectInfo {
serverName: string;
serverRegion: string;
clientsOnline: number;
clientsMax: number;
connectCountUniqueId: number;
connectCountAddress: number;
hostBannerUrl: string;
hostBannerMode: number;
}
export declare type CurrentClientChannel = {
name: string;
channelId: number;
path: string;
passwordHash: string;
};
export interface ModalBookmarkVariables {
readonly bookmarks: BookmarkListEntry[];
bookmarkSelected: {
type?: "empty" | "bookmark" | "directory";
id: string | undefined;
};
readonly connectProfiles: {
id: string;
name: string;
}[];
readonly currentClientChannel: CurrentClientChannel | undefined;
bookmarkName: string;
bookmarkConnectProfile: string;
bookmarkConnectOnStartup: boolean;
bookmarkServerAddress: string;
bookmarkServerPassword: string | undefined;
bookmarkDefaultChannel: string | undefined;
bookmarkDefaultChannelPassword: string | undefined;
bookmarkInfo: BookmarkConnectInfo | undefined;
}
export interface ModalBookmarkEvents {
action_create_bookmark: {
entryType: "bookmark" | "directory";
order: {
type: "previous";
entry: string;
} | {
type: "parent";
entry: string;
} | {
type: "selected";
};
displayName: string | undefined;
};
action_duplicate_bookmark: {
uniqueId: string;
displayName: string | undefined;
originalName: string;
};
action_delete_bookmark: {
uniqueId: string;
};
action_connect: {
uniqueId: string;
newTab: boolean;
closeModal: boolean;
};
action_export: {};
action_import: {
payload: string | undefined;
};
notify_export_data: {
payload: string;
};
notify_import_result: {
status: "success";
importedBookmarks: number;
} | {
status: "error";
message: string;
};
}

View File

@ -0,0 +1,15 @@
import { AbstractModal } from "tc-shared/ui/react-elements/modal/Definitions";
import { IpcVariableDescriptor } from "tc-shared/ui/utils/IpcVariable";
import { ModalBookmarkEvents, ModalBookmarkVariables } from "tc-shared/ui/modal/bookmarks/Definitions";
import { IpcRegistryDescription, Registry } from "tc-events";
import { UiVariableConsumer } from "tc-shared/ui/utils/Variable";
import * as React from "react";
declare class ModalBookmarks extends AbstractModal {
readonly events: Registry<ModalBookmarkEvents>;
readonly variables: UiVariableConsumer<ModalBookmarkVariables>;
constructor(events: IpcRegistryDescription<ModalBookmarkEvents>, variables: IpcVariableDescriptor<ModalBookmarkVariables>);
protected onDestroy(): void;
renderBody(): React.ReactElement;
renderTitle(): string | React.ReactElement;
}
export = ModalBookmarks;

View File

@ -11,7 +11,6 @@ declare class ConnectModal extends AbstractModal {
protected onDestroy(): void;
renderBody(): React.ReactElement;
renderTitle(): string | React.ReactElement;
color(): "none" | "blue";
verticalAlignment(): "top" | "center" | "bottom";
}
export = ConnectModal;

View File

@ -50,7 +50,7 @@ export interface PermissionModalEvents {
id: number | string | undefined;
};
action_set_permission_editor_subject: {
mode: PermissionEditorSubject;
mode: PermissionEditorSubject | undefined;
groupId?: number;
channelId?: number;
clientDatabaseId?: number;
@ -108,32 +108,18 @@ export interface PermissionModalEvents {
query_groups: {
target: "server" | "channel";
};
query_groups_result: {
target: "server" | "channel";
groups: GroupProperties[];
};
query_group_clients: {
id: number;
};
query_group_clients_result: {
id: number;
status: "success" | "error" | "no-permissions";
error?: string;
clients?: {
name: string;
databaseId: number;
uniqueId: string;
}[];
};
query_channels: {};
query_channels_result: {
channels: ChannelInfo[];
};
query_client_permissions: {};
query_client_info: {
client: number | string;
};
query_client_info_result: {
notify_channels: {
channels: ChannelInfo[];
};
notify_client_info: {
client: number | string;
state: "success" | "error" | "no-such-client" | "no-permission";
error?: string;
@ -157,7 +143,21 @@ export interface PermissionModalEvents {
target: "server" | "channel";
groups: number[];
};
notify_group_clients: {
id: number;
status: "success" | "error" | "no-permissions";
error?: string;
clients?: {
name: string;
databaseId: number;
uniqueId: string;
}[];
};
notify_groups_reset: {};
notify_groups: {
target: "server" | "channel";
groups: GroupProperties[];
};
notify_client_permissions: {
permissionModifyPower: number;
serverGroupCreate: boolean;

View File

@ -0,0 +1,6 @@
import { ConnectionHandler } from "tc-shared/ConnectionHandler";
export declare function spawnPokeModal(handler: ConnectionHandler, client: {
clientName: string;
clientId: number;
clientUniqueId: string;
}, message: string): void;

View File

@ -0,0 +1,17 @@
export declare type PokeRecord = {
uniqueId: string;
timestamp: number;
handlerId: string;
serverName: string;
serverUniqueId: string;
clientId: number;
clientUniqueId: string;
clientName: string;
message: string;
};
export interface ModalPokeVariables {
readonly pokeList: PokeRecord[];
}
export interface ModalPokeEvents {
action_close: {};
}

View File

@ -0,0 +1,15 @@
import { AbstractModal } from "tc-shared/ui/react-elements/modal/Definitions";
import React from "react";
import { UiVariableConsumer } from "tc-shared/ui/utils/Variable";
import { ModalPokeEvents, ModalPokeVariables } from "tc-shared/ui/modal/poke/Definitions";
import { IpcRegistryDescription, Registry } from "tc-events";
import { IpcVariableDescriptor } from "tc-shared/ui/utils/IpcVariable";
declare class PokeModal extends AbstractModal {
readonly variables: UiVariableConsumer<ModalPokeVariables>;
readonly events: Registry<ModalPokeEvents>;
constructor(events: IpcRegistryDescription<ModalPokeEvents>, variables: IpcVariableDescriptor<ModalPokeVariables>);
renderBody(): React.ReactElement;
renderTitle(): string | React.ReactElement;
verticalAlignment(): "top" | "center" | "bottom";
}
export default PokeModal;

View File

@ -1,5 +1,5 @@
import { Registry } from "tc-shared/events";
import { DeviceListState } from "tc-shared/audio/recorder";
import { DeviceListState } from "tc-shared/audio/Recorder";
export declare type MicrophoneSetting = "volume" | "vad-type" | "ppt-key" | "ppt-release-delay" | "ppt-release-delay-active" | "threshold-threshold" | "rnnoise";
export declare type MicrophoneDevice = {
id: string;
@ -42,8 +42,6 @@ export interface MicrophoneSettingsEvents {
target: SelectedMicrophone;
};
"action_set_selected_device_result": {
status: "success";
} | {
status: "error";
reason: string;
};

View File

@ -1,4 +1,4 @@
import { ConnectionHandler } from "../../../ConnectionHandler";
import { Registry } from "../../../events";
import { Registry } from "tc-events";
import { FileBrowserEvents } from "tc-shared/ui/modal/transfer/FileDefinitions";
export declare function initializeRemoteFileBrowserController(connection: ConnectionHandler, events: Registry<FileBrowserEvents>): void;

View File

@ -1,4 +1,4 @@
import { ConnectionHandler } from "../../../ConnectionHandler";
import { Registry } from "../../../events";
import { Registry } from "tc-events";
import { TransferInfoEvents } from "tc-shared/ui/modal/transfer/FileTransferInfoDefinitions";
export declare const initializeTransferInfoController: (connection: ConnectionHandler, events: Registry<TransferInfoEvents>) => void;

View File

@ -1,9 +1,9 @@
import { Registry } from "tc-shared/events";
import * as React from "react";
import { ModalVideoSourceEvents } from "tc-shared/ui/modal/video-source/Definitions";
import { InternalModal } from "tc-shared/ui/react-elements/internal-modal/Controller";
import { Translatable } from "tc-shared/ui/react-elements/i18n";
import { VideoBroadcastType } from "tc-shared/connection/VideoConnection";
import { InternalModal } from "tc-shared/ui/react-elements/modal/Definitions";
export declare class ModalVideoSource extends InternalModal {
protected readonly events: Registry<ModalVideoSourceEvents>;
private readonly sourceType;

View File

@ -0,0 +1,4 @@
export interface ModalWhatsNewVariables {
}
export interface ModalWhatsNewEvents {
}

View File

@ -1,4 +1,3 @@
import { ReactComponentBase } from "tc-shared/ui/react-elements/ReactComponentBase";
import * as React from "react";
export interface ButtonProperties {
color?: "green" | "blue" | "red" | "purple" | "brown" | "yellow" | "default" | "none";
@ -13,7 +12,7 @@ export interface ButtonProperties {
export interface ButtonState {
disabled?: boolean;
}
export declare class Button extends ReactComponentBase<ButtonProperties, ButtonState> {
protected defaultState(): ButtonState;
export declare class Button extends React.Component<ButtonProperties, ButtonState> {
constructor(props: any);
render(): JSX.Element;
}

View File

@ -0,0 +1,5 @@
/// <reference types="react" />
export declare const CountryIcon: (props: {
country: string;
className?: string;
}) => JSX.Element;

View File

@ -2,7 +2,7 @@ import * as React from "react";
interface ErrorBoundaryState {
errorOccurred: boolean;
}
export declare class ErrorBoundary extends React.Component<{}, ErrorBoundaryState> {
export declare class ErrorBoundary extends React.PureComponent<{}, ErrorBoundaryState> {
constructor(props: any);
render(): {};
componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void;

View File

@ -0,0 +1,4 @@
import * as React from "react";
export declare const FontSizeObserver: React.MemoExoticComponent<(props: {
children: (fontSize: number) => string | number | boolean | {} | React.ReactElement<any, string | ((props: any) => React.ReactElement<any, string | any | (new (props: any) => React.Component<any, any, any>)>) | (new (props: any) => React.Component<any, any, any>)> | React.ReactNodeArray | React.ReactPortal | React.ReactNode[];
}) => JSX.Element>;

View File

@ -3,5 +3,5 @@ import { RegistryKey, RegistryValueType, ValuedRegistryKey } from "tc-shared/set
export declare function useDependentState<S>(factory: (prevState?: S) => S, inputs: ReadonlyArray<any>): [S, Dispatch<SetStateAction<S>>];
export declare function useTr(message: string): string;
export declare function joinClassList(...classes: any[]): string;
export declare function useGlobalSetting<V extends RegistryValueType, DV>(key: RegistryKey<V>, defaultValue: DV): V | DV;
export declare function useGlobalSetting<V extends RegistryValueType>(key: ValuedRegistryKey<V>, defaultValue?: V): V;
export declare function useGlobalSetting<V extends RegistryValueType, DV>(key: RegistryKey<V>, defaultValue: DV): V | DV;

View File

@ -20,6 +20,7 @@ export declare const ControlledBoxedInputField: (props: {
onFocus?: () => void;
onBlur?: () => void;
finishOnEnter?: boolean;
refInput?: React.RefObject<HTMLInputElement>;
}) => JSX.Element;
export interface BoxedInputFieldProperties {
prefix?: string;

View File

@ -8,6 +8,7 @@ export interface TooltipState {
}
export interface TooltipProperties {
tooltip: () => ReactElement | ReactElement[] | string;
className?: string;
}
export declare class Tooltip extends React.Component<TooltipProperties, TooltipState> {
readonly tooltipId: string;
@ -23,4 +24,5 @@ export declare class Tooltip extends React.Component<TooltipProperties, TooltipS
export declare const IconTooltip: (props: {
children?: React.ReactElement<any, string | ((props: any) => React.ReactElement<any, string | any | (new (props: any) => React.Component<any, any, any>)>) | (new (props: any) => React.Component<any, any, any>)> | React.ReactElement<any, string | ((props: any) => React.ReactElement<any, string | any | (new (props: any) => React.Component<any, any, any>)>) | (new (props: any) => React.Component<any, any, any>)>[];
className?: string;
outerClassName?: string;
}) => JSX.Element;

View File

@ -1,26 +0,0 @@
import { ChannelMessage } from "../../../ipc/BrowserIPC";
import { Registry } from "tc-events";
import { EventControllerBase, Popout2ControllerMessages, PopoutIPCMessage } from "../../../ui/react-elements/external-modal/IPCMessage";
import { ModalController, ModalEvents, ModalOptions, ModalState } from "../../../ui/react-elements/ModalDefinitions";
export declare abstract class AbstractExternalModalController extends EventControllerBase<"controller"> implements ModalController {
readonly modalType: string;
readonly constructorArguments: any[];
private readonly modalEvents;
private modalState;
private readonly documentUnloadListener;
private callbackWindowInitialized;
protected constructor(modalType: string, constructorArguments: any[]);
getOptions(): Readonly<ModalOptions>;
getEvents(): Registry<ModalEvents>;
getState(): ModalState;
protected abstract spawnWindow(): Promise<boolean>;
protected abstract focusWindow(): void;
protected abstract destroyWindow(): void;
show(): Promise<void>;
private doDestroyWindow;
hide(): Promise<void>;
destroy(): void;
protected handleWindowClosed(): void;
protected handleIPCMessage(remoteId: string, broadcast: boolean, message: ChannelMessage): void;
protected handleTypedIPCMessage<T extends Popout2ControllerMessages>(remoteId: string, isBroadcast: boolean, type: T, payload: PopoutIPCMessage[T]): void;
}

View File

@ -1,35 +0,0 @@
import { IPCChannel } from "../../../ipc/BrowserIPC";
export declare const kPopoutIPCChannelId = "popout-channel";
export interface PopoutIPCMessage {
"hello-popout": {
version: string;
authenticationCode: string;
};
"hello-controller": {
accepted: boolean;
message?: string;
constructorArguments?: any[];
};
"invoke-modal-action": {
action: "close" | "minimize";
};
}
export declare type Controller2PopoutMessages = "hello-controller";
export declare type Popout2ControllerMessages = "hello-popout" | "invoke-modal-action";
export interface SendIPCMessage {
"controller": Controller2PopoutMessages;
"popout": Popout2ControllerMessages;
}
export interface ReceivedIPCMessage {
"controller": Popout2ControllerMessages;
"popout": Controller2PopoutMessages;
}
export declare abstract class EventControllerBase<Type extends "controller" | "popout"> {
protected readonly ipcAuthenticationCode: string;
protected ipcRemotePeerId: string;
protected ipcChannel: IPCChannel;
protected constructor(ipcAuthenticationCode: string);
protected sendIPCMessage<T extends SendIPCMessage[Type]>(type: T, payload: PopoutIPCMessage[T]): void;
protected handleTypedIPCMessage<T extends ReceivedIPCMessage[Type]>(remoteId: string, isBroadcast: boolean, type: T, payload: PopoutIPCMessage[T]): void;
protected destroyIPC(): void;
}

View File

@ -1,13 +0,0 @@
import { Controller2PopoutMessages, EventControllerBase, PopoutIPCMessage } from "../../../ui/react-elements/external-modal/IPCMessage";
export declare function getPopoutController(): PopoutController;
declare class PopoutController extends EventControllerBase<"popout"> {
private constructorArguments;
private callbackControllerHello;
constructor();
getConstructorArguments(): any[];
initialize(): Promise<void>;
protected handleTypedIPCMessage<T extends Controller2PopoutMessages>(remoteId: string, isBroadcast: boolean, type: T, payload: PopoutIPCMessage[T]): void;
doClose(): void;
doMinimize(): void;
}
export {};

View File

@ -1,2 +0,0 @@
import "../../../file/RemoteAvatars";
import "../../../file/RemoteIcons";

View File

@ -1,16 +0,0 @@
import { AbstractModal, ModalRenderer } from "tc-shared/ui/react-elements/ModalDefinitions";
export interface ModalControlFunctions {
close(): any;
minimize(): any;
}
export declare class ClientModalRenderer implements ModalRenderer {
private readonly functionController;
private readonly titleElement;
private readonly container;
private readonly titleChangeObserver;
private titleContainer;
private currentModal;
constructor(functionController: ModalControlFunctions);
renderModal(modal: AbstractModal | undefined): void;
private updateTitle;
}

View File

@ -1,8 +0,0 @@
import { AbstractModal, ModalRenderer } from "tc-shared/ui/react-elements/ModalDefinitions";
export declare class WebModalRenderer implements ModalRenderer {
private readonly titleRenderer;
private readonly bodyRenderer;
private currentModal;
constructor();
renderModal(modal: AbstractModal | undefined): void;
}

View File

@ -1,7 +0,0 @@
import "./Controller";
import { ModalController, ModalOptions } from "../ModalDefinitions";
export declare type ControllerFactory = (modalType: string, constructorArguments?: any[], options?: ModalOptions) => ModalController;
export declare function setExternalModalControllerFactory(factory: ControllerFactory): void;
export declare function spawnExternalModal<EventClass extends {
[key: string]: any;
}>(modalType: string, constructorArguments?: any[], options?: ModalOptions): ModalController;

View File

@ -1,9 +1,7 @@
import * as React from "react";
export declare class Translatable extends React.Component<{
children: string | (string | React.ReactElement<HTMLBRElement>)[];
__cacheKey?: string;
trIgnore?: boolean;
enforceTextOnly?: boolean;
}, {
translated: string;
}> {
@ -16,7 +14,6 @@ export declare class Translatable extends React.Component<{
export declare type VariadicTranslatableChild = React.ReactElement | string | number;
export declare const VariadicTranslatable: (props: {
text: string;
__cacheKey?: string;
children?: string | number | React.ReactElement<any, string | ((props: any) => React.ReactElement<any, string | any | (new (props: any) => React.Component<any, any, any>)>) | (new (props: any) => React.Component<any, any, any>)> | VariadicTranslatableChild[];
}) => JSX.Element;
declare global {

View File

@ -1,23 +0,0 @@
import { Registry } from "../../../events";
import { AbstractModal, ModalController, ModalEvents, ModalOptions, ModalState } from "../../../ui/react-elements/ModalDefinitions";
import { RegisteredModal } from "tc-shared/ui/react-elements/modal/Registry";
export declare class InternalModalController implements ModalController {
readonly events: Registry<ModalEvents>;
private readonly modalType;
private readonly constructorArguments;
private modalInstance;
private initializedPromise;
private domElement;
private refModal;
private modalState_;
constructor(modalType: RegisteredModal<any>, constructorArguments: any[]);
getOptions(): Readonly<ModalOptions>;
getEvents(): Registry<ModalEvents>;
getState(): ModalState;
private initialize;
show(): Promise<void>;
hide(): Promise<void>;
destroy(): void;
}
export declare abstract class InternalModal extends AbstractModal {
}

View File

@ -1,23 +0,0 @@
import * as React from "react";
import { AbstractModal } from "tc-shared/ui/react-elements/ModalDefinitions";
export declare const InternalModalContentRenderer: React.MemoExoticComponent<(props: {
modal: AbstractModal;
onClose?: () => void;
onMinimize?: () => void;
containerClass?: string;
headerClass?: string;
headerTitleClass?: string;
bodyClass?: string;
refContent?: React.Ref<HTMLDivElement>;
}) => JSX.Element>;
export declare class InternalModalRenderer extends React.PureComponent<{
modal: AbstractModal;
onClose: () => void;
}, {
show: boolean;
}> {
private readonly refModal;
constructor(props: any);
render(): JSX.Element;
private onBackdropClick;
}

View File

@ -0,0 +1,22 @@
import { InternalModal, ModalConstructorArguments, ModalController, ModalEvents, ModalOptions, ModalState } from "tc-shared/ui/react-elements/modal/Definitions";
import { Registry } from "tc-events";
export declare class GenericModalController<T extends keyof ModalConstructorArguments> implements ModalController {
private readonly events;
private readonly modalType;
private readonly modalConstructorArguments;
private readonly modalOptions;
private modalKlass;
private instance;
private popedOut;
static fromInternalModal<ModalClass extends InternalModal>(klass: new (...args: any[]) => ModalClass, constructorArguments: any[]): GenericModalController<"__internal__modal__">;
constructor(modalType: T, constructorArguments: ModalConstructorArguments[T], options: ModalOptions);
private getModalClass;
private createModalInstance;
private destroyModalInstance;
destroy(): void;
getEvents(): Registry<ModalEvents>;
getOptions(): Readonly<ModalOptions>;
getState(): ModalState;
hide(): Promise<void>;
show(): Promise<void>;
}

View File

@ -4,9 +4,11 @@ import { ChannelEditEvents } from "tc-shared/ui/modal/channel-edit/Definitions";
import { EchoTestEvents } from "tc-shared/ui/modal/echo-test/Definitions";
import { ModalGlobalSettingsEditorEvents } from "tc-shared/ui/modal/global-settings-editor/Definitions";
import { InviteUiEvents, InviteUiVariables } from "tc-shared/ui/modal/invite/Definitions";
import { ReactElement } from "react";
import * as React from "react";
import React, { ReactElement } from "react";
import { IpcVariableDescriptor } from "tc-shared/ui/utils/IpcVariable";
import { ModalBookmarkEvents, ModalBookmarkVariables } from "tc-shared/ui/modal/bookmarks/Definitions";
import { ModalBookmarksAddServerEvents, ModalBookmarksAddServerVariables } from "tc-shared/ui/modal/bookmarks-add-server/Definitions";
import { ModalPokeEvents, ModalPokeVariables } from "tc-shared/ui/modal/poke/Definitions";
export declare type ModalType = "error" | "warning" | "info" | "none";
export declare type ModalRenderType = "page" | "dialog";
export interface ModalOptions {
@ -45,13 +47,6 @@ export interface ModalOptions {
*/
popedOut?: boolean;
}
export interface ModalFunctionController {
minimize(): any;
supportMinimize(): boolean;
maximize(): any;
supportMaximize(): boolean;
close(): any;
}
export interface ModalEvents {
"open": {};
"close": {};
@ -62,6 +57,22 @@ export declare enum ModalState {
HIDDEN = 1,
DESTROYED = 2
}
export interface ModalInstanceEvents {
action_close: {};
action_minimize: {};
action_popout: {};
notify_open: {};
notify_minimize: {};
notify_close: {};
notify_destroy: {};
}
export interface ModalInstanceController {
getState(): ModalState;
getEvents(): Registry<ModalInstanceEvents>;
show(): Promise<void>;
hide(): Promise<void>;
destroy(): any;
}
export interface ModalController {
getOptions(): Readonly<ModalOptions>;
getEvents(): Registry<ModalEvents>;
@ -70,7 +81,11 @@ export interface ModalController {
hide(): Promise<void>;
destroy(): any;
}
export interface ModalInstanceProperties {
windowed: boolean;
}
export declare abstract class AbstractModal {
protected readonly properties: ModalInstanceProperties;
protected constructor();
abstract renderBody(): ReactElement;
abstract renderTitle(): string | React.ReactElement;
@ -82,10 +97,11 @@ export declare abstract class AbstractModal {
protected onClose(): void;
protected onOpen(): void;
}
export interface ModalRenderer {
renderModal(modal: AbstractModal | undefined): any;
export declare abstract class InternalModal extends AbstractModal {
}
export declare function constructAbstractModalClass<T extends keyof ModalConstructorArguments>(klass: new (...args: ModalConstructorArguments[T]) => AbstractModal, properties: ModalInstanceProperties, args: ModalConstructorArguments[T]): AbstractModal;
export interface ModalConstructorArguments {
"__internal__modal__": any[];
"video-viewer": [IpcRegistryDescription<VideoViewerEvents>, string];
"channel-edit": [IpcRegistryDescription<ChannelEditEvents>, boolean];
"echo-test": [IpcRegistryDescription<EchoTestEvents>];
@ -95,4 +111,7 @@ export interface ModalConstructorArguments {
"channel-tree": any;
"modal-connect": any;
"modal-invite": [IpcRegistryDescription<InviteUiEvents>, IpcVariableDescriptor<InviteUiVariables>, string];
"modal-bookmarks": [IpcRegistryDescription<ModalBookmarkEvents>, IpcVariableDescriptor<ModalBookmarkVariables>];
"modal-bookmark-add-server": [IpcRegistryDescription<ModalBookmarksAddServerEvents>, IpcVariableDescriptor<ModalBookmarksAddServerVariables>];
"modal-poked": [IpcRegistryDescription<ModalPokeEvents>, IpcVariableDescriptor<ModalPokeVariables>];
}

View File

@ -2,7 +2,9 @@ import { AbstractModal } from "../../../ui/react-elements/ModalDefinitions";
import { ModalConstructorArguments } from "tc-shared/ui/react-elements/modal/Definitions";
export interface RegisteredModal<T extends keyof ModalConstructorArguments> {
modalId: T;
classLoader: () => Promise<new (...args: ModalConstructorArguments[T]) => AbstractModal>;
classLoader: () => Promise<{
default: new (...args: ModalConstructorArguments[T]) => AbstractModal;
}>;
popoutSupported: boolean;
}
export declare function findRegisteredModal<T extends keyof ModalConstructorArguments>(name: T): RegisteredModal<T> | undefined;

View File

@ -0,0 +1,44 @@
import { AbstractModal } from "tc-shared/ui/react-elements/modal/Definitions";
import React from "react";
export declare class ModalFrameTopRenderer extends React.PureComponent<{
modalInstance: AbstractModal;
className?: string;
onClose?: () => void;
onPopout?: () => void;
onMinimize?: () => void;
replacePageTitle: boolean;
}> {
private readonly refTitle;
private titleElement;
private observer;
componentDidMount(): void;
componentWillUnmount(): void;
render(): JSX.Element;
private updatePageTitle;
}
export declare class ModalBodyRenderer extends React.PureComponent<{
modalInstance: AbstractModal;
className?: string;
}> {
constructor(props: any);
render(): JSX.Element;
}
export declare class ModalFrameRenderer extends React.PureComponent<{
windowed: boolean;
children: [React.ReactElement<ModalFrameTopRenderer>, React.ReactElement<ModalBodyRenderer>];
}> {
render(): JSX.Element;
}
export declare class PageModalRenderer extends React.PureComponent<{
modalInstance: AbstractModal;
onBackdropClicked: () => void;
children: React.ReactElement<ModalFrameRenderer>;
}, {
shown: boolean;
}> {
constructor(props: any);
render(): JSX.Element;
}
export declare const WindowModalRenderer: (props: {
children: [React.ReactElement<ModalFrameTopRenderer, string | ((props: any) => React.ReactElement<any, string | any | (new (props: any) => React.Component<any, any, any>)>) | (new (props: any) => React.Component<any, any, any>)>, React.ReactElement<ModalBodyRenderer, string | ((props: any) => React.ReactElement<any, string | any | (new (props: any) => React.Component<any, any, any>)>) | (new (props: any) => React.Component<any, any, any>)>];
}) => JSX.Element;

View File

@ -0,0 +1,27 @@
import { Registry } from "tc-events";
import { ModalOptions } from "tc-shared/ui/react-elements/modal/Definitions";
import { ModalInstanceController, ModalInstanceEvents, ModalState } from "tc-shared/ui/react-elements/modal/Definitions";
export declare class ExternalModalController implements ModalInstanceController {
private readonly modalType;
private readonly modalOptions;
private readonly constructorArguments;
private readonly mainModalId;
private readonly ipcMessageHandler;
private ipcRemotePeerId;
private ipcChannel;
private readonly modalEvents;
private modalInitializeCallback;
private windowId;
private windowListener;
private windowMutatePromise;
constructor(modalType: string, constructorArguments: any[], modalOptions: ModalOptions);
destroy(): void;
getEvents(): Registry<ModalInstanceEvents>;
getState(): ModalState;
show(): Promise<void>;
hide(): Promise<void>;
private mutateWindow;
private handleWindowDestroyed;
private registerIpcMessageHandler;
private sendIpcMessage;
}

View File

@ -0,0 +1,25 @@
export interface ModalIPCMessages {
"hello-renderer": {
version: string;
};
"hello-controller": {
accepted: true;
modalId: string;
modalType: string;
constructorArguments: any[];
} | {
accepted: false;
message: string;
};
"invoke-modal-action": {
modalId: string;
action: "close" | "minimize";
};
"invalidate-modal-instance": {};
}
export declare type ModalIPCRenderer2ControllerMessages = Pick<ModalIPCMessages, "hello-renderer" | "invoke-modal-action">;
export declare type ModalIPCController2Renderer = Pick<ModalIPCMessages, "hello-controller" | "invalidate-modal-instance">;
export declare type ModalIPCMessage<Messages, T extends keyof Messages = keyof Messages> = {
type: T;
payload: Messages[T];
};

View File

@ -0,0 +1,21 @@
export declare type ModalInstanceInitializeResult = {
status: "success";
modalId: string;
modalType: string;
constructorArguments: any[];
} | {
status: "timeout";
} | {
status: "rejected";
message: string;
};
export declare class ModalWindowControllerInstance {
private readonly ipcMessageHandler;
private ipcRemotePeerId;
private ipcChannel;
constructor(modalChannelId: string);
initialize(): Promise<ModalInstanceInitializeResult>;
triggerModalAction(modalId: string, action: "minimize" | "close"): void;
private registerIpcMessageHandler;
private sendIpcMessage;
}

View File

@ -0,0 +1,2 @@
import "../../../../../file/RemoteAvatars";
import "../../../../../file/RemoteIcons";

View File

@ -0,0 +1,12 @@
import { AbstractModal } from "tc-shared/ui/react-elements/ModalDefinitions";
import "./ModalRenderer.scss";
export interface ModalControlFunctions {
close(): any;
minimize(): any;
}
export declare class ModalRenderer {
private readonly functionController;
private readonly container;
constructor(functionController: ModalControlFunctions);
renderModal(modal: AbstractModal | undefined): void;
}

View File

@ -1,11 +1,9 @@
import { ModalConstructorArguments } from "tc-shared/ui/react-elements/modal/Definitions";
import { InternalModal, ModalConstructorArguments } from "tc-shared/ui/react-elements/modal/Definitions";
import { ModalController, ModalOptions } from "tc-shared/ui/react-elements/ModalDefinitions";
import { InternalModal, InternalModalController } from "tc-shared/ui/react-elements/internal-modal/Controller";
export declare function spawnModal<T extends keyof ModalConstructorArguments>(modal: T, constructorArguments: ModalConstructorArguments[T], options?: ModalOptions): ModalController;
export declare function spawnReactModal<ModalClass extends InternalModal, A1>(modalClass: new () => ModalClass): InternalModalController;
export declare function spawnReactModal<ModalClass extends InternalModal, A1>(modalClass: new (..._: [A1]) => ModalClass, arg1: A1): InternalModalController;
export declare function spawnReactModal<ModalClass extends InternalModal, A1, A2>(modalClass: new (..._: [A1, A2]) => ModalClass, arg1: A1, arg2: A2): InternalModalController;
export declare function spawnReactModal<ModalClass extends InternalModal, A1, A2, A3>(modalClass: new (..._: [A1, A2, A3]) => ModalClass, arg1: A1, arg2: A2, arg3: A3): InternalModalController;
export declare function spawnReactModal<ModalClass extends InternalModal, A1, A2, A3, A4>(modalClass: new (..._: [A1, A2, A3, A4]) => ModalClass, arg1: A1, arg2: A2, arg3: A3, arg4: A4): InternalModalController;
export declare function spawnReactModal<ModalClass extends InternalModal, A1, A2, A3, A4, A5>(modalClass: new (..._: [A1, A2, A3, A4]) => ModalClass, arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5): InternalModalController;
export declare function spawnInternalModal<T extends keyof ModalConstructorArguments>(modal: T, constructorArguments: ModalConstructorArguments[T], options?: ModalOptions): InternalModalController;
export declare function spawnReactModal<ModalClass extends InternalModal, A1>(modalClass: new () => ModalClass): ModalController;
export declare function spawnReactModal<ModalClass extends InternalModal, A1>(modalClass: new (..._: [A1]) => ModalClass, arg1: A1): ModalController;
export declare function spawnReactModal<ModalClass extends InternalModal, A1, A2>(modalClass: new (..._: [A1, A2]) => ModalClass, arg1: A1, arg2: A2): ModalController;
export declare function spawnReactModal<ModalClass extends InternalModal, A1, A2, A3>(modalClass: new (..._: [A1, A2, A3]) => ModalClass, arg1: A1, arg2: A2, arg3: A3): ModalController;
export declare function spawnReactModal<ModalClass extends InternalModal, A1, A2, A3, A4>(modalClass: new (..._: [A1, A2, A3, A4]) => ModalClass, arg1: A1, arg2: A2, arg3: A3, arg4: A4): ModalController;
export declare function spawnReactModal<ModalClass extends InternalModal, A1, A2, A3, A4, A5>(modalClass: new (..._: [A1, A2, A3, A4]) => ModalClass, arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5): ModalController;

View File

@ -0,0 +1,25 @@
import { ModalInstanceController, ModalInstanceEvents, ModalOptions, ModalState } from "tc-shared/ui/react-elements/modal/Definitions";
import { RegisteredModal } from "tc-shared/ui/react-elements/modal/Registry";
import { Registry } from "tc-events";
export declare class InternalModalInstance implements ModalInstanceController {
readonly events: Registry<ModalInstanceEvents>;
private readonly modalKlass;
private readonly constructorArguments;
private readonly rendererInstance;
private readonly modalOptions;
private state;
private modalInstance;
private htmlContainer;
private modalInitializePromise;
constructor(modalType: RegisteredModal<any>, constructorArguments: any[], modalOptions: ModalOptions);
private constructModal;
private destructModal;
getState(): ModalState;
getEvents(): Registry<ModalInstanceEvents>;
show(): Promise<void>;
hide(): Promise<void>;
destroy(): void;
private getCloseCallback;
private getPopoutCallback;
private getMinimizeCallback;
}

View File

@ -1,15 +1,21 @@
/// <reference types="react" />
export declare const ClientTag: (props: {
import * as React from "react";
export declare const ServerTag: React.MemoExoticComponent<(props: {
serverName: string;
handlerId: string;
serverUniqueId?: string;
className?: string;
}) => JSX.Element>;
export declare const ClientTag: React.MemoExoticComponent<(props: {
clientName: string;
clientUniqueId: string;
handlerId: string;
clientId?: number;
clientDatabaseId?: number;
className?: string;
}) => JSX.Element;
export declare const ChannelTag: (props: {
}) => JSX.Element>;
export declare const ChannelTag: React.MemoExoticComponent<(props: {
channelName: string;
channelId: number;
handlerId: string;
className?: string;
}) => JSX.Element;
}) => JSX.Element>;

View File

@ -1,22 +1,8 @@
import { ReadonlyKeys, WritableKeys } from "tc-shared/proto";
export declare type UiVariable = Transferable | undefined | null | number | string | object;
export declare type UiVariableMap = {
[key: string]: any;
};
declare type IfEquals<X, Y, A = X, B = never> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? A : B;
declare type WritableKeys<T> = {
[P in keyof T]-?: IfEquals<{
[Q in P]: T[P];
}, {
-readonly [Q in P]: T[P];
}, P, never>;
}[keyof T];
declare type ReadonlyKeys<T> = {
[P in keyof T]: IfEquals<{
[Q in P]: T[P];
}, {
-readonly [Q in P]: T[P];
}, never, P>;
}[keyof T];
export declare type ReadonlyVariables<Variables extends UiVariableMap> = Pick<Variables, ReadonlyKeys<Variables>>;
export declare type WriteableVariables<Variables extends UiVariableMap> = Pick<Variables, WritableKeys<Variables>>;
declare type UiVariableEditor<Variables extends UiVariableMap, T extends keyof Variables> = Variables[T] extends {
@ -28,8 +14,11 @@ declare type UiVariableEditorPromise<Variables extends UiVariableMap, T extends
export declare abstract class UiVariableProvider<Variables extends UiVariableMap> {
private variableProvider;
private variableEditor;
private artificialDelay;
protected constructor();
destroy(): void;
getArtificialDelay(): number;
setArtificialDelay(value: number): void;
setVariableProvider<T extends keyof Variables>(variable: T, provider: (customData: any) => Variables[T] | Promise<Variables[T]>): void;
/**
* @param variable
@ -70,6 +59,7 @@ export declare abstract class UiVariableConsumer<Variables extends UiVariableMap
destroy(): void;
private getOrCreateVariable;
private derefVariable;
setVariable<T extends keyof WriteableVariables<Variables>>(variable: T, customData: any, newValue: Variables[T]): void;
useVariable<T extends keyof WriteableVariables<Variables>>(variable: T, customData?: any, defaultValue?: Variables[T]): UiVariableStatus<Variables, T>;
useReadOnly<T extends keyof Variables>(variable: T, customData?: any, defaultValue?: never): UiReadOnlyVariableStatus<Variables, T>;
useReadOnly<T extends keyof Variables>(variable: T, customData: any | undefined, defaultValue: Variables[T]): Variables[T];

View File

@ -0,0 +1,44 @@
import { Registry } from "tc-events";
export declare type WindowCreateResult = {
status: "success";
windowId: string;
} | {
status: "error-unknown";
message: string;
} | {
status: "error-user-rejected";
};
export interface WindowManagerEvents {
notify_window_created: {
windowId: string;
};
notify_window_focused: {
windowId: string;
};
notify_window_destroyed: {
windowId: string;
};
}
export declare type WindowAction = "focus" | "maximize" | "minimize";
export interface WindowSpawnOptions {
uniqueId: string;
loaderTarget: string;
windowName?: string;
appParameters?: {
[key: string]: string;
};
defaultSize?: {
width: number;
height: number;
};
}
export interface WindowManager {
getEvents(): Registry<WindowManagerEvents>;
createWindow(options: WindowSpawnOptions): Promise<WindowCreateResult>;
destroyWindow(windowId: string): any;
getActiveWindowId(): string | undefined;
isActionSupported(windowId: string, action: WindowAction): boolean;
executeAction(windowId: string, action: WindowAction): Promise<void>;
}
export declare function getWindowManager(): WindowManager;
export declare function setWindowManager(newWindowManager: WindowManager): void;

View File

@ -1,4 +1,4 @@
import { IDevice } from "../audio/recorder";
import { InputDevice } from "../audio/Recorder";
import { Registry } from "../events";
import { Filter, FilterType, FilterTypeClass } from "../voice/Filter";
export declare enum InputConsumerType {
@ -91,7 +91,7 @@ export interface AbstractInput {
setVolume(volume: number): any;
}
export interface LevelMeter {
getDevice(): IDevice;
getDevice(): InputDevice;
setObserver(callback: (value: number) => any): any;
destroy(): any;
}

View File

@ -1,7 +1,7 @@
import { AbstractInput } from "../voice/RecorderBase";
import { KeyDescriptor } from "../PPTListener";
import { ConnectionHandler } from "../ConnectionHandler";
import { IDevice } from "../audio/recorder";
import { InputDevice } from "../audio/Recorder";
import { Registry } from "tc-shared/events";
export declare type VadType = "threshold" | "push_to_talk" | "active";
export interface RecorderProfileConfig {
@ -61,8 +61,8 @@ export declare class RecorderProfile {
setPushToTalkKey(key: KeyDescriptor): void;
getPushToTalkDelay(): number;
setPushToTalkDelay(value: number): void;
getDeviceId(): string | typeof IDevice.DefaultDeviceId | typeof IDevice.NoDeviceId;
setDevice(device: IDevice | typeof IDevice.DefaultDeviceId | typeof IDevice.NoDeviceId): Promise<void>;
getDeviceId(): string | typeof InputDevice.DefaultDeviceId | typeof InputDevice.NoDeviceId;
setDevice(device: InputDevice | typeof InputDevice.DefaultDeviceId | typeof InputDevice.NoDeviceId): Promise<void>;
getVolume(): number;
setVolume(volume: number): void;
}

View File

@ -121,7 +121,7 @@ function deploy_client() {
}
#install_npm
compile_scripts
#compile_scripts
#compile_native
package_client
deploy_client

View File

@ -1,5 +1,5 @@
import {ObjectProxyServer} from "../../shared/proxy/Server";
import {ExternalModal, kIPCChannelExternalModal} from "../../shared/ipc/ExternalModal";
import {IpcWindowInstance, kIPCChannelWindowManager} from "../../shared/ipc/IpcWindowInstance";
import {ProxiedClass} from "../../shared/proxy/Definitions";
import {BrowserWindow, dialog} from "electron";
import {loadWindowBounds, startTrackWindowBounds} from "../../shared/window";
@ -7,24 +7,24 @@ import {Arguments, processArguments} from "../../shared/process-arguments";
import {openURLPreview} from "../url-preview";
import * as path from "path";
class ProxyImplementation extends ProxiedClass<ExternalModal> implements ExternalModal {
class ProxyImplementation extends ProxiedClass<IpcWindowInstance> implements IpcWindowInstance {
private windowInstance: BrowserWindow;
public constructor(props) {
super(props);
}
async focus(): Promise<any> {
async focus(): Promise<void> {
this.windowInstance?.focusOnWebView();
}
async minimize(): Promise<any> {
async minimize(): Promise<void> {
this.windowInstance?.minimize();
}
async spawnWindow(modalTarget: string, url: string): Promise<boolean> {
async maximize(): Promise<void> {
this.windowInstance?.maximize();
}
async initialize(loaderTarget: string, windowId: string, url: string): Promise<boolean> {
if(this.windowInstance) {
return;
return false;
}
this.windowInstance = new BrowserWindow({
@ -45,8 +45,8 @@ class ProxyImplementation extends ProxiedClass<ExternalModal> implements Externa
show: true
});
loadWindowBounds("modal-" + modalTarget, this.windowInstance).then(() => {
startTrackWindowBounds("modal-" + modalTarget, this.windowInstance);
loadWindowBounds("window-" + windowId, this.windowInstance).then(() => {
startTrackWindowBounds("window-" + windowId, this.windowInstance);
});
this.windowInstance.webContents.on('new-window', (event, url_str, frameName, disposition, options, additionalFeatures) => {
@ -109,5 +109,5 @@ class ProxyImplementation extends ProxiedClass<ExternalModal> implements Externa
}
}
const server = new ObjectProxyServer<ExternalModal>(kIPCChannelExternalModal, ProxyImplementation);
const server = new ObjectProxyServer<IpcWindowInstance>(kIPCChannelWindowManager, ProxyImplementation);
server.initialize();

View File

@ -5,7 +5,6 @@ import ipcMain = electron.ipcMain;
import BrowserWindow = electron.BrowserWindow;
import {openChangeLog as open_changelog} from "../app-updater/changelog";
import * as updater from "../app-updater";
import {execute_connect_urls} from "../MultiInstanceHandler";
import {processArguments} from "../../shared/process-arguments";

View File

@ -1,7 +1,7 @@
import {NativeClientBackend, NativeClientVersionInfo} from "tc-shared/backend/NativeClient";
import {ipcRenderer, remote} from "electron";
import {Arguments, processArguments} from "../../shared/process-arguments";
import * as os from "os";
import {NativeClientBackend, NativeClientVersionInfo} from "tc-shared/backend/NativeClient";
import {Arguments, processArguments} from "../shared/process-arguments";
const call_basic_action = (name: string, ...args: any[]) => ipcRenderer.send('basic-action', name, ...args);
let versionInfo: NativeClientVersionInfo;

View File

@ -1,71 +0,0 @@
import {AbstractExternalModalController} from "tc-shared/ui/react-elements/external-modal/Controller";
import {Popout2ControllerMessages, PopoutIPCMessage} from "tc-shared/ui/react-elements/external-modal/IPCMessage";
import {ExternalModal, kIPCChannelExternalModal} from "../shared/ipc/ExternalModal";
import {ObjectProxyClient} from "../shared/proxy/Client";
import {ProxiedClass} from "../shared/proxy/Definitions";
import {getIpcInstance} from "tc-shared/ipc/BrowserIPC";
import {ModalOptions} from "tc-shared/ui/react-elements/modal/Definitions";
const modalClient = new ObjectProxyClient<ExternalModal>(kIPCChannelExternalModal);
modalClient.initialize();
export class ExternalModalController extends AbstractExternalModalController {
private handle: ProxiedClass<ExternalModal> & ExternalModal;
constructor(modalType: string, constructorArguments?: any[], options?: ModalOptions) {
super(modalType, constructorArguments);
}
protected async spawnWindow(): Promise<boolean> {
if(!this.handle) {
this.handle = await modalClient.createNewInstance();
}
const parameters = {
"loader-target": "manifest",
"chunk": "modal-external",
"modal-target": this.modalType,
"modal-identify": this.ipcAuthenticationCode,
"ipc-address": getIpcInstance().getApplicationChannelId(),
"ipc-core-peer": getIpcInstance().getLocalPeerId(),
"loader-abort": 0,
"animation-short": 1
};
const baseUrl = location.origin + location.pathname + "?";
const url = baseUrl + Object.keys(parameters).map(e => e + "=" + encodeURIComponent(parameters[e])).join("&");
return await this.handle.spawnWindow(this.modalType, url);
}
protected destroyWindow(): void {
this.handle?.destroy();
this.handle = undefined;
}
protected focusWindow(): void {
this.handle?.focus().then(() => {});
}
protected handleTypedIPCMessage<T extends Popout2ControllerMessages>(remoteId: string, isBroadcast: boolean, type: T, payload: PopoutIPCMessage[T]): void {
super.handleTypedIPCMessage(remoteId, isBroadcast, type, payload);
switch (type) {
case "invoke-modal-action":
const data = payload as PopoutIPCMessage["invoke-modal-action"];
switch (data.action) {
case "close":
this.destroy();
break;
case "minimize":
this.handle?.minimize().then(() => {});
break;
}
break;
case "hello-popout":
break;
}
}
}

View File

@ -0,0 +1,51 @@
import {KeyEvent as NKeyEvent, RegisterCallback, UnregisterCallback} from "tc-native/ppt";
import {AbstractKeyBoard, EventType, KeyEvent, KeyHook, SpecialKey} from "tc-shared/PPTListener";
import {tr} from "tc-shared/i18n/localize";
import {LogCategory, logTrace} from "tc-shared/log";
export class NativeKeyBoard extends AbstractKeyBoard {
private readonly listener;
constructor() {
super();
RegisterCallback(this.listener = event => this.handleNativeKeyEvent(event));
}
destroy() {
UnregisterCallback(this.listener);
}
private handleNativeKeyEvent(nativeEvent: NKeyEvent) {
let type;
switch (nativeEvent.type) {
case 0:
type = EventType.KEY_PRESS;
break;
case 1:
type = EventType.KEY_RELEASE;
break;
case 2:
type = EventType.KEY_TYPED;
break;
default:
return;
}
const event: KeyEvent = {
type: type,
key: nativeEvent.key_code,
keyCode: nativeEvent.key_code,
keyCtrl: nativeEvent.key_ctrl,
keyShift: nativeEvent.key_shift,
keyAlt: nativeEvent.key_alt,
keyWindows: nativeEvent.key_windows,
};
this.fireKeyEvent(event);
}
}

View File

@ -1,139 +0,0 @@
import {KeyEvent as NKeyEvent, RegisterCallback, UnregisterCallback} from "tc-native/ppt";
import {EventType, KeyEvent, KeyHook, SpecialKey} from "tc-shared/PPTListener";
import {tr} from "tc-shared/i18n/localize";
import {LogCategory, logTrace} from "tc-shared/log";
import * as log from "tc-shared/log";
let key_listener: ((_: KeyEvent) => any)[] = [];
function listener_key(type: EventType, nevent: NKeyEvent) {
if(nevent.key_code === 'VoidSymbol' || nevent.key_code === 'error')
nevent.key_code = undefined; /* trigger event for state update */
let event: KeyEvent = {
type: type,
key: nevent.key_code,
key_code: nevent.key_code,
key_ctrl: nevent.key_ctrl,
key_shift: nevent.key_shift,
key_alt: nevent.key_alt,
key_windows: nevent.key_windows
} as any;
for (const listener of key_listener)
listener && listener(event);
}
function native_keyhook(event: NKeyEvent) {
//console.log("Native event!: %o", event);
if(event.type == 0)
listener_key(EventType.KEY_PRESS, event);
else if(event.type == 1)
listener_key(EventType.KEY_RELEASE, event);
else if(event.type == 2)
listener_key(EventType.KEY_TYPED, event);
else
console.warn(tr("Received unknown native event: %o"), event);
}
export async function initialize() : Promise<void> {
register_key_listener(listener_hook);
RegisterCallback(native_keyhook);
}
export function finalize() {
unregister_key_listener(listener_hook);
UnregisterCallback(native_keyhook);
}
export function register_key_listener(listener: (_: KeyEvent) => any) {
key_listener.push(listener);
}
export function unregister_key_listener(listener: (_: KeyEvent) => any) {
const index = key_listener.findIndex(e => e === listener);
if(index !== -1) key_listener.splice(index, 1);
}
let key_hooks: KeyHook[] = [];
interface CurrentState {
keys: {[code: string]:KeyEvent};
special: { [key:number]:boolean };
}
let current_state: CurrentState = {
special: []
} as any;
let key_hooks_active: KeyHook[] = [];
function listener_hook(event: KeyEvent) {
if(event.type == EventType.KEY_TYPED)
return;
let old_hooks = [...key_hooks_active];
let new_hooks = [];
current_state.special[SpecialKey.ALT] = event.key_alt;
current_state.special[SpecialKey.CTRL] = event.key_ctrl;
current_state.special[SpecialKey.SHIFT] = event.key_shift;
current_state.special[SpecialKey.WINDOWS] = event.key_windows;
current_state[event.key_code] = undefined;
if(event.type == EventType.KEY_PRESS) {
current_state[event.key_code] = event;
for(const hook of key_hooks) {
if(hook.key_code !== event.key_code) continue;
if(hook.key_alt != event.key_alt) continue;
if(hook.key_ctrl != event.key_ctrl) continue;
if(hook.key_shift != event.key_shift) continue;
if(hook.key_windows != event.key_windows) continue;
new_hooks.push(hook);
const index = old_hooks.findIndex(e => e === hook);
if(index === -1 && hook.callback_press) {
hook.callback_press();
logTrace(LogCategory.GENERAL, tr("Trigger key press for %o!"), hook);
}
}
}
//We have a new situation
for(const hook of old_hooks) {
//Do not test for meta key states because they could differ in a key release event
if(hook.key_code === event.key_code) {
if(hook.callback_release) {
hook.callback_release();
logTrace(LogCategory.GENERAL, tr("Trigger key release for %o!"), hook);
}
} else {
new_hooks.push(hook);
}
}
key_hooks_active = new_hooks;
}
export function register_key_hook(hook: KeyHook) {
key_hooks.push(hook);
}
export function unregister_key_hook(hook: KeyHook) {
let index;
index = key_hooks.findIndex(e => e === hook);
if(index !== -1) key_hooks.splice(index, 1);
index = key_hooks_active.findIndex(e => e === hook);
if(index !== -1) key_hooks_active.splice(index, 1);
}
export function key_pressed(code: string | SpecialKey) : boolean {
if(typeof(code) === 'string')
return typeof(current_state[code]) === "object";
return current_state.special[code];
}

View File

@ -0,0 +1,108 @@
import {
WindowAction,
WindowCreateResult,
WindowManager,
WindowManagerEvents,
WindowSpawnOptions
} from "tc-shared/ui/windows/WindowManager";
import {Registry} from "tc-events";
import {assertMainApplication} from "tc-shared/ui/utils";
import {ObjectProxyClient} from "../shared/proxy/Client";
import {IpcWindowInstance, kIPCChannelWindowManager} from "../shared/ipc/IpcWindowInstance";
import {ProxiedClass} from "../shared/proxy/Definitions";
import {guid} from "tc-shared/crypto/uid";
import {getIpcInstance} from "tc-shared/ipc/BrowserIPC";
assertMainApplication();
const modalClient = new ObjectProxyClient<IpcWindowInstance>(kIPCChannelWindowManager);
modalClient.initialize();
export class NativeWindowManager implements WindowManager {
private readonly events: Registry<WindowManagerEvents>;
private readonly windowInstances: { [key: string]: ProxiedClass<IpcWindowInstance> & IpcWindowInstance };
constructor() {
this.windowInstances = {};
this.events = new Registry<WindowManagerEvents>();
}
getEvents(): Registry<WindowManagerEvents> {
return this.events;
}
async createWindow(options: WindowSpawnOptions): Promise<WindowCreateResult> {
const windowHandle = await modalClient.createNewInstance();
const parameters = {
"loader-target": "manifest",
"loader-chunk": "modal-external",
"ipc-address": getIpcInstance().getApplicationChannelId(),
"ipc-core-peer": getIpcInstance().getLocalPeerId(),
"loader-abort": 0,
"animation-short": 1
};
Object.assign(parameters, options.appParameters);
const baseUrl = location.origin + location.pathname + "?";
const url = baseUrl + Object.keys(parameters).map(e => e + "=" + encodeURIComponent(parameters[e])).join("&");
const result = await windowHandle.initialize("modal-external", options.uniqueId, url);
if(!result) {
windowHandle.destroy();
return { status: "error-unknown", message: tr("failed to spawn window") };
}
const windowId = guid();
windowHandle.events.onClose = () => this.destroyWindow(windowId);
this.windowInstances[windowId] = windowHandle;
return { status: "success", windowId: windowId };
}
destroyWindow(windowId: string): any {
if(!this.windowInstances[windowId]) {
return;
}
this.windowInstances[windowId].destroy();
delete this.windowInstances[windowId];
this.events.fire("notify_window_destroyed", { windowId: windowId });
}
getActiveWindowId(): string | undefined {
/* TODO! */
return undefined;
}
async executeAction(windowId: string, action: WindowAction): Promise<void> {
if(!this.windowInstances[windowId]) {
return;
}
const window = this.windowInstances[windowId];
switch (action) {
case "focus":
await window.focus();
break;
case "maximize":
await window.maximize();
break;
case "minimize":
await window.minimize();
break;
}
}
isActionSupported(windowId: string, action: WindowAction): boolean {
switch (action) {
case "minimize":
case "focus":
case "maximize":
return true;
default:
return false;
}
}
}

View File

@ -1,6 +1,6 @@
import {audio} from "tc-native/connection";
import {FilterType, StateFilter, ThresholdFilter, VoiceLevelFilter} from "tc-shared/voice/Filter";
import {NativeInput} from "./AudioRecorder";
import {FilterType, StateFilter, ThresholdFilter, VoiceLevelFilter} from "tc-shared/voice/Filter";
export abstract class NativeFilter {
readonly priority: number;
@ -79,8 +79,9 @@ export class NThresholdFilter extends NativeFilter implements ThresholdFilter {
setMarginFrames(value: number) {
this.marginFrames = value;
if(this.filter)
if(this.filter) {
this.filter.set_margin_time(value / 960 / 1000);
}
}
getAttackSmooth(): number {
@ -93,14 +94,16 @@ export class NThresholdFilter extends NativeFilter implements ThresholdFilter {
setAttackSmooth(value: number) {
this._attack_smooth = value;
if(this.filter)
if(this.filter) {
this.filter.set_attack_smooth(value);
}
}
setReleaseSmooth(value: number) {
this._release_smooth = value;
if(this.filter)
if(this.filter) {
this.filter.set_release_smooth(value);
}
}
setThreshold(value: number): Promise<void> {

View File

@ -1,4 +1,5 @@
import * as native from "tc-native/connection";
import {AudioBackend, OutputDevice} from "tc-shared/audio/Player";
//FIXME: Native audio initialize handle!
export interface Device {
@ -70,4 +71,108 @@ export function get_master_volume() : number {
}
export function set_master_volume(volume: number) {
native.audio.playback.set_master_volume(volume);
}
export class NativeAudioPlayer implements AudioBackend {
private readonly audioContext: AudioContext;
private initializedPromises: (() => void)[];
private currentDevice: native.audio.AudioDevice;
constructor() {
this.audioContext = new AudioContext();
this.initializedPromises = [];
native.audio.initialize(() => {
const promises = this.initializedPromises;
this.initializedPromises = undefined;
promises.forEach(callback => callback());
});
}
executeWhenInitialized(callback: () => void): any {
if(this.initializedPromises) {
this.initializedPromises.push(callback);
} else {
callback();
}
}
getMasterVolume(): number {
return native.audio.playback.get_master_volume();
}
setMasterVolume(volume: number): any {
native.audio.playback.set_master_volume(volume);
}
getAudioContext(): AudioContext | undefined {
return this.audioContext;
}
async getAvailableDevices(): Promise<OutputDevice[]> {
return native.audio.available_devices().filter(e => e.output_supported || e.output_default).map(entry => ({
device_id: entry.device_id,
driver: entry.driver,
name: entry.name
}));
}
getCurrentDevice(): OutputDevice {
if(this.currentDevice) {
return this.currentDevice;
}
const defaultDevice = native.audio.available_devices().find(entry => entry.output_default);
if(defaultDevice) {
return {
name: defaultDevice.name,
driver: defaultDevice.driver,
device_id: defaultDevice.device_id
};
}
return {
name: "Default device",
device_id: "default",
driver: "default driver"
};
}
async setCurrentDevice(targetId: string | undefined): Promise<void> {
const device = native.audio.available_devices().find(e => e.device_id == targetId);
if(!device) {
console.warn("Missing audio device with is %s", targetId);
throw "invalid device id";
}
try {
native.audio.playback.set_device(device.device_id);
} catch(error) {
if(error instanceof Error) {
throw error.message;
}
throw error;
}
this.currentDevice = device;
}
getDefaultDeviceId(): string {
return native.audio.available_devices().find(entry => entry.output_default).device_id;
}
isDeviceRefreshAvailable(): boolean {
return false;
}
isInitialized(): boolean {
return !this.initializedPromises;
}
refreshDevices(): Promise<void> {
return Promise.resolve(undefined);
}
}

View File

@ -13,7 +13,7 @@ import {tr} from "tc-shared/i18n/localize";
import {Registry} from "tc-shared/events";
import {Filter, FilterType, FilterTypeClass} from "tc-shared/voice/Filter";
import {NativeFilter, NStateFilter, NThresholdFilter, NVoiceLevelFilter} from "./AudioFilter";
import {getRecorderBackend, IDevice} from "tc-shared/audio/recorder";
import {getRecorderBackend, InputDevice} from "tc-shared/audio/Recorder";
import {LogCategory, logError, logTrace, logWarn} from "tc-shared/log";
import {Settings, settings} from "tc-shared/settings";
import NativeFilterMode = audio.record.FilterMode;
@ -80,9 +80,9 @@ export class NativeInput implements AbstractInput {
logTrace(LogCategory.AUDIO, tr("Starting input for device %o", this.deviceId));
try {
let deviceId;
if(this.deviceId === IDevice.NoDeviceId) {
if(this.deviceId === InputDevice.NoDeviceId) {
throw tr("no device selected");
} else if(this.deviceId === IDevice.DefaultDeviceId) {
} else if(this.deviceId === InputDevice.DefaultDeviceId) {
deviceId = getRecorderBackend().getDeviceList().getDefaultDeviceId();
} else {
deviceId = this.deviceId;
@ -271,7 +271,7 @@ export class NativeInput implements AbstractInput {
export class NativeLevelMeter implements LevelMeter {
static readonly instances: NativeLevelMeter[] = [];
readonly targetDevice: IDevice;
readonly targetDevice: InputDevice;
public nativeRecorder: audio.record.AudioRecorder;
public nativeConsumer: audio.record.AudioConsumer;
@ -279,7 +279,7 @@ export class NativeLevelMeter implements LevelMeter {
private callback: (num: number) => any;
private nativeFilter: audio.record.ThresholdConsumeFilter;
constructor(device: IDevice) {
constructor(device: InputDevice) {
this.targetDevice = device;
this.callback = () => {};
}
@ -341,7 +341,7 @@ export class NativeLevelMeter implements LevelMeter {
this.nativeFilter = undefined;
}
getDevice(): IDevice {
getDevice(): InputDevice {
return this.targetDevice;
}

View File

@ -1,12 +1,12 @@
import {AbstractDeviceList, DeviceListEvents, IDevice, PermissionState} from "tc-shared/audio/recorder";
import {Registry} from "tc-shared/events";
import {AbstractDeviceList, DeviceListEvents, InputDevice, PermissionState} from "tc-shared/audio/Recorder";
import {Registry} from "tc-events";
import * as loader from "tc-loader";
import * as native from "tc-native/connection";
import {audio} from "tc-native/connection";
import {LogCategory, logTrace} from "tc-shared/log";
interface NativeIDevice extends IDevice {
interface NativeIDevice extends InputDevice {
isDefault: boolean
}

View File

@ -0,0 +1,27 @@
import {audio as naudio} from "tc-native/connection";
import {SoundBackend, SoundFile} from "tc-shared/audio/Sounds";
import * as paths from "path";
export class NativeSoundBackend implements SoundBackend {
playSound(sound: SoundFile): Promise<void> {
return new Promise((resolve, reject) => {
let pathname = paths.dirname(decodeURIComponent(location.pathname));
if(pathname[0] === '/' && pathname[2] === ':') //e.g.: /C:/test...
pathname = pathname.substr(1);
const path = paths.join(pathname, sound.path);
console.log("replaying %s (volume: %f)", sound.path, sound.volume);
naudio.sounds.playback_sound({
callback: (result, message) => {
if(result == naudio.sounds.PlaybackResult.SUCCEEDED)
resolve();
else
reject(naudio.sounds.PlaybackResult[result].toLowerCase() + ": " + message);
},
file: path,
volume: typeof sound.volume === "number" ? sound.volume : 1
});
});
}
}

View File

@ -1,24 +0,0 @@
import {audio as naudio} from "tc-native/connection";
import * as paths from "path";
import {SoundFile} from "tc-shared/sound/Sounds";
export async function play_sound(file: SoundFile) : Promise<void> {
await new Promise((resolve, reject) => {
let pathname = paths.dirname(decodeURIComponent(location.pathname));
if(pathname[0] === '/' && pathname[2] === ':') //e.g.: /C:/test...
pathname = pathname.substr(1);
const path = paths.join(pathname, file.path);
console.log("replaying %s (volume: %f)", file.path, file.volume);
naudio.sounds.playback_sound({
callback: (result, message) => {
if(result == naudio.sounds.PlaybackResult.SUCCEEDED)
resolve();
else
reject(naudio.sounds.PlaybackResult[result].toLowerCase() + ": " + message);
},
file: path,
volume: file.volume || 1
});
});
}

Some files were not shown because too many files have changed in this diff Show More