TelegramPWA/src/hooks/usePeerColor.ts
2025-11-06 11:36:26 +01:00

109 lines
3.4 KiB
TypeScript

import { useRef } from '@teact';
import type { ApiPeer, ApiTypePeerColor } from '../api/types';
import type { CustomPeer, ThemeKey } from '../types';
import { getPeerColorCollectibleColorCount, getPeerColorCount, getPeerColorKey } from '../global/helpers';
import buildStyle from '../util/buildStyle';
import { generateColorVariations, generatePeerColorGradient } from '../util/theme';
import useSyncEffect from './useSyncEffect';
type PeerColorAttributes = {
className?: string;
style?: string;
};
type PeerColorProperties = PeerColorAttributes & {
backgroundEmojiId?: string;
giftEmojiId?: string;
};
export default function usePeerColor({
peer,
color,
noUserColors,
shouldReset,
theme,
}: {
peer?: ApiPeer | CustomPeer;
color?: ApiTypePeerColor;
noUserColors?: boolean;
shouldReset?: boolean;
theme: ThemeKey;
}): PeerColorProperties {
const propertiesRef = useRef<PeerColorAttributes>({});
const realPeer = peer && !('isCustomPeer' in peer) ? peer : undefined;
useSyncEffect(() => {
if (!peer) {
if (!shouldReset) {
propertiesRef.current = {};
return;
}
propertiesRef.current = {
className: noUserColors ? getPeerColorCountClass(1) : getPeerColorClass(0),
};
return;
}
if ('isCustomPeer' in peer) {
if (peer.peerColorId === undefined) {
propertiesRef.current = {};
return;
}
propertiesRef.current = { className: `peer-color-${peer.peerColorId}`, style: undefined };
return;
}
const peerColor = color || peer.color;
const isCollectible = peerColor?.type === 'collectible';
const colorCount = peer ? getPeerColorCount(peer)
: isCollectible ? getPeerColorCollectibleColorCount(peerColor) : 1;
const colorCountClass = getPeerColorCountClass(colorCount);
const key = (isCollectible || !peerColor?.color) ? getPeerColorKey(peer) : peerColor.color;
if (noUserColors) {
propertiesRef.current = { className: colorCountClass };
return;
}
if (peerColor?.type === 'collectible' && !noUserColors) {
const accentColor = theme === 'dark' && peerColor.darkAccentColor
? peerColor.darkAccentColor : peerColor.accentColor;
const colors = theme === 'dark' && peerColor.darkColors ? peerColor.darkColors : peerColor.colors;
const gradient = generatePeerColorGradient(colors);
const { bg, bgActive } = generateColorVariations(accentColor);
propertiesRef.current = {
className: colorCountClass,
style: buildStyle(
`--bar-gradient: ${gradient}`,
`--accent-color: ${accentColor}`,
`--accent-background-color: ${bg}`,
`--accent-background-active-color: ${bgActive}`,
),
};
return;
}
const className = (noUserColors || key === undefined) ? colorCountClass : getPeerColorClass(key);
propertiesRef.current = { className, style: undefined };
}, [noUserColors, shouldReset, theme, color, peer]);
return {
style: propertiesRef.current.style,
className: propertiesRef.current.className,
backgroundEmojiId: realPeer?.color?.backgroundEmojiId,
giftEmojiId: realPeer?.color?.type === 'collectible' ? realPeer.color.giftEmojiId : undefined,
};
}
export function getPeerColorClass(colorIndex: number) {
return `peer-color-${colorIndex}`;
}
export function getPeerColorCountClass(colorCount: number) {
return `peer-color-count-${colorCount}`;
}