256 lines
8.5 KiB
JavaScript
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
|