Skip to content

Commit

Permalink
#209: Sponge 프로그램 내 모든 문자열을 resx로 분리
Browse files Browse the repository at this point in the history
  • Loading branch information
rkttu committed May 13, 2024
1 parent 12d74fb commit 8fb77e5
Show file tree
Hide file tree
Showing 9 changed files with 284 additions and 74 deletions.
10 changes: 6 additions & 4 deletions src/Sponge/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModel="clr-namespace:Sponge.ViewModels"
xmlns:componentModels="clr-namespace:System.ComponentModel;assembly=netstandard"
xmlns:res="clr-namespace:TableCloth.Resources;assembly=TableCloth.Resources"
mc:Ignorable="d"
Style="{DynamicResource MainWindowStyle}"
WindowStartupLocation="CenterScreen" Topmost="True"
Title="Sponge" Width="320" Height="200" MinWidth="320" MinHeight="160" Closing="Window_Closing" Loaded="Window_Loaded">
<Window.Resources>
<componentModels:BackgroundWorker
Expand All @@ -28,10 +30,10 @@
<ColumnDefinition Width="50*"/>
<ColumnDefinition Width="50*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="이 프로그램은 식탁보 실행과 함께 복사된 공동 인증서 파일을 복구 불가능하게 삭제할 수 있도록 돕습니다." TextWrapping="Wrap" Margin="10,0,10,0" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="2"/>
<CheckBox x:Name="UseSecureDelete" Content="여러 번 덮어써서 삭제하기" Margin="10,10,0,0" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" IsChecked="{Binding Path=OverwriteMultipleTimes}" IsEnabled="{Binding Path=WorkInProgress, Converter={StaticResource InverseBooleanConverter}}" />
<TextBlock Text="{x:Static res:UIStringResources.Sponge_Introduction}" TextWrapping="Wrap" Margin="10,0,10,0" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="2"/>
<CheckBox x:Name="UseSecureDelete" Content="{x:Static res:UIStringResources.Sponge_OverwriteMultipleTimes}" Margin="10,10,0,0" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" IsChecked="{Binding Path=OverwriteMultipleTimes}" IsEnabled="{Binding Path=WorkInProgress, Converter={StaticResource InverseBooleanConverter}}" />
<ProgressBar x:Name="ProgressBar" Height="15" Margin="10,0,10,0" VerticalAlignment="Center" Grid.ColumnSpan="2" Grid.Row="1" Value="{Binding Path=ProgressRate}" Visibility="{Binding Path=WorkInProgress, Converter={StaticResource BooleanToVisibilityConverter}}" />
<Button x:Name="DeleteButton" Content="삭제하기" Margin="10,10,10,10" Grid.Row="3" Click="DeleteButton_Click" IsEnabled="{Binding Path=WorkInProgress, Converter={StaticResource InverseBooleanConverter}}" />
<Button x:Name="QuitButton" Content="종료하기" Margin="10,10,10,10" Grid.Column="1" Grid.Row="3" Click="QuitButton_Click" IsEnabled="{Binding Path=WorkInProgress, Converter={StaticResource InverseBooleanConverter}}" />
<Button x:Name="DeleteButton" Content="{x:Static res:UIStringResources.Sponge_PerformDelete}" Margin="10,10,10,10" Grid.Row="3" Click="DeleteButton_Click" IsEnabled="{Binding Path=WorkInProgress, Converter={StaticResource InverseBooleanConverter}}" />
<Button x:Name="QuitButton" Content="{x:Static res:UIStringResources.Sponge_Exit}" Margin="10,10,10,10" Grid.Column="1" Grid.Row="3" Click="QuitButton_Click" IsEnabled="{Binding Path=WorkInProgress, Converter={StaticResource InverseBooleanConverter}}" />
</Grid>
</Window>
143 changes: 74 additions & 69 deletions src/Sponge/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Windows;
using TableCloth;
using TableCloth.Models.Answers;
using TableCloth.Resources;

namespace Sponge
{
Expand All @@ -30,71 +31,6 @@ public MainWindowViewModel ViewModel
public BackgroundWorker BackgroundWorker
=> (BackgroundWorker)Resources["BackgroundWorker"];

private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var args = e.Argument as RemovePrivacyFilesRequest;

if (args == default)
return;

var repeatCount = args.OverwriteCount;
var succeedFileCount = 0;
var failedFileCount = 0;

try
{
BackgroundWorker.ReportProgress(0, "공동 인증서 파일을 검색 중입니다...");
var localLowNpkiDirectoryPath = NativeMethods.GetKnownFolderPath(NativeMethods.LocalLowFolderGuid);

if (!Directory.Exists(localLowNpkiDirectoryPath))
return;

var fileList = Directory.GetFiles(localLowNpkiDirectoryPath, "*.*", SearchOption.AllDirectories)
.Where(x =>
{
return
string.Equals(".der", System.IO.Path.GetExtension(x), StringComparison.OrdinalIgnoreCase) ||
string.Equals(".key", System.IO.Path.GetExtension(x), StringComparison.OrdinalIgnoreCase) ||
string.Equals(".pfx", System.IO.Path.GetExtension(x), StringComparison.OrdinalIgnoreCase);
})
.Distinct()
.ToList();

var totalFileCount = fileList.Count;
var processedFileCount = 0;

foreach (var eachFile in fileList)
{
var fileInfo = new FileInfo(eachFile);

try
{
fileInfo.SecureDelete(repeatCount, SecureDeleteObfuscationMode.All);
succeedFileCount++;
}
catch
{
failedFileCount++;
}
finally
{
BackgroundWorker.ReportProgress((int)((double)++processedFileCount / totalFileCount * 100d), $"파일 삭제 완료 ({totalFileCount}개 중 {processedFileCount}개)");
}
}
}
finally
{
var fragments = new List<string>();
if (succeedFileCount > 0)
fragments.Add($"{succeedFileCount}개 파일 삭제 완료");
if (failedFileCount > 0)
fragments.Add($"{failedFileCount}개 파일 삭제 실패");

BackgroundWorker.ReportProgress(100, $"모든 작업을 완료했습니다. ({string.Join(", ", fragments)})");
e.Result = new RemovePrivacyFilesResult(succeedFileCount, failedFileCount);
}
}

private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ViewModel.ProgressRate = e.ProgressPercentage;
Expand All @@ -106,25 +42,25 @@ private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerComplet

if (e.Cancelled)
{
MessageBox.Show(this, "작업이 도중에 취소되었습니다.", Title, MessageBoxButton.OK, MessageBoxImage.Warning, MessageBoxResult.OK);
MessageBox.Show(this, ErrorStrings.Error_Sponge_TaskCancelled, Title, MessageBoxButton.OK, MessageBoxImage.Warning, MessageBoxResult.OK);
return;
}

if (e.Error != null)
{
var actualError = e.Error is AggregateException ? e.Error.InnerException : e.Error;
MessageBox.Show(this, $"예기치 않은 오류가 발생했습니다. {actualError.Message}", Title, MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
MessageBox.Show(this, string.Format(ErrorStrings.Error_Sponge_UnexpectedErrorOccurred, actualError.Message), Title, MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
return;
}

var result = e.Result as RemovePrivacyFilesResult;
if (result == null)
{
MessageBox.Show(this, "작업을 완료했지만 결과를 확인할 수 없습니다.", Title, MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
MessageBox.Show(this, ErrorStrings.Error_Sponge_NoCompatibleResultFound, Title, MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
return;
}

MessageBox.Show(this, $"총 {result.SucceedFileCount}개의 파일을 삭제했고, {result.FailedFileCount}개의 파일을 삭제하지 못했습니다.", Title, MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
MessageBox.Show(this, result.Message, Title, MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
Close();
}

Expand Down Expand Up @@ -183,5 +119,74 @@ private SpongeAnswers DeserializeSpongeAnswersJson(Stream targetStream)

return JsonSerializer.Deserialize<SpongeAnswers>(targetStream);
}

private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var args = e.Argument as RemovePrivacyFilesRequest;

if (args == default)
return;

var repeatCount = args.OverwriteCount;
var succeedFileCount = 0;
var failedFileCount = 0;

try
{
BackgroundWorker.ReportProgress(0, UIStringResources.Sponge_WorkInProgress);
var localLowNpkiDirectoryPath = NativeMethods.GetKnownFolderPath(NativeMethods.LocalLowFolderGuid);

if (!Directory.Exists(localLowNpkiDirectoryPath))
return;

var fileList = Directory.GetFiles(localLowNpkiDirectoryPath, "*.*", SearchOption.AllDirectories)
.Where(x =>
{
return
string.Equals(".der", System.IO.Path.GetExtension(x), StringComparison.OrdinalIgnoreCase) ||
string.Equals(".key", System.IO.Path.GetExtension(x), StringComparison.OrdinalIgnoreCase) ||
string.Equals(".pfx", System.IO.Path.GetExtension(x), StringComparison.OrdinalIgnoreCase);
})
.Distinct()
.ToList();

var totalFileCount = fileList.Count;
var processedFileCount = 0;

foreach (var eachFile in fileList)
{
var fileInfo = new FileInfo(eachFile);

try
{
fileInfo.SecureDelete(repeatCount, SecureDeleteObfuscationMode.All);
succeedFileCount++;
}
catch
{
failedFileCount++;
}
finally
{
BackgroundWorker.ReportProgress((int)((double)++processedFileCount / totalFileCount * 100d), string.Format(UIStringResources.Sponge_DeleteProgressMessage, totalFileCount, processedFileCount));
}
}
}
finally
{
var fragments = new List<string>();
if (succeedFileCount > 0)
fragments.Add(string.Format(UIStringResources.Sponge_DeletedFileCount, succeedFileCount));
if (failedFileCount > 0)
fragments.Add(string.Format(UIStringResources.Sponge_DeleteFailedFileCount, failedFileCount));

var message = fragments.Count() > 0 ?
$"{UIStringResources.Sponge_OperationCompleted} ({string.Join(", ", fragments)})" :
UIStringResources.Sponge_OperationCompleted_WithNoResult;

BackgroundWorker.ReportProgress(100, message);
e.Result = new RemovePrivacyFilesResult(succeedFileCount, failedFileCount, message);
}
}
}
}
4 changes: 3 additions & 1 deletion src/Sponge/Models/RemovePrivacyFilesResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@
{
public class RemovePrivacyFilesResult
{
public RemovePrivacyFilesResult(int succeedFileCount, int failedFileCount)
public RemovePrivacyFilesResult(int succeedFileCount, int failedFileCount, string message)
{
SucceedFileCount = succeedFileCount;
FailedFileCount = failedFileCount;
Message = message;
}

public int SucceedFileCount { get; } = 0;
public int FailedFileCount { get; } = 0;
public int TotalFileCount => SucceedFileCount + FailedFileCount;
public string Message { get; } = string.Empty;

public override string ToString() => $"Succeed: {SucceedFileCount}, Failed: {FailedFileCount}";
}
Expand Down
27 changes: 27 additions & 0 deletions src/TableCloth.Resources/ErrorStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions src/TableCloth.Resources/ErrorStrings.ko.resx
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,16 @@ Ctrl 키나 Shift 키를 누른 채로 선택하거나, 파일 선택 창에서
<data name="Error_Sponge_Missing" xml:space="preserve">
<value>스폰지 실행 파일을 찾을 수 없습니다. 프로그램을 다시 설치해주세요.</value>
</data>
<data name="Error_Sponge_NoCompatibleResultFound" xml:space="preserve">
<value>작업을 완료했지만 결과를 확인할 수 없습니다.</value>
<comment>This item is used by Sponge</comment>
</data>
<data name="Error_Sponge_TaskCancelled" xml:space="preserve">
<value>작업이 도중에 취소되었습니다.</value>
<comment>This item is used by Sponge</comment>
</data>
<data name="Error_Sponge_UnexpectedErrorOccurred" xml:space="preserve">
<value>예기치 않은 오류가 발생했습니다. {0}</value>
<comment>This item is used by Sponge</comment>
</data>
</root>
12 changes: 12 additions & 0 deletions src/TableCloth.Resources/ErrorStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -273,4 +273,16 @@ If the device or disk is stolen, forensics may reveal sensitive data, so be sure
<data name="Error_Sponge_Missing" xml:space="preserve">
<value>The sponge executable file was not found, please reinstall the program.</value>
</data>
<data name="Error_Sponge_NoCompatibleResultFound" xml:space="preserve">
<value>Completed the action, but can't see the result.</value>
<comment>This item is used by Sponge</comment>
</data>
<data name="Error_Sponge_TaskCancelled" xml:space="preserve">
<value>The job was canceled midway through.</value>
<comment>This item is used by Sponge</comment>
</data>
<data name="Error_Sponge_UnexpectedErrorOccurred" xml:space="preserve">
<value>An unexpected error occurred: {0}</value>
<comment>This item is used by Sponge</comment>
</data>
</root>
90 changes: 90 additions & 0 deletions src/TableCloth.Resources/UIStringResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 8fb77e5

Please sign in to comment.