From dbb8039f64bd0d3e97d263a886a7fe5ba6b48cbf Mon Sep 17 00:00:00 2001 From: WolverinDEV Date: Wed, 24 Mar 2021 17:48:01 +0100 Subject: [PATCH] Allowing to view the own clients avatar --- ChangeLog.md | 1 + .../js/ui/frames/side/ClientInfoRenderer.scss | 5 + .../js/ui/frames/side/ClientInfoRenderer.tsx | 43 +++++- shared/js/ui/react-elements/Avatar.tsx | 140 ++++++++++++------ 4 files changed, 133 insertions(+), 56 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 092f3963..cb2bb076 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,6 +1,7 @@ # Changelog: * **24.03.21** - Improved the avatar upload modal (now way more intuitive) + - Fixed a bug which cause client avatars to be stuck within the loading screen * **23.03.21** - Made the permission editor popoutable diff --git a/shared/js/ui/frames/side/ClientInfoRenderer.scss b/shared/js/ui/frames/side/ClientInfoRenderer.scss index 7a62c00d..6e3ee7ef 100644 --- a/shared/js/ui/frames/side/ClientInfoRenderer.scss +++ b/shared/js/ui/frames/side/ClientInfoRenderer.scss @@ -206,6 +206,11 @@ $bot_thumbnail_height: 9em; &:hover { opacity: .75; } + + &.disabled { + opacity: 0!important; + pointer-events: none!important; + } } &.editable { diff --git a/shared/js/ui/frames/side/ClientInfoRenderer.tsx b/shared/js/ui/frames/side/ClientInfoRenderer.tsx index 0af04069..37f7f802 100644 --- a/shared/js/ui/frames/side/ClientInfoRenderer.tsx +++ b/shared/js/ui/frames/side/ClientInfoRenderer.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import {useContext, useEffect, useState} from "react"; +import {useContext, useEffect, useRef, useState} from "react"; import { ClientCountryInfo, ClientForumInfo, @@ -25,31 +25,60 @@ import {ClientIconRenderer} from "tc-shared/ui/react-elements/Icons"; import {getIconManager} from "tc-shared/file/Icons"; import {RemoteIconRenderer} from "tc-shared/ui/react-elements/Icon"; import {CountryCode} from "tc-shared/ui/react-elements/CountryCode"; +import {getKeyBoard, SpecialKey} from "tc-shared/PPTListener"; const cssStyle = require("./ClientInfoRenderer.scss"); const EventsContext = React.createContext>(undefined); const ClientContext = React.createContext(undefined); -const Avatar = React.memo(() => { +const EditOverlay = React.memo(() => { const events = useContext(EventsContext); + + const refContainer = useRef(); + + useEffect(() => { + const keyboard = getKeyBoard(); + return keyboard.registerHook({ + keyShift: true, + + callbackPress: () => { + refContainer.current?.classList.add(cssStyle.disabled); + }, + callbackRelease: () => { + refContainer.current?.classList.remove(cssStyle.disabled); + } + }); + }, []); + + return ( +
events.fire("action_edit_avatar")} + > + +
+ ); +}); + +const Avatar = React.memo(() => { const client = useContext(ClientContext); let avatar: "loading" | ClientAvatar; if(client.type === "none") { avatar = "loading"; } else { - avatar = getGlobalAvatarManagerFactory().getManager(client.handlerId).resolveClientAvatar({ id: client.clientId, clientUniqueId: client.clientUniqueId, database_id: client.clientDatabaseId }); + avatar = getGlobalAvatarManagerFactory().getManager(client.handlerId) + .resolveClientAvatar({ id: client.clientId, clientUniqueId: client.clientUniqueId, database_id: client.clientDatabaseId }); } return (
- -
-
events.fire("action_edit_avatar")}> - +
+
) }); diff --git a/shared/js/ui/react-elements/Avatar.tsx b/shared/js/ui/react-elements/Avatar.tsx index bdae2aaf..e231eeb1 100644 --- a/shared/js/ui/react-elements/Avatar.tsx +++ b/shared/js/ui/react-elements/Avatar.tsx @@ -1,77 +1,119 @@ import * as React from "react"; -import {useEffect, useState} from "react"; +import {useState} from "react"; import {ClientAvatar, kDefaultAvatarImage, kLoadingAvatarImage} from "tc-shared/file/Avatars"; -import * as image_preview from "tc-shared/ui/frames/ImagePreview"; +import {useTr} from "tc-shared/ui/react-elements/Helper"; +import {showImagePreview} from "tc-shared/ui/frames/ImagePreview"; const ImageStyle = { height: "100%", width: "100%", cursor: "pointer" }; -export const AvatarRenderer = React.memo((props: { avatar: ClientAvatar | "loading" | "default", className?: string, alt?: string }) => { - let [ revision, setRevision ] = useState(0); + +const AvatarLoadingImage = React.memo((props: { alt?: string }) => ( + {typeof +)); + +const AvatarDefaultImage = React.memo((props: { className?: string, alt?: string }) => ( + {typeof { + if(event.isDefaultPrevented()) { + return; + } + + event.preventDefault(); + showImagePreview(kDefaultAvatarImage, undefined); + }} + /> +)); + +const ClientAvatarRenderer = React.memo((props: { avatar: ClientAvatar, className?: string, alt?: string }) => { + const [ , setRevision ] = useState(0); let image; - let avatar: ClientAvatar; - if(props.avatar === "loading") { - image = {tr("loading")}/; - } else if(props.avatar === "default") { - image = {tr("default; - } else { - const imageUrl = props.avatar.getAvatarUrl(); - switch (props.avatar.getState()) { - case "unset": - image = {typeof { - if(event.isDefaultPrevented()) - return; + switch (props.avatar.getState()) { + case "unset": + image = ( + + ); + break; - event.preventDefault(); - image_preview.showImagePreview(imageUrl, undefined); - }} - draggable={false} - />; - break; + case "loading": + image = ( + + ); + break; - case "loaded": - image = {typeof { - if(event.isDefaultPrevented()) + if(event.isDefaultPrevented()) { return; + } event.preventDefault(); - image_preview.showImagePreview(imageUrl, undefined); + showImagePreview(imageUrl, undefined); }} draggable={false} - />; - break; + /> + ); + break; - case "errored": - image = {typeof; - break; + case "errored": + image = ( + {typeof + ); + break; - case "loading": - image = {typeof; - break; - - case undefined: - break; - } - - avatar = props.avatar; + case undefined: + break; } - useEffect(() => avatar && avatar.events.on("avatar_state_changed", () => setRevision(revision + 1)), [ props.avatar ]); + props.avatar.events.reactUse("avatar_state_changed", () => { + setRevision(performance.now()); + }, undefined, []); + + return image; +}); + +export const AvatarRenderer = React.memo((props: { avatar: ClientAvatar | "loading" | "default", className?: string, alt?: string }) => { + let body; + if(props.avatar === "loading") { + body = ( + + ); + } else if(props.avatar === "default") { + body = ( + + ); + } else if(props.avatar instanceof ClientAvatar) { + body = ( + + ); + } return (
- {image} + {body}
- ) + ); }); \ No newline at end of file