@using MudBlazor.Services @using PlaylistShared.Pwa.Components.Global @inherits LayoutComponentBase @inject PwaUpdateService PwaUpdateService @inject IJSRuntime JSRuntime @inject NavigationManager NavigationManager @inject ContextualActionBarService ContextualActionBarService @inject IBrowserViewportService BrowserViewportService @implements IBrowserViewportObserver @implements IDisposable @if (_actionBarContent != null) { @_actionBarContent } else { Git } @Body @code { private RenderFragment? _actionBarContent; private bool _actionBarBottom => _contextualPosition switch { ContextualActionBarPosition.Bottom => true, ContextualActionBarPosition.Top => false, _ => _isMobile, }; private bool _isMobile = false; private ContextualActionBarPosition _contextualPosition = ContextualActionBarPosition.Default; private bool _drawerOpen = true; private bool _isDarkMode = true; private MudTheme? _theme; private DotNetObjectReference? _dotNetRef; protected override void OnInitialized() { base.OnInitialized(); _theme = new() { PaletteLight = _lightPalette, PaletteDark = _darkPalette, LayoutProperties = new LayoutProperties() }; ContextualActionBarService.OnChanged += OnContextualChangedHandler; NavigationManager.LocationChanged += OnLocationChanged; } private void OnLocationChanged(object? sender, Microsoft.AspNetCore.Components.Routing.LocationChangedEventArgs e) { if (_isMobile) { _drawerOpen = false; InvokeAsync(StateHasChanged); } } public void Dispose() { NavigationManager.LocationChanged -= OnLocationChanged; ContextualActionBarService.OnChanged -= OnContextualChangedHandler; } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { _dotNetRef = DotNetObjectReference.Create(PwaUpdateService); await JSRuntime.InvokeVoidAsync("registerSWMessageHandler", _dotNetRef); await BrowserViewportService.SubscribeAsync(this, fireImmediately: true); var savedTheme = await JSRuntime.InvokeAsync("localStorage.getItem", "theme"); if (savedTheme != null) { _isDarkMode = savedTheme != "light"; StateHasChanged(); } } } private void OnContextualChangedHandler() { _actionBarContent = ContextualActionBarService.Content; _contextualPosition = ContextualActionBarService.Position; StateHasChanged(); } private void DrawerToggle() { _drawerOpen = !_drawerOpen; } private async Task DarkModeToggle() { _isDarkMode = !_isDarkMode; await JSRuntime.InvokeVoidAsync("localStorage.setItem", "theme", _isDarkMode ? "dark" : "light"); } private readonly PaletteLight _lightPalette = new() { Black = "#110e2d", AppbarText = "#424242", AppbarBackground = "rgba(255,255,255,0.8)", DrawerBackground = "#ffffff", GrayLight = "#e8e8e8", GrayLighter = "#f9f9f9", }; private readonly PaletteDark _darkPalette = new() { Primary = "#7e6fff", Surface = "#1e1e2d", Background = "#1a1a27", BackgroundGray = "#151521", AppbarText = "#92929f", AppbarBackground = "rgba(26,26,39,0.8)", DrawerBackground = "#1a1a27", ActionDefault = "#74718e", ActionDisabled = "#9999994d", ActionDisabledBackground = "#605f6d4d", TextPrimary = "#b2b0bf", TextSecondary = "#92929f", TextDisabled = "#ffffff33", DrawerIcon = "#92929f", DrawerText = "#92929f", GrayLight = "#2a2833", GrayLighter = "#1e1e2d", Info = "#4a86ff", Success = "#3dcb6c", Warning = "#ffb545", Error = "#ff3f5f", LinesDefault = "#33323e", TableLines = "#33323e", Divider = "#292838", OverlayLight = "#1e1e2d80", }; public string DarkLightModeButtonIcon => _isDarkMode switch { true => Icons.Material.Rounded.AutoMode, false => Icons.Material.Outlined.DarkMode, }; Guid IBrowserViewportObserver.Id { get; } = Guid.NewGuid(); ResizeOptions IBrowserViewportObserver.ResizeOptions { get; } = new() { ReportRate = 250, NotifyOnBreakpointOnly = true }; Task IBrowserViewportObserver.NotifyBrowserViewportChangeAsync(BrowserViewportEventArgs browserViewportEventArgs) { var wasMobile = _isMobile; _isMobile = browserViewportEventArgs.Breakpoint <= Breakpoint.Sm; if (!wasMobile && _isMobile) _drawerOpen = false; else if (wasMobile && !_isMobile) _drawerOpen = true; return InvokeAsync(StateHasChanged); } }