tengri/Content/Toasts/Compontents/AC_ToastSystem.ts

193 lines
5.7 KiB
TypeScript

// Content/Toasts/Components/AC_ToastSystem.ts
// TODO: Написать тесты
import {AddToArray, CreateWidget, GetGameTimeInSeconds, IsValid, Print, RemoveIndexFromArray} from "../../functions.js";
import {WBP_ToastContainer} from "../UI/WBP_ToastContainer.js";
import type {Float, Integer, Text} from "../../types.js";
import {E_MessageType} from "../Enums/E_MessageType.js";
import type {S_ToastMessage} from "../Structs/S_ToastMessage.js";
import type {S_ToastSettings} from "../Structs/S_ToastSettings.js";
import type {WBP_Toast} from "../UI/WBP_Toast.js";
export class AC_ToastSystem {
// Category: "System Configuration"
// Instance Editable: true
/**
* Toast system configuration settings
* Simplified - no positioning settings needed
* Instance editable for designer customization
*/
public ToastSettings: S_ToastSettings = {
MaxVisibleToasts: 5,
DefaultDuration: 3.0,
AlsoLogToConsole: true,
IsEnabled: true
};
// Category: "System State"
/**
* System initialization state flag
* Set to true after successful InitializeToastSystem call
*/
private IsInitialized: boolean = false;
// Category: "System State"
/**
* Next unique ID for new toasts
* Incremented for each new toast
*/
private NextToastID: Integer = 1;
// Category: "Container Management"
/**
* Toast container widget that handles all positioning
* Replaces manual position management
*/
private ToastContainer: WBP_ToastContainer | null = null;
// Category: "Toast Management"
/**
* Array of currently active toast messages
* Contains all visible toasts
*/
private ActiveToasts: S_ToastMessage[] = [];
// Category: "Widget Management"
/**
* Array of toast widget instances
* Corresponds to ActiveToasts array
*/
private ToastWidgets: WBP_Toast[] = [];
// Category: "Toast Management"
// Pure: true
/**
* Check if toast system should process updates this frame
* @returns True if system is initialized and enabled
* @pure Function has no side effects
*/
private ShouldProcessToasts(): boolean {
return this.IsInitialized && this.ToastSettings.IsEnabled && IsValid(this.ToastContainer);
}
// Category: "Toast Lifecycle"
/**
* Remove expired toasts from the system
* @private Internal cleanup method
*/
private RemoveExpiredToasts(): void {
let i = 0;
while (i < this.ActiveToasts.length) {
if ((GetGameTimeInSeconds() - this.ActiveToasts[i].CreatedTime) > this.ActiveToasts[i].Duration) {
if (IsValid(this.ToastWidgets[i]) && IsValid(this.ToastContainer)) {
this.ToastContainer.RemoveToast(this.ToastWidgets[i]);
}
RemoveIndexFromArray(this.ActiveToasts, i);
RemoveIndexFromArray(this.ToastWidgets, i);
} else {
i++;
}
}
}
// Category: "Toast Lifecycle"
/**
* Enforce maximum visible toasts limit
* Uses container's capacity management
* @private Internal management method
*/
private EnforceToastLimit(): void {
while(this.ActiveToasts.length >= this.ToastSettings.MaxVisibleToasts) {
if (IsValid(this.ToastWidgets[0])) {
this.ToastContainer.RemoveToast(this.ToastWidgets[0]);
}
RemoveIndexFromArray(this.ActiveToasts, 0);
RemoveIndexFromArray(this.ToastWidgets, 0);
}
}
// Category: "Toast Creation"
/**
* Create and display a new toast message
* Uses container for automatic positioning
* @param Message - Text to display in the toast
* @param Type - Type of toast (affects color and styling)
* @param Duration - How long to display toast (optional, uses default)
* @returns Toast ID for tracking
* @public Main interface for creating toasts
* @example
* // Create success toast
* ShowToast("Test passed!", E_ToastType.Success, 2.0)
* // Create error toast with default duration
* ShowToast("Test failed!", E_ToastType.Error)
*/
public ShowToast(Message: Text, Type: E_MessageType, Duration?: Float): Integer {
if (this.ShouldProcessToasts()) {
const toastDuration = Duration === 0 ? this.ToastSettings.DefaultDuration : Duration;
const currentTime = GetGameTimeInSeconds();
const newToast: S_ToastMessage = {
ID: this.NextToastID++,
Message: Message,
Type: Type,
Duration: toastDuration,
CreatedTime: currentTime,
}
this.EnforceToastLimit();
const toastWidget = this.ToastContainer.AddToast(Message, Type);
if (IsValid(toastWidget)) {
AddToArray(this.ActiveToasts, newToast);
AddToArray(this.ToastWidgets, toastWidget);
if (this.ToastSettings.AlsoLogToConsole) {
Print(`[${Type}] ${Message}`, false, true);
}
return newToast.ID;
} else {
return -1;
}
}
if (this.ToastSettings.AlsoLogToConsole) {
Print(`[${Type}] ${Message}`, false, true);
}
return -1;
}
// Category: "System Main Loop"
/**
* Simplified update loop for toast system
* Container handles positioning automatically
* @public Called by BP_MainCharacter or game framework
*/
public UpdateToastSystem(): void {
if (this.ShouldProcessToasts()) {
this.RemoveExpiredToasts();
}
}
// Category: "System Setup"
/**
* Initialize toast system with container
* @public Called by BP_MainCharacter during initialization
* @example
* // Initialize toast system in main character
* this.ToastSystemComponent.InitializeToastSystem();
*/
public InitializeToastSystem(): void {
this.ToastContainer = CreateWidget(new WBP_ToastContainer);
this.ToastContainer.InitializeContainer();
this.IsInitialized = true;
this.NextToastID = 1;
this.ShowToast(("Toast System Initialized" as Text), E_MessageType.Info);
}
}