Skip to content

Commit

Permalink
WIP Uno Hosting
Browse files Browse the repository at this point in the history
  • Loading branch information
aritchie committed Feb 7, 2025
1 parent 82b1106 commit cad170d
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 0 deletions.
6 changes: 6 additions & 0 deletions ShinyMediator.sln
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.Api", "samples\Sampl
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shiny.Mediator.DapperRequests", "src\Shiny.Mediator.DapperRequests\Shiny.Mediator.DapperRequests.csproj", "{C49D80C1-68E1-4730-8AAE-A4890ECF89C4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shiny.Mediator.Uno", "src\Shiny.Mediator.Uno\Shiny.Mediator.Uno.csproj", "{24DB79F2-629D-45C2-A63A-1780D6A6C921}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -120,6 +122,10 @@ Global
{C49D80C1-68E1-4730-8AAE-A4890ECF89C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C49D80C1-68E1-4730-8AAE-A4890ECF89C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C49D80C1-68E1-4730-8AAE-A4890ECF89C4}.Release|Any CPU.Build.0 = Release|Any CPU
{24DB79F2-629D-45C2-A63A-1780D6A6C921}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{24DB79F2-629D-45C2-A63A-1780D6A6C921}.Debug|Any CPU.Build.0 = Debug|Any CPU
{24DB79F2-629D-45C2-A63A-1780D6A6C921}.Release|Any CPU.ActiveCfg = Release|Any CPU
{24DB79F2-629D-45C2-A63A-1780D6A6C921}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{0075777D-C7AF-4075-ACEA-88D1E1BE205A} = {967E9F7E-D082-4E7F-934B-D3BD05D1C22F}
Expand Down
30 changes: 30 additions & 0 deletions src/Shiny.Mediator.Uno/ConnectivityBroadcaster.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Microsoft.Extensions.Logging;
using Shiny.Mediator.Infrastructure;
using Uno.Extensions.Hosting;

namespace Shiny.Mediator;


public class ConnectivityBroadcaster(
ILogger<ConnectivityBroadcaster> logger,
IMediator mediator,
IInternetService internetService
) : IServiceInitialize
{
public void Initialize()
{
internetService.StateChanged += async (_, connected) =>
{
try
{
await mediator.Publish(new ConnectivityChanged(connected));
}
catch (Exception ex)
{
logger.LogError(ex, "Error occured while connectivity Sprayer");
}
};
}
}

public record ConnectivityChanged(bool Connected) : IEvent;
5 changes: 5 additions & 0 deletions src/Shiny.Mediator.Uno/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using System.Threading;
global using System.Threading.Tasks;
40 changes: 40 additions & 0 deletions src/Shiny.Mediator.Uno/Http/UnoHttpRequestDecorator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Globalization;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.Extensions.Logging;

namespace Shiny.Mediator.Http;


public class UnoHttpRequestDecorator<TRequest, TResult>(
ILogger<UnoHttpRequestDecorator<TRequest, TResult>> logger
) : IHttpRequestDecorator<TRequest, TResult> where TRequest : IHttpRequest<TResult>
{
public async Task Decorate(HttpRequestMessage httpMessage, TRequest request)
{
var pkg = Windows.ApplicationModel.Package.Current;

httpMessage.Headers.Add("AppId", pkg.Id.FullName);
httpMessage.Headers.Add("AppVersion", pkg.Id.Version.ToString() ?? "1.0.0");
// httpMessage.Headers.Add("DeviceManufacturer", deviceInfo.Manufacturer);
// httpMessage.Headers.Add("DeviceModel", deviceInfo.Model);
// httpMessage.Headers.Add("DevicePlatform", deviceInfo.Platform.ToString());
// httpMessage.Headers.Add("DeviceVersion", deviceInfo.Version.ToString());
httpMessage.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(CultureInfo.CurrentCulture.Name));

// try
// {
// var result = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
// if (result == PermissionStatus.Granted)
// {
// var gps = await geolocation.GetLastKnownLocationAsync();
// if (gps != null)
// httpMessage.Headers.Add("GpsCoords", $"{gps.Latitude},{gps.Longitude}");
// }
// }
// catch (Exception ex)
// {
// logger.LogInformation(ex, "Failed to get GPS");
// }
}
}
24 changes: 24 additions & 0 deletions src/Shiny.Mediator.Uno/Infrastructure/AlertDialogService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Microsoft.Extensions.Logging;
using Microsoft.UI.Xaml.Controls;

namespace Shiny.Mediator.Infrastructure;


public class AlertDialogService(ILogger<AlertDialogService> logger) : IAlertDialogService
{
public void Display(string title, string message)
{
// TODO: could use acr userdialogs
// ContentDialog deleteFileDialog = new ContentDialog
// {
// Title = "Delete file permanently?",
// Content = "If you delete this file, you won't be able to recover it. Do you want to delete it?",
// PrimaryButtonText = "Delete",
// CloseButtonText = "Cancel"
// };
//
// deleteFileDialog.XamlRoot = anyLoadedControl.XamlRoot;
//
// ContentDialogResult result = await deleteFileDialog.ShowAsync();
}
}
63 changes: 63 additions & 0 deletions src/Shiny.Mediator.Uno/Infrastructure/InternetService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using Windows.Networking.Connectivity;

namespace Shiny.Mediator.Infrastructure;


// https://platform.uno/docs/articles/features/windows-networking.html

public class InternetService : IInternetService
{
EventHandler<bool>? handler;
public event EventHandler<bool>? StateChanged
{
add
{
if (this.handler == null)
{
//NetworkInformation.NetworkStatusChanged += handler;
}
this.handler += value;
}
remove
{
//NetworkInformation.NetworkStatusChanged -= handler;
}
}

public bool IsAvailable
{
get
{
var profile = NetworkInformation.GetInternetConnectionProfile();
if (profile == null)
return false;

var level = profile.GetNetworkConnectivityLevel();
return level == NetworkConnectivityLevel.InternetAccess;
}
}


public async Task WaitForAvailable(CancellationToken cancelToken = default)
{
if (this.IsAvailable)
return;

var tcs = new TaskCompletionSource();
var handler = new NetworkStatusChangedEventHandler(_ =>
{
if (this.IsAvailable)
tcs.TrySetResult();
});
try
{
using var _ = cancelToken.Register(() => tcs.TrySetCanceled());
NetworkInformation.NetworkStatusChanged += handler;
await tcs.Task.ConfigureAwait(false);
}
finally
{
NetworkInformation.NetworkStatusChanged -= handler;
}
}
}
57 changes: 57 additions & 0 deletions src/Shiny.Mediator.Uno/Infrastructure/StorageService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Uno.Extensions.Storage;

namespace Shiny.Mediator.Infrastructure;


public class StorageService(IStorage storage, ISerializerService serializer) : IStorageService
{
public Task Set<T>(string key, T value)
{
// var path = this.GetFilePath(key);
// var json = serializer.Serialize(value);
// File.WriteAllText(path, json);

return Task.CompletedTask;
}


public Task<T?> Get<T>(string key)
{
// T? returnValue = default;
// var path = this.GetFilePath(key);
// if (File.Exists(path))
// {
// var json = File.ReadAllText(path);
// returnValue = serializer.Deserialize<T>(json)!;
// }

//return Task.FromResult(returnValue);
return Task.FromResult((T?)default);
}



public Task Remove(string key)
{
// var fn = this.GetFilePath(key);
// if (File.Exists(fn))
// File.Delete(fn);
//
// return Task.CompletedTask;
return null;
}

public Task RemoveByPrefix(string prefix) => this.DeleteBy(prefix + "*.mediator");
public Task Clear() => this.DeleteBy("*.mediator");


Task DeleteBy(string pattern)
{
// var dir = new DirectoryInfo(fileSystem.CacheDirectory);
// var files = dir.GetFiles(pattern);
// foreach (var file in files)
// file.Delete();
//
return Task.CompletedTask;
}
}
14 changes: 14 additions & 0 deletions src/Shiny.Mediator.Uno/Shiny.Mediator.Uno.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Uno.Sdk/5.6.22">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<UnoSingleProject>true</UnoSingleProject>
<OutputType>Library</OutputType>
<Nullable>enable</Nullable>

<UnoFeatures>Hosting;Storage</UnoFeatures>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Shiny.Mediator.AppSupport\Shiny.Mediator.AppSupport.csproj"/>
</ItemGroup>
</Project>
63 changes: 63 additions & 0 deletions src/Shiny.Mediator.Uno/UnoExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Shiny.Mediator.Infrastructure;
using Uno.Extensions.Hosting;

namespace Shiny.Mediator;


public static class UnoExtensions
{
/// <summary>
/// Add shiny mediator to Uno
/// </summary>
/// <param name="builder"></param>
/// <param name="configure"></param>
/// <param name="includeStandardMiddleware"></param>
/// <returns></returns>
public static IHostBuilder AddShinyMediator(this IHostBuilder builder, Action<ShinyConfigurator> configure, bool includeStandardMiddleware = true)
{
// TODO: Uno Event Collector... How?
builder.ConfigureServices(x => x.AddShinyMediator(
cfg =>
{
if (includeStandardMiddleware)
{
cfg.AddStandardAppSupportMiddleware();
cfg.AddUnoInfrastructure();
}
},
includeStandardMiddleware
));
return builder;
}


/// <summary>
/// Adds necessary infrastructure for standard app middleware
/// </summary>
/// <param name="cfg"></param>
/// <returns></returns>
public static ShinyConfigurator AddUnoInfrastructure(this ShinyConfigurator cfg)
{
cfg.Services.TryAddSingleton<IInternetService, InternetService>();
cfg.Services.TryAddSingleton<IAlertDialogService, AlertDialogService>();
cfg.Services.TryAddSingleton<IStorageService, StorageService>();
return cfg;
}


/// <summary>
/// Adds connectivity broadcaster
/// </summary>
/// <param name="configurator"></param>
/// <returns></returns>
public static ShinyConfigurator AddConnectivityBroadcaster(this ShinyConfigurator configurator)
{
configurator.AddUnoInfrastructure();
configurator.Services.AddSingleton<IServiceInitialize, ConnectivityBroadcaster>();
return configurator;
}
}

0 comments on commit cad170d

Please sign in to comment.