Skip to content
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

FileCleanup Improvements #633

Merged
merged 27 commits into from
Dec 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
982cbfc
[ZZZ GSP] Add experimental Mobile Mode toggle
bagusnl Aug 4, 2024
82f5caa
Merge branch 'main' into zzz-mobile-mode
bagusnl Aug 4, 2024
3cffc8c
sync zzz-mobile-mode with main (#604)
bagusnl Nov 15, 2024
afeb190
what in the absolute FRICK - Fix cleanup method when using >1000 files
bagusnl Dec 19, 2024
a3ca990
fix logging
bagusnl Dec 19, 2024
a65b937
how is it not clear that idk what im doing
bagusnl Dec 19, 2024
442fcf4
Hilariously improve select all speed by using a one-liner instead of …
bagusnl Dec 19, 2024
5edc9c6
Merge remote-tracking branch 'origin/filecleanup-improvement' into fi…
bagusnl Dec 19, 2024
32c6cae
More improvements
bagusnl Dec 19, 2024
474422f
Merge remote-tracking branch 'origin/zzz-mobile-mode' into filecleanu…
bagusnl Dec 20, 2024
d2038b0
Use .NET's built-in SIMD Sum tool instead on ListView_SelectionChanged
bagusnl Dec 20, 2024
2a3373c
Localize and tidy up
bagusnl Dec 20, 2024
699e1f7
Revert "Merge remote-tracking branch 'origin/zzz-mobile-mode' into fi…
bagusnl Dec 20, 2024
6bedf77
Merge branch 'main' into filecleanup-improvement
bagusnl Dec 20, 2024
7b139bc
Remove unnecessary refresh on FileInfo.EnsureNoReadOnly
neon-nyan Dec 21, 2024
19b0959
Reduce memory allocation on RecycleBin tool
neon-nyan Dec 21, 2024
2d9d3ee
[Perf] Improve after-deletion item removal on FileInfoSource
neon-nyan Dec 21, 2024
19b66d8
[Perf] Improve LocalFileInfo injection process
neon-nyan Dec 21, 2024
314c21a
[Perf] Detach thread on normal deletion
neon-nyan Dec 21, 2024
0e7b845
Catch exceptions on deletion method
neon-nyan Dec 21, 2024
3c5fc36
Fix wrong list to reset on cancelled delete
neon-nyan Dec 21, 2024
0e724fd
Fix Recycle Bin cancellation not thrown
neon-nyan Dec 21, 2024
1e521a9
Use DispatcherQueue on Show/HideLoadingFrame if necessary
neon-nyan Dec 21, 2024
6a8fc67
Improve FileCleanupPage methods (again)
bagusnl Dec 21, 2024
66dac00
Fix inconsistent deletedItems entry
neon-nyan Dec 21, 2024
1bda3ec
Another Improvements
neon-nyan Dec 21, 2024
afc9dd8
Remove unused namespace :teriderp:
neon-nyan Dec 21, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace CollapseLauncher.Extension
{
/// <summary>
/// Provides extension methods for <see cref="ObservableCollection{T}"/>.
/// </summary>
/// <typeparam name="T">The type of elements in the collection.</typeparam>
internal static class ObservableCollectionExtension<T>
{
/// <summary>
/// Gets the backing list of the specified collection.
/// </summary>
/// <param name="source">The collection to get the backing list from.</param>
/// <returns>A reference to the backing list of the collection.</returns>
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "items")]
internal static extern ref IList<T> GetBackedCollectionList(Collection<T> source);

/// <summary>
/// Invokes the OnCountPropertyChanged method on the specified observable collection.
/// </summary>
/// <param name="source">The observable collection to invoke the method on.</param>
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "OnCountPropertyChanged")]
internal static extern void OnCountPropertyChanged(ObservableCollection<T> source);

/// <summary>
/// Invokes the OnIndexerPropertyChanged method on the specified observable collection.
/// </summary>
/// <param name="source">The observable collection to invoke the method on.</param>
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "OnIndexerPropertyChanged")]
internal static extern void OnIndexerPropertyChanged(ObservableCollection<T> source);

/// <summary>
/// Invokes the OnCollectionChanged method on the specified observable collection.
/// </summary>
/// <param name="source">The observable collection to invoke the method on.</param>
/// <param name="e">The event arguments for the collection changed event.</param>
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "OnCollectionChanged")]
internal static extern void OnCollectionChanged(ObservableCollection<T> source, NotifyCollectionChangedEventArgs e);

/// <summary>
/// Refreshes all events for the specified observable collection.
/// </summary>
/// <param name="source">The observable collection to invoke the method on.</param>
internal static void RefreshAllEvents(ObservableCollection<T> source)
{
OnCountPropertyChanged(source);
OnIndexerPropertyChanged(source);
OnCollectionChanged(source, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}

/// <summary>
/// Removes a range of items from the specified observable collection quickly.
/// </summary>
/// <param name="sourceRange">The list of items to remove from the target collection.</param>
/// <param name="target">The observable collection from which the items will be removed.</param>
/// <exception cref="InvalidCastException">Thrown when the backing list of the target collection cannot be cast to a List{T}.</exception>
/// <remarks>
/// This method directly manipulates the backing list of the observable collection to remove the specified items,
/// and then fires the necessary property changed and collection changed events to update any bindings.
/// </remarks>
internal static void RemoveItemsFast(List<T> sourceRange, ObservableCollection<T> target)
{
// Get the backed list instance of the collection
List<T> targetBackedList = GetBackedCollectionList(target) as List<T> ?? throw new InvalidCastException();

// Get the count and iterate the reference of the T from the source range
ReadOnlySpan<T> sourceRangeSpan = CollectionsMarshal.AsSpan(sourceRange);
int len = sourceRangeSpan.Length - 1;
for (; len >= 0; len--)
{
// Remove the reference of the item T from the target backed list
_ = targetBackedList.Remove(sourceRangeSpan[len]);
}

// Fire the changes event
RefreshAllEvents(target);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Microsoft.UI.Input;
using Microsoft.UI.Xaml;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Runtime.CompilerServices;

#nullable enable
namespace CollapseLauncher.Extension
{
internal static partial class UIElementExtensions
{
/// <summary>
/// Set the cursor for the element.
/// </summary>
/// <param name="element">The <seealso cref="UIElement"/> member of an element</param>
/// <param name="inputCursor">The cursor you want to set. Use <see cref="InputSystemCursor.Create"/> to choose the cursor you want to set.</param>
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_ProtectedCursor")]
internal static extern void SetCursor(this UIElement element, InputCursor inputCursor);

/// <summary>
/// Set the cursor for the element.
/// </summary>
/// <param name="element">The <seealso cref="UIElement"/> member of an element</param>
/// <param name="inputCursor">The cursor you want to set. Use <see cref="InputSystemCursor.Create"/> to choose the cursor you want to set.</param>
internal static ref T WithCursor<T>(this T element, InputCursor inputCursor) where T : UIElement
{
element.SetCursor(inputCursor);
return ref Unsafe.AsRef(ref element);
}
}
}
22 changes: 2 additions & 20 deletions CollapseLauncher/Classes/Extension/UIElementExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using Windows.UI;
using Windows.UI.Text;
using Hi3Helper.SentryHelper;
using System.Collections.ObjectModel;

namespace CollapseLauncher.Extension
{
Expand All @@ -28,27 +29,8 @@ internal class NavigationViewItemLocaleTextProperty
public string LocalePropertyName { get; set; }
}

internal static class UIElementExtensions
internal static partial class UIElementExtensions
{
/// <summary>
/// Set the cursor for the element.
/// </summary>
/// <param name="element">The <seealso cref="UIElement"/> member of an element</param>
/// <param name="inputCursor">The cursor you want to set. Use <see cref="InputSystemCursor.Create"/> to choose the cursor you want to set.</param>
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_ProtectedCursor")]
internal static extern void SetCursor(this UIElement element, InputCursor inputCursor);

/// <summary>
/// Set the cursor for the element.
/// </summary>
/// <param name="element">The <seealso cref="UIElement"/> member of an element</param>
/// <param name="inputCursor">The cursor you want to set. Use <see cref="InputSystemCursor.Create"/> to choose the cursor you want to set.</param>
internal static ref T WithCursor<T>(this T element, InputCursor inputCursor) where T : UIElement
{
element.SetCursor(inputCursor);
return ref Unsafe.AsRef(ref element);
}

#nullable enable
/// <summary>
/// Set the initial navigation view item's locale binding before getting set with <seealso cref="ApplyNavigationViewItemLocaleTextBindings"/>
Expand Down
55 changes: 39 additions & 16 deletions CollapseLauncher/Classes/Helper/Loading/LoadingMessageHelper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using CollapseLauncher.Extension;
using CollapseLauncher.Helper.Animation;
using CommunityToolkit.WinUI;
using CommunityToolkit.WinUI.Animations;
using Microsoft.UI.Text;
using Microsoft.UI.Xaml;
Expand Down Expand Up @@ -64,43 +65,65 @@ internal static void SetProgressBarState(double maxValue = 100d, bool isProgress
/// Show the loading frame.
/// </summary>
internal static async void ShowLoadingFrame()
{
if (currentMainWindow.LoadingStatusBackgroundGrid.DispatcherQueue.HasThreadAccess)
{
await ShowLoadingFrameInner();
return;
}

await currentMainWindow.LoadingStatusBackgroundGrid.DispatcherQueue.EnqueueAsync(ShowLoadingFrameInner);
}

private static async Task ShowLoadingFrameInner()
{
if (isCurrentlyShow) return;

isCurrentlyShow = true;
currentMainWindow!.LoadingStatusGrid!.Visibility = Visibility.Visible;
isCurrentlyShow = true;
currentMainWindow!.LoadingStatusGrid!.Visibility = Visibility.Visible;
currentMainWindow!.LoadingStatusBackgroundGrid!.Visibility = Visibility.Visible;

TimeSpan duration = TimeSpan.FromSeconds(0.25);

await Task.WhenAll(
AnimationHelper.StartAnimation(currentMainWindow.LoadingStatusBackgroundGrid, duration,
currentMainWindow.LoadingStatusBackgroundGrid.GetElementCompositor()!.CreateScalarKeyFrameAnimation("Opacity", 1, 0)),
AnimationHelper.StartAnimation(currentMainWindow.LoadingStatusGrid, duration,
currentMainWindow.LoadingStatusGrid.GetElementCompositor()!.CreateVector3KeyFrameAnimation("Translation", new Vector3(0,0,currentMainWindow.LoadingStatusGrid.Translation.Z), new Vector3(0, (float)(currentMainWindow.LoadingStatusGrid.ActualHeight + 16), currentMainWindow.LoadingStatusGrid.Translation.Z)),
currentMainWindow.LoadingStatusGrid.GetElementCompositor()!.CreateScalarKeyFrameAnimation("Opacity", 1, 0))
);
AnimationHelper.StartAnimation(currentMainWindow.LoadingStatusBackgroundGrid, duration,
currentMainWindow.LoadingStatusBackgroundGrid.GetElementCompositor()!.CreateScalarKeyFrameAnimation("Opacity", 1, 0)),
AnimationHelper.StartAnimation(currentMainWindow.LoadingStatusGrid, duration,
currentMainWindow.LoadingStatusGrid.GetElementCompositor()!.CreateVector3KeyFrameAnimation("Translation", new Vector3(0, 0, currentMainWindow.LoadingStatusGrid.Translation.Z), new Vector3(0, (float)(currentMainWindow.LoadingStatusGrid.ActualHeight + 16), currentMainWindow.LoadingStatusGrid.Translation.Z)),
currentMainWindow.LoadingStatusGrid.GetElementCompositor()!.CreateScalarKeyFrameAnimation("Opacity", 1, 0))
);
}

/// <summary>
/// Hide the loading frame (also hide the action button).
/// </summary>
internal static async void HideLoadingFrame()
{
if (currentMainWindow.LoadingStatusBackgroundGrid.DispatcherQueue.HasThreadAccess)
{
await HideLoadingFrameInner();
return;
}

await currentMainWindow.LoadingStatusBackgroundGrid.DispatcherQueue.EnqueueAsync(HideLoadingFrameInner);
}

private static async Task HideLoadingFrameInner()
{
if (!isCurrentlyShow) return;

isCurrentlyShow = false;

TimeSpan duration = TimeSpan.FromSeconds(0.25);
await Task.WhenAll(
AnimationHelper.StartAnimation(currentMainWindow.LoadingStatusBackgroundGrid, duration,
currentMainWindow.LoadingStatusBackgroundGrid.GetElementCompositor()!.CreateScalarKeyFrameAnimation("Opacity", 0, 1)),
AnimationHelper.StartAnimation(currentMainWindow.LoadingStatusGrid, duration,
currentMainWindow.LoadingStatusGrid.GetElementCompositor()!.CreateVector3KeyFrameAnimation("Translation", new Vector3(0, (float)(currentMainWindow.LoadingStatusGrid.ActualHeight + 16), currentMainWindow.LoadingStatusGrid.Translation.Z), new Vector3(0,0,currentMainWindow.LoadingStatusGrid.Translation.Z)),
currentMainWindow.LoadingStatusGrid.GetElementCompositor()!.CreateScalarKeyFrameAnimation("Opacity", 0, 1))
);

currentMainWindow.LoadingStatusGrid.Visibility = Visibility.Collapsed;
AnimationHelper.StartAnimation(currentMainWindow.LoadingStatusBackgroundGrid, duration,
currentMainWindow.LoadingStatusBackgroundGrid.GetElementCompositor()!.CreateScalarKeyFrameAnimation("Opacity", 0, 1)),
AnimationHelper.StartAnimation(currentMainWindow.LoadingStatusGrid, duration,
currentMainWindow.LoadingStatusGrid.GetElementCompositor()!.CreateVector3KeyFrameAnimation("Translation", new Vector3(0, (float)(currentMainWindow.LoadingStatusGrid.ActualHeight + 16), currentMainWindow.LoadingStatusGrid.Translation.Z), new Vector3(0, 0, currentMainWindow.LoadingStatusGrid.Translation.Z)),
currentMainWindow.LoadingStatusGrid.GetElementCompositor()!.CreateScalarKeyFrameAnimation("Opacity", 0, 1))
);

currentMainWindow.LoadingStatusGrid.Visibility = Visibility.Collapsed;
currentMainWindow.LoadingStatusBackgroundGrid!.Visibility = Visibility.Collapsed;
HideActionButton();
}
Expand Down
6 changes: 4 additions & 2 deletions CollapseLauncher/Classes/Helper/StreamUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,14 @@ private static void EnsureFilePathExist([NotNull] string? path)
*/

internal static FileInfo EnsureNoReadOnly(this FileInfo fileInfo)
=> fileInfo.EnsureNoReadOnly(out _);

internal static FileInfo EnsureNoReadOnly(this FileInfo fileInfo, out bool isFileExist)
{
if (!fileInfo.Exists)
if (!(isFileExist = fileInfo.Exists))
return fileInfo;

fileInfo.IsReadOnly = false;
fileInfo.Refresh();

return fileInfo;
}
Expand Down
Loading