Public Access
Merge branch 'claude/card-selection-state-sharing-f9348c'
This commit is contained in:
@@ -262,6 +262,11 @@
|
||||
opens a shell on a host. One click used to mean both, and a card was then the only place a
|
||||
group could be named while also being the control that threw the rest of the grid away.
|
||||
|
||||
◆ ONE SELECTION, TWO LISTS. Selecting a card here takes the mark off the host grid below, and
|
||||
selecting a host takes it off this one. Two controls each keep their own SelectedItem, so the
|
||||
vault is what joins them — see VaultViewModel.OnSelectedHostChanged. Without it both grids
|
||||
could be lit at once, which is two chosen things under two pairs of buttons.
|
||||
|
||||
◆ THIS IS ONE LEVEL, NOT EVERY GROUP. It binds VisibleGroups: what is inside the group the
|
||||
trail above ends with, or the outermost groups when it ends at ALL HOSTS. Folded away entirely
|
||||
at a group with nothing inside it, which is an ordinary thing to open — the trail and the two
|
||||
|
||||
@@ -1408,6 +1408,14 @@ internal sealed partial class VaultViewModel(
|
||||
[ObservableProperty]
|
||||
private VaultChoiceViewModel? selectedTargetVault;
|
||||
|
||||
/// <summary>
|
||||
/// The host card that is selected, or null when none is.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The application's selection, which everything that acts on a host reads — connecting, editing,
|
||||
/// deleting. <b>It shares one selection with <see cref="SelectedGroup"/>:</b> selecting a host takes the
|
||||
/// mark off a group card and the other way about. See <see cref="OnSelectedHostChanged"/>.
|
||||
/// </remarks>
|
||||
[ObservableProperty]
|
||||
private HostRowViewModel? selectedHost;
|
||||
|
||||
@@ -1435,8 +1443,14 @@ internal sealed partial class VaultViewModel(
|
||||
/// The group card that is selected, or null when none is.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// One click, and nothing more than a highlight: it is what the group's own EDIT and DELETE act on. What
|
||||
/// it deliberately no longer does is narrow the grid — see <see cref="OpenGroup"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <b>It shares one selection with <see cref="SelectedHost"/>.</b> Setting either clears the other, so
|
||||
/// exactly one card on the screen is ever lit. See <see cref="OnSelectedHostChanged"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[ObservableProperty]
|
||||
private HostGroupRowViewModel? selectedGroup;
|
||||
@@ -3023,9 +3037,7 @@ internal sealed partial class VaultViewModel(
|
||||
Hosts.Add(host);
|
||||
}
|
||||
|
||||
// Selection survives a reload. Losing it on every sync would move the terminal's target out from
|
||||
// under the user.
|
||||
SelectedHost = Hosts.FirstOrDefault(row => row.EntityId == selectedId) ?? Hosts.FirstOrDefault();
|
||||
SelectedHost = SelectionAfterReload(selectedId);
|
||||
|
||||
// Both, in this order: the group rows carry a host count, and the sidebar's headings are built from
|
||||
// the group rows.
|
||||
@@ -3035,6 +3047,25 @@ internal sealed partial class VaultViewModel(
|
||||
return unreadable;
|
||||
}
|
||||
|
||||
/// <summary>Which host a freshly filled <see cref="Hosts"/> leaves selected.</summary>
|
||||
/// <param name="selectedId">Whatever was selected before the list was refilled.</param>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The selection survives a reload, because losing it on every sync would move the terminal's target out
|
||||
/// from under the user. The first host is the fallback rather than nothing, so that a fresh unlock has
|
||||
/// something under CONNECT.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// That fallback is skipped while a group card holds the selection, and it has to be: the two grids
|
||||
/// share one mark — see <see cref="OnSelectedHostChanged"/> — so a sync that invented a host would
|
||||
/// quietly unselect a group nobody had touched, once a minute. Read before <see cref="RebuildGroups"/>
|
||||
/// runs, which is where <see cref="SelectedGroup"/> is re-resolved against the rows this pass makes.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
private HostRowViewModel? SelectionAfterReload(Guid? selectedId) =>
|
||||
Hosts.FirstOrDefault(row => row.EntityId == selectedId)
|
||||
?? (SelectedGroup is null ? Hosts.FirstOrDefault() : null);
|
||||
|
||||
/// <returns>How many buckets would not decrypt.</returns>
|
||||
/// <remarks>
|
||||
/// The selection survives a reload and a reload never invents one, as the key and credential lists do and
|
||||
@@ -4710,11 +4741,21 @@ internal sealed partial class VaultViewModel(
|
||||
}
|
||||
|
||||
/// <summary>Loads the group being acted on into the box, so saving renames it.</summary>
|
||||
/// <remarks>The selected card, or the open group when no card is selected. See <see cref="GroupTarget"/>.</remarks>
|
||||
/// <param name="group">
|
||||
/// The group to edit, or null for whatever the screen is aimed at — the selected card, or the open group
|
||||
/// when no card is selected. See <see cref="GroupTarget"/>. The desktop's EDIT button passes nothing and
|
||||
/// means the second; the phone has no card to select and passes the group its heading names.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// Taking it as an argument is what keeps the phone from having to select a group in order to edit one.
|
||||
/// A selection is shared with the host grid now — see <see cref="OnSelectedHostChanged"/> — so a command
|
||||
/// reachable only through <see cref="SelectedGroup"/> would deselect the machine somebody was about to
|
||||
/// connect to, on a screen that draws no group cards at all.
|
||||
/// </remarks>
|
||||
[RelayCommand]
|
||||
private void EditGroup()
|
||||
private void EditGroup(HostGroupRowViewModel? group)
|
||||
{
|
||||
if (GroupTarget is not { } row)
|
||||
if ((group ?? GroupTarget) is not { } row)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -4769,6 +4810,12 @@ internal sealed partial class VaultViewModel(
|
||||
/// deleted by a sync between the list being drawn and the button being pressed — is ignored rather than
|
||||
/// opening an editor on nothing.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The row is handed to <see cref="EditGroup"/> rather than selected first, which it used to be. A group
|
||||
/// selection now clears the host selection — the two grids share one mark — and the phone draws no group
|
||||
/// cards, so selecting one here would have taken the highlight off the machine in the list with nothing
|
||||
/// on screen to say where it had gone.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[RelayCommand]
|
||||
private void EditGroupFromHeading(SidebarGroupHeader? header)
|
||||
@@ -4779,8 +4826,7 @@ internal sealed partial class VaultViewModel(
|
||||
return;
|
||||
}
|
||||
|
||||
SelectedGroup = row;
|
||||
EditGroupCommand.Execute(null);
|
||||
EditGroupCommand.Execute(row);
|
||||
}
|
||||
|
||||
/// <summary>Starts a new group, inside whichever one the screen is showing.</summary>
|
||||
@@ -7918,6 +7964,16 @@ internal sealed partial class VaultViewModel(
|
||||
|
||||
partial void OnSelectedHostChanged(HostRowViewModel? value)
|
||||
{
|
||||
// One selection, across both grids. The two lists are drawn one above the other and they are marked
|
||||
// the same way, so two lit cards read as two things chosen — and the buttons underneath them are two
|
||||
// pairs, only one of which would act. Losing a selection leaves the other alone: a null here is what
|
||||
// a filter matching nothing writes, and taking the mark off a group card because a search box
|
||||
// emptied the grid beneath it would be this rule firing at something that is not a choice.
|
||||
if (value is not null)
|
||||
{
|
||||
SelectedGroup = null;
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(SelectedHostAsksForAPassword));
|
||||
OnPropertyChanged(nameof(SelectedHostAuthenticationNote));
|
||||
OnPropertyChanged(nameof(ShowsConnectBar));
|
||||
@@ -7996,8 +8052,18 @@ internal sealed partial class VaultViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// The other half of the shared selection; see <see cref="OnSelectedHostChanged"/>. Clearing the host
|
||||
/// takes the drawer with it, and that is the point rather than a side effect: a pane about one machine
|
||||
/// cannot go on standing beside a marked group, since nothing on it would be about what is selected.
|
||||
/// </remarks>
|
||||
partial void OnSelectedGroupChanged(HostGroupRowViewModel? value)
|
||||
{
|
||||
if (value is not null)
|
||||
{
|
||||
SelectedHost = null;
|
||||
}
|
||||
|
||||
DisarmIfAimedElsewhere(DeletionTarget.Group, GroupTarget?.EntityId);
|
||||
|
||||
OnPropertyChanged(nameof(GroupTarget));
|
||||
|
||||
Reference in New Issue
Block a user