diff --git a/SalmonEgg/SalmonEgg/Presentation/Views/Start/StartView.xaml.cs b/SalmonEgg/SalmonEgg/Presentation/Views/Start/StartView.xaml.cs index dbbc064c..9888d1f4 100644 --- a/SalmonEgg/SalmonEgg/Presentation/Views/Start/StartView.xaml.cs +++ b/SalmonEgg/SalmonEgg/Presentation/Views/Start/StartView.xaml.cs @@ -101,13 +101,27 @@ private void RefreshHeroSuggestionFocusTargets() continue; } - button.XYFocusLeft = i > 0 + var leftTarget = i > 0 ? FindSuggestionButton(ViewModel.Suggestions[i - 1].AutomationId) : null; - button.XYFocusRight = i + 1 < ViewModel.Suggestions.Count + if (leftTarget is not null) + { + button.XYFocusLeft = leftTarget; + } + + var rightTarget = i + 1 < ViewModel.Suggestions.Count ? FindSuggestionButton(ViewModel.Suggestions[i + 1].AutomationId) : null; - button.XYFocusDown = FindPromptBox(); + if (rightTarget is not null) + { + button.XYFocusRight = rightTarget; + } + + var downTarget = FindPromptBox(); + if (downTarget is not null) + { + button.XYFocusDown = downTarget; + } } } diff --git a/global.json b/global.json index 9d942998..bdd9fefe 100644 --- a/global.json +++ b/global.json @@ -3,7 +3,7 @@ "Uno.Sdk": "6.5.33" }, "sdk": { - "version": "10.0.202", + "version": "10.0.103", "rollForward": "latestPatch", "allowPrerelease": false } diff --git a/src/SalmonEgg.Presentation.Core/ViewModels/Chat/Overlay/ChatConversationSurfaceProjectionCoordinator.cs b/src/SalmonEgg.Presentation.Core/ViewModels/Chat/Overlay/ChatConversationSurfaceProjectionCoordinator.cs index fcbdfafd..1ce16862 100644 --- a/src/SalmonEgg.Presentation.Core/ViewModels/Chat/Overlay/ChatConversationSurfaceProjectionCoordinator.cs +++ b/src/SalmonEgg.Presentation.Core/ViewModels/Chat/Overlay/ChatConversationSurfaceProjectionCoordinator.cs @@ -4,18 +4,31 @@ namespace SalmonEgg.Presentation.Core.ViewModels.Chat.Overlay; internal sealed class ChatConversationSurfaceProjectionCoordinator { + private bool _hasLoadedActiveConversationRoot; + private bool _hasLoadedTranscriptSurface; + public ChatConversationSurfaceProjection Project(ChatConversationSurfaceStateInput input) { var state = ChatConversationSurfaceStatePresenter.Resolve(input); + if (state.ShouldShowActiveConversationRoot) + { + _hasLoadedActiveConversationRoot = true; + } + + if (state.ShouldShowTranscriptSurface) + { + _hasLoadedTranscriptSurface = true; + } + return new ChatConversationSurfaceProjection( state.IsActivationOverlayVisible, state.IsOverlayVisible, state.ShouldShowActiveConversationRoot, - state.ShouldShowActiveConversationRoot, + _hasLoadedActiveConversationRoot, state.ShouldShowSessionHeader, state.ShouldShowTranscriptSurface, - state.ShouldShowTranscriptSurface, + _hasLoadedTranscriptSurface, state.ShouldShowConversationInputSurface, state.ShouldShowBlockingLoadingMask, state.ShouldShowLoadingOverlayStatusPill, diff --git a/tests/SalmonEgg.Presentation.Core.Tests/Chat/ChatViewModelTests.cs b/tests/SalmonEgg.Presentation.Core.Tests/Chat/ChatViewModelTests.cs index 4c323afc..ce4cd9ce 100644 --- a/tests/SalmonEgg.Presentation.Core.Tests/Chat/ChatViewModelTests.cs +++ b/tests/SalmonEgg.Presentation.Core.Tests/Chat/ChatViewModelTests.cs @@ -54,7 +54,7 @@ namespace SalmonEgg.Presentation.Core.Tests.Chat; [Collection("NonParallel")] - public partial class ChatViewModelTests +public partial class ChatViewModelTests { private static ViewModelFixture CreateViewModel( SynchronizationContext? syncContext = null, @@ -10155,10 +10155,10 @@ await fixture.UpdateStateAsync(state => state with runtimeState.IsSessionActivationInProgress = true; Assert.False(fixture.ViewModel.ShouldShowActiveConversationRoot); - Assert.False(fixture.ViewModel.ShouldLoadActiveConversationRoot); + Assert.True(fixture.ViewModel.ShouldLoadActiveConversationRoot); Assert.False(fixture.ViewModel.ShouldShowSessionHeader); Assert.False(fixture.ViewModel.ShouldShowTranscriptSurface); - Assert.False(fixture.ViewModel.ShouldLoadTranscriptSurface); + Assert.True(fixture.ViewModel.ShouldLoadTranscriptSurface); Assert.False(fixture.ViewModel.ShouldShowConversationInputSurface); Assert.Equal(SessionNamePolicy.CreateDefault("conv-1"), fixture.ViewModel.CurrentSessionDisplayName); Assert.Equal(string.Empty, fixture.ViewModel.PresentedSessionHeaderDisplayName); @@ -11215,10 +11215,10 @@ await fixture.DispatchConnectionAsync(new SetNewSessionDraftAction(new NewSessio syncContext.RunAll(); Assert.False(fixture.ViewModel.ShouldShowActiveConversationRoot); - Assert.False(fixture.ViewModel.ShouldLoadActiveConversationRoot); + Assert.True(fixture.ViewModel.ShouldLoadActiveConversationRoot); Assert.False(fixture.ViewModel.ShouldShowSessionHeader); Assert.False(fixture.ViewModel.ShouldShowTranscriptSurface); - Assert.False(fixture.ViewModel.ShouldLoadTranscriptSurface); + Assert.True(fixture.ViewModel.ShouldLoadTranscriptSurface); Assert.False(fixture.ViewModel.ShouldShowConversationInputSurface); var switchTask = fixture.ViewModel.SwitchConversationAsync("conv-2"); @@ -11235,10 +11235,10 @@ await fixture.DispatchConnectionAsync(new SetNewSessionDraftAction(new NewSessio syncContext.RunAll(); Assert.False(fixture.ViewModel.ShouldShowActiveConversationRoot); - Assert.False(fixture.ViewModel.ShouldLoadActiveConversationRoot); + Assert.True(fixture.ViewModel.ShouldLoadActiveConversationRoot); Assert.False(fixture.ViewModel.ShouldShowSessionHeader); Assert.False(fixture.ViewModel.ShouldShowTranscriptSurface); - Assert.False(fixture.ViewModel.ShouldLoadTranscriptSurface); + Assert.True(fixture.ViewModel.ShouldLoadTranscriptSurface); Assert.False(fixture.ViewModel.ShouldShowConversationInputSurface); Assert.Equal("conv-2", runtimeState.DesiredSessionId); Assert.True(runtimeState.IsSessionActivationInProgress); diff --git a/tests/SalmonEgg.Presentation.Core.Tests/Chat/Overlay/ChatConversationSurfaceProjectionCoordinatorTests.cs b/tests/SalmonEgg.Presentation.Core.Tests/Chat/Overlay/ChatConversationSurfaceProjectionCoordinatorTests.cs index 6dca3376..b1bc7652 100644 --- a/tests/SalmonEgg.Presentation.Core.Tests/Chat/Overlay/ChatConversationSurfaceProjectionCoordinatorTests.cs +++ b/tests/SalmonEgg.Presentation.Core.Tests/Chat/Overlay/ChatConversationSurfaceProjectionCoordinatorTests.cs @@ -50,7 +50,7 @@ public void Project_WhenActiveConversationRootWasShown_KeepsLoadStateWhenLaterHi Assert.True(visible.ShouldShowActiveConversationRoot); Assert.True(visible.ShouldLoadActiveConversationRoot); Assert.False(hidden.ShouldShowActiveConversationRoot); - Assert.False(hidden.ShouldLoadActiveConversationRoot); + Assert.True(hidden.ShouldLoadActiveConversationRoot); } [Fact] @@ -97,6 +97,6 @@ public void Project_WhenTranscriptSurfaceWasShown_KeepsLoadStateWhenLaterHidden( Assert.True(visible.ShouldShowTranscriptSurface); Assert.True(visible.ShouldLoadTranscriptSurface); Assert.False(hidden.ShouldShowTranscriptSurface); - Assert.False(hidden.ShouldLoadTranscriptSurface); + Assert.True(hidden.ShouldLoadTranscriptSurface); } } diff --git a/tests/SalmonEgg.Presentation.Core.Tests/NavigationCoreTests.cs b/tests/SalmonEgg.Presentation.Core.Tests/NavigationCoreTests.cs index bebfc375..01094ce8 100644 --- a/tests/SalmonEgg.Presentation.Core.Tests/NavigationCoreTests.cs +++ b/tests/SalmonEgg.Presentation.Core.Tests/NavigationCoreTests.cs @@ -629,7 +629,7 @@ public void StartView_ComposerMoveUpEscapeHandler_ReturnsInputFocusToHeroSuggest Assert.Contains("ComposerShell.MoveUpEscapeHandler = HandlePromptMoveUpEscape;", code, StringComparison.Ordinal); Assert.Contains("promptBox.XYFocusUp = firstSuggestion;", code, StringComparison.Ordinal); - Assert.Contains("button.XYFocusDown = FindPromptBox();", code, StringComparison.Ordinal); + Assert.Contains("button.XYFocusDown = downTarget;", code, StringComparison.Ordinal); } [Fact] diff --git a/tests/SalmonEgg.Presentation.Core.Tests/Ui/XamlComplianceTests.cs b/tests/SalmonEgg.Presentation.Core.Tests/Ui/XamlComplianceTests.cs index f0f25dae..a77b9533 100644 --- a/tests/SalmonEgg.Presentation.Core.Tests/Ui/XamlComplianceTests.cs +++ b/tests/SalmonEgg.Presentation.Core.Tests/Ui/XamlComplianceTests.cs @@ -2459,7 +2459,7 @@ public void StartView_HeroSuggestions_UseStableButtonIdsInsteadOfListSelectionSt Assert.Contains("IPrimaryContentFocusTarget", code, StringComparison.Ordinal); Assert.Contains("FindSuggestionButton(ViewModel.Suggestions[0].AutomationId)", code, StringComparison.Ordinal); Assert.Contains("promptBox.XYFocusUp = firstSuggestion;", code, StringComparison.Ordinal); - Assert.Contains("button.XYFocusDown = FindPromptBox();", code, StringComparison.Ordinal); + Assert.Contains("button.XYFocusDown = downTarget;", code, StringComparison.Ordinal); Assert.DoesNotContain("TryConsumeNavigationIntent", code, StringComparison.Ordinal); Assert.DoesNotContain("TryMoveFocusedSuggestion", code, StringComparison.Ordinal); Assert.DoesNotContain("ResolveFocusedSuggestionIndex", code, StringComparison.Ordinal);