diff --git a/src/Files.App.Launcher/Files.App.Launcher.vcxproj b/src/Files.App.Launcher/Files.App.Launcher.vcxproj index 93862737d1f1..87b940ed867a 100644 --- a/src/Files.App.Launcher/Files.App.Launcher.vcxproj +++ b/src/Files.App.Launcher/Files.App.Launcher.vcxproj @@ -89,7 +89,7 @@ - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _DEBUG;_CONSOLE;%(PreprocessorDefinitions);_SILENCE_EXPERIMENTAL_COROUTINE_DEPRECATION_WARNINGS MultiThreadedDebug @@ -103,7 +103,7 @@ true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_SILENCE_EXPERIMENTAL_COROUTINE_DEPRECATION_WARNINGS MultiThreaded diff --git a/src/Files.App/Data/Items/EncodingItem.cs b/src/Files.App/Data/Items/EncodingItem.cs index 51ec61b121e9..361ffe6abe62 100644 --- a/src/Files.App/Data/Items/EncodingItem.cs +++ b/src/Files.App/Data/Items/EncodingItem.cs @@ -50,7 +50,7 @@ public EncodingItem(Encoding encoding, string name) //reference: https://en.wikipedia.org/wiki/Windows_code_page //East Asian "shift_jis", //Japanese - "gb2312", //Simplified Chinese + "gb18030", //Simplified Chinese "big5", //Traditional Chinese "ks_c_5601-1987", //Korean diff --git a/src/Files.App/Data/Models/CurrentInstanceViewModel.cs b/src/Files.App/Data/Models/CurrentInstanceViewModel.cs index ffc6a977f291..f77555489655 100644 --- a/src/Files.App/Data/Models/CurrentInstanceViewModel.cs +++ b/src/Files.App/Data/Models/CurrentInstanceViewModel.cs @@ -146,6 +146,20 @@ public bool IsPageTypeLibrary } } + private string? zipEncodingName; + public string? ZipEncodingName + { + get => zipEncodingName; + set => SetProperty(ref zipEncodingName, value); + } + + private bool isZipEncodingUndetermined; + public bool IsZipEncodingUndetermined + { + get => isZipEncodingUndetermined; + set => SetProperty(ref isZipEncodingUndetermined, value); + } + public bool CanCopyPathInPage { get => !isPageTypeMtpDevice && !isPageTypeRecycleBin && isPageTypeNotHome && !isPageTypeSearchResults && !IsPageTypeReleaseNotes && !IsPageTypeSettings; diff --git a/src/Files.App/Data/Models/DirectoryPropertiesViewModel.cs b/src/Files.App/Data/Models/DirectoryPropertiesViewModel.cs index 1109998f2b6a..9845a7fad451 100644 --- a/src/Files.App/Data/Models/DirectoryPropertiesViewModel.cs +++ b/src/Files.App/Data/Models/DirectoryPropertiesViewModel.cs @@ -1,6 +1,11 @@ // Copyright (c) Files Community // Licensed under the MIT License. +using Files.App.Data.Items; +using Files.App.Utils.Storage; +using Microsoft.Extensions.Logging; +using System.ComponentModel; +using System.Text; using System.Windows.Input; namespace Files.App.ViewModels.UserControls @@ -9,6 +14,8 @@ public sealed partial class StatusBarViewModel : ObservableObject { private IContentPageContext ContentPageContext { get; } = Ioc.Default.GetRequiredService(); private IDevToolsSettingsService DevToolsSettingsService = Ioc.Default.GetRequiredService(); + private readonly IStorageArchiveService StorageArchiveService = Ioc.Default.GetRequiredService(); + private CurrentInstanceViewModel? InstanceViewModel => ContentPageContext.ShellPage?.InstanceViewModel; // The first branch will always be the active one. public const int ACTIVE_BRANCH_INDEX = 0; @@ -81,6 +88,26 @@ public string ExtendedStatusInfo set => SetProperty(ref _ExtendedStatusInfo, value); } + private bool _IsZipEncodingSelectorVisible; + public bool IsZipEncodingSelectorVisible + { + get => _IsZipEncodingSelectorVisible; + set => SetProperty(ref _IsZipEncodingSelectorVisible, value); + } + + public List ZipEncodingOptions { get; } = EncodingItem.Defaults.ToList(); + + private EncodingItem? _SelectedZipEncoding; + public EncodingItem? SelectedZipEncoding + { + get => _SelectedZipEncoding; + set + { + if (SetProperty(ref _SelectedZipEncoding, value) && value is not null) + _ = OnZipEncodingChangedAsync(value); + } + } + public bool ShowOpenInIDEButton { get @@ -112,6 +139,24 @@ public StatusBarViewModel() break; } }; + + SubscribeToShellPage(); + ContentPageContext.PropertyChanged += OnContentPageContextPropertyChanged; + } + + private void OnContentPageContextPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(ContentPageContext.ShellPage)) + { + UnsubscribeFromInstanceViewModel(); + SubscribeToShellPage(); + } + } + + private void SubscribeToShellPage() + { + SubscribeToInstanceViewModel(); + _ = UpdateZipEncodingStateAsync(); } public void UpdateGitInfo(bool isGitRepository, string? repositoryPath, BranchItem? head) @@ -164,5 +209,97 @@ public Task ExecuteDeleteBranch(string? branchName) { return GitHelpers.DeleteBranchAsync(_gitRepositoryPath, GitBranchDisplayName, branchName); } + + public async Task UpdateZipEncodingStateAsync() + { + var instanceVM = InstanceViewModel; + if (instanceVM is null) + return; + + if (!instanceVM.IsPageTypeZipFolder) + { + IsZipEncodingSelectorVisible = false; + ZipStorageFolder.CurrentEncoding = null; + return; + } + + var workingDir = ContentPageContext.ShellPage?.ShellViewModel.WorkingDirectory; + if (string.IsNullOrEmpty(workingDir) || !ZipStorageFolder.IsZipPath(workingDir)) + return; + + try + { + var isUndetermined = await StorageArchiveService.IsEncodingUndeterminedAsync(workingDir); + instanceVM.IsZipEncodingUndetermined = isUndetermined; + + if (!isUndetermined) + { + IsZipEncodingSelectorVisible = false; + return; + } + + var detected = await StorageArchiveService.DetectEncodingAsync(workingDir); + if (detected is not null) + { + instanceVM.ZipEncodingName = detected.WebName; + EncodingItem? ZipEncodingItem = ZipEncodingOptions.FirstOrDefault(e => + e.Encoding?.WebName.Equals(detected.WebName, StringComparison.OrdinalIgnoreCase) == true); + if(ZipEncodingItem == null) + { + ZipEncodingItem = new EncodingItem(detected, detected.EncodingName); + } + ZipEncodingOptions.Add(ZipEncodingItem); + SelectedZipEncoding = ZipEncodingItem; + } + else + { + instanceVM.ZipEncodingName = null; + SelectedZipEncoding = ZipEncodingOptions.FirstOrDefault(e => e.Encoding is null); + } + + IsZipEncodingSelectorVisible = true; + } + catch (Exception ex) + { + App.Logger.LogError(ex, "Error checking zip encoding."); + IsZipEncodingSelectorVisible = false; + } + } + + private async Task OnZipEncodingChangedAsync(EncodingItem encodingItem) + { + if (ContentPageContext.ShellPage is null) + return; + + var workingDir = ContentPageContext.ShellPage.ShellViewModel.WorkingDirectory; + if (string.IsNullOrEmpty(workingDir)) + return; + + ZipStorageFolder.CurrentEncoding = encodingItem.Encoding; + + ContentPageContext.ShellPage.ShellViewModel.RefreshItems(null); + } + + internal void SubscribeToInstanceViewModel() + { + var instanceVM = InstanceViewModel; + if (instanceVM is not null) + instanceVM.PropertyChanged += OnInstanceViewModelPropertyChanged; + } + + internal void UnsubscribeFromInstanceViewModel() + { + var instanceVM = InstanceViewModel; + if (instanceVM is not null) + instanceVM.PropertyChanged -= OnInstanceViewModelPropertyChanged; + } + + private void OnInstanceViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName is nameof(CurrentInstanceViewModel.IsPageTypeZipFolder)) + { + _ = UpdateZipEncodingStateAsync(); + } + } } } diff --git a/src/Files.App/Services/Storage/StorageArchiveService.cs b/src/Files.App/Services/Storage/StorageArchiveService.cs index 991519dc89ef..3ecd0a9dde89 100644 --- a/src/Files.App/Services/Storage/StorageArchiveService.cs +++ b/src/Files.App/Services/Storage/StorageArchiveService.cs @@ -361,7 +361,9 @@ public async Task IsEncodingUndeterminedAsync(string archiveFilePath) { using (ZipFile zipFile = new ZipFile(archiveFilePath)) { - return !zipFile.Cast().All(entry => entry.IsUnicodeText); + return !zipFile.Cast().All( + entry => entry.IsUnicodeText || entry.Name.All(c => char.IsAscii(c)) + ); } } catch (Exception ex) diff --git a/src/Files.App/UserControls/StatusBar.xaml b/src/Files.App/UserControls/StatusBar.xaml index 95d7f9e32fde..510e0611f968 100644 --- a/src/Files.App/UserControls/StatusBar.xaml +++ b/src/Files.App/UserControls/StatusBar.xaml @@ -30,6 +30,7 @@ + @@ -193,10 +194,57 @@ Background="{ThemeResource DividerStrokeColorDefaultBrush}" /> + + +