diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fa8cc9a..e570158 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,6 +13,12 @@ jobs: # uses GitHub's checkout action to checkout code form the main branch - uses: actions/checkout@v4.1.1 + - name: UpdateVersionInMainLayout + uses: datamonsters/replace-action@v2 + with: + files: 'TiredDoctorManhattan.Wasm/Pages/Index.razor.cs' + replacements: '%%CACHE_VERSION%%=${{ github.run_id }}' + # sets up .NET SDK - name: Setup .NET Core SDK uses: actions/setup-dotnet@v4.0.0 @@ -41,6 +47,12 @@ jobs: - name: Add .nojekyll file run: touch release/wwwroot/.nojekyll + - name: UpdateVersion + uses: datamonsters/replace-action@v2 + with: + files: 'release/wwwroot/service-worker.published.js' + replacements: '%%CACHE_VERSION%%=${{ github.run_id }}' + - name: Commit wwwroot to GitHub Pages uses: JamesIves/github-pages-deploy-action@v4.5.0 with: diff --git a/TiredDoctorManhattan.Wasm/GlobalUsings.cs b/TiredDoctorManhattan.Wasm/GlobalUsings.cs index 791aaf5..f98d9a2 100644 --- a/TiredDoctorManhattan.Wasm/GlobalUsings.cs +++ b/TiredDoctorManhattan.Wasm/GlobalUsings.cs @@ -1,6 +1,7 @@ global using Microsoft.AspNetCore.Components; global using Microsoft.AspNetCore.Components.Web; global using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +global using Microsoft.JSInterop; global using SixLabors.Fonts; global using SixLabors.ImageSharp; global using SixLabors.ImageSharp.Drawing; @@ -11,4 +12,5 @@ global using System.Diagnostics; global using System.Diagnostics.CodeAnalysis; global using TiredDoctorManhattan.Wasm; +global using TiredDoctorManhattan.Wasm.Services; global using TiredDoctorManhattan.Wasm.Shared; diff --git a/TiredDoctorManhattan.Wasm/Pages/Index.razor b/TiredDoctorManhattan.Wasm/Pages/Index.razor index c4efa65..1dc39a6 100644 --- a/TiredDoctorManhattan.Wasm/Pages/Index.razor +++ b/TiredDoctorManhattan.Wasm/Pages/Index.razor @@ -4,6 +4,19 @@ @PageTitle +@if (IsUpdateAvailable) +{ + +} +

@PageTitle

diff --git a/TiredDoctorManhattan.Wasm/Pages/Index.razor.cs b/TiredDoctorManhattan.Wasm/Pages/Index.razor.cs index b2a2b26..772fe44 100644 --- a/TiredDoctorManhattan.Wasm/Pages/Index.razor.cs +++ b/TiredDoctorManhattan.Wasm/Pages/Index.razor.cs @@ -1,10 +1,14 @@ namespace TiredDoctorManhattan.Wasm.Pages; -public partial class Index +public partial class Index : IDisposable { private const string BackgroundImageLocation = "assets/background.png"; private const string FontLocation = "assets/KMKDSPK_.ttf"; +#pragma warning disable IDE0051 // Remove unused private members + private const string DeploymentId = "%%CACHE_VERSION%%"; +#pragma warning restore IDE0051 // Remove unused private members + [Parameter] public string? TextToRender { get; set; } private static string PageTitle => "Tired Doctor Manhattan"; @@ -13,6 +17,8 @@ public partial class Index private byte[]? ImageBytes { get; set; } + private bool IsUpdateAvailable { get; set; } = false; + private string? GetImageBase64 => ImageBytes is null ? null : Convert.ToBase64String(ImageBytes); @@ -21,6 +27,17 @@ public partial class Index private TimeSpan? GenerationTime { get; set; } + protected override void OnInitialized() => UpdateAlertService.OnUpdateAvailable += ShowUpdateMessage; + + public void Dispose() => UpdateAlertService.OnUpdateAvailable -= ShowUpdateMessage; + + public void ShowUpdateMessage() + { + // Display the alert when an update is available + IsUpdateAvailable = true; + StateHasChanged(); + } + private async Task GenerateImage() { IsWorking = true; diff --git a/TiredDoctorManhattan.Wasm/Program.cs b/TiredDoctorManhattan.Wasm/Program.cs index bc30265..93b6f81 100644 --- a/TiredDoctorManhattan.Wasm/Program.cs +++ b/TiredDoctorManhattan.Wasm/Program.cs @@ -1,11 +1,14 @@ var builder = WebAssemblyHostBuilder.CreateDefault(args); +var services = builder.Services; builder.RootComponents.Add("#app"); builder.RootComponents.Add("head::after"); -builder.Services.AddScoped(_ => new HttpClient -{ - BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) -}); +services + .AddSingleton(_ => new HttpClient + { + BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) + }) + .AddSingleton(); await builder.Build().RunAsync(); diff --git a/TiredDoctorManhattan.Wasm/Services/IUpdateAlertService.cs b/TiredDoctorManhattan.Wasm/Services/IUpdateAlertService.cs new file mode 100644 index 0000000..a0becbe --- /dev/null +++ b/TiredDoctorManhattan.Wasm/Services/IUpdateAlertService.cs @@ -0,0 +1,8 @@ +namespace TiredDoctorManhattan.Wasm.Services; + +public interface IUpdateAlertService +{ + event Action? OnUpdateAvailable; + + void ShowUpdateMessage(); +} diff --git a/TiredDoctorManhattan.Wasm/Services/UpdateAlertService.cs b/TiredDoctorManhattan.Wasm/Services/UpdateAlertService.cs new file mode 100644 index 0000000..1f0f07c --- /dev/null +++ b/TiredDoctorManhattan.Wasm/Services/UpdateAlertService.cs @@ -0,0 +1,15 @@ +namespace TiredDoctorManhattan.Wasm.Services; + +public class UpdateAlertService : IUpdateAlertService +{ + public static UpdateAlertService? Instance { get; private set; } + + public event Action? OnUpdateAvailable; + + public UpdateAlertService() => Instance = this; + + void IUpdateAlertService.ShowUpdateMessage() => ShowUpdateMessage(); + + [JSInvokable(nameof(ShowUpdateMessage))] + public static void ShowUpdateMessage() => Instance?.OnUpdateAvailable?.Invoke(); +} diff --git a/TiredDoctorManhattan.Wasm/TiredDoctorManhattan.Wasm.csproj b/TiredDoctorManhattan.Wasm/TiredDoctorManhattan.Wasm.csproj index 6a6b074..193f835 100644 --- a/TiredDoctorManhattan.Wasm/TiredDoctorManhattan.Wasm.csproj +++ b/TiredDoctorManhattan.Wasm/TiredDoctorManhattan.Wasm.csproj @@ -10,6 +10,9 @@ 268435456 false true + true + true + true @@ -24,6 +27,10 @@ + + + + PreserveNewest diff --git a/TiredDoctorManhattan.Wasm/_Imports.razor b/TiredDoctorManhattan.Wasm/_Imports.razor index f8a684b..fcf87bf 100644 --- a/TiredDoctorManhattan.Wasm/_Imports.razor +++ b/TiredDoctorManhattan.Wasm/_Imports.razor @@ -7,6 +7,8 @@ @using Microsoft.AspNetCore.Components.WebAssembly.Http @using Microsoft.JSInterop @using TiredDoctorManhattan.Wasm +@using TiredDoctorManhattan.Wasm.Services @using TiredDoctorManhattan.Wasm.Shared @inject HttpClient HttpClient +@inject IUpdateAlertService UpdateAlertService diff --git a/TiredDoctorManhattan.Wasm/wwwroot/BrowserNotSupported.html b/TiredDoctorManhattan.Wasm/wwwroot/BrowserNotSupported.html new file mode 100644 index 0000000..11dfcf4 --- /dev/null +++ b/TiredDoctorManhattan.Wasm/wwwroot/BrowserNotSupported.html @@ -0,0 +1,22 @@ + + + + + + + Tired Doctor Manhattan + + + + + + + +

+ Tired Doctor Manhattan +

+ + Tired Doctor Manhattan is not supported in the current browser. For a list of compatible browsers, see here: https://caniuse.com/wasm + + + diff --git a/TiredDoctorManhattan.Wasm/wwwroot/index.html b/TiredDoctorManhattan.Wasm/wwwroot/index.html index e5f0fb7..5640855 100644 --- a/TiredDoctorManhattan.Wasm/wwwroot/index.html +++ b/TiredDoctorManhattan.Wasm/wwwroot/index.html @@ -3,7 +3,7 @@ - + Tired Doctor Manhattan @@ -17,6 +17,9 @@ + +
+
@@ -30,8 +33,57 @@ Reload 🗙
- - + + + + + + + diff --git a/TiredDoctorManhattan.Wasm/wwwroot/manifest.json b/TiredDoctorManhattan.Wasm/wwwroot/manifest.json index b88d925..6ae7203 100644 --- a/TiredDoctorManhattan.Wasm/wwwroot/manifest.json +++ b/TiredDoctorManhattan.Wasm/wwwroot/manifest.json @@ -2,6 +2,7 @@ "name": "Tired Doctor Manhattan", "short_name": "Tired Dr Manhattan", "start_url": "./", + "scope": "/", "display": "standalone", "background_color": "#ffffff", "theme_color": "#03173d", diff --git a/TiredDoctorManhattan.Wasm/wwwroot/service-worker.published.js b/TiredDoctorManhattan.Wasm/wwwroot/service-worker.published.js index 105b713..6415f1f 100644 --- a/TiredDoctorManhattan.Wasm/wwwroot/service-worker.published.js +++ b/TiredDoctorManhattan.Wasm/wwwroot/service-worker.published.js @@ -2,12 +2,21 @@ // offline support. See https://aka.ms/blazor-offline-considerations self.importScripts('./service-worker-assets.js'); -self.addEventListener('install', event => event.waitUntil(onInstall(event))); -self.addEventListener('activate', event => event.waitUntil(onActivate(event))); +self.addEventListener('install', event => { + self.skipWaiting(); + event.waitUntil(onInstall(event)); +}); + +self.addEventListener('activate', event => { + event.waitUntil(onActivate(event)); + self.clients.claim(); +}); self.addEventListener('fetch', event => event.respondWith(onFetch(event))); const cacheNamePrefix = 'offline-cache-'; -const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`; +const CACHE_VERSION = '%%CACHE_VERSION%%' +const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}${CACHE_VERSION}`; + const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/, /\.blat$/, /\.dat$/ ]; const offlineAssetsExclude = [ /^service-worker\.js$/ ];