// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Maui.Controls; namespace Microsoft.Maui.Platform; /// /// Base class for state triggers that automatically activate visual states. /// public abstract class SkiaStateTriggerBase { private bool _isActive; private SkiaVisualState? _ownerState; private SkiaView? _ownerView; /// /// Gets whether this trigger is currently active. /// public bool IsActive { get => _isActive; protected set { if (_isActive != value) { _isActive = value; OnIsActiveChanged(); } } } /// /// Gets or sets the visual state this trigger belongs to. /// internal SkiaVisualState? OwnerState { get => _ownerState; set => _ownerState = value; } /// /// Gets or sets the view this trigger is attached to. /// internal SkiaView? OwnerView { get => _ownerView; set { _ownerView = value; OnAttached(); } } /// /// Called when the trigger is attached to a view. /// protected virtual void OnAttached() { } /// /// Called when IsActive changes. /// protected virtual void OnIsActiveChanged() { if (_isActive && _ownerState != null && _ownerView != null) { SkiaVisualStateManager.GoToState(_ownerView, _ownerState.Name); } } } /// /// A trigger that activates based on a boolean property. /// Maps to MAUI StateTrigger. /// public class SkiaStateTrigger : SkiaStateTriggerBase { private bool _isActiveValue; /// /// Gets or sets whether this trigger should be active. /// public bool IsActiveValue { get => _isActiveValue; set { _isActiveValue = value; IsActive = value; } } } /// /// A trigger that activates based on window size thresholds. /// Maps to MAUI AdaptiveTrigger. /// public class SkiaAdaptiveTrigger : SkiaStateTriggerBase { private double _minWindowWidth = -1; private double _minWindowHeight = -1; /// /// Gets or sets the minimum window width for this trigger to activate. /// public double MinWindowWidth { get => _minWindowWidth; set { _minWindowWidth = value; UpdateIsActive(); } } /// /// Gets or sets the minimum window height for this trigger to activate. /// public double MinWindowHeight { get => _minWindowHeight; set { _minWindowHeight = value; UpdateIsActive(); } } protected override void OnAttached() { base.OnAttached(); // Subscribe to window size changes if needed UpdateIsActive(); } private void UpdateIsActive() { if (OwnerView == null) { IsActive = false; return; } // Get current window size from the view's bounds var width = OwnerView.Bounds.Width; var height = OwnerView.Bounds.Height; bool widthMet = _minWindowWidth < 0 || width >= _minWindowWidth; bool heightMet = _minWindowHeight < 0 || height >= _minWindowHeight; IsActive = widthMet && heightMet; } } /// /// A trigger that activates when a property equals a specific value. /// Maps to MAUI CompareStateTrigger. /// public class SkiaCompareStateTrigger : SkiaStateTriggerBase { private object? _property; private object? _value; /// /// Gets or sets the property value to compare. /// public object? Property { get => _property; set { _property = value; UpdateIsActive(); } } /// /// Gets or sets the value to compare against. /// public object? Value { get => _value; set { _value = value; UpdateIsActive(); } } private void UpdateIsActive() { if (_property == null && _value == null) { IsActive = true; return; } if (_property == null || _value == null) { IsActive = _property == _value; return; } // Try to compare values IsActive = _property.Equals(_value); } } /// /// A trigger that activates based on device idiom (Desktop, Phone, Tablet, etc.). /// public class SkiaDeviceStateTrigger : SkiaStateTriggerBase { private string _deviceType = ""; /// /// Gets or sets the device type to match (Desktop, Phone, Tablet, Watch, TV). /// public string DeviceType { get => _deviceType; set { _deviceType = value; UpdateIsActive(); } } protected override void OnAttached() { base.OnAttached(); UpdateIsActive(); } private void UpdateIsActive() { // On Linux, we're always Desktop IsActive = string.Equals(_deviceType, "Desktop", StringComparison.OrdinalIgnoreCase); } } /// /// A trigger that activates based on orientation (Portrait or Landscape). /// public class SkiaOrientationStateTrigger : SkiaStateTriggerBase { private SkiaDisplayOrientation _orientation = SkiaDisplayOrientation.Portrait; /// /// Gets or sets the orientation to match. /// public SkiaDisplayOrientation Orientation { get => _orientation; set { _orientation = value; UpdateIsActive(); } } protected override void OnAttached() { base.OnAttached(); UpdateIsActive(); } private void UpdateIsActive() { if (OwnerView == null) { IsActive = false; return; } var width = OwnerView.Bounds.Width; var height = OwnerView.Bounds.Height; var currentOrientation = width > height ? SkiaDisplayOrientation.Landscape : SkiaDisplayOrientation.Portrait; IsActive = currentOrientation == _orientation; } } /// /// Display orientation values for state triggers. /// public enum SkiaDisplayOrientation { Portrait, Landscape }