Fixed some bookmark icon related issues

master
WolverinDEV 2021-06-11 11:43:53 +02:00
parent b524fdeb5c
commit ebc5b178e0
12 changed files with 98 additions and 38 deletions

View File

@ -3,6 +3,8 @@
- Fixed the bug that cause the file transfer to timeout if the user hasn't been quick enough to save his file
- Fixed the emoji picker being cut off
- Fixed the file transfer sidebar not working
- Instantly reflect changes to the server icon for the bookmark menu bar
- Fixed a bug which prevented the proper context menu appear within the bookmark manage modal
* **26.05.21**
- Fixed automated builds

View File

@ -2,9 +2,10 @@ import {LogCategory, logError, logWarn} from "tc-shared/log";
import {tr, tra} from "tc-shared/i18n/localize";
import * as loader from "tc-loader";
import {Stage} from "tc-loader";
import {ConnectionHandler} from "tc-shared/ConnectionHandler";
import {ConnectionHandler, ConnectionState} from "tc-shared/ConnectionHandler";
import {server_connections} from "tc-shared/ConnectionManager";
import {ServerProperties} from "tc-shared/tree/Server";
import {Registry} from "tc-events";
export const kUnknownHistoryServerUniqueId = "unknown";
@ -44,10 +45,17 @@ export type ConnectionHistoryServerInfo = {
passwordProtected: boolean
}
export interface ConnectionHistoryEvents {
notify_server_info_updated: { serverUniqueId: string, keys: (keyof ConnectionHistoryServerInfo)[] }
}
export class ConnectionHistory {
readonly events: Registry<ConnectionHistoryEvents>;
private database: IDBDatabase;
constructor() { }
constructor() {
this.events = new Registry<ConnectionHistoryEvents>();
}
async initializeDatabase() {
const openRequest = indexedDB.open("connection-log", 1);
@ -306,16 +314,29 @@ export class ConnectionHistory {
return;
}
await this.updateDatabaseServerInfo(serverUniqueId, databaseValue => {
databaseValue.name = info.name;
databaseValue.iconId = info.iconId;
const changes: (keyof ConnectionHistoryServerInfo)[] = [];
const updateValue = (databaseKey: string, infoKey: keyof ConnectionHistoryServerInfo) => {
if(databaseValue[databaseKey] === info[infoKey]) {
return;
}
databaseValue.clientsOnline = info.clientsOnline;
databaseValue.clientsMax = info.clientsMax;
databaseValue[databaseKey] = info[infoKey];
changes.push(infoKey);
}
databaseValue.hostBannerUrl = info.hostBannerUrl
databaseValue.hostBannerMode = info.hostBannerMode;
updateValue("name", "name");
updateValue("iconId", "iconId");
updateValue("clientsOnline", "clientsOnline");
updateValue("clientsMax", "clientsMax");
updateValue("hostBannerUrl", "hostBannerUrl");
updateValue("hostBannerMode", "hostBannerMode");
if(changes.length > 0) {
this.events.fire("notify_server_info_updated", { serverUniqueId: serverUniqueId, keys: changes });
}
});
}
@ -542,7 +563,15 @@ class ConnectionHistoryUpdateListener {
}
private registerConnectionHandler(handler: ConnectionHandler) {
handler.channelTree.server.events.on("notify_properties_updated", event => {
const events = this.listenerConnectionHandler[handler.handlerId] = [];
events.push(handler.channelTree.server.events.on("notify_properties_updated", event => {
switch(handler.connection_state) {
case ConnectionState.UNCONNECTED:
case ConnectionState.DISCONNECTING:
/* We don't want any changes here */
return;
}
if("virtualserver_unique_identifier" in event.updated_properties) {
if(handler.currentConnectId > 0) {
this.history.updateConnectionServerUniqueId(handler.currentConnectId, event.server_properties.virtualserver_unique_identifier)
@ -573,7 +602,7 @@ class ConnectionHistoryUpdateListener {
break;
}
}
});
}));
}
}
@ -581,7 +610,7 @@ export let connectionHistory: ConnectionHistory;
let historyInfoListener: ConnectionHistoryUpdateListener;
loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
priority: 0,
priority: 40,
name: "Chat history setup",
function: async () => {
if(!('indexedDB' in window)) {

View File

@ -127,7 +127,7 @@ export class AppController {
}
export let appViewController: AppController;
loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
loader.register_task(Stage.LOADED, {
name: "app view",
function: async () => {
appViewController = new AppController();
@ -137,5 +137,5 @@ loader.register_task(Stage.JAVASCRIPT_INITIALIZING, {
(window as any).AppController = AppController;
(window as any).appViewController = appViewController;
},
priority: 0
priority: 100
});

View File

@ -167,16 +167,6 @@ html:root {
right: 0;
}
.iconContainer {
margin-right: .25em;
display: flex;
flex-direction: column;
flex-shrink: 0;
flex-grow: 0;
}
.dropdownEntry {
position: relative;
@ -305,4 +295,11 @@ html:root {
transform: rotate(45deg);
-webkit-transform: rotate(45deg);
}
}
.iconContainer {
margin-right: .25em;
display: flex;
flex-direction: column;
}

View File

@ -23,6 +23,8 @@ import {connectionHistory} from "tc-shared/connectionlog/History";
import {RemoteIconInfo} from "tc-shared/file/Icons";
import {spawnModalAddCurrentServerToBookmarks} from "tc-shared/ui/modal/bookmarks-add-server/Controller";
import {getAudioBackend, OutputDevice} from "tc-shared/audio/Player";
import {ignorePromise} from "tc-shared/proto";
import {LogCategory, logTrace} from "tc-shared/log";
class InfoController {
private readonly mode: ControlBarMode;
@ -34,6 +36,8 @@ class InfoController {
private handlerRegisteredEvents: (() => void)[] = [];
private defaultRecorderListener: () => void;
private bookmarkServerUniqueIds: string[] = [];
constructor(events: Registry<ControlBarEvents>, mode: ControlBarMode) {
this.events = events;
this.mode = mode;
@ -61,6 +65,16 @@ class InfoController {
this.sendVideoState("camera");
}));
bookmarks.events.on(["notify_bookmark_edited", "notify_bookmark_created", "notify_bookmark_deleted", "notify_bookmarks_imported"], () => this.sendBookmarks());
events.push(connectionHistory.events.on("notify_server_info_updated", event => {
if(this.bookmarkServerUniqueIds.indexOf(event.serverUniqueId) === -1) {
return;
}
if(event.keys.indexOf("iconId") !== -1) {
/* An icon for a bookmark has changed. Send the full new list. */
ignorePromise(this.sendBookmarks());
}
}));
events.push(getVideoDriver().getEvents().on("notify_device_list_changed", () => this.sendCameraList()));
events.push(getRecorderBackend().getDeviceList().getEvents().on("notify_list_updated", () => this.sendMicrophoneList()));
events.push(defaultRecorderEvents.on("notify_default_recorder_changed", () => {
@ -202,7 +216,9 @@ class InfoController {
});
}
/* Note: This method might be executed concurrently */
public async sendBookmarks() {
this.bookmarkServerUniqueIds = [];
const bookmarkList = bookmarks.getOrderedRegisteredBookmarks();
const parent: Bookmark[] = [];
@ -216,15 +232,17 @@ class InfoController {
let icon: RemoteIconInfo;
try {
const connectInfo = await connectionHistory.lastConnectInfo(bookmark.entry.serverAddress, "address");
const connectInfo = await connectionHistory.lastConnectInfo(bookmark.entry.serverAddress, "address", true);
if(connectInfo) {
this.bookmarkServerUniqueIds.push(connectInfo.serverUniqueId);
const info = await connectionHistory.queryServerInfo(connectInfo.serverUniqueId);
if(info && info.iconId > 0) {
icon = { iconId: info.iconId, serverUniqueId: connectInfo.serverUniqueId };
}
}
} catch (_) {
/* no need for any error handling */
} catch (error) {
/* No need to warn in prod build */
logTrace(LogCategory.BOOKMARKS, "Failed to query last connect info: %o", error);
}
parentList.push({

View File

@ -1,5 +1,4 @@
import * as React from "react";
import {ReactComponentBase} from "tc-shared/ui/react-elements/ReactComponentBase";
import {IconRenderer, RemoteIconRenderer} from "tc-shared/ui/react-elements/Icon";
import {getIconManager, RemoteIconInfo} from "tc-shared/file/Icons";
import {joinClassList} from "tc-shared/ui/react-elements/Helper";

View File

@ -11,6 +11,7 @@ import {bookmarks} from "tc-shared/Bookmarks";
import {RemoteIconInfo} from "tc-shared/file/Icons";
import {connectionHistory} from "tc-shared/connectionlog/History";
import {spawnModalAddCurrentServerToBookmarks} from "tc-shared/ui/modal/bookmarks-add-server/Controller";
import {LogCategory, logTrace} from "tc-shared/log";
function renderConnectionItems() {
const items: MenuBarEntry[] = [];
@ -52,7 +53,9 @@ function renderConnectionItems() {
return items;
}
let bookmarkServerUniqueIds: string[] = [];
async function renderBookmarkItems() {
bookmarkServerUniqueIds = [];
const bookmarkList = bookmarks.getOrderedRegisteredBookmarks();
const bookmarkItems: MenuBarEntry[] = [];
@ -66,15 +69,17 @@ async function renderBookmarkItems() {
let icon: RemoteIconInfo;
try {
const connectInfo = await connectionHistory.lastConnectInfo(bookmark.entry.serverAddress, "address");
const connectInfo = await connectionHistory.lastConnectInfo(bookmark.entry.serverAddress, "address", true);
if(connectInfo) {
bookmarkServerUniqueIds.push(connectInfo.serverUniqueId);
const info = await connectionHistory.queryServerInfo(connectInfo.serverUniqueId);
if(info && info.iconId > 0) {
icon = { iconId: info.iconId, serverUniqueId: connectInfo.serverUniqueId };
}
}
} catch (_) {
/* no need for any error handling */
} catch (error) {
/* No need to warn in prod build */
logTrace(LogCategory.BOOKMARKS, "Failed to query last connect info: %o", error);
}
parentList.push({
@ -363,6 +368,16 @@ class MenuBarUpdateListener {
}));
this.generalHandlerEvents.push(server_connections.events().on("notify_active_handler_changed", () => updateMenuBar()));
this.generalHandlerEvents.push(bookmarks.events.on(["notify_bookmark_deleted", "notify_bookmark_created", "notify_bookmark_edited", "notify_bookmarks_imported"], () => updateMenuBar()));
this.generalHandlerEvents.push(connectionHistory.events.on("notify_server_info_updated", event => {
if(bookmarkServerUniqueIds.indexOf(event.serverUniqueId) === -1) {
return;
}
if(event.keys.indexOf("iconId") !== -1) {
/* An icon for a bookmark has changed. Send the menu bar with the new icons. */
updateMenuBar();
}
}));
server_connections.getAllConnectionHandlers().forEach(handler => this.registerHandlerEvents(handler));
}

View File

@ -567,7 +567,7 @@ class BookmarkModalController {
}
return this.bookmarkUniqueServerIds[bookmarkId] = (async () => {
const info = await connectionHistory.lastConnectInfo(bookmark.serverAddress, "address");
const info = await connectionHistory.lastConnectInfo(bookmark.serverAddress, "address", true);
if(!info) {
return undefined;
}

View File

@ -109,7 +109,7 @@ const BookmarkListEntryRenderer = React.memo((props: { entry: BookmarkListEntry
events.fire("action_connect", { uniqueId: props.entry.uniqueId, newTab: false, closeModal: true });
}}
onContextMenu={event => {
event.preventDefault();
event.stopPropagation();
if(selectedItem.remoteValue?.id !== props.entry.uniqueId) {
selectedItem.setValue({ id: props.entry.uniqueId });
@ -195,9 +195,8 @@ const BookmarkList = React.memo(() => {
<div
className={cssStyle.containerBookmarks}
onContextMenu={event => {
event.preventDefault();
if(bookmarks.length === 0) {
/* We've an extra overlay for not having any bookmarks. */
return;
}

View File

@ -4,6 +4,7 @@ import * as dompurify from "dompurify";
import {ChangeLog, ChangeLogEntry, ChangeSet} from "tc-shared/update/ChangeLog";
import {Translatable, VariadicTranslatable} from "tc-shared/ui/react-elements/i18n";
import {guid} from "tc-shared/crypto/uid";
import moment from "moment";
const {Remarkable} = require("remarkable");
const cssStyle = require("./Renderer.scss");
@ -108,7 +109,7 @@ export const WhatsNew = (props: { changesUI?: ChangeLog, changesClient?: ChangeL
<VariadicTranslatable key={"info-web"}
text={"The web client has been updated to the version from {}."}
>
{versionUIDate}
{moment(__build.timestamp).format("dd.MM.YY")}
</VariadicTranslatable>
);
} else if (props.changesUI && props.changesClient) {

View File

@ -29,7 +29,7 @@ export class Checkbox extends React.Component<CheckboxProperties, CheckboxState>
render() {
const disabled = typeof this.state.disabled === "boolean" ? this.state.disabled : this.props.disabled;
const checked = typeof this.props.value === "boolean" ? this.props.value : typeof this.state.checked === "boolean" ? this.state.checked : this.props.initialValue;
const checked = (typeof this.props.value === "boolean" ? this.props.value : typeof this.state.checked === "boolean" ? this.state.checked : this.props.initialValue) || false;
const disabledClass = disabled ? cssStyle.disabled : "";
return (

View File

@ -64,7 +64,7 @@ export const RemoteIconRenderer = React.memo((props: { icon: RemoteIcon | undefi
}
return (
<IconUrl iconUrl={props.icon.getImageUrl()} title={props.title || ("icon " + props.icon.iconId)} key={"icon-" + props.icon.iconId} />
<IconUrl iconUrl={props.icon.getImageUrl()} title={props.title || ("icon " + props.icon.iconId)} key={"icon-" + props.icon.iconId} className={props.className} />
);
case "loading":