// 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 "../../UI/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); } }