Skip to content

Feature: Added advanced options when creating archives #10524

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 29 commits into from
Nov 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
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
156 changes: 156 additions & 0 deletions src/Files.App/Dialogs/CreateArchiveDialog.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<ContentDialog
x:Class="Files.App.Dialogs.CreateArchiveDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:helpers="using:Files.App.Helpers"
xmlns:local="using:Files.App.Dialogs"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="{helpers:ResourceString Name=CreateArchive}"
d:DesignHeight="300"
d:DesignWidth="400"
CloseButtonText="{helpers:ResourceString Name=Cancel}"
Closing="ContentDialog_Closing"
CornerRadius="{StaticResource OverlayCornerRadius}"
DefaultButton="Primary"
IsPrimaryButtonEnabled="True"
Loaded="ContentDialog_Loaded"
PrimaryButtonText="{helpers:ResourceString Name=Create}"
RequestedTheme="{x:Bind helpers:ThemeHelper.RootTheme}"
Style="{StaticResource DefaultContentDialogStyle}"
mc:Ignorable="d">
<StackPanel Width="440" Spacing="8">

<!-- Archive Name -->
<Grid
Padding="12"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
ColumnSpacing="8"
CornerRadius="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
VerticalAlignment="Center"
Text="{helpers:ResourceString Name=Name}" />
<TextBox
x:Name="FileNameBox"
Grid.Column="1"
Width="260"
PlaceholderText="{helpers:ResourceString Name=EnterName}"
Text="{x:Bind ViewModel.FileName, Mode=TwoWay}" />
</Grid>

<!-- Archive Options -->
<Grid
Padding="12"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
ColumnSpacing="8"
CornerRadius="4"
RowSpacing="12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<!-- Archive Format -->
<TextBlock
Grid.Row="0"
Grid.Column="0"
VerticalAlignment="Center"
Text="{helpers:ResourceString Name=Format}" />
<ComboBox
x:Name="FileFormatSelector"
Grid.Row="0"
Grid.Column="1"
Width="160"
ItemsSource="{x:Bind ViewModel.FileFormats}"
SelectedItem="{x:Bind ViewModel.FileFormat, Mode=TwoWay}"
DisplayMemberPath="Label"
SelectedValuePath="Key" />

<!-- Compression Level -->
<TextBlock
Grid.Row="1"
Grid.Column="0"
VerticalAlignment="Center"
Text="{helpers:ResourceString Name=CompressionLevel}" />
<ComboBox
x:Name="CompressionLevelSelector"
Grid.Row="1"
Grid.Column="1"
Width="160"
HorizontalAlignment="Right"
DisplayMemberPath="Label"
ItemsSource="{x:Bind ViewModel.CompressionLevels}"
SelectedItem="{x:Bind ViewModel.CompressionLevel, Mode=TwoWay}"
SelectedValuePath="Key" />

<!-- Splitting Size -->
<TextBlock
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Center"
Text="{helpers:ResourceString Name=SplittingSize}" />
<ComboBox
x:Name="SplittingSizeSelector"
Grid.Row="2"
Grid.Column="1"
Width="160"
HorizontalAlignment="Right"
IsEnabled="{x:Bind ViewModel.CanSplit, Mode=OneWay}"
ItemsSource="{x:Bind ViewModel.SplittingSizes}"
SelectedItem="{x:Bind ViewModel.SplittingSize, Mode=TwoWay}"
SelectedValuePath="Key">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="local:SplittingSizeItem">
<StackPanel Orientation="Horizontal" Spacing="4">
<TextBlock Text="{x:Bind Label}" />
<TextBlock Text="{x:Bind Separator}" Visibility="{Binding IsDropDownOpen, ElementName=SplittingSizeSelector}" />
<TextBlock Text="{x:Bind Description}" Visibility="{Binding IsDropDownOpen, ElementName=SplittingSizeSelector}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>

<!-- Encryption Options -->
<Expander
HorizontalAlignment="Stretch"
Header="{helpers:ResourceString Name=Encryption}"
IsExpanded="{x:Bind ViewModel.UseEncryption, Mode=TwoWay}">
<Expander.Content>
<Grid Width="400">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
VerticalAlignment="Center"
Text="{helpers:ResourceString Name=Password}" />
<PasswordBox
x:Name="PasswordBox"
Grid.Column="1"
Width="260"
IsPasswordRevealButtonEnabled="True"
Loading="PasswordBox_Loading"
Password="{x:Bind ViewModel.Password, Mode=TwoWay}"
PasswordRevealMode="Peek"
PlaceholderText="{helpers:ResourceString Name=Password}" />
</Grid>
</Expander.Content>
</Expander>
</StackPanel>
</ContentDialog>
208 changes: 208 additions & 0 deletions src/Files.App/Dialogs/CreateArchiveDialog.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Files.App.Extensions;
using Files.App.Filesystem.Archive;
using Files.Backend.Models;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Windows.Foundation.Metadata;

namespace Files.App.Dialogs
{
public sealed partial class CreateArchiveDialog : ContentDialog
{
private bool canCreate = false;
public bool CanCreate => canCreate;

public string FileName
{
get => ViewModel.FileName;
set => ViewModel.FileName = value;
}

public bool UseEncryption
{
get => ViewModel.UseEncryption;
set => ViewModel.UseEncryption = value;
}

public string Password
{
get => ViewModel.Password;
set => ViewModel.Password = value;
}

public ArchiveFormats FileFormat
{
get => ViewModel.FileFormat.Key;
set => ViewModel.FileFormat = ViewModel.FileFormats.First(format => format.Key == value);
}

public ArchiveCompressionLevels CompressionLevel
{
get => ViewModel.CompressionLevel.Key;
set => ViewModel.CompressionLevel = ViewModel.CompressionLevels.First(level => level.Key == value);
}

public ArchiveSplittingSizes SplittingSize
{
get => ViewModel.SplittingSize.Key;
set => ViewModel.SplittingSize = ViewModel.SplittingSizes.First(size => size.Key == value);
}

private DialogViewModel ViewModel { get; } = new();

public CreateArchiveDialog()
{
InitializeComponent();
ViewModel.PropertyChanged += ViewModel_PropertyChanged;
}

public new Task<ContentDialogResult> ShowAsync() => SetContentDialogRoot(this).ShowAsync().AsTask();

private static ContentDialog SetContentDialogRoot(ContentDialog contentDialog)
{
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
contentDialog.XamlRoot = App.Window.Content.XamlRoot; // WinUi3
return contentDialog;
}

private void ContentDialog_Loaded(object _, RoutedEventArgs e)
{
Loaded -= ContentDialog_Loaded;

FileNameBox.SelectionStart = FileNameBox.Text.Length;
FileNameBox.Focus(FocusState.Programmatic);
}
private void ContentDialog_Closing(ContentDialog _, ContentDialogClosingEventArgs e)
{
Closing -= ContentDialog_Closing;
ViewModel.PropertyChanged -= ViewModel_PropertyChanged;

if (e.Result is ContentDialogResult.Primary)
canCreate = true;
}

private void PasswordBox_Loading(FrameworkElement _, object e)
=> PasswordBox.Focus(FocusState.Programmatic);

private void ViewModel_PropertyChanged(object? _, PropertyChangedEventArgs e)
{
if (e.PropertyName is nameof(DialogViewModel.UseEncryption) && ViewModel.UseEncryption)
PasswordBox.Focus(FocusState.Programmatic);
}

private class DialogViewModel : ObservableObject
{
private string fileName = string.Empty;
public string FileName
{
get => fileName;
set => SetProperty(ref fileName, value);
}

private FileFormatItem fileFormat;
public FileFormatItem FileFormat
{
get => fileFormat;
set
{
if (SetProperty(ref fileFormat, value))
OnPropertyChanged(nameof(CanSplit));
}
}

private CompressionLevelItem compressionLevel;
public CompressionLevelItem CompressionLevel
{
get => compressionLevel;
set => SetProperty(ref compressionLevel, value);
}

public bool CanSplit => FileFormat.Key is ArchiveFormats.SevenZip;

private SplittingSizeItem splittingSize;
public SplittingSizeItem SplittingSize
{
get => splittingSize;
set => SetProperty(ref splittingSize, value);
}

private bool useEncryption = false;
public bool UseEncryption
{
get => useEncryption;
set
{
if (SetProperty(ref useEncryption, value) && !useEncryption)
Password = string.Empty;
}
}

private string password = string.Empty;
public string Password
{
get => password;
set
{
if (SetProperty(ref password, value) && !string.IsNullOrEmpty(password))
UseEncryption = true;
}
}

public IImmutableList<FileFormatItem> FileFormats { get; } = new List<FileFormatItem>
{
new(ArchiveFormats.Zip, ".zip"),
new(ArchiveFormats.SevenZip, ".7z"),
}.ToImmutableList();

public IImmutableList<CompressionLevelItem> CompressionLevels { get; } = new List<CompressionLevelItem>
{
new CompressionLevelItem(ArchiveCompressionLevels.Ultra, "CompressionLevelUltra".GetLocalizedResource()),
new CompressionLevelItem(ArchiveCompressionLevels.High, "CompressionLevelHigh".GetLocalizedResource()),
new CompressionLevelItem(ArchiveCompressionLevels.Normal, "CompressionLevelNormal".GetLocalizedResource()),
new CompressionLevelItem(ArchiveCompressionLevels.Low, "CompressionLevelLow".GetLocalizedResource()),
new CompressionLevelItem(ArchiveCompressionLevels.Fast, "CompressionLevelFast".GetLocalizedResource()),
new CompressionLevelItem(ArchiveCompressionLevels.None, "CompressionLevelNone".GetLocalizedResource()),
}.ToImmutableList();

public IImmutableList<SplittingSizeItem> SplittingSizes { get; } = new List<SplittingSizeItem>
{
new(ArchiveSplittingSizes.None, "Do not split".GetLocalizedResource()),
new(ArchiveSplittingSizes.Mo10, ToSizeText(10)),
new(ArchiveSplittingSizes.Mo100, ToSizeText(100)),
new(ArchiveSplittingSizes.Cd650, ToSizeText(650), "CD".GetLocalizedResource()),
new(ArchiveSplittingSizes.Cd700, ToSizeText(700), "CD".GetLocalizedResource()),
new(ArchiveSplittingSizes.Mo1024, ToSizeText(1024)),
new(ArchiveSplittingSizes.Fat4092, ToSizeText(4092), "FAT".GetLocalizedResource()),
new(ArchiveSplittingSizes.Dvd4480, ToSizeText(4480), "DVD".GetLocalizedResource()),
new(ArchiveSplittingSizes.Mo5120, ToSizeText(5120)),
new(ArchiveSplittingSizes.Dvd8128, ToSizeText(8128), "DVD".GetLocalizedResource()),
new(ArchiveSplittingSizes.Bd23040, ToSizeText(23040), "Bluray".GetLocalizedResource()),
}.ToImmutableList();

public DialogViewModel()
{
fileFormat = FileFormats.First(format => format.Key is ArchiveFormats.Zip);
compressionLevel = CompressionLevels.First(level => level.Key is ArchiveCompressionLevels.Normal);
splittingSize = SplittingSizes.First(size => size.Key is ArchiveSplittingSizes.None);
}

private static string ToSizeText(ulong megaBytes) => ByteSize.FromMebiBytes(megaBytes).ShortString;

public record FileFormatItem(ArchiveFormats Key, string Label);

public record CompressionLevelItem(ArchiveCompressionLevels Key, string Label);
}
}

internal record SplittingSizeItem(ArchiveSplittingSizes Key, string Label, string Description = "")
{
public string Separator => string.IsNullOrEmpty(Description) ? string.Empty : "-";
}
}
12 changes: 12 additions & 0 deletions src/Files.App/Filesystem/Archive/ArchiveCompressionLevels.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Files.App.Filesystem.Archive
{
public enum ArchiveCompressionLevels
{
Ultra,
High,
Normal,
Low,
Fast,
None,
}
}
Loading