Files
2025-04-06 12:54:48 -04:00

256 lines
8.5 KiB
JavaScript

/**
* LearningStateManager - Manages state related to controller mapping learning
* Replaces global variables for learning state
*/
export class LearningStateManager {
constructor(eventBus) {
this._eventBus = eventBus;
this._isLearning = false;
this._learningTarget = null;
this._selectedControl = null;
this._learningDialog = null;
this._isQuickLearning = false;
this._learningType = null;
this._quickLearningContext = null;
this._lastDetectedInput = null;
// Set up event listeners
this._setupEventListeners();
}
_setupEventListeners() {
// Listen for controller:input events
this._eventBus.on('controller:input', (controlInput) => {
// If learning mode is active, handle the input
if (this._isLearning || this._isQuickLearning) {
// Directly forward to handleControllerInput
this.handleControllerInput(controlInput);
}
});
}
/**
* Get whether learning mode is active
* @returns {boolean} - Whether learning mode is active
*/
get isLearning() {
return this._isLearning;
}
/**
* Get the current learning target
* @returns {Object|null} - The target information or null
*/
get learningTarget() {
return this._learningTarget;
}
/**
* Get the currently selected control
* @returns {Object|null} - The control information or null
*/
get selectedControl() {
return this._selectedControl;
}
/**
* Get the current learning dialog element
* @returns {HTMLElement|null} - The dialog element or null
*/
get learningDialog() {
return this._learningDialog;
}
/**
* Get whether quick learning mode is active
* @returns {boolean} - Whether quick learning mode is active
*/
get isQuickLearning() {
return this._isQuickLearning;
}
/**
* Get the current learning type
* @returns {string|null} - The learning type or null
*/
get learningType() {
return this._learningType;
}
/**
* Get the current quick learning context
* @returns {Object|null} - The quick learning context or null
*/
get quickLearningContext() {
return this._quickLearningContext;
}
/**
* Get the last detected input
* @returns {Object|null} - The last detected input or null
*/
get lastDetectedInput() {
return this._lastDetectedInput;
}
/**
* Start the learning process for a target
* @param {string} type - The learning type
* @param {Object} target - The target information
*/
startLearning(type, target) {
if (this._isLearning || this._isQuickLearning) this.cancelLearning(); // Cancel any existing learning
this._isLearning = true;
this._isQuickLearning = false; // Ensure quick learning is off
this._learningType = type;
this._learningTarget = target;
this._lastDetectedInput = null;
this._eventBus.emit('learning:started', { type, target });
}
/**
* Start quick learning for a widget
* @param {Object} node - The node information
* @param {Object} widget - The widget information
* @param {Object} defaultSettings - The default settings for the widget
*/
startQuickLearning(node, widget, defaultSettings) {
if (this._isLearning || this._isQuickLearning) this.cancelLearning(); // Cancel any existing learning
this._isLearning = false; // Ensure standard learning is off
this._isQuickLearning = true;
this._learningType = 'widget'; // Quick learning is always for widgets
this._quickLearningContext = { node, widget, defaultSettings };
this._lastDetectedInput = null;
this._eventBus.emit('learning:quickStarted', { node, widget });
}
/**
* Select a control for the current learning target
* @param {Object} control - The control information
*/
selectControl(control) {
this._selectedControl = control;
this._eventBus.emit('learning:controlSelected', control, this._learningTarget);
}
/**
* Cancel the learning process
*/
cancelLearning() {
const wasLearning = this._isLearning || this._isQuickLearning;
this._isLearning = false;
this._isQuickLearning = false;
this._learningTarget = null;
this._selectedControl = null;
this._learningType = null;
this._quickLearningContext = null;
this._lastDetectedInput = null;
if (wasLearning) {
this._eventBus.emit('learning:canceled');
}
}
/**
* Complete the learning process with a mapping
* @param {Object} mapping - The created mapping (optional, not always available)
*/
completeLearning(mapping) {
const wasLearning = this._isLearning || this._isQuickLearning; // Check if any learning was active
this._isLearning = false; // Reset standard learning flag
this._isQuickLearning = false; // Reset quick learning flag
const target = this._learningTarget;
const control = this._selectedControl;
const quickContext = this._quickLearningContext; // Capture context if needed for event
// Clear all learning-related state properties
this._learningTarget = null;
this._selectedControl = null;
this._learningType = null;
this._quickLearningContext = null;
this._lastDetectedInput = null; // Also clear last detected input
// Close dialog if it exists (relevant for standard learning)
if (this._learningDialog) {
try {
if (document.body.contains(this._learningDialog)) {
if(this._learningDialog.cleanupEvents) this._learningDialog.cleanupEvents(); // Clean up dialog listeners
document.body.removeChild(this._learningDialog);
}
} catch (error) {
console.warn("ControlFreak: Error removing learning dialog on complete:", error);
}
this._learningDialog = null;
}
// Emit event only if learning was active
if (wasLearning) {
// Pass relevant info based on which mode was active
const eventData = mapping ? { mapping, target, control } : { quickContext };
this._eventBus.emit('learning:completed', eventData);
}
}
/**
* Set the learning dialog element
* @param {HTMLElement|null} dialog - The dialog element
*/
setDialog(dialog) {
this._learningDialog = dialog;
}
/**
* Handle controller input during learning
* @param {Object} controlInput - The controller input information
* @returns {boolean} - Whether the input was handled
*/
handleControllerInput(controlInput) {
if (!this._isLearning && !this._isQuickLearning) return false;
this._eventBus.emit('learning:controlInput', controlInput, this._learningTarget);
return true;
}
/**
* Update the last detected input
* @param {Object} controlInput - The controller input information
*/
updateDetectedInput(controlInput) {
this._lastDetectedInput = controlInput;
this._eventBus.emit('learning:inputDetected', controlInput);
}
/**
* Get learning information
* @returns {Object|null} - The learning information or null
*/
getLearningInfo() {
if (!this._isLearning && !this._isQuickLearning) return null;
if (this._isQuickLearning) {
return { type: this._learningType, target: this._quickLearningContext, isQuickLearning: true };
}
return { type: this._learningType, target: this._learningTarget, isQuickLearning: false };
}
/**
* Get the quick learning context
* @returns {Object|null} - The quick learning context or null
*/
getQuickLearningContext() {
return this._isQuickLearning ? this._quickLearningContext : null;
}
// Static singleton instance
static getInstance(eventBus) {
if (!LearningStateManager._instance) {
LearningStateManager._instance = new LearningStateManager(eventBus);
}
return LearningStateManager._instance;
}
}
// Don't export a singleton instance here
// It will be created and registered by the main module