6 changed files with 298 additions and 47 deletions
@ -0,0 +1,128 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using XamlX.Ast; |
|||
using XamlX.Transform; |
|||
using XamlX.Transform.Transformers; |
|||
using XamlX.TypeSystem; |
|||
|
|||
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; |
|||
|
|||
internal class OnFormFactorTransformer : IXamlAstTransformer |
|||
{ |
|||
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node) |
|||
{ |
|||
if (node is XamlAstObjectNode xmlobj |
|||
&& xmlobj.Type is XamlAstXmlTypeReference xmlref |
|||
&& xmlref.Name.StartsWith("OnFormFactor") |
|||
&& !xmlref.GenericArguments.Any()) |
|||
{ |
|||
IXamlType propertyType = null; |
|||
|
|||
if (context.ParentNodes().FirstOrDefault() is XamlAstXamlPropertyValueNode parentPropertyValueNode) |
|||
{ |
|||
var property = (XamlAstNamePropertyReference)parentPropertyValueNode.Property; |
|||
var declaringType = TypeReferenceResolver.ResolveType(context, (XamlAstXmlTypeReference)property.DeclaringType, context.StrictMode); |
|||
propertyType = declaringType.Type.GetAllProperties().First(p => p.Name == property.Name).PropertyType; |
|||
} |
|||
else if (context.ParentNodes().FirstOrDefault() is XamlAstObjectNode parentNode) |
|||
{ |
|||
var parentType = parentNode.Type is XamlAstClrTypeReference clrType |
|||
? clrType.Type |
|||
: TypeReferenceResolver.ResolveType(context, (XamlAstXmlTypeReference)parentNode.Type, context.StrictMode).Type; |
|||
var contentProperty = context.Configuration.FindContentProperty(parentType); |
|||
propertyType = contentProperty.PropertyType; |
|||
} |
|||
|
|||
if (propertyType is null) |
|||
{ |
|||
throw new InvalidOperationException("Unable to find OnFormFactor property type"); |
|||
} |
|||
|
|||
xmlobj.Type = TypeReferenceResolver.ResolveType(context, xmlref.XmlNamespace, xmlref.Name, |
|||
xmlref.IsMarkupExtension, new[] { new XamlAstClrTypeReference(xmlref, propertyType, false) }, |
|||
xmlref, context.StrictMode); |
|||
} |
|||
|
|||
if (node is XamlAstNamePropertyReference xmlprop |
|||
&& xmlprop.DeclaringType is XamlAstXmlTypeReference propxmlref |
|||
&& propxmlref.Name.StartsWith("OnFormFactor") |
|||
&& !propxmlref.GenericArguments.Any()) |
|||
{ |
|||
var expectedType = context.ParentNodes().OfType<XamlAstObjectNode>() |
|||
.First(n => n.Type is XamlAstClrTypeReference clrRef && clrRef.Type.Name.StartsWith("OnFormFactor") |
|||
|| n.Type is XamlAstXmlTypeReference xmlRef && xmlRef.Name.StartsWith("OnFormFactor")) |
|||
.Type; |
|||
xmlprop.DeclaringType = expectedType; |
|||
xmlprop.TargetType = expectedType; |
|||
} |
|||
|
|||
// if (node is XamlAstObjectNode onobj
|
|||
// && onobj.Type is XamlAstXmlTypeReference onref
|
|||
// && onref.Name == "On")
|
|||
// {
|
|||
// var platformStr = (onobj.Children.OfType<XamlAstXamlPropertyValueNode>()
|
|||
// .FirstOrDefault(v => ((XamlAstNamePropertyReference)v.Property).Name == "Platform")?.Values.Single() as XamlAstTextNode)?
|
|||
// .Text;
|
|||
// if (string.IsNullOrWhiteSpace(platformStr))
|
|||
// {
|
|||
// throw new InvalidOperationException("On.Platform string must be set");
|
|||
// }
|
|||
// var content = onobj.Children.OfType<XamlAstObjectNode>().FirstOrDefault();
|
|||
// if (content is null)
|
|||
// {
|
|||
// throw new InvalidOperationException("On content object must be set");
|
|||
// }
|
|||
//
|
|||
// var parentOnFormFactorObject = context.ParentNodes().OfType<XamlAstObjectNode>()
|
|||
// .First(n => n.Type is XamlAstClrTypeReference clrRef && clrRef.Type.Name.StartsWith("OnFormFactor")
|
|||
// || n.Type is XamlAstXmlTypeReference xmlRef && xmlRef.Name.StartsWith("OnFormFactor"));
|
|||
// parentOnFormFactorObject.Children.Remove(onobj);
|
|||
// foreach (var platform in platformStr.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
|||
// {
|
|||
// var propertyNode = new XamlAstXamlPropertyValueNode(onobj,
|
|||
// new XamlAstNamePropertyReference(onobj, parentOnFormFactorObject.Type, platform.Trim(),
|
|||
// parentOnFormFactorObject.Type), content);
|
|||
// parentOnFormFactorObject.Children.Add(propertyNode);
|
|||
// }
|
|||
//
|
|||
// return parentOnFormFactorObject.Children.Last();
|
|||
// }
|
|||
// if (node is XamlAstXamlPropertyValueNode propNode)
|
|||
// {
|
|||
// var type = (propNode.Property as XamlAstNamePropertyReference).TargetType as XamlAstXmlTypeReference;
|
|||
//
|
|||
// propNode.VisitChildren(new OnFormFactorGenericTypeVisitor(type));
|
|||
//
|
|||
// return node;
|
|||
// }
|
|||
|
|||
return node; |
|||
} |
|||
|
|||
private class OnFormFactorGenericTypeVisitor : IXamlAstVisitor |
|||
{ |
|||
private readonly XamlAstXmlTypeReference _type; |
|||
public OnFormFactorGenericTypeVisitor(IXamlAstTypeReference type) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public IXamlAstNode Visit(IXamlAstNode node) |
|||
{ |
|||
if (node is XamlAstXmlTypeReference { Name: "OnFormFactor" } xmlref) |
|||
{ |
|||
xmlref.GenericArguments.Add(_type); |
|||
} |
|||
|
|||
return node; |
|||
} |
|||
|
|||
public void Push(IXamlAstNode node) |
|||
{ |
|||
} |
|||
|
|||
public void Pop() |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
#nullable enable |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Avalonia.Platform; |
|||
|
|||
namespace Avalonia.Markup.Xaml.MarkupExtensions; |
|||
|
|||
public class OnFormFactorExtension<TReturn> |
|||
{ |
|||
private readonly Dictionary<string, TReturn?> _values = new(); |
|||
|
|||
public OnFormFactorExtension(TReturn defaultValue) |
|||
{ |
|||
Default = defaultValue; |
|||
} |
|||
|
|||
public TReturn? Default |
|||
{ |
|||
get => _values.TryGetValue(nameof(Default), out var value) ? value : default; |
|||
set { _values[nameof(Default)] = value; } |
|||
} |
|||
|
|||
public TReturn? Desktop |
|||
{ |
|||
get => _values.TryGetValue(nameof(Desktop), out var value) ? value : default; |
|||
set { _values[nameof(Desktop)] = value; } |
|||
} |
|||
|
|||
public TReturn? Mobile |
|||
{ |
|||
get => _values.TryGetValue(nameof(Mobile), out var value) ? value : default; |
|||
set { _values[nameof(Mobile)] = value; } |
|||
} |
|||
|
|||
|
|||
public object? ProvideValue() |
|||
{ |
|||
if (!_values.Any()) |
|||
{ |
|||
throw new InvalidOperationException( |
|||
"OnPlatformExtension requires a value to be specified for at least one platform or Default."); |
|||
} |
|||
|
|||
var (value, hasValue) = TryGetValueForPlatform(); |
|||
return !hasValue ? AvaloniaProperty.UnsetValue : value; |
|||
} |
|||
|
|||
private (object? value, bool hasValue) TryGetValueForPlatform() |
|||
{ |
|||
var runtimeInfo = AvaloniaLocator.Current.GetRequiredService<IRuntimePlatform>().GetRuntimeInfo(); |
|||
|
|||
TReturn val; |
|||
|
|||
if (runtimeInfo.IsDesktop) |
|||
{ |
|||
if (_values.TryGetValue(nameof(Desktop), out val)) |
|||
{ |
|||
return (val, true); |
|||
} |
|||
} |
|||
|
|||
if (runtimeInfo.IsMobile) |
|||
{ |
|||
if (_values.TryGetValue(nameof(Mobile), out val)) |
|||
{ |
|||
return (val, true); |
|||
} |
|||
} |
|||
|
|||
if (_values.TryGetValue(nameof(Default), out val)) |
|||
{ |
|||
return (val, true); |
|||
} |
|||
|
|||
return default; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue