Extract display name logic to NameFormatService, refactor colored name parsing, and improve channel list scrolling.
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
import {inject, Injectable} from '@angular/core';
|
||||
import {ChatChannel} from '@pages/altitude/chat/objects/chat-channel.object';
|
||||
import {ColoredNameSegment} from '@pages/altitude/chat/objects/colored-name-segment.object';
|
||||
import {ChatService} from "./chat.service";
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class NameFormatService {
|
||||
|
||||
private readonly chatService: ChatService = inject(ChatService);
|
||||
|
||||
public getDisplayName(channel: ChatChannel): ColoredNameSegment[] {
|
||||
return this.parseColoredName(this.getNameFromType(channel));
|
||||
}
|
||||
|
||||
private getNameFromType(channel: ChatChannel): string {
|
||||
if (channel.type === 'PARTY') {
|
||||
return this.chatService.partieMap().get(channel.name) ?? channel.name;
|
||||
}
|
||||
if (channel.type === 'DM' || channel.type === 'SPY') {
|
||||
return this.chatService.userNameMap().get(channel.name) ?? channel.name;
|
||||
}
|
||||
return channel.name;
|
||||
}
|
||||
|
||||
private parseColoredName(name: string): ColoredNameSegment[] {
|
||||
const markerRegex = /\{#([0-9a-fA-F]{6})(<>|[<>]?)}/g;
|
||||
const segments: ColoredNameSegment[] = [];
|
||||
let currentColor: string | undefined;
|
||||
let gradientStartColor: string | undefined;
|
||||
let gradientStartSegmentIndex: number | undefined;
|
||||
let lastIndex = 0;
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
while ((match = markerRegex.exec(name)) !== null) {
|
||||
this.addColoredTextSegment(segments, name.slice(lastIndex, match.index), currentColor);
|
||||
|
||||
const markerColor = `#${match[1]}`;
|
||||
const markerType = match[2];
|
||||
|
||||
if (markerType === '>') {
|
||||
currentColor = markerColor;
|
||||
gradientStartColor = markerColor;
|
||||
gradientStartSegmentIndex = segments.length;
|
||||
} else if (markerType === '<') {
|
||||
if (gradientStartColor !== undefined && gradientStartSegmentIndex !== undefined) {
|
||||
this.applyGradient(segments, gradientStartSegmentIndex, gradientStartColor, markerColor);
|
||||
}
|
||||
currentColor = markerColor;
|
||||
gradientStartColor = undefined;
|
||||
gradientStartSegmentIndex = undefined;
|
||||
} else if (markerType === '<>') {
|
||||
if (gradientStartColor !== undefined && gradientStartSegmentIndex !== undefined) {
|
||||
this.applyGradient(segments, gradientStartSegmentIndex, gradientStartColor, markerColor);
|
||||
}
|
||||
currentColor = markerColor;
|
||||
gradientStartColor = markerColor;
|
||||
gradientStartSegmentIndex = segments.length;
|
||||
} else {
|
||||
currentColor = markerColor;
|
||||
gradientStartColor = undefined;
|
||||
gradientStartSegmentIndex = undefined;
|
||||
}
|
||||
|
||||
lastIndex = markerRegex.lastIndex;
|
||||
}
|
||||
|
||||
this.addColoredTextSegment(segments, name.slice(lastIndex), currentColor);
|
||||
|
||||
return segments.length > 0 ? segments : [{text: name}];
|
||||
}
|
||||
|
||||
private addColoredTextSegment(segments: ColoredNameSegment[], text: string, color?: string): void {
|
||||
if (text.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
segments.push({text, color});
|
||||
}
|
||||
|
||||
private applyGradient(
|
||||
segments: ColoredNameSegment[],
|
||||
startSegmentIndex: number,
|
||||
startColor: string,
|
||||
endColor: string
|
||||
): void {
|
||||
const text = segments.slice(startSegmentIndex).map((segment) => segment.text).join('');
|
||||
const length = text.length;
|
||||
const start = this.hexToRgb(startColor);
|
||||
const end = this.hexToRgb(endColor);
|
||||
|
||||
if (length === 0 || start === null || end === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const gradientSegments: ColoredNameSegment[] = [];
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const ratio = length === 1 ? 0 : i / (length - 1);
|
||||
gradientSegments.push({
|
||||
text: text[i],
|
||||
color: this.rgbToHex(
|
||||
start.r + (end.r - start.r) * ratio,
|
||||
start.g + (end.g - start.g) * ratio,
|
||||
start.b + (end.b - start.b) * ratio
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
segments.splice(startSegmentIndex, segments.length - startSegmentIndex, ...gradientSegments);
|
||||
}
|
||||
|
||||
private hexToRgb(hex: string): { r: number; g: number; b: number } | null {
|
||||
const match = /^#?([0-9a-fA-F]{6})$/.exec(hex);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const value = Number.parseInt(match[1], 16);
|
||||
return {
|
||||
r: (value >> 16) & 255,
|
||||
g: (value >> 8) & 255,
|
||||
b: value & 255
|
||||
};
|
||||
}
|
||||
|
||||
private rgbToHex(r: number, g: number, b: number): string {
|
||||
return `#${[r, g, b]
|
||||
.map((value) => Math.round(value).toString(16).padStart(2, '0'))
|
||||
.join('')}`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user