From a5e0d7b870e3b1a82183d6173eee87dc0232a5bb Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Mon, 9 Feb 2026 18:07:27 -0600 Subject: [PATCH] UI polish: model display fixes, dock badges, sidebar sync, and throttling - Fix model display inconsistency between grid and expanded views - Handle SessionModelChangeEvent from SDK to track actual model - Update session.Model from all usage events (not just resumed sessions) - Add GetSessionModel() for consistent model display across views - Add session model to dropdown options if not in available list - Add dock badge notifications for completed sessions (Mac Catalyst/iOS) - Badge clears automatically when app becomes active - Dynamic model list from SDK (ListModelsAsync) with fallback - Model selection persistence across app restarts via UiState - Sidebar session sync with Tab/Shift+Tab navigation - Card focus-within highlight for active session - Card message windowing with load-more button - Throttle Dashboard SafeRefreshAsync and sidebar RefreshSessions to prevent rapid re-renders from blocking click events --- Components/Layout/SessionSidebar.razor | 46 ++++++++++++++- Components/Pages/Dashboard.razor | 78 +++++++++++++++++++++---- Components/Pages/Dashboard.razor.css | 23 ++++++++ MauiProgram.cs | 24 +++++--- Services/CopilotService.cs | 80 ++++++++++++++++++++++++-- 5 files changed, 225 insertions(+), 26 deletions(-) diff --git a/Components/Layout/SessionSidebar.razor b/Components/Layout/SessionSidebar.razor index 14cbef93d6..42ba32cea4 100644 --- a/Components/Layout/SessionSidebar.razor +++ b/Components/Layout/SessionSidebar.razor @@ -28,7 +28,7 @@ else if (IsFlyoutPanel)
- @foreach (var model in availableModels) { @@ -83,7 +83,7 @@ else
- @foreach (var model in availableModels) { @@ -252,6 +252,7 @@ else }; private string selectedModel = "claude-opus-4.6"; + private string _lastSavedModel = ""; private string sessionFilter = ""; private bool isCreating = false; private bool hasSessionName = false; @@ -270,18 +271,27 @@ else await OnToggleFlyout.InvokeAsync(); } - private readonly string[] availableModels = new[] + private static readonly string[] _fallbackModels = new[] { "claude-opus-4.6", + "claude-opus-4.6-fast", + "claude-opus-4.5", "claude-sonnet-4.5", "claude-sonnet-4", "claude-haiku-4.5", "gpt-5.2", + "gpt-5.2-codex", "gpt-5.1", + "gpt-5.1-codex", + "gpt-5.1-codex-max", + "gpt-5.1-codex-mini", "gpt-5", "gpt-5-mini", + "gpt-4.1", "gemini-3-pro-preview", }; + private IReadOnlyList availableModels => + CopilotService.AvailableModels.Count > 0 ? CopilotService.AvailableModels : _fallbackModels; private IEnumerable filteredPersistedSessions => (string.IsNullOrWhiteSpace(sessionFilter) @@ -302,6 +312,16 @@ else CopilotService.OnSessionComplete += HandleSessionComplete; RefreshSessions(); LoadPersistedSessions(); + + // Restore last selected model + var uiState = CopilotService.LoadUiState(); + if (!string.IsNullOrEmpty(uiState?.SelectedModel)) + selectedModel = uiState.SelectedModel; + } + + private void SaveSelectedModel() + { + CopilotService.SaveUiState(currentPage, selectedModel: selectedModel); } private HashSet completedSessions = new(); @@ -334,8 +354,28 @@ else } } + private DateTime _lastSidebarRefresh = DateTime.MinValue; + private bool _sidebarRefreshPending; + private void RefreshSessions() { + var now = DateTime.UtcNow; + if ((now - _lastSidebarRefresh).TotalMilliseconds < 500) + { + if (!_sidebarRefreshPending) + { + _sidebarRefreshPending = true; + _ = Task.Delay(500).ContinueWith(_ => InvokeAsync(() => { + _sidebarRefreshPending = false; + _lastSidebarRefresh = DateTime.UtcNow; + sessions = CopilotService.GetAllSessions().ToList(); + LoadPersistedSessions(); + StateHasChanged(); + })); + } + return; + } + _lastSidebarRefresh = now; sessions = CopilotService.GetAllSessions().ToList(); LoadPersistedSessions(); InvokeAsync(StateHasChanged); diff --git a/Components/Pages/Dashboard.razor b/Components/Pages/Dashboard.razor index e08cf22a52..75ddd00ccb 100644 --- a/Components/Pages/Dashboard.razor +++ b/Components/Pages/Dashboard.razor @@ -135,6 +135,11 @@
ยท