Skip to content

Commit 4b0b85f

Browse files
committed
Added design and basic functionality for Shelf
1 parent 16f39b6 commit 4b0b85f

File tree

6 files changed

+193
-8
lines changed

6 files changed

+193
-8
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using Files.Shared.Utils;
2+
3+
namespace Files.App.Data.Items
4+
{
5+
[Bindable(true)]
6+
public sealed partial class ShelfItem : ObservableObject, IWrapper<IStorable>, IAsyncInitialize
7+
{
8+
private readonly IImageService _imageService;
9+
10+
[ObservableProperty] private IImage? _Icon;
11+
[ObservableProperty] private string? _Name;
12+
[ObservableProperty] private string? _Path;
13+
14+
/// <inheritdoc/>
15+
public IStorable Inner { get; }
16+
17+
public ShelfItem(IStorable storable, IImage? icon = null)
18+
{
19+
_imageService = Ioc.Default.GetRequiredService<IImageService>();
20+
Inner = storable;
21+
Icon = icon;
22+
Name = storable.Name;
23+
Path = storable.Id;
24+
}
25+
26+
/// <inheritdoc/>
27+
public async Task InitAsync(CancellationToken cancellationToken = default)
28+
{
29+
Icon = await _imageService.GetIconAsync(Inner, cancellationToken);
30+
}
31+
}
32+
}

src/Files.App/UserControls/Pane/ShelfPane.xaml

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,74 @@
33
x:Class="Files.App.UserControls.ShelfPane"
44
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
55
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
6-
xmlns:controls="using:Files.App.Controls"
76
xmlns:converters="using:Files.App.Converters"
87
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
98
xmlns:data="using:Files.App.Data.Items"
10-
xmlns:helpers="using:Files.App.Helpers"
119
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
12-
xmlns:usercontrols="using:Files.App.UserControls"
1310
mc:Ignorable="d">
1411

12+
<UserControl.Resources>
13+
<converters:ImageModelToImageConverter x:Key="ImageModelToImageConverter" />
14+
</UserControl.Resources>
15+
1516
<Grid
1617
Width="240"
18+
Padding="16,0"
19+
AllowDrop="True"
1720
Background="{ThemeResource App.Theme.InfoPane.BackgroundBrush}"
1821
BackgroundSizing="InnerBorderEdge"
1922
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
2023
BorderThickness="1"
21-
CornerRadius="8" />
24+
CornerRadius="8"
25+
DragOver="Shelf_DragOver"
26+
Drop="Shelf_Drop"
27+
RowSpacing="8">
28+
29+
<Grid.RowDefinitions>
30+
<RowDefinition Height="Auto" />
31+
<RowDefinition />
32+
<RowDefinition Height="Auto" />
33+
</Grid.RowDefinitions>
34+
35+
<!-- Title -->
36+
<Border
37+
Grid.Row="0"
38+
Padding="12"
39+
BorderBrush="{ThemeResource ControlStrokeColorSecondaryBrush}"
40+
BorderThickness="0,0,0,1">
41+
<TextBlock
42+
HorizontalAlignment="Center"
43+
Opacity="0.8"
44+
Text="Your Shelf" />
45+
</Border>
46+
47+
<!-- Items List -->
48+
<ListView
49+
Grid.Row="1"
50+
DragItemsStarting="ListView_DragItemsStarting"
51+
ItemsSource="{x:Bind ItemsSource, Mode=OneWay}"
52+
SelectionMode="Extended">
53+
<ListView.ItemTemplate>
54+
<DataTemplate x:DataType="data:ShelfItem">
55+
<StackPanel Orientation="Horizontal" Spacing="8">
56+
<Image Height="20" Source="{x:Bind Icon, Mode=OneWay, Converter={StaticResource ImageModelToImageConverter}}" />
57+
<TextBlock Text="{x:Bind Name, Mode=OneWay}" />
58+
</StackPanel>
59+
</DataTemplate>
60+
</ListView.ItemTemplate>
61+
</ListView>
62+
63+
<!-- Bottom Actions -->
64+
<StackPanel
65+
Grid.Row="2"
66+
Padding="8"
67+
BorderBrush="{ThemeResource ControlStrokeColorSecondaryBrush}"
68+
BorderThickness="0,1,0,0">
69+
<HyperlinkButton
70+
HorizontalAlignment="Center"
71+
VerticalAlignment="Center"
72+
Command="{x:Bind ClearCommand, Mode=OneWay}"
73+
Content="Clear Items" />
74+
</StackPanel>
75+
</Grid>
2276
</UserControl>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,102 @@
11
// Copyright (c) Files Community
22
// Licensed under the MIT License.
33

4+
using Microsoft.UI.Xaml;
45
using Microsoft.UI.Xaml.Controls;
6+
using System.Runtime.InteropServices.ComTypes;
7+
using System.Windows.Input;
8+
using Vanara.PInvoke;
9+
using Windows.ApplicationModel.DataTransfer;
10+
using WinRT;
511

612
namespace Files.App.UserControls
713
{
814
public sealed partial class ShelfPane : UserControl
915
{
1016
public ShelfPane()
1117
{
18+
// TODO: [Shelf] Remove once view model is connected
19+
ItemsSource = new ObservableCollection<ShelfItem>();
20+
1221
InitializeComponent();
1322
}
23+
24+
private void Shelf_DragOver(object sender, DragEventArgs e)
25+
{
26+
if (!FilesystemHelpers.HasDraggedStorageItems(e.DataView))
27+
return;
28+
29+
e.Handled = true;
30+
e.AcceptedOperation = DataPackageOperation.Link;
31+
}
32+
33+
private async void Shelf_Drop(object sender, DragEventArgs e)
34+
{
35+
if (ItemsSource is null)
36+
return;
37+
38+
// Get items
39+
var storageService = Ioc.Default.GetRequiredService<IStorageService>();
40+
var storageItems = (await FilesystemHelpers.GetDraggedStorageItems(e.DataView)).ToArray();
41+
42+
// Add to list
43+
foreach (var item in storageItems)
44+
{
45+
var storable = item switch
46+
{
47+
StorageFileWithPath => (IStorable?)await storageService.TryGetFileAsync(item.Path),
48+
StorageFolderWithPath => (IStorable?)await storageService.TryGetFolderAsync(item.Path),
49+
_ => null
50+
};
51+
52+
if (storable is null)
53+
continue;
54+
55+
var shelfItem = new ShelfItem(storable);
56+
_ = shelfItem.InitAsync();
57+
58+
ItemsSource.Add(shelfItem);
59+
}
60+
}
61+
62+
private void ListView_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
63+
{
64+
if (ItemsSource is null)
65+
return;
66+
67+
var shellItemList = SafetyExtensions.IgnoreExceptions(() => ItemsSource.Select(x => new Vanara.Windows.Shell.ShellItem(x.Inner.Id)).ToArray());
68+
if (shellItemList?[0].FileSystemPath is not null)
69+
{
70+
var iddo = shellItemList[0].Parent?.GetChildrenUIObjects<IDataObject>(HWND.NULL, shellItemList);
71+
if (iddo is null)
72+
return;
73+
74+
shellItemList.ForEach(x => x.Dispose());
75+
var dataObjectProvider = e.Data.As<Shell32.IDataObjectProvider>();
76+
dataObjectProvider.SetDataObject(iddo);
77+
}
78+
else
79+
{
80+
// Only support IStorageItem capable paths
81+
var storageItems = ItemsSource.Select(x => VirtualStorageItem.FromPath(x.Inner.Id));
82+
e.Data.SetStorageItems(storageItems, false);
83+
}
84+
}
85+
86+
public IList<ShelfItem>? ItemsSource
87+
{
88+
get => (IList<ShelfItem>?)GetValue(ItemsSourceProperty);
89+
set => SetValue(ItemsSourceProperty, value);
90+
}
91+
public static readonly DependencyProperty ItemsSourceProperty =
92+
DependencyProperty.Register(nameof(ItemsSource), typeof(IList<ShelfItem>), typeof(ShelfPane), new PropertyMetadata(null));
93+
94+
public ICommand? ClearCommand
95+
{
96+
get => (ICommand?)GetValue(ClearCommandProperty);
97+
set => SetValue(ClearCommandProperty, value);
98+
}
99+
public static readonly DependencyProperty ClearCommandProperty =
100+
DependencyProperty.Register(nameof(ClearCommand), typeof(ICommand), typeof(ShelfPane), new PropertyMetadata(null));
14101
}
15102
}

src/Files.App/Views/MainPage.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@
248248
ShowInfoText="{x:Bind SidebarAdaptiveViewModel.PaneHolder.ActivePaneOrColumn.InstanceViewModel.IsPageTypeNotHome, Mode=OneWay}"
249249
Visibility="{x:Bind SidebarAdaptiveViewModel.PaneHolder.ActivePaneOrColumn.InstanceViewModel.IsPageTypeNotHome, Mode=OneWay}" />
250250

251+
<!-- Shelf Pane -->
251252
<uc:ShelfPane
252253
x:Name="ShelfPane"
253254
Grid.Row="0"

src/Files.Shared/Utils/IAsyncInitialize.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
// Copyright (c) Files Community
2-
// Licensed under the MIT License.
3-
4-
using System.Threading;
1+
using System.Threading;
52
using System.Threading.Tasks;
63

74
namespace Files.Shared.Utils

src/Files.Shared/Utils/IWrapper.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace Files.Shared.Utils
2+
{
3+
/// <summary>
4+
/// Wraps and exposes <typeparamref name="T"/> implementation for access.
5+
/// </summary>
6+
/// <typeparam name="T">The wrapped type.</typeparam>
7+
public interface IWrapper<out T>
8+
{
9+
/// <summary>
10+
/// Gets the inner member wrapped by the implementation.
11+
/// </summary>
12+
T Inner { get; }
13+
}
14+
}

0 commit comments

Comments
 (0)