defmodule Raxol.Animation.Adaptation do @moduledoc """ Handles animation adaptation based on user preferences and accessibility settings. This module is responsible for: - Re-adapting animations when user preferences change - Managing animation adaptation for accessibility - Handling preference change notifications """ require Raxol.Core.Runtime.Log alias Raxol.Animation.StateManager alias Raxol.Animation.Accessibility, as: AnimAccessibility alias Raxol.Animation.Lifecycle @doc """ Re-adapt existing animations if settings have changed. This function checks if user preferences have changed and re-adapts all active animations accordingly. Returns a list of animations that were completed due to being disabled. """ def re_adapt_animations_if_needed( user_preferences_pid, active_animations \\ nil ) do active_animations = active_animations || StateManager.get_active_animations() Raxol.Core.Runtime.Log.debug( "[Animation] Re-adapting #{map_size(active_animations)} active animations" ) # Fetch current preferences current_reduced_motion = Raxol.Core.UserPreferences.get( [:accessibility, :reduced_motion], user_preferences_pid ) || false current_cognitive_accessibility = Raxol.Core.UserPreferences.get( [:accessibility, :cognitive_accessibility], user_preferences_pid ) || false # Update StateManager settings settings = StateManager.get_settings() new_settings = %{ settings | reduced_motion: current_reduced_motion, cognitive_accessibility: current_cognitive_accessibility } StateManager.init(new_settings) # Now re-fetch settings for use below settings = StateManager.get_settings() reduce_motion? = Map.get(settings, :reduced_motion, false) cognitive_accessibility? = Map.get(settings, :cognitive_accessibility, false) completed_due_to_disable = Enum.flat_map(active_animations, fn {element_id, element_animations} -> Enum.flat_map(element_animations, fn {animation_name, instance} -> animation = instance.animation # Re-adapt the animation adapted_animation = AnimAccessibility.adapt_animation( animation, reduce_motion?, cognitive_accessibility? ) # Update the instance with the adapted animation updated_instance = Map.put(instance, :animation, adapted_animation) # Handle disabled animations properly if AnimAccessibility.disabled?(adapted_animation) do # For disabled animations, mark as pending completion and ensure they complete quickly updated_instance = Map.put(updated_instance, :pending_completion, true) # Immediately send completion message for disabled animations Lifecycle.handle_animation_completion( adapted_animation, element_id, animation_name, updated_instance, user_preferences_pid ) # Return as completed due to disable [{element_id, animation_name, updated_instance}] else # For enabled animations, remove pending_completion flag if it was set _updated_instance = Map.delete(updated_instance, :pending_completion) # Not completed [] end # Update the instance in the state manager StateManager.put_active_animation( element_id, animation_name, updated_instance ) [] end) end) completed_due_to_disable end @doc """ Check if animations should be reduced due to user preferences. """ def should_reduce_motion?(user_preferences_pid \\ nil) do Raxol.Core.UserPreferences.get( [:accessibility, :reduced_motion], user_preferences_pid ) || false end @doc """ Check if cognitive accessibility should be applied. """ def should_apply_cognitive_accessibility? do Raxol.Core.UserPreferences.get([:accessibility, :cognitive_accessibility]) || false end end