Finishing the notification system and some fixups for the native client

canary
WolverinDEV 2020-07-23 20:00:25 +02:00
parent 324869e3fd
commit b3743c554a
11 changed files with 83 additions and 23 deletions

View File

@ -23,4 +23,7 @@ setTimeout(() => appLoader.execute(), 0);
export {};
//window.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = function () {};
if(__build.target === "client") {
/* do this so we don't get a react dev tools warning within the client */
(window as any).__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = function () {};
}

View File

@ -8,6 +8,7 @@
border-width: 0 .2em .2em 0;
padding: .21em;
height: .5em;
width: .5em;
&.right {
transform: rotate(-45deg);

View File

@ -1828,6 +1828,7 @@
<!-- <div class="entry" container="general-updates">{{tr "Updates" /}}</div> -->
<div class="entry" container="general-chat">{{tr "Chat" /}}</div>
<div class="entry" container="general-keymap">{{tr "Keymap" /}}</div>
<div class="entry" container="general-notifications">{{tr "Notifications" /}}</div>
<div class="entry group">{{tr "Audio" /}}</div>
<div class="entry" container="audio-microphone">{{tr "Microphone" /}}</div>
@ -1889,7 +1890,8 @@
</div>
<div class="container general-updates">{{tr "GU" /}}</div>
<div class="container general-keymap"></div>
<div class="container general-chat">
<div class="container general-chat"></div>
<div class="container general-notifications">
<label>
<div class="checkbox">
<input type="checkbox" class="option-fixed-timestamps">

View File

@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 400 400">
<defs>
<style>
.cls-1 {
fill: #b3b3b3;
fill-rule: evenodd;
}
</style>
</defs>
<path id="icon" class="cls-1" d="M200.012,0c110.457,0,200,89.545,200,200s-89.54,200-200,200S0.015,310.456.015,200,89.557,0,200.012,0Zm0.01,38.636A160.629,160.629,0,1,1,39.395,199.268,160.632,160.632,0,0,1,200.022,38.639ZM159.407,153.478s42.867-5.468,19.8,68.014c-24.208,77.113-66.566,140.45,63.467,81.447,0,0-64.556,21.6-42.619-37.407,12.79-34.406,28.292-81.421,27.092-93.4C225.387,154.546,207.6,141.025,159.407,153.478Zm65.564-79a24.685,24.685,0,1,1-24.687,24.684A24.685,24.685,0,0,1,224.971,74.479Z"/>
</svg>

After

Width:  |  Height:  |  Size: 760 B

View File

@ -1,11 +1,11 @@
//Used by CertAccept popup
/* setup jsrenderer */
(window as any).$ = require("jquery");
(window as any).jQuery = $;
import "jsrender";
if(__build.target === "web") {
(window as any).$ = require("jquery");
(window as any).jQuery = $;
import * as jsrenderInit from "jsrender";
const jsrender = jsrenderInit($);
require("jsrender")($);
}
declare global {
function setInterval(handler: TimerHandler, timeout?: number, ...arguments: any[]): number;

View File

@ -538,7 +538,21 @@ export class Settings extends StaticSettings {
static readonly FN_EVENTS_NOTIFICATION_ENABLED: (event: string) => SettingsKey<boolean> = event => {
return {
key: "notification_" + event + "_enabled",
key: "event_notification_" + event + "_enabled",
valueType: "boolean"
}
};
static readonly FN_EVENTS_LOG_ENABLED: (event: string) => SettingsKey<boolean> = event => {
return {
key: "event_log_" + event + "_enabled",
valueType: "boolean"
}
};
static readonly FN_EVENTS_FOCUS_ENABLED: (event: string) => SettingsKey<boolean> = event => {
return {
key: "event_focus_" + event + "_enabled",
valueType: "boolean"
}
};

View File

@ -5,7 +5,13 @@ const focusDefaultStatus = {};
focusDefaultStatus[EventType.CLIENT_POKE_RECEIVED] = true;
export function requestWindowFocus() {
window.focus();
if(__build.target === "web") {
window.focus();
} else {
/* TODO: Abstract that! */
const { remote } = __non_webpack_require__("electron");
remote.getCurrentWindow().show();
}
}
export function isFocusRequestEnabled(type: EventType) {

View File

@ -427,12 +427,20 @@ export class Conversation extends AbstractChat<ConversationUIEvents> {
this.pendingHistoryQueries.push(() => {
this.historyQueryResponse = [];
return this.handle.connection.serverConnection.send_command("conversationhistory", {
cid: this.conversationId,
timestamp_begin: criteria.begin,
message_count: criteria.limit,
timestamp_end: criteria.end
}, { flagset: [ "merge" ], process_result: false }).then(() => {
const requestObject = {
cid: this.conversationId
} as any;
if(typeof criteria.begin === "number")
requestObject.timestamp_begin = criteria.begin;
if(typeof criteria.end === "number")
requestObject.timestamp_end = criteria.end;
if(typeof criteria.limit === "number")
requestObject.message_count = criteria.limit;
return this.handle.connection.serverConnection.send_command("conversationhistory", requestObject, { flagset: [ "merge" ], process_result: false }).then(() => {
resolve({ status: "success", events: this.historyQueryResponse.map(e => {
return {
type: "message",
@ -778,6 +786,8 @@ export class ConversationManager extends AbstractChatManager<ConversationUIEvent
queryUnreadFlags() {
/* FIXME: Test for old TeaSpeak servers which don't support this */
return;
const commandData = this.connection.channelTree.channels.map(e => { return { cid: e.channelId, cpw: e.cached_password() }});
this.connection.serverConnection.send_command("conversationfetch", commandData).catch(error => {
log.warn(LogCategory.CHAT, tr("Failed to query conversation indexes: %o"), error);

View File

@ -2,7 +2,8 @@ import * as React from "react";
const cssStyle = require("./Switch.scss");
export interface SwitchProperties {
initialState: boolean;
value?: boolean;
initialState?: boolean;
className?: string;
@ -36,10 +37,14 @@ export class Switch extends React.Component<SwitchProperties, SwitchState> {
return (
<label ref={this.ref} className={cssStyle.container + " " + (this.props.className || "") + " " + (disabled ? cssStyle.disabled : "")} onBlur={this.props.onBlur}>
<div className={cssStyle.switch}>
<input type="checkbox" onChange={e => {
this.setState({ checked: e.currentTarget.checked });
this.props.onChange && this.props.onChange(e.currentTarget.checked);
}} disabled={disabled} checked={this.state.checked} />
<input
type="checkbox"
onChange={e => {
this.setState({ checked: e.currentTarget.checked });
this.props.onChange && this.props.onChange(e.currentTarget.checked);
}} disabled={disabled}
checked={typeof this.props.value === "boolean" ? this.props.value : this.state.checked}
/>
<span className={cssStyle.slider}>
<span className={cssStyle.dot} />
</span>

View File

@ -1,12 +1,14 @@
import * as React from "react";
import * as ReactDOM from "react-dom";
import {ReactElement} from "react";
import {guid} from "tc-shared/crypto/uid";
const cssStyle = require("./Tooltip.scss");
interface GlobalTooltipState {
pageX: number;
pageY: number;
tooltipId: string;
}
class GlobalTooltip extends React.Component<{}, GlobalTooltipState> {
@ -18,7 +20,8 @@ class GlobalTooltip extends React.Component<{}, GlobalTooltipState> {
this.state = {
pageX: 0,
pageY: 0
pageY: 0,
tooltipId: "unset"
};
}
@ -47,7 +50,7 @@ class GlobalTooltip extends React.Component<{}, GlobalTooltipState> {
if(!this.currentTooltip_ || this.isUnmount) {
return (
<div className={cssStyle.container} style={{ top: this.state.pageY, left: this.state.pageX }}>
{this.currentTooltip_?.props.tooltip()}
<React.Fragment key={this.state.tooltipId}>{this.currentTooltip_?.props.tooltip()}</React.Fragment>
</div>
);
}
@ -73,6 +76,7 @@ export interface TooltipProperties {
}
export class Tooltip extends React.Component<TooltipProperties, TooltipState> {
readonly tooltipId = guid();
private refContainer = React.createRef<HTMLSpanElement>();
private currentContainer: HTMLElement;
@ -105,6 +109,7 @@ export class Tooltip extends React.Component<TooltipProperties, TooltipState> {
globalTooltipRef.current?.setState({
pageY: this.state.pageY,
pageX: this.state.pageX,
tooltipId: this.tooltipId
});
} else if(prevState.forceShow || prevState.hovered) {
globalTooltipRef.current?.unmountTooltip(this);

View File

@ -18,5 +18,8 @@ export = () => config_base.config("client").then(config => {
callback();
});
config.externals.push({ "jquery": "window.$" });
config.externals.push({ "jsrender": "window.$" });
return Promise.resolve(config);
});