Public Access
Desktop: virtualise the transfer queue and the import lists
This commit is contained in:
1 parent
7b072bcded
commit
8759b12d47
4 files changed
+108
-16
No files matched your search
@@ -253,8 +253,20 @@
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<ScrollViewer Grid.Row="1">
|
||||
<ItemsControl ItemsSource="{Binding Rows}" Margin="12,8">
|
||||
<!-- Virtualised, for an inventory of hundreds of machines: see the transfer queue's own note. -->
|
||||
<ItemsControl Grid.Row="1" ItemsSource="{Binding Rows}">
|
||||
<ItemsControl.Template>
|
||||
<ControlTemplate>
|
||||
<ScrollViewer>
|
||||
<ItemsPresenter Name="PART_ItemsPresenter" ItemsPanel="{TemplateBinding ItemsPanel}" Margin="12,8" />
|
||||
</ScrollViewer>
|
||||
</ControlTemplate>
|
||||
</ItemsControl.Template>
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:HetznerRowViewModel">
|
||||
<Border Classes="importrow" CornerRadius="8">
|
||||
@@ -290,8 +302,7 @@
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</ItemsControl>
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
@@ -131,8 +131,20 @@
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<ScrollViewer Grid.Row="1">
|
||||
<ItemsControl ItemsSource="{Binding Rows}" Margin="12,8">
|
||||
<!-- Virtualised, for an inventory of hundreds of machines: see the transfer queue's own note. -->
|
||||
<ItemsControl Grid.Row="1" ItemsSource="{Binding Rows}">
|
||||
<ItemsControl.Template>
|
||||
<ControlTemplate>
|
||||
<ScrollViewer>
|
||||
<ItemsPresenter Name="PART_ItemsPresenter" ItemsPanel="{TemplateBinding ItemsPanel}" Margin="12,8" />
|
||||
</ScrollViewer>
|
||||
</ControlTemplate>
|
||||
</ItemsControl.Template>
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:ImportRowViewModel">
|
||||
<Border Classes="importrow" CornerRadius="8">
|
||||
@@ -161,8 +173,7 @@
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</ItemsControl>
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
@@ -1190,8 +1190,24 @@
|
||||
Text="{Binding Status}" IsVisible="{Binding IsConnected}" />
|
||||
</Grid>
|
||||
|
||||
<ScrollViewer Grid.Row="2">
|
||||
<ItemsControl ItemsSource="{Binding Transfers}">
|
||||
<!--
|
||||
Virtualised: a folder download queues a row per file, and a stack panel inside an outer scroller
|
||||
laid out and drew every one of them, thousands deep. The scroller is the control's own so the panel
|
||||
knows the viewport it has to fill and realises only those rows.
|
||||
-->
|
||||
<ItemsControl Grid.Row="2" ItemsSource="{Binding Transfers}">
|
||||
<ItemsControl.Template>
|
||||
<ControlTemplate>
|
||||
<ScrollViewer>
|
||||
<ItemsPresenter Name="PART_ItemsPresenter" ItemsPanel="{TemplateBinding ItemsPanel}" />
|
||||
</ScrollViewer>
|
||||
</ControlTemplate>
|
||||
</ItemsControl.Template>
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:TransferRowViewModel">
|
||||
<!--
|
||||
@@ -1239,7 +1255,6 @@
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
|
||||
<Button Grid.Row="3" Classes="ghost" Content="CLEAR FINISHED" Margin="0,10,0,0"
|
||||
HorizontalAlignment="Left" Command="{Binding ClearCompletedCommand}" />
|
||||
|
||||
@@ -1386,6 +1386,48 @@ public sealed class ScreenLayoutTests : IAsyncLifetime
|
||||
await MeasureTransfersAsync(faults => faults.ShouldBeEmpty());
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// A folder download queues a row per file. The queue was a plain stack inside an outer scroller, which
|
||||
/// measured and drew every row however deep — so the number of rows built here is the claim, not the
|
||||
/// layout: a few screens' worth out of two thousand.
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public async Task ADeepQueue_BuildsOnlyTheRowsOnScreen()
|
||||
{
|
||||
transfers.IsConnected = true;
|
||||
|
||||
for (var file = 0; file < 2000; file++)
|
||||
{
|
||||
Enqueue(TransferDirection.Download, $"asset-{file:0000}.png", 4096, 0, TransferState.Queued);
|
||||
}
|
||||
|
||||
await LayoutHarness.OnTheUiThreadAsync(
|
||||
() =>
|
||||
{
|
||||
var screen = new TransfersScreen { DataContext = transfers };
|
||||
|
||||
var window = LayoutHarness.HostAtMinimumSize(
|
||||
screen,
|
||||
LayoutHarness.SessionScreenWidth(transfers.IsConnected),
|
||||
LayoutHarness.SessionScreenHeight);
|
||||
|
||||
try
|
||||
{
|
||||
var built = screen.GetVisualDescendants()
|
||||
.OfType<ProgressBar>()
|
||||
.Count(bar => bar.Classes.Contains("transferbar"));
|
||||
|
||||
built.ShouldBeGreaterThan(0, "the rows on screen are still drawn");
|
||||
built.ShouldBeLessThan(200, "the rest of the two thousand are not");
|
||||
}
|
||||
finally
|
||||
{
|
||||
window.Close();
|
||||
}
|
||||
},
|
||||
Token);
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// The edit strip, which shares the questions' Grid row and is the tallest thing that can be in it: a
|
||||
/// heading, a path, a scrolling log of saves, the conflict card and a button. Its log is bounded for the
|
||||
@@ -1632,11 +1674,24 @@ public sealed class ScreenLayoutTests : IAsyncLifetime
|
||||
|
||||
try
|
||||
{
|
||||
var words = screen.GetVisualDescendants()
|
||||
.OfType<TextBlock>()
|
||||
.Where(text => text.Classes.Contains("transferstatus"))
|
||||
.Select(text => text.Text ?? string.Empty)
|
||||
.ToList();
|
||||
// Row by row, scrolled to: the queue is virtualised, so a row off the bottom of the strip is
|
||||
// not built until it is scrolled to — see ADeepQueue_BuildsOnlyTheRowsOnScreen.
|
||||
var queue = screen.GetVisualDescendants().OfType<ItemsControl>()
|
||||
.First(control => ReferenceEquals(control.ItemsSource, transfers.Transfers));
|
||||
|
||||
var words = new List<string>();
|
||||
|
||||
for (var row = 0; row < expected.Length; row++)
|
||||
{
|
||||
queue.ScrollIntoView(row);
|
||||
window.UpdateLayout();
|
||||
|
||||
words.Add(queue.ContainerFromIndex(row).ShouldNotBeNull()
|
||||
.GetVisualDescendants()
|
||||
.OfType<TextBlock>()
|
||||
.Single(text => text.Classes.Contains("transferstatus"))
|
||||
.Text ?? string.Empty);
|
||||
}
|
||||
|
||||
words.ShouldBe(expected);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user