Public Access
Desktop: virtualise the transfer queue and the import lists
This commit is contained in:
1 parent
7b072bcded
commit
8759b12d47
4 files changed
+105
-13
No files matched your search
@@ -253,8 +253,20 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<ScrollViewer Grid.Row="1">
|
<!-- Virtualised, for an inventory of hundreds of machines: see the transfer queue's own note. -->
|
||||||
<ItemsControl ItemsSource="{Binding Rows}" Margin="12,8">
|
<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>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate x:DataType="vm:HetznerRowViewModel">
|
<DataTemplate x:DataType="vm:HetznerRowViewModel">
|
||||||
<Border Classes="importrow" CornerRadius="8">
|
<Border Classes="importrow" CornerRadius="8">
|
||||||
@@ -291,7 +303,6 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
</ScrollViewer>
|
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@@ -131,8 +131,20 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<ScrollViewer Grid.Row="1">
|
<!-- Virtualised, for an inventory of hundreds of machines: see the transfer queue's own note. -->
|
||||||
<ItemsControl ItemsSource="{Binding Rows}" Margin="12,8">
|
<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>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate x:DataType="vm:ImportRowViewModel">
|
<DataTemplate x:DataType="vm:ImportRowViewModel">
|
||||||
<Border Classes="importrow" CornerRadius="8">
|
<Border Classes="importrow" CornerRadius="8">
|
||||||
@@ -162,7 +174,6 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
</ScrollViewer>
|
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@@ -1190,8 +1190,24 @@
|
|||||||
Text="{Binding Status}" IsVisible="{Binding IsConnected}" />
|
Text="{Binding Status}" IsVisible="{Binding IsConnected}" />
|
||||||
</Grid>
|
</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>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate x:DataType="vm:TransferRowViewModel">
|
<DataTemplate x:DataType="vm:TransferRowViewModel">
|
||||||
<!--
|
<!--
|
||||||
@@ -1239,7 +1255,6 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
</ScrollViewer>
|
|
||||||
|
|
||||||
<Button Grid.Row="3" Classes="ghost" Content="CLEAR FINISHED" Margin="0,10,0,0"
|
<Button Grid.Row="3" Classes="ghost" Content="CLEAR FINISHED" Margin="0,10,0,0"
|
||||||
HorizontalAlignment="Left" Command="{Binding ClearCompletedCommand}" />
|
HorizontalAlignment="Left" Command="{Binding ClearCompletedCommand}" />
|
||||||
|
|||||||
@@ -1386,6 +1386,48 @@ public sealed class ScreenLayoutTests : IAsyncLifetime
|
|||||||
await MeasureTransfersAsync(faults => faults.ShouldBeEmpty());
|
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>
|
/// <remarks>
|
||||||
/// The edit strip, which shares the questions' Grid row and is the tallest thing that can be in it: a
|
/// 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
|
/// 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
|
try
|
||||||
{
|
{
|
||||||
var words = screen.GetVisualDescendants()
|
// 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>()
|
.OfType<TextBlock>()
|
||||||
.Where(text => text.Classes.Contains("transferstatus"))
|
.Single(text => text.Classes.Contains("transferstatus"))
|
||||||
.Select(text => text.Text ?? string.Empty)
|
.Text ?? string.Empty);
|
||||||
.ToList();
|
}
|
||||||
|
|
||||||
words.ShouldBe(expected);
|
words.ShouldBe(expected);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user