Skip to content

Commit

Permalink
Merge pull request #1 from timia2109/feature/hass
Browse files Browse the repository at this point in the history
Feature/hass
  • Loading branch information
timia2109 authored Mar 22, 2024
2 parents a12ccc7 + 5dddd8c commit 064f63b
Show file tree
Hide file tree
Showing 20 changed files with 335 additions and 83 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -482,3 +482,4 @@ $RECYCLE.BIN/

# Vim temporary swap files
*.swp
appsettings.Local.json
2 changes: 2 additions & 0 deletions DisplayUtil.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
<PackageReference Include="NetDaemon.Client" Version="24.8.0" />
<PackageReference Include="NetDaemon.HassModel" Version="24.8.0" />
<PackageReference Include="Scriban" Version="5.9.1" />
<PackageReference Include="SkiaSharp" Version="2.88.7" />
<PackageReference Include="SkiaSharp.Extended" Version="1.60.0" />
Expand Down
8 changes: 4 additions & 4 deletions Layouting/IconElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@ namespace DisplayUtil.Layouting;
/// An FontAwesome Icon Element
/// </summary>
/// <param name="iconName">Name of the Icon</param>
/// <param name="width">Width of the Icon</param>
/// <param name="height">Width of the Icon</param>
/// <param name="iconDrawer">The Icon Drawer</param>
public class IconElement(string iconName, int width, FaIconDrawer iconDrawer) : Element
public class IconElement(string iconName, int height, FaIconDrawer iconDrawer) : Element
{
public override void Draw(DrawContext drawContext)
{
iconDrawer.DrawIcon(
iconName,
width,
height,
drawContext.StartPoint,
drawContext.Canvas
);
}

protected override SKSize CalculateSize(DrawContext drawContext)
{
var size = iconDrawer.GetSize(iconName, width);
var size = iconDrawer.GetSize(iconName, height);
return size.GetValueOrDefault();
}
}
2 changes: 1 addition & 1 deletion Layouting/TextElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class TextElement(string content, SKPaint paint) : Element
public override void Draw(DrawContext drawContext)
{
var point = drawContext.StartPoint;
point.Y += paint.TextSize;
point.Y -= paint.FontMetrics.Ascent;

drawContext.Canvas.DrawText(content, point, paint);
}
Expand Down
15 changes: 11 additions & 4 deletions Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,26 @@
using DisplayUtil.Utils;

var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("appsettings.Local.json", true);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.AddHassSupport();

builder.Services.AddSingleton(FontProvider.Create())
.AddSingleton<XmlLayoutDeserializer>()
.AddSingleton<TemplateRenderer>();
.AddSingleton<XmlLayoutDeserializer>();

builder.Services.AddScoped<TemplateRenderer>()
.AddScoped<TemplateContextProvider>();

builder.Services.AddTransient<FaIconDrawer>();

builder.Services.AddScreenProvider(o => o
.Add<TestProvider>("test")
.Add<TestLayoutProvider>("layout")
.AddSingleton<TestProvider>("test")
.AddSingleton<TestLayoutProvider>("layout")
.AddSingleton<TestFontSizeProvider>("testFont")
.AddScribanFiles()
);

Expand Down
Binary file added Resources/fonts/Roboto-Medium.ttf
Binary file not shown.
41 changes: 26 additions & 15 deletions Resources/screens/main.sbntxt
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,38 @@
ret date.to_string date.now sFormat
end }}

{{ func icon_data(sIconName, sText) }}
<HBox Gap="2">
<Icon IconName="{{sIconName}}" Height="20" />
<Text Content="{{sText}}" Size="20" />
</HBox>
{{ end }}

<Screen>
<Flexbox Direction="Vertical">

<!-- Date Flexbox -->
<Border>
<!-- Header Bar -->
<VBox Gap="3">
<!-- Date Flexbox -->
<Border>
<Flexbox AlignItems="Center">
<VBox>
{{ icon_data "calendar" (now_format "%A")}}
<Text Content="{{now_format "%d %B %Y"}}" />
</VBox>
<Text Content="{{now_format "%H:%M"}}" Font="ProductSansBold" Size="64" />
</Flexbox>
<Padding>
<Bottom>2</Bottom>
</Padding>
</Border>

<Flexbox AlignItems="Center">
<VBox>
<HBox>
<Icon IconName="calendar" />
<Text Content="{{now_format "%A"}}" />
</HBox>
<Text Content="{{now_format "%d %B %Y"}}" />
</VBox>
<Text Content="{{now_format "%H:%M"}}" Font="ProductSansBold" Size="64" />
{{ icon_data "couch" (hass_get_state "sensor.ble_temperature_dc1e00000998" | string.slice 0 5)}}
{{ icon_data "cloud-sun" (hass_get_state "sensor.hue_outdoor_motion_sensor_1_temperature" | string.slice 0 5)}}
</Flexbox>
<Padding>
<Bottom>2</Bottom>
</Padding>
</Border>

<Text Content="WOW" />
</VBox>

</Flexbox>
</Screen>
15 changes: 15 additions & 0 deletions Screens/IScreenProviderSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace DisplayUtil.Scenes;

/// <summary>
/// Provides <see cref="IScreenProvider"> by Ids
/// </summary>
public interface IScreenProviderSource
{
/// <summary>
/// Returns the <see cref="IScreenProvider"> if this source contains it
/// </summary>
/// <param name="id">Id</param>
/// <returns>Screen Provider If found</returns>
public IScreenProvider? GetScreenProvider(string id);

}
48 changes: 21 additions & 27 deletions Screens/ScreenRepoBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,29 @@
namespace DisplayUtil.Scenes;

public class ScreenRepoBuilder(
Dictionary<string, Func<IServiceProvider, IScreenProvider>> screenProviders,
Dictionary<string, Type> staticScreenProviderTypes,
IServiceCollection services
)
{
public ScreenRepoBuilder Add<TType>(string providerId)
public ScreenRepoBuilder AddSingleton<TType>(string providerId)
where TType : class, IScreenProvider
{
staticScreenProviderTypes.Add(providerId, typeof(TType));
services.AddSingleton<TType>();
screenProviders.Add(
providerId,
e => (IScreenProvider)e.GetRequiredService(typeof(TType))
);
return this;
}

public ScreenRepoBuilder AddScribanFiles(string? path = null)
public ScreenRepoBuilder AddScoped<TType>(string providerId)
where TType : class, IScreenProvider
{
path ??= @"./Resources/screens";

var files = Directory.EnumerateFiles(path, "*.sbntxt")
.Select(p => new { Path = p, Name = Path.GetFileNameWithoutExtension(p) })
.Select(p => new KeyValuePair<string, Func<IServiceProvider, IScreenProvider>>(
p.Name,
e => ActivatorUtilities.CreateInstance<ScribanScreenProvider>(e, [p.Path])
));

foreach (var (k, v) in files)
{
screenProviders.Add(k, v);
}
staticScreenProviderTypes.Add(providerId, typeof(TType));
services.AddScoped<TType>();
return this;
}

public ScreenRepoBuilder AddScribanFiles(string? path = null)
{
services.AddScoped<IScreenProviderSource, ScibanScreenProviderSource>();
return this;
}
}
Expand All @@ -44,18 +36,20 @@ public static class ScreenRepoBuilderExtension
public static IServiceCollection AddScreenProvider(
this IServiceCollection services, Action<ScreenRepoBuilder> action)
{
var dictionary = new Dictionary<string, Func<IServiceProvider, IScreenProvider>>();
var dictionary = new Dictionary<string, Type>();
var builder = new ScreenRepoBuilder(dictionary, services);
action(builder);

services.AddSingleton(o =>
// Add static
if (dictionary.Count != 0)
{
var types = dictionary
.ToDictionary(k => k.Key, v => v.Value(o))
.ToFrozenDictionary();
services.AddSingleton<IScreenProviderSource>(s => new StaticScreenProviderSource(
s, dictionary.ToFrozenDictionary()
));
}

services.AddScoped<ScreenRepository>();

return new ScreenRepository(types);
});
return services;
}

Expand Down
24 changes: 19 additions & 5 deletions Screens/ScreenRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,30 @@
namespace DisplayUtil.Scenes;

public class ScreenRepository(
IReadOnlyDictionary<string, IScreenProvider> screenProviders
IEnumerable<IScreenProviderSource> screenProviderSources
)
{
public Task<SKBitmap> GetImageAsync(string screenProviderId)
/// <summary>
/// Search the <see cref="IScreenProvider"/> with it's Id
/// </summary>
/// <param name="screenProviderId">Id of the screen provider</param>
/// <returns>ScreenProvider</returns>
/// <exception cref="Exception">Not found</exception>
public IScreenProvider GetScreenProvider(string screenProviderId)
{
if (!screenProviders.TryGetValue(screenProviderId, out var storedScreenProvider))
foreach (var screenProviderSource in screenProviderSources)
{
throw new Exception($"ScreenProvider with Id {screenProviderId} not found");
var screenProvider = screenProviderSource
.GetScreenProvider(screenProviderId);

if (screenProvider is not null) return screenProvider;
}

return storedScreenProvider.GetImageAsync();
throw new Exception($"ScreenProvider with Id {screenProviderId} not found");
}

public Task<SKBitmap> GetImageAsync(string screenProviderId)
{
return GetScreenProvider(screenProviderId).GetImageAsync();
}
}
14 changes: 14 additions & 0 deletions Screens/StaticScreenProviderSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace DisplayUtil.Scenes;

internal class StaticScreenProviderSource(
IServiceProvider serviceProvider,
IReadOnlyDictionary<string, Type> typeList
) : IScreenProviderSource
{
public IScreenProvider? GetScreenProvider(string id)
{
if (!typeList.TryGetValue(id, out var type)) return null;

return (IScreenProvider)serviceProvider.GetRequiredService(type);
}
}
4 changes: 2 additions & 2 deletions Serializing/Models/Icon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ public class Icon : IXmlModel
public string IconName = null!;

[XmlAttribute]
public int Width = 20;
public int Height = 20;

public override Element AsElement(FaIconDrawer iconDrawer, FontProvider fontProvider)
{
return new IconElement(IconName, Width, iconDrawer);
return new IconElement(IconName, Height, iconDrawer);
}
}
3 changes: 1 addition & 2 deletions Serializing/Models/Text.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@ public class Text : IXmlModel

public override Element AsElement(FaIconDrawer iconDrawer, FontProvider fontProvider)
{
var font = fontProvider.GetFont(Font ?? "ProductSansRegular");
var font = fontProvider.GetFont(Font ?? "Roboto-Medium");

var paint = new SKPaint
{
IsAntialias = true,
TextSize = Size,
TextAlign = SKTextAlign.Left,
Color = SKColors.Black,
Style = SKPaintStyle.Fill,
Typeface = font
Expand Down
25 changes: 24 additions & 1 deletion Template/ScribanScreenProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,30 @@

namespace DisplayUtil.Template;

public class ScribanScreenProvider(
internal class ScibanScreenProviderSource(IServiceProvider serviceProvider)
: IScreenProviderSource
{

private const string TemplatePath = "./Resources/screens";

private static readonly ObjectFactory<ScribanScreenProvider>
factory = ActivatorUtilities.CreateFactory<ScribanScreenProvider>([
typeof(string)
]);

public IScreenProvider? GetScreenProvider(string id)
{
var path = Path.GetFullPath(
Path.Combine(TemplatePath, $"{id}.sbntxt")
);

if (!File.Exists(path)) return null;

return factory(serviceProvider, [path]);
}
}

internal class ScribanScreenProvider(
TemplateRenderer renderer,
XmlLayoutDeserializer layoutDeserializer,
string path)
Expand Down
Loading

0 comments on commit 064f63b

Please sign in to comment.