Skip to content

Commit dbe3202

Browse files
authored
Feature: Added hashes tab to properties window (#11521)
1 parent 639f511 commit dbe3202

File tree

9 files changed

+559
-19
lines changed

9 files changed

+559
-19
lines changed

src/Files.App/ResourceDictionaries/NavigationViewStoreStyle.xaml

Lines changed: 162 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
<ResourceDictionary.ThemeDictionaries>
77
<ResourceDictionary x:Key="Dark">
8-
<StaticResource x:Key="NavigationViewItemBackgroundPointerOver" ResourceKey="SubtleFillColorSecondaryBrush" />
9-
<StaticResource x:Key="NavigationViewItemBackgroundPressed" ResourceKey="SubtleFillColorTertiaryBrush" />
8+
<StaticResource x:Key="NavigationViewItemBackgroundPointerOver" ResourceKey="ControlFillColorSecondaryBrush" />
9+
<StaticResource x:Key="NavigationViewItemBackgroundPressed" ResourceKey="ControlFillColorTertiaryBrush" />
1010
<StaticResource x:Key="NavigationViewItemBackgroundSelected" ResourceKey="ControlFillColorDefaultBrush" />
1111
<StaticResource x:Key="NavigationViewItemBackgroundSelectedPointerOver" ResourceKey="ControlFillColorDefaultBrush" />
1212
<StaticResource x:Key="NavigationViewItemBackgroundSelectedPressed" ResourceKey="ControlFillColorDefaultBrush" />
@@ -66,6 +66,7 @@
6666
<Setter Property="Template">
6767
<Setter.Value>
6868
<ControlTemplate TargetType="primitives:NavigationViewItemPresenter">
69+
6970
<Grid
7071
x:Name="LayoutRoot"
7172
MinHeight="{ThemeResource NavigationViewItemOnLeftMinHeight}"
@@ -78,21 +79,20 @@
7879
</Grid.BackgroundTransition>
7980

8081
<!-- Selection indicator -->
81-
<Rectangle
82-
x:Name="SelectionIndicator"
83-
Width="{ThemeResource NavigationViewSelectionIndicatorWidth}"
84-
Height="{ThemeResource NavigationViewSelectionIndicatorHeight}"
85-
HorizontalAlignment="Left"
86-
VerticalAlignment="Center"
87-
Fill="{ThemeResource NavigationViewSelectionIndicatorForeground}"
88-
Opacity="0.0"
89-
RadiusX="{ThemeResource NavigationViewSelectionIndicatorRadius}"
90-
RadiusY="{ThemeResource NavigationViewSelectionIndicatorRadius}" />
82+
<Grid HorizontalAlignment="Left" VerticalAlignment="Center">
83+
<Rectangle
84+
x:Name="SelectionIndicator"
85+
Width="{ThemeResource NavigationViewSelectionIndicatorWidth}"
86+
Height="{ThemeResource NavigationViewSelectionIndicatorHeight}"
87+
Fill="{ThemeResource NavigationViewSelectionIndicatorForeground}"
88+
Opacity="0.0"
89+
RadiusX="{ThemeResource NavigationViewSelectionIndicatorRadius}"
90+
RadiusY="{ThemeResource NavigationViewSelectionIndicatorRadius}" />
91+
</Grid>
9192

9293
<!-- Content grid -->
9394
<ContentPresenter
9495
x:Name="ContentPresenter"
95-
Grid.Column="1"
9696
MinHeight="{ThemeResource NavigationViewItemOnLeftMinHeight}"
9797
Margin="{ThemeResource NavigationViewItemContentPresenterMargin}"
9898
Padding="{TemplateBinding Padding}"
@@ -170,6 +170,155 @@
170170
</VisualStateGroup>
171171
</VisualStateManager.VisualStateGroups>
172172
</Grid>
173+
174+
</ControlTemplate>
175+
</Setter.Value>
176+
</Setter>
177+
</Style>
178+
179+
<Style TargetType="NavigationViewItem">
180+
<Setter Property="Foreground" Value="{ThemeResource NavigationViewItemForeground}" />
181+
<Setter Property="Background" Value="{ThemeResource NavigationViewItemBackground}" />
182+
<Setter Property="BorderBrush" Value="{ThemeResource NavigationViewItemBorderBrush}" />
183+
<Setter Property="BorderThickness" Value="{StaticResource NavigationViewItemBorderThickness}" />
184+
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
185+
<Setter Property="FontWeight" Value="Normal" />
186+
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
187+
<Setter Property="Margin" Value="{ThemeResource NavigationViewItemMargin}" />
188+
<Setter Property="UseSystemFocusVisuals" Value="True" />
189+
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
190+
<Setter Property="TabNavigation" Value="Once" />
191+
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
192+
<Setter Property="Template">
193+
<Setter.Value>
194+
<ControlTemplate TargetType="NavigationViewItem">
195+
196+
<Grid x:Name="NVIRootGrid">
197+
<Grid.RowDefinitions>
198+
<RowDefinition Height="*" />
199+
<RowDefinition Height="Auto" />
200+
</Grid.RowDefinitions>
201+
<Grid.BackgroundTransition>
202+
<BrushTransition Duration="0:0:0.083" />
203+
</Grid.BackgroundTransition>
204+
205+
<!-- Primitive NavigationViewItem Presenter -->
206+
<primitives:NavigationViewItemPresenter
207+
x:Name="NavigationViewItemPresenter"
208+
Margin="{TemplateBinding Margin}"
209+
Padding="{TemplateBinding Padding}"
210+
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
211+
VerticalAlignment="{TemplateBinding VerticalAlignment}"
212+
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
213+
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
214+
Background="{TemplateBinding Background}"
215+
BorderBrush="{TemplateBinding BorderBrush}"
216+
BorderThickness="{TemplateBinding BorderThickness}"
217+
Content="{TemplateBinding Content}"
218+
ContentTemplate="{TemplateBinding ContentTemplate}"
219+
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
220+
ContentTransitions="{TemplateBinding ContentTransitions}"
221+
Control.IsTemplateFocusTarget="True"
222+
CornerRadius="{TemplateBinding CornerRadius}"
223+
Foreground="{TemplateBinding Foreground}"
224+
Icon="{TemplateBinding Icon}"
225+
IsTabStop="false"
226+
UseSystemFocusVisuals="{TemplateBinding UseSystemFocusVisuals}" />
227+
228+
<!-- NavigationViewItem's MenuItems Repeater -->
229+
<ItemsRepeater
230+
x:Name="NavigationViewItemMenuItemsHost"
231+
Grid.Row="1"
232+
Visibility="Collapsed">
233+
<ItemsRepeater.Layout>
234+
<StackLayout Orientation="Vertical" />
235+
</ItemsRepeater.Layout>
236+
</ItemsRepeater>
237+
238+
<!-- NavigationViewItem's Flyout -->
239+
<FlyoutBase.AttachedFlyout>
240+
<Flyout x:Name="ChildrenFlyout" Placement="RightEdgeAlignedTop">
241+
<Flyout.FlyoutPresenterStyle>
242+
<Style TargetType="FlyoutPresenter">
243+
<Setter Property="Padding" Value="{ThemeResource NavigationViewItemChildrenMenuFlyoutPadding}" />
244+
<!-- Set negative top margin to make the flyout align exactly with the button -->
245+
<Setter Property="Margin" Value="0,-4,0,0" />
246+
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Auto" />
247+
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
248+
<Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto" />
249+
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
250+
<Setter Property="ScrollViewer.ZoomMode" Value="Disabled" />
251+
<Setter Property="CornerRadius" Value="{ThemeResource OverlayCornerRadius}" />
252+
<Setter Property="Template">
253+
<Setter.Value>
254+
<ControlTemplate TargetType="FlyoutPresenter">
255+
<ScrollViewer
256+
x:Name="ScrollViewer"
257+
AutomationProperties.AccessibilityView="Raw"
258+
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
259+
HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
260+
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
261+
VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
262+
ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
263+
<ContentPresenter
264+
x:Name="ContentPresenter"
265+
Padding="{TemplateBinding Padding}"
266+
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
267+
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
268+
Background="{TemplateBinding Background}"
269+
BorderBrush="{TemplateBinding BorderBrush}"
270+
BorderThickness="{TemplateBinding BorderThickness}"
271+
Content="{TemplateBinding Content}"
272+
ContentTemplate="{TemplateBinding ContentTemplate}"
273+
ContentTransitions="{TemplateBinding ContentTransitions}"
274+
CornerRadius="{TemplateBinding CornerRadius}" />
275+
</ScrollViewer>
276+
</ControlTemplate>
277+
</Setter.Value>
278+
</Setter>
279+
</Style>
280+
</Flyout.FlyoutPresenterStyle>
281+
<Grid x:Name="FlyoutRootGrid">
282+
<Grid x:Name="FlyoutContentGrid" />
283+
</Grid>
284+
</Flyout>
285+
</FlyoutBase.AttachedFlyout>
286+
287+
<VisualStateManager.VisualStateGroups>
288+
<VisualStateGroup x:Name="ItemOnNavigationViewListPositionStates">
289+
<VisualState x:Name="OnLeftNavigation">
290+
<VisualState.Setters>
291+
<Setter Target="NavigationViewItemPresenter.Style" Value="{StaticResource MUX_NavigationViewItemPresenterStyleWhenOnLeftPane}" />
292+
</VisualState.Setters>
293+
</VisualState>
294+
<VisualState x:Name="OnLeftNavigationReveal">
295+
<VisualState.Setters>
296+
<Setter Target="NavigationViewItemPresenter.Style" Value="{StaticResource MUX_NavigationViewItemPresenterStyleWhenOnLeftPaneWithRevealFocus}" />
297+
</VisualState.Setters>
298+
</VisualState>
299+
<VisualState x:Name="OnTopNavigationPrimary">
300+
<VisualState.Setters>
301+
<Setter Target="NavigationViewItemPresenter.Margin" Value="{ThemeResource TopNavigationViewItemMargin}" />
302+
<Setter Target="NavigationViewItemPresenter.Style" Value="{StaticResource MUX_NavigationViewItemPresenterStyleWhenOnTopPane}" />
303+
<Setter Target="ChildrenFlyout.Placement" Value="BottomEdgeAlignedLeft" />
304+
</VisualState.Setters>
305+
</VisualState>
306+
<VisualState x:Name="OnTopNavigationPrimaryReveal">
307+
<VisualState.Setters>
308+
<Setter Target="NavigationViewItemPresenter.Margin" Value="{ThemeResource TopNavigationViewItemMargin}" />
309+
<Setter Target="NavigationViewItemPresenter.Style" Value="{StaticResource MUX_NavigationViewItemPresenterStyleWhenOnTopPaneWithRevealFocus}" />
310+
<Setter Target="ChildrenFlyout.Placement" Value="BottomEdgeAlignedLeft" />
311+
</VisualState.Setters>
312+
</VisualState>
313+
<VisualState x:Name="OnTopNavigationOverflow">
314+
<VisualState.Setters>
315+
<Setter Target="NavigationViewItemPresenter.Style" Value="{StaticResource MUX_NavigationViewItemPresenterStyleWhenOnTopPaneOverflow}" />
316+
</VisualState.Setters>
317+
</VisualState>
318+
</VisualStateGroup>
319+
</VisualStateManager.VisualStateGroups>
320+
</Grid>
321+
173322
</ControlTemplate>
174323
</Setter.Value>
175324
</Setter>

src/Files.App/Strings/en-US/Resources.resw

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2604,4 +2604,10 @@
26042604
<data name="MultiSelect" xml:space="preserve">
26052605
<value>Multiselect</value>
26062606
</data>
2607+
<data name="Hashes" xml:space="preserve">
2608+
<value>Hashes</value>
2609+
</data>
2610+
<data name="UnableToCalcHashes" xml:space="preserve">
2611+
<value>Unable to calculate hashes due to a system error</value>
2612+
</data>
26072613
</root>
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
using CommunityToolkit.Mvvm.ComponentModel;
2+
using CommunityToolkit.Mvvm.Input;
3+
using CommunityToolkit.WinUI;
4+
using Files.App.Filesystem;
5+
using Files.Backend.Models;
6+
using Files.Shared.Helpers;
7+
using System;
8+
using System.Collections.ObjectModel;
9+
using System.IO;
10+
using System.Threading;
11+
using System.Threading.Tasks;
12+
13+
namespace Files.App.ViewModels.Properties
14+
{
15+
public class HashesViewModel : ObservableObject, IDisposable
16+
{
17+
public HashesViewModel(ListedItem item)
18+
{
19+
Item = item;
20+
Hashes = new();
21+
CanAccessFile = true;
22+
CancellationTokenSource = new();
23+
LoadAndCalcHashesCommand = new(ExecuteLoadAndCalcHashesCommandAsync);
24+
}
25+
26+
public ListedItem Item { get; }
27+
28+
private bool _canAccessFile;
29+
public bool CanAccessFile
30+
{
31+
get => _canAccessFile;
32+
set => SetProperty(ref _canAccessFile, value);
33+
}
34+
35+
private HashInfoItem _selectedItem;
36+
public HashInfoItem SelectedItem
37+
{
38+
get => _selectedItem;
39+
set => SetProperty(ref _selectedItem, value);
40+
}
41+
42+
public ObservableCollection<HashInfoItem> Hashes { get; set; }
43+
44+
private Stream _stream;
45+
46+
public AsyncRelayCommand LoadAndCalcHashesCommand { get; set; }
47+
48+
public CancellationTokenSource CancellationTokenSource { get; set; }
49+
50+
private bool _isLoading;
51+
public bool IsLoading
52+
{
53+
get => _isLoading;
54+
set => SetProperty(ref _isLoading, value);
55+
}
56+
57+
public async Task ExecuteLoadAndCalcHashesCommandAsync(CancellationToken cancellationToken)
58+
{
59+
try
60+
{
61+
IsLoading = true;
62+
63+
_stream = File.OpenRead(Item.ItemPath);
64+
65+
CanAccessFile = true;
66+
await GetHashesAsync(cancellationToken);
67+
}
68+
catch (OperationCanceledException)
69+
{
70+
CanAccessFile = false;
71+
}
72+
catch (Exception)
73+
{
74+
CanAccessFile = false;
75+
}
76+
finally
77+
{
78+
IsLoading = false;
79+
}
80+
}
81+
82+
private async Task GetHashesAsync(CancellationToken cancellationToken)
83+
{
84+
Hashes.Add(new()
85+
{
86+
Algorithm = "MD5",
87+
HashValue = await ChecksumHelpers.CreateMD5(_stream, cancellationToken),
88+
});
89+
Hashes.Add(new()
90+
{
91+
Algorithm = "SHA1",
92+
HashValue = await ChecksumHelpers.CreateSHA1(_stream, cancellationToken),
93+
});
94+
Hashes.Add(new()
95+
{
96+
Algorithm = "SHA256",
97+
HashValue = await ChecksumHelpers.CreateSHA256(_stream, cancellationToken),
98+
});
99+
Hashes.Add(new()
100+
{
101+
Algorithm = "SHA384",
102+
HashValue = await ChecksumHelpers.CreateSHA384(_stream, cancellationToken),
103+
});
104+
Hashes.Add(new()
105+
{
106+
Algorithm = "SHA512",
107+
HashValue = await ChecksumHelpers.CreateSHA512(_stream, cancellationToken),
108+
});
109+
}
110+
111+
public void Dispose()
112+
{
113+
CancellationTokenSource.Cancel();
114+
}
115+
}
116+
}

0 commit comments

Comments
 (0)