Skip to content

Commit ad68647

Browse files
authored
Merge pull request #510 from IridiumIO/UIRefresh
Rebuild UI - Switch from ModernWPF to WPFUI - Major UI rewrite - Use Dependency Injection / Hosting - Add support for queuing multiple folders for compression at once - Lots of small and large refactors that I've lost track of - Add support for multiple queued folders
2 parents 57a03f2 + eddd8f7 commit ad68647

File tree

76 files changed

+4362
-2898
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+4362
-2898
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,3 +362,6 @@ MigrationBackup/
362362
# Fody - auto-generated XML schema
363363
FodyWeavers.xsd
364364
/CompactGUI/My Project/launchSettings.json
365+
366+
# IntelliJ
367+
.idea/

CompactGUI.Core/Analyser.vb

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Public Class Analyser
1515
FolderName = folder
1616
End Sub
1717

18-
18+
<MeasurePerformance.IL.Weaver.MeasurePerformance>
1919
Public Async Function AnalyseFolder(cancellationToken As CancellationToken) As Task(Of Boolean)
2020
Dim allFiles = Await Task.Run(Function() Directory.EnumerateFiles(FolderName, "*", New EnumerationOptions() With {.RecurseSubdirectories = True, .IgnoreInaccessible = True}).AsShortPathNames, cancellationToken).ConfigureAwait(False)
2121
Dim fileDetails As New List(Of AnalysedFileDetails)
@@ -33,7 +33,7 @@ Public Class Analyser
3333
SyncLock fileDetails
3434
fileDetails.Add(details)
3535
End SyncLock
36-
If details.CompressionMode <> CompressionAlgorithm.NO_COMPRESSION Then
36+
If details.CompressionMode <> WOFCompressionAlgorithm.NO_COMPRESSION Then
3737
Interlocked.Increment(compressedFilesCount)
3838
End If
3939
Interlocked.Add(localCompressedBytes, details.CompressedSize)
@@ -63,7 +63,7 @@ Public Class Analyser
6363
If compSize < 0 Then
6464
compSize = unCompSize ' GetFileSizeOnDisk failed, fall back to unCompSize
6565
End If
66-
Dim cLevel As CompressionAlgorithm = If(compSize = unCompSize, CompressionAlgorithm.NO_COMPRESSION, DetectCompression(fInfo))
66+
Dim cLevel As WOFCompressionAlgorithm = If(compSize = unCompSize, WOFCompressionAlgorithm.NO_COMPRESSION, DetectCompression(fInfo))
6767

6868
Return New AnalysedFileDetails With {.FileName = file, .CompressedSize = compSize, .UncompressedSize = unCompSize, .CompressionMode = cLevel, .FileInfo = fInfo}
6969
Catch ex As IOException
@@ -80,7 +80,7 @@ Public Class Analyser
8080
Dim extRes As New Concurrent.ConcurrentDictionary(Of String, ExtensionResult)
8181
Parallel.ForEach(FileCompressionDetailsList,
8282
Sub(fl)
83-
Dim xt = New IO.FileInfo(fl.FileName).Extension
83+
Dim xt = New FileInfo(fl.FileName).Extension
8484
If fl.UncompressedSize = 0 Then Return
8585

8686
extRes.AddOrUpdate(xt,
@@ -110,16 +110,16 @@ Public Class Analyser
110110
End Function
111111

112112

113-
Private Function DetectCompression(fInfo As FileInfo) As CompressionAlgorithm
113+
Private Function DetectCompression(fInfo As FileInfo) As WOFCompressionAlgorithm
114114

115115
Dim isextFile As Integer
116116
Dim prov As ULong
117117
Dim info As WOF_FILE_COMPRESSION_INFO_V1
118118
Dim buf As UInt16 = 8
119119

120120
Dim ret = WofIsExternalFile(fInfo.FullName, isextFile, prov, info, buf)
121-
If isextFile = 0 Then info.Algorithm = CompressionAlgorithm.NO_COMPRESSION
122-
If (fInfo.Attributes And 2048) <> 0 Then info.Algorithm = CompressionAlgorithm.LZNT1
121+
If isextFile = 0 Then info.Algorithm = WOFCompressionAlgorithm.NO_COMPRESSION
122+
If (fInfo.Attributes And 2048) <> 0 Then info.Algorithm = WOFCompressionAlgorithm.LZNT1
123123
Return info.Algorithm
124124

125125
End Function

CompactGUI.Core/Compactor.vb

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Imports System.Threading
55

66
Public Class Compactor : Implements IDisposable
77

8-
Public Sub New(folder As String, cLevel As CompressionAlgorithm, excludedFilesTypes As String())
8+
Public Sub New(folder As String, cLevel As WOFCompressionAlgorithm, excludedFilesTypes As String())
99

1010
If Not verifyFolder(folder).isValid Then Return
1111

@@ -21,7 +21,7 @@ Public Class Compactor : Implements IDisposable
2121

2222
Private _workingDir As String
2323
Private _excludedFileTypes() As String
24-
Private _WOFCompressionLevel As CompressionAlgorithm
24+
Private _WOFCompressionLevel As WOFCompressionAlgorithm
2525

2626
Private _EFInfo As WOF_FILE_COMPRESSION_INFO_V1
2727
Private _EFInfoPtr As IntPtr
@@ -34,7 +34,7 @@ Public Class Compactor : Implements IDisposable
3434

3535

3636

37-
Public Async Function RunCompactAsync(Optional progressMonitor As IProgress(Of (percentageProgress As Integer, currentFile As String)) = Nothing, Optional MaxParallelism As Integer = 1) As Task(Of Boolean)
37+
Public Async Function RunCompactAsync(Optional progressMonitor As IProgress(Of CompressionProgress) = Nothing, Optional MaxParallelism As Integer = 1) As Task(Of Boolean)
3838
If _cancellationTokenSource.IsCancellationRequested Then Return False
3939

4040
Dim FilesList = Await BuildWorkingFilesList()
@@ -49,6 +49,12 @@ Public Class Compactor : Implements IDisposable
4949

5050
Dim paraOptions As New ParallelOptions With {.MaxDegreeOfParallelism = MaxParallelism}
5151

52+
'For Each file In FilesList
53+
' Threading.Thread.Sleep(2000)
54+
' Await PauseAndProcessFile(file.Item1, _cancellationTokenSource.Token, file.Item2, totalFilesSize, progressMonitor)
55+
'Next
56+
57+
5258
Await Parallel.ForEachAsync(FilesList, paraOptions,
5359
Function(file, _ctx) As ValueTask
5460
If _ctx.IsCancellationRequested Then Return ValueTask.FromCanceled(_ctx)
@@ -66,7 +72,7 @@ Public Class Compactor : Implements IDisposable
6672
Return True
6773
End Function
6874

69-
Private Async Function PauseAndProcessFile(file As String, _ctx As CancellationToken, fileSize As Long, totalFilesSize As Long, Optional progressMonitor As IProgress(Of (percentageProgress As Integer, currentFile As String)) = Nothing) As Task
75+
Private Async Function PauseAndProcessFile(file As String, _ctx As CancellationToken, fileSize As Long, totalFilesSize As Long, Optional progressMonitor As IProgress(Of CompressionProgress) = Nothing) As Task
7076

7177
If _ctx.IsCancellationRequested Then Return
7278
Try
@@ -84,7 +90,7 @@ Public Class Compactor : Implements IDisposable
8490
Interlocked.Add(_processedFilesBytes, fileSize)
8591
Dim incremented = _processedFilesBytes
8692

87-
progressMonitor?.Report((CInt(((incremented / totalFilesSize) * 100)), file))
93+
progressMonitor?.Report(New CompressionProgress(CInt(((incremented / totalFilesSize) * 100)), file))
8894

8995
End Function
9096

@@ -140,7 +146,7 @@ Public Class Compactor : Implements IDisposable
140146
Public Sub Dispose() Implements IDisposable.Dispose
141147
_cancellationTokenSource.Dispose()
142148
_pauseSemaphore.Dispose()
143-
If _EFInfoPtr <> IntPtr.Zero Then
149+
If Not _EFInfoPtr.Equals(IntPtr.Zero) Then
144150
Marshal.FreeHGlobal(_EFInfoPtr)
145151
_EFInfoPtr = IntPtr.Zero
146152
End If

CompactGUI.Core/SharedMethods.vb

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ Public Module SharedMethods
77

88
Function verifyFolder(folder As String) As (isValid As Boolean, msg As String)
99

10-
If Not IO.Directory.Exists(folder) Then : Return (False, "Directory does not exist")
11-
ElseIf folder.Contains((Environment.GetFolderPath(Environment.SpecialFolder.Windows))) Then : Return (False, "Cannot compress system directory")
10+
If Not Directory.Exists(folder) Then : Return (False, "Directory does not exist")
11+
ElseIf folder.ToLowerInvariant.Contains((Environment.GetFolderPath(Environment.SpecialFolder.Windows)).ToLowerInvariant) Then : Return (False, "Cannot compress system directory")
1212
ElseIf folder.EndsWith(":\") Then : Return (False, "Cannot compress root directory")
1313
ElseIf IsDirectoryEmptySafe(folder) Then : Return (False, "This directory is either empty or you are not authorized to access its files.")
1414
ElseIf IsOneDriveFolder(folder) Then : Return (False, "Files synced with OneDrive cannot be compressed as they use a different storage structure")
@@ -22,27 +22,10 @@ Public Module SharedMethods
2222
Function IsDirectoryEmptySafe(folder As String)
2323

2424
Try
25-
Return Not IO.Directory.EnumerateFileSystemEntries(folder).Any()
25+
Return Not Directory.EnumerateFileSystemEntries(folder).Any()
2626

27-
For Each subdir In IO.Directory.EnumerateDirectories(folder)
28-
Try
29-
If Not IsDirectoryEmptySafe(subdir) Then Return False
30-
Catch ex As System.UnauthorizedAccessException
3127

32-
End Try
33-
Next
34-
35-
For Each file In IO.Directory.EnumerateFiles(folder)
36-
Try
37-
Return False
38-
Catch ex As System.UnauthorizedAccessException
39-
40-
End Try
41-
Next
42-
43-
Return True
44-
45-
Catch ex As System.UnauthorizedAccessException
28+
Catch ex As UnauthorizedAccessException
4629
MsgBox("You are not authorized to access some items in this folder." & vbCrLf & "Please try running CompactGUI as an administrator, otherwise these items will be skipped.", MsgBoxStyle.Exclamation, "Unauthorized Access")
4730
Return False
4831

@@ -138,16 +121,16 @@ Public Module SharedMethods
138121

139122
<DllImport("kernel32.dll", CharSet:=CharSet.Auto)>
140123
Private Function GetShortPathName(
141-
<MarshalAs(UnmanagedType.LPTStr)> ByVal path As String,
142-
<MarshalAs(UnmanagedType.LPTStr)> ByVal shortPath As StringBuilder, ByVal shortPathLength As Integer) As Integer
124+
<MarshalAs(UnmanagedType.LPTStr)> path As String,
125+
<MarshalAs(UnmanagedType.LPTStr)> shortPath As StringBuilder, shortPathLength As Integer) As Integer
143126

144127
End Function
145128

146129

147130

148131
<DllImport("kernel32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
149132
Private Function GetDiskFreeSpace(
150-
ByVal lpRootPathName As String,
133+
lpRootPathName As String,
151134
<Out> ByRef lpSectorsPerCluster As UInteger,
152135
<Out> ByRef lpBytesPerSector As UInteger,
153136
<Out> ByRef lpNumberOfFreeClusters As UInteger,

CompactGUI.Core/SharedObjects.vb

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
Public Class AnalysedFileDetails
22

3-
Public FileName As String
4-
Public UncompressedSize As Long
5-
Public CompressedSize As Long
6-
Public CompressionMode As CompressionAlgorithm
7-
Public FileInfo As IO.FileInfo
3+
Public Property FileName As String
4+
Public Property UncompressedSize As Long
5+
Public Property CompressedSize As Long
6+
Public Property CompressionMode As WOFCompressionAlgorithm
7+
Public Property FileInfo As IO.FileInfo
88
End Class
99

1010

@@ -23,7 +23,28 @@ Public Class ExtensionResult
2323

2424
End Class
2525

26-
Public Enum CompressionAlgorithm
26+
Public Structure CompressionProgress
27+
Public ProgressPercent As Integer
28+
Public FileName As String
29+
30+
Public Sub New(_progressPercent As Integer, _fileName As String)
31+
ProgressPercent = _progressPercent
32+
FileName = _fileName
33+
End Sub
34+
35+
End Structure
36+
37+
38+
39+
Public Enum CompressionMode
40+
XPRESS4K
41+
XPRESS8K
42+
XPRESS16K
43+
LZX
44+
None
45+
End Enum
46+
47+
Public Enum WOFCompressionAlgorithm
2748
NO_COMPRESSION = -2
2849
LZNT1 = -1
2950
XPRESS4K = 0

CompactGUI.Core/Uncompactor.vb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Public Class Uncompactor
99
Private _cancellationTokenSource As New CancellationTokenSource
1010

1111

12-
Public Async Function UncompactFiles(filesList As List(Of String), Optional progressMonitor As IProgress(Of (percentageProgress As Integer, currentFile As String)) = Nothing, Optional MaxParallelism As Integer = 1) As Task(Of Boolean)
12+
Public Async Function UncompactFiles(filesList As List(Of String), Optional progressMonitor As IProgress(Of CompressionProgress) = Nothing, Optional MaxParallelism As Integer = 1) As Task(Of Boolean)
1313

1414
Dim totalFiles As Integer = filesList.Count
1515

@@ -36,7 +36,7 @@ Public Class Uncompactor
3636
Return True
3737
End Function
3838

39-
Private Async Function PauseAndProcessFile(file As String, _ctx As CancellationToken, totalFiles As Integer, progressMonitor As IProgress(Of (percentageProgress As Integer, currentFile As String))) As Task
39+
Private Async Function PauseAndProcessFile(file As String, _ctx As CancellationToken, totalFiles As Integer, progressMonitor As IProgress(Of CompressionProgress)) As Task
4040
If _ctx.IsCancellationRequested Then Return
4141

4242
Try
@@ -51,7 +51,7 @@ Public Class Uncompactor
5151
Dim res = WOFDecompressFile(file)
5252
_processedFileCount.TryAdd(file, 1)
5353
Dim incremented = _processedFileCount.Count
54-
progressMonitor?.Report((CInt(((incremented / totalFiles) * 100)), file))
54+
progressMonitor?.Report(New CompressionProgress((CInt(((incremented / totalFiles) * 100))), file))
5555
End Function
5656

5757
Private Function WOFDecompressFile(path As String)

CompactGUI.Core/WOFHelper.vb

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,47 @@ Public Module WOFHelper
88
Public Function WOFConvertCompressionLevel(compressionlevel As Integer) As Integer
99

1010
Select Case compressionlevel
11-
Case 0 : Return CompressionAlgorithm.XPRESS4K
12-
Case 1 : Return CompressionAlgorithm.XPRESS8K
13-
Case 2 : Return CompressionAlgorithm.XPRESS16K
14-
Case 3 : Return CompressionAlgorithm.LZX
15-
Case Else : Return CompressionAlgorithm.XPRESS4K
11+
Case 0 : Return WOFCompressionAlgorithm.XPRESS4K
12+
Case 1 : Return WOFCompressionAlgorithm.XPRESS8K
13+
Case 2 : Return WOFCompressionAlgorithm.XPRESS16K
14+
Case 3 : Return WOFCompressionAlgorithm.LZX
15+
Case Else : Return WOFCompressionAlgorithm.XPRESS4K
1616
End Select
1717

1818
End Function
1919

20+
Public Function WOFConvertCompressionLevel(compressionlevel As CompressionMode) As Integer
21+
Select Case compressionlevel
22+
Case CompressionMode.XPRESS4K : Return WOFCompressionAlgorithm.XPRESS4K
23+
Case CompressionMode.XPRESS8K : Return WOFCompressionAlgorithm.XPRESS8K
24+
Case CompressionMode.XPRESS16K : Return WOFCompressionAlgorithm.XPRESS16K
25+
Case CompressionMode.LZX : Return WOFCompressionAlgorithm.LZX
26+
Case Else : Return WOFCompressionAlgorithm.XPRESS4K
27+
End Select
28+
End Function
29+
2030

21-
Public Function WOFConvertBackCompressionLevel(WOFCompressionLevel As CompressionAlgorithm) As Integer
31+
Public Function WOFConvertBackCompressionLevel(WOFCompressionLevel As WOFCompressionAlgorithm) As Integer
2232

2333
Select Case WOFCompressionLevel
24-
Case CompressionAlgorithm.XPRESS4K : Return 0
25-
Case CompressionAlgorithm.XPRESS8K : Return 1
26-
Case CompressionAlgorithm.XPRESS16K : Return 2
27-
Case CompressionAlgorithm.LZX : Return 3
34+
Case WOFCompressionAlgorithm.XPRESS4K : Return 0
35+
Case WOFCompressionAlgorithm.XPRESS8K : Return 1
36+
Case WOFCompressionAlgorithm.XPRESS16K : Return 2
37+
Case WOFCompressionAlgorithm.LZX : Return 3
2838
Case Else : Return 0
2939
End Select
3040

3141
End Function
3242

3343
Public Structure WOF_FILE_COMPRESSION_INFO_V1
34-
Public Algorithm As CompressionAlgorithm
44+
Public Algorithm As WOFCompressionAlgorithm
3545
Public Flags As ULong
3646
End Structure
3747

3848

3949
<DllImport("WofUtil.dll")>
4050
Friend Function WofIsExternalFile(
41-
<MarshalAs(UnmanagedType.LPWStr)> ByVal Filepath As String,
51+
<MarshalAs(UnmanagedType.LPWStr)> Filepath As String,
4252
<Out> ByRef IsExternalFile As Integer,
4353
<Out> ByRef Provider As UInteger,
4454
<Out> ByRef Info As WOF_FILE_COMPRESSION_INFO_V1,

CompactGUI.Watcher/BackgroundCompactor.vb

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
Imports System.Collections.ObjectModel
2-
Imports System.Runtime
32
Imports System.Threading
43

54
Public Class BackgroundCompactor
@@ -47,9 +46,9 @@ Public Class BackgroundCompactor
4746
End If
4847
End Sub
4948

50-
Public Function BeginCompacting(folder As String, compressionLevel As Core.CompressionAlgorithm) As Task(Of Boolean)
49+
Public Function BeginCompacting(folder As String, compressionLevel As Core.WOFCompressionAlgorithm) As Task(Of Boolean)
5150

52-
If compressionLevel = Core.CompressionAlgorithm.NO_COMPRESSION Then Return Task.FromResult(False)
51+
If compressionLevel = Core.WOFCompressionAlgorithm.NO_COMPRESSION Then Return Task.FromResult(False)
5352

5453
_compactor = New Core.Compactor(folder, compressionLevel, _excludedFileTypes)
5554

@@ -66,7 +65,7 @@ Public Class BackgroundCompactor
6665
Dim currentProcess As Process = Process.GetCurrentProcess()
6766
currentProcess.PriorityClass = ProcessPriorityClass.Idle
6867

69-
Dim foldersCopy As List(Of WatchedFolder) = folders.Where(Function(f) f.DecayPercentage <> 0 AndAlso f.CompressionLevel <> Core.CompressionAlgorithm.NO_COMPRESSION).ToList()
68+
Dim foldersCopy As List(Of WatchedFolder) = folders.Where(Function(f) f.DecayPercentage <> 0 AndAlso f.CompressionLevel <> Core.WOFCompressionAlgorithm.NO_COMPRESSION).ToList()
7069

7170
Dim monitorsCopy As List(Of FolderMonitor) = monitors.ToList()
7271

CompactGUI.Watcher/IdleDetector.vb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Public Class IdleDetector
1515
Public Shared Property IsEnabled As Boolean = True
1616

1717
Shared Sub New()
18-
_idletimer = New PeriodicTimer(TimeSpan.FromSeconds(2))
18+
_idletimer = New PeriodicTimer(TimeSpan.FromSeconds(5))
1919
End Sub
2020

2121
Public Shared Sub Start()
@@ -32,7 +32,7 @@ Public Class IdleDetector
3232
Private Shared Async Function IdleTimerDoWorkAsync() As Task
3333

3434
Try
35-
While Await IdleDetector._idletimer.WaitForNextTickAsync(_cts.Token) AndAlso Not _cts.Token.IsCancellationRequested
35+
While Await _idletimer.WaitForNextTickAsync(_cts.Token) AndAlso Not _cts.Token.IsCancellationRequested
3636

3737
If GetIdleTime() > 300 AndAlso Not Paused AndAlso IsEnabled Then
3838
RaiseEvent IsIdle(Nothing, EventArgs.Empty)

CompactGUI.Watcher/WatchedFolder.vb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,25 @@ Public Class WatchedFolder : Inherits ObservableObject
1414
Public Property LastSystemModifiedDate As DateTime
1515
Public Property LastCheckedDate As DateTime
1616
Public Property LastCheckedSize As Long
17-
Public Property CompressionLevel As Core.CompressionAlgorithm
17+
Public Property CompressionLevel As Core.WOFCompressionAlgorithm
1818
<JsonIgnore>
1919
Public Property IsWorking As Boolean
2020
Public ReadOnly Property DecayPercentage As Decimal
2121
Get
2222
If LastCompressedSize = 0 Then Return 1
23-
Return If(LastUncompressedSize = LastCompressedSize OrElse LastCompressedSize > LastUncompressedSize, 0D, Math.Clamp((LastCheckedSize - LastCompressedSize) / (LastUncompressedSize - LastCompressedSize), 0, 1))
23+
Return If(LastUncompressedSize = LastCompressedSize OrElse LastCompressedSize > LastUncompressedSize, 1D, Math.Clamp((LastCheckedSize - LastCompressedSize) / (LastUncompressedSize - LastCompressedSize), 0, 1))
2424
End Get
2525
End Property
2626
<JsonIgnore>
2727
Public ReadOnly Property SavedSpace As Long
2828
Get
29-
Return LastUncompressedSize - LastCompressedSize
29+
Return LastUncompressedSize - LastCheckedSize
3030
End Get
3131
End Property
3232

3333
Public Sub RefreshProperties()
3434
For Each prop In Me.GetType.GetProperties
35-
Me.OnPropertyChanged(prop.Name)
35+
OnPropertyChanged(prop.Name)
3636
Next
3737
End Sub
3838

0 commit comments

Comments
 (0)