Skip to content

Feature: Added hashes tab to properties window #11521

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 33 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5879194
Introduce Hash page
0x5bfa Mar 1, 2023
8406d90
Update src/Files.App/Strings/en-US/Resources.resw
0x5bfa Mar 1, 2023
ba8290e
Merge branch 'main' into 5bfa/introduce-hashprops
0x5bfa Mar 1, 2023
1a1caf7
Revert unrelated changes
0x5bfa Mar 1, 2023
e599cb0
Merge branch '5bfa/introduce-hashprops' of https://github.com/onein52…
0x5bfa Mar 1, 2023
62e2139
Merge branch 'main' into 5bfa/introduce-hashprops
0x5bfa Mar 1, 2023
1e1f24c
Fix build issues
0x5bfa Mar 1, 2023
8949bc7
Merge branch '5bfa/introduce-hashprops' of https://github.com/onein52…
0x5bfa Mar 1, 2023
cb88e71
Added some mockup code
0x5bfa Mar 1, 2023
b3c6288
Merge branch 'main' into 5bfa/introduce-hashprops
0x5bfa Mar 1, 2023
96ddf12
Add collection for listing hashes
0x5bfa Mar 1, 2023
c64c71b
Merge branch '5bfa/introduce-hashprops' of https://github.com/onein52…
0x5bfa Mar 1, 2023
9da531a
Merge branch 'main' into 5bfa/introduce-hashprops
0x5bfa Mar 1, 2023
6f79819
Merge branch 'main' into 5bfa/introduce-hashprops
0x5bfa Mar 2, 2023
f3c0807
Update hashes page and fix NavigationStoreStyle
0x5bfa Mar 2, 2023
8b2c25d
Merge branch '5bfa/introduce-hashprops' of https://github.com/onein52…
0x5bfa Mar 2, 2023
cecac16
Merge branch 'main' into 5bfa/introduce-hashprops
0x5bfa Mar 2, 2023
9dac8dc
Merge branch 'main' into 5bfa/introduce-hashprops
yaira2 Mar 2, 2023
b0da4c1
Added tooltip
yaira2 Mar 2, 2023
615ea90
Fixed copy button
yaira2 Mar 2, 2023
38879d5
Try to make the file loader being high performance when loading large…
0x5bfa Mar 2, 2023
da51c14
Merge branch '5bfa/introduce-hashprops' of https://github.com/onein52…
0x5bfa Mar 2, 2023
9ed28f5
Fix: Fix an issue where hash copy button doesn't work
0x5bfa Mar 4, 2023
ec681a9
Merge branch 'main' into 5bfa/introduce-hashprops
0x5bfa Mar 4, 2023
1ba83f4
Feature: Add loading button on hashes page
0x5bfa Mar 4, 2023
d48b772
Merge branch '5bfa/introduce-hashprops' of https://github.com/onein52…
0x5bfa Mar 4, 2023
104e159
Fix: Update the behaviour when loading hashes and displaying error on…
0x5bfa Mar 4, 2023
101bba7
Feature: Introduce CancellationToken to hashes page
0x5bfa Mar 5, 2023
9fcffc8
Fix: Change the way of firing file content loader method
0x5bfa Mar 5, 2023
8979965
Trial and error 1
0x5bfa Mar 6, 2023
541cbbe
Trial and error 2
0x5bfa Mar 8, 2023
0d39d79
Fix up
0x5bfa Mar 8, 2023
e51a28f
Fix up again
0x5bfa Mar 8, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 162 additions & 13 deletions src/Files.App/ResourceDictionaries/NavigationViewStoreStyle.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Dark">
<StaticResource x:Key="NavigationViewItemBackgroundPointerOver" ResourceKey="SubtleFillColorSecondaryBrush" />
<StaticResource x:Key="NavigationViewItemBackgroundPressed" ResourceKey="SubtleFillColorTertiaryBrush" />
<StaticResource x:Key="NavigationViewItemBackgroundPointerOver" ResourceKey="ControlFillColorSecondaryBrush" />
<StaticResource x:Key="NavigationViewItemBackgroundPressed" ResourceKey="ControlFillColorTertiaryBrush" />
<StaticResource x:Key="NavigationViewItemBackgroundSelected" ResourceKey="ControlFillColorDefaultBrush" />
<StaticResource x:Key="NavigationViewItemBackgroundSelectedPointerOver" ResourceKey="ControlFillColorDefaultBrush" />
<StaticResource x:Key="NavigationViewItemBackgroundSelectedPressed" ResourceKey="ControlFillColorDefaultBrush" />
Expand Down Expand Up @@ -66,6 +66,7 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="primitives:NavigationViewItemPresenter">

<Grid
x:Name="LayoutRoot"
MinHeight="{ThemeResource NavigationViewItemOnLeftMinHeight}"
Expand All @@ -78,21 +79,20 @@
</Grid.BackgroundTransition>

<!-- Selection indicator -->
<Rectangle
x:Name="SelectionIndicator"
Width="{ThemeResource NavigationViewSelectionIndicatorWidth}"
Height="{ThemeResource NavigationViewSelectionIndicatorHeight}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Fill="{ThemeResource NavigationViewSelectionIndicatorForeground}"
Opacity="0.0"
RadiusX="{ThemeResource NavigationViewSelectionIndicatorRadius}"
RadiusY="{ThemeResource NavigationViewSelectionIndicatorRadius}" />
<Grid HorizontalAlignment="Left" VerticalAlignment="Center">
<Rectangle
x:Name="SelectionIndicator"
Width="{ThemeResource NavigationViewSelectionIndicatorWidth}"
Height="{ThemeResource NavigationViewSelectionIndicatorHeight}"
Fill="{ThemeResource NavigationViewSelectionIndicatorForeground}"
Opacity="0.0"
RadiusX="{ThemeResource NavigationViewSelectionIndicatorRadius}"
RadiusY="{ThemeResource NavigationViewSelectionIndicatorRadius}" />
</Grid>

<!-- Content grid -->
<ContentPresenter
x:Name="ContentPresenter"
Grid.Column="1"
MinHeight="{ThemeResource NavigationViewItemOnLeftMinHeight}"
Margin="{ThemeResource NavigationViewItemContentPresenterMargin}"
Padding="{TemplateBinding Padding}"
Expand Down Expand Up @@ -170,6 +170,155 @@
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>

</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

<Style TargetType="NavigationViewItem">
<Setter Property="Foreground" Value="{ThemeResource NavigationViewItemForeground}" />
<Setter Property="Background" Value="{ThemeResource NavigationViewItemBackground}" />
<Setter Property="BorderBrush" Value="{ThemeResource NavigationViewItemBorderBrush}" />
<Setter Property="BorderThickness" Value="{StaticResource NavigationViewItemBorderThickness}" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="Margin" Value="{ThemeResource NavigationViewItemMargin}" />
<Setter Property="UseSystemFocusVisuals" Value="True" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="TabNavigation" Value="Once" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="NavigationViewItem">

<Grid x:Name="NVIRootGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.BackgroundTransition>
<BrushTransition Duration="0:0:0.083" />
</Grid.BackgroundTransition>

<!-- Primitive NavigationViewItem Presenter -->
<primitives:NavigationViewItemPresenter
x:Name="NavigationViewItemPresenter"
Margin="{TemplateBinding Margin}"
Padding="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"
ContentTransitions="{TemplateBinding ContentTransitions}"
Control.IsTemplateFocusTarget="True"
CornerRadius="{TemplateBinding CornerRadius}"
Foreground="{TemplateBinding Foreground}"
Icon="{TemplateBinding Icon}"
IsTabStop="false"
UseSystemFocusVisuals="{TemplateBinding UseSystemFocusVisuals}" />

<!-- NavigationViewItem's MenuItems Repeater -->
<ItemsRepeater
x:Name="NavigationViewItemMenuItemsHost"
Grid.Row="1"
Visibility="Collapsed">
<ItemsRepeater.Layout>
<StackLayout Orientation="Vertical" />
</ItemsRepeater.Layout>
</ItemsRepeater>

<!-- NavigationViewItem's Flyout -->
<FlyoutBase.AttachedFlyout>
<Flyout x:Name="ChildrenFlyout" Placement="RightEdgeAlignedTop">
<Flyout.FlyoutPresenterStyle>
<Style TargetType="FlyoutPresenter">
<Setter Property="Padding" Value="{ThemeResource NavigationViewItemChildrenMenuFlyoutPadding}" />
<!-- Set negative top margin to make the flyout align exactly with the button -->
<Setter Property="Margin" Value="0,-4,0,0" />
<Setter Property="ScrollViewer.HorizontalScrollMode" Value="Auto" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.ZoomMode" Value="Disabled" />
<Setter Property="CornerRadius" Value="{ThemeResource OverlayCornerRadius}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="FlyoutPresenter">
<ScrollViewer
x:Name="ScrollViewer"
AutomationProperties.AccessibilityView="Raw"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
<ContentPresenter
x:Name="ContentPresenter"
Padding="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}"
CornerRadius="{TemplateBinding CornerRadius}" />
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Flyout.FlyoutPresenterStyle>
<Grid x:Name="FlyoutRootGrid">
<Grid x:Name="FlyoutContentGrid" />
</Grid>
</Flyout>
</FlyoutBase.AttachedFlyout>

<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ItemOnNavigationViewListPositionStates">
<VisualState x:Name="OnLeftNavigation">
<VisualState.Setters>
<Setter Target="NavigationViewItemPresenter.Style" Value="{StaticResource MUX_NavigationViewItemPresenterStyleWhenOnLeftPane}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="OnLeftNavigationReveal">
<VisualState.Setters>
<Setter Target="NavigationViewItemPresenter.Style" Value="{StaticResource MUX_NavigationViewItemPresenterStyleWhenOnLeftPaneWithRevealFocus}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="OnTopNavigationPrimary">
<VisualState.Setters>
<Setter Target="NavigationViewItemPresenter.Margin" Value="{ThemeResource TopNavigationViewItemMargin}" />
<Setter Target="NavigationViewItemPresenter.Style" Value="{StaticResource MUX_NavigationViewItemPresenterStyleWhenOnTopPane}" />
<Setter Target="ChildrenFlyout.Placement" Value="BottomEdgeAlignedLeft" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="OnTopNavigationPrimaryReveal">
<VisualState.Setters>
<Setter Target="NavigationViewItemPresenter.Margin" Value="{ThemeResource TopNavigationViewItemMargin}" />
<Setter Target="NavigationViewItemPresenter.Style" Value="{StaticResource MUX_NavigationViewItemPresenterStyleWhenOnTopPaneWithRevealFocus}" />
<Setter Target="ChildrenFlyout.Placement" Value="BottomEdgeAlignedLeft" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="OnTopNavigationOverflow">
<VisualState.Setters>
<Setter Target="NavigationViewItemPresenter.Style" Value="{StaticResource MUX_NavigationViewItemPresenterStyleWhenOnTopPaneOverflow}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>

</ControlTemplate>
</Setter.Value>
</Setter>
Expand Down
6 changes: 6 additions & 0 deletions src/Files.App/Strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -2607,4 +2607,10 @@
<data name="MultiSelect" xml:space="preserve">
<value>Multiselect</value>
</data>
<data name="Hashes" xml:space="preserve">
<value>Hashes</value>
</data>
<data name="UnableToCalcHashes" xml:space="preserve">
<value>Unable to calculate hashes due to a system error</value>
</data>
</root>
116 changes: 116 additions & 0 deletions src/Files.App/ViewModels/Properties/HashesViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.WinUI;
using Files.App.Filesystem;
using Files.Backend.Models;
using Files.Shared.Helpers;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace Files.App.ViewModels.Properties
{
public class HashesViewModel : ObservableObject, IDisposable
{
public HashesViewModel(ListedItem item)
{
Item = item;
Hashes = new();
CanAccessFile = true;
CancellationTokenSource = new();
LoadAndCalcHashesCommand = new(ExecuteLoadAndCalcHashesCommandAsync);
}

public ListedItem Item { get; }

private bool _canAccessFile;
public bool CanAccessFile
{
get => _canAccessFile;
set => SetProperty(ref _canAccessFile, value);
}

private HashInfoItem _selectedItem;
public HashInfoItem SelectedItem
{
get => _selectedItem;
set => SetProperty(ref _selectedItem, value);
}

public ObservableCollection<HashInfoItem> Hashes { get; set; }

private Stream _stream;

public AsyncRelayCommand LoadAndCalcHashesCommand { get; set; }

public CancellationTokenSource CancellationTokenSource { get; set; }

private bool _isLoading;
public bool IsLoading
{
get => _isLoading;
set => SetProperty(ref _isLoading, value);
}

public async Task ExecuteLoadAndCalcHashesCommandAsync(CancellationToken cancellationToken)
{
try
{
IsLoading = true;

_stream = File.OpenRead(Item.ItemPath);

CanAccessFile = true;
await GetHashesAsync(cancellationToken);
}
catch (OperationCanceledException)
{
CanAccessFile = false;
}
catch (Exception)
{
CanAccessFile = false;
}
finally
{
IsLoading = false;
}
}

private async Task GetHashesAsync(CancellationToken cancellationToken)
{
Hashes.Add(new()
{
Algorithm = "MD5",
HashValue = await ChecksumHelpers.CreateMD5(_stream, cancellationToken),
});
Hashes.Add(new()
{
Algorithm = "SHA1",
HashValue = await ChecksumHelpers.CreateSHA1(_stream, cancellationToken),
});
Hashes.Add(new()
{
Algorithm = "SHA256",
HashValue = await ChecksumHelpers.CreateSHA256(_stream, cancellationToken),
});
Hashes.Add(new()
{
Algorithm = "SHA384",
HashValue = await ChecksumHelpers.CreateSHA384(_stream, cancellationToken),
});
Hashes.Add(new()
{
Algorithm = "SHA512",
HashValue = await ChecksumHelpers.CreateSHA512(_stream, cancellationToken),
});
}

public void Dispose()
{
CancellationTokenSource.Cancel();
}
}
}
Loading