mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2026-05-01 10:12:31 +00:00
Add PowerKit and replace custom utility extensions (#1525)
Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -7,13 +7,13 @@ using Avalonia.Platform;
|
||||
using DiscordChatExporter.Gui.Framework;
|
||||
using DiscordChatExporter.Gui.Localization;
|
||||
using DiscordChatExporter.Gui.Services;
|
||||
using DiscordChatExporter.Gui.Utils;
|
||||
using DiscordChatExporter.Gui.Utils.Extensions;
|
||||
using DiscordChatExporter.Gui.ViewModels;
|
||||
using DiscordChatExporter.Gui.ViewModels.Components;
|
||||
using DiscordChatExporter.Gui.ViewModels.Dialogs;
|
||||
using Material.Styles.Themes;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using PowerKit;
|
||||
using PowerKit.Extensions;
|
||||
|
||||
namespace DiscordChatExporter.Gui;
|
||||
|
||||
@@ -22,7 +22,7 @@ public class App : Application, IDisposable
|
||||
private readonly ServiceProvider _services;
|
||||
private readonly SettingsService _settingsService;
|
||||
|
||||
private readonly DisposableCollector _eventRoot = new();
|
||||
private readonly IDisposable _eventSubscription;
|
||||
|
||||
private bool _isDisposed;
|
||||
|
||||
@@ -54,7 +54,7 @@ public class App : Application, IDisposable
|
||||
_settingsService = _services.GetRequiredService<SettingsService>();
|
||||
|
||||
// Re-initialize the theme when the user changes it
|
||||
_eventRoot.Add(
|
||||
_eventSubscription = Disposable.Merge(
|
||||
_settingsService.WatchProperty(
|
||||
o => o.Theme,
|
||||
v =>
|
||||
@@ -131,7 +131,7 @@ public class App : Application, IDisposable
|
||||
|
||||
_isDisposed = true;
|
||||
|
||||
_eventRoot.Dispose();
|
||||
_eventSubscription.Dispose();
|
||||
_services.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
<PackageReference Include="Material.Icons.Avalonia" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
|
||||
<PackageReference Include="Onova" />
|
||||
<PackageReference Include="PowerKit" PrivateAssets="all" />
|
||||
<PackageReference Include="ThisAssembly.Project" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -3,20 +3,19 @@ using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using DiscordChatExporter.Gui.Services;
|
||||
using DiscordChatExporter.Gui.Utils;
|
||||
using DiscordChatExporter.Gui.Utils.Extensions;
|
||||
using PowerKit;
|
||||
using PowerKit.Extensions;
|
||||
|
||||
namespace DiscordChatExporter.Gui.Localization;
|
||||
|
||||
public partial class LocalizationManager : ObservableObject, IDisposable
|
||||
{
|
||||
private readonly DisposableCollector _eventRoot = new();
|
||||
private readonly IDisposable _eventSubscription;
|
||||
|
||||
public LocalizationManager(SettingsService settingsService)
|
||||
{
|
||||
_eventRoot.Add(settingsService.WatchProperty(o => o.Language, v => Language = v, true));
|
||||
|
||||
_eventRoot.Add(
|
||||
_eventSubscription = Disposable.Merge(
|
||||
settingsService.WatchProperty(o => o.Language, v => Language = v, true),
|
||||
this.WatchProperty(
|
||||
o => o.Language,
|
||||
_ =>
|
||||
@@ -66,7 +65,7 @@ public partial class LocalizationManager : ObservableObject, IDisposable
|
||||
return $"Missing localization for '{key}'";
|
||||
}
|
||||
|
||||
public void Dispose() => _eventRoot.Dispose();
|
||||
public void Dispose() => _eventSubscription.Dispose();
|
||||
}
|
||||
|
||||
public partial class LocalizationManager
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace DiscordChatExporter.Gui.Utils;
|
||||
|
||||
internal class Disposable(Action dispose) : IDisposable
|
||||
{
|
||||
public static IDisposable Create(Action dispose) => new Disposable(dispose);
|
||||
|
||||
public void Dispose() => dispose();
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiscordChatExporter.Gui.Utils.Extensions;
|
||||
|
||||
namespace DiscordChatExporter.Gui.Utils;
|
||||
|
||||
internal class DisposableCollector : IDisposable
|
||||
{
|
||||
private readonly object _lock = new();
|
||||
private readonly List<IDisposable> _items = [];
|
||||
|
||||
public void Add(IDisposable item)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_items.DisposeAll();
|
||||
_items.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace DiscordChatExporter.Gui.Utils.Extensions;
|
||||
|
||||
internal static class CommandExtensions
|
||||
{
|
||||
extension(ICommand command)
|
||||
{
|
||||
public void ExecuteIfCan(object? parameter = null)
|
||||
{
|
||||
if (command.CanExecute(parameter))
|
||||
command.Execute(parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace DiscordChatExporter.Gui.Utils.Extensions;
|
||||
|
||||
internal static class DisposableExtensions
|
||||
{
|
||||
extension(IEnumerable<IDisposable> disposables)
|
||||
{
|
||||
public void DisposeAll()
|
||||
{
|
||||
var exceptions = default(List<Exception>);
|
||||
|
||||
foreach (var disposable in disposables)
|
||||
{
|
||||
try
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
(exceptions ??= []).Add(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (exceptions?.Any() == true)
|
||||
throw new AggregateException(exceptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace DiscordChatExporter.Gui.Utils.Extensions;
|
||||
|
||||
internal static class NotifyPropertyChangedExtensions
|
||||
{
|
||||
extension<TOwner>(TOwner owner)
|
||||
where TOwner : INotifyPropertyChanged
|
||||
{
|
||||
public IDisposable WatchProperty<TProperty>(
|
||||
Expression<Func<TOwner, TProperty>> propertyExpression,
|
||||
Action<TProperty> callback,
|
||||
bool watchInitialValue = false
|
||||
)
|
||||
{
|
||||
var memberExpression = propertyExpression.Body as MemberExpression;
|
||||
if (memberExpression?.Member is not PropertyInfo property)
|
||||
throw new ArgumentException("Provided expression must reference a property.");
|
||||
|
||||
var getValue = propertyExpression.Compile();
|
||||
|
||||
void OnPropertyChanged(object? sender, PropertyChangedEventArgs args)
|
||||
{
|
||||
if (
|
||||
string.IsNullOrWhiteSpace(args.PropertyName)
|
||||
|| string.Equals(args.PropertyName, property.Name, StringComparison.Ordinal)
|
||||
)
|
||||
{
|
||||
callback(getValue(owner));
|
||||
}
|
||||
}
|
||||
|
||||
owner.PropertyChanged += OnPropertyChanged;
|
||||
|
||||
if (watchInitialValue)
|
||||
callback(getValue(owner));
|
||||
|
||||
return Disposable.Create(() => owner.PropertyChanged -= OnPropertyChanged);
|
||||
}
|
||||
|
||||
public IDisposable WatchAllProperties(Action callback, bool watchInitialValues = false)
|
||||
{
|
||||
void OnPropertyChanged(object? sender, PropertyChangedEventArgs args) => callback();
|
||||
owner.PropertyChanged += OnPropertyChanged;
|
||||
|
||||
if (watchInitialValues)
|
||||
callback();
|
||||
|
||||
return Disposable.Create(() => owner.PropertyChanged -= OnPropertyChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace DiscordChatExporter.Gui.Utils.Extensions;
|
||||
|
||||
internal static class ProcessExtensions
|
||||
{
|
||||
extension(Process)
|
||||
{
|
||||
public static void StartShellExecute(string path)
|
||||
{
|
||||
using var process = new Process();
|
||||
process.StartInfo = new ProcessStartInfo(path) { UseShellExecute = true };
|
||||
|
||||
process.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,15 +10,14 @@ using DiscordChatExporter.Core.Discord;
|
||||
using DiscordChatExporter.Core.Discord.Data;
|
||||
using DiscordChatExporter.Core.Exceptions;
|
||||
using DiscordChatExporter.Core.Exporting;
|
||||
using DiscordChatExporter.Core.Utils.Extensions;
|
||||
using DiscordChatExporter.Gui.Framework;
|
||||
using DiscordChatExporter.Gui.Localization;
|
||||
using DiscordChatExporter.Gui.Models;
|
||||
using DiscordChatExporter.Gui.Services;
|
||||
using DiscordChatExporter.Gui.Utils;
|
||||
using DiscordChatExporter.Gui.Utils.Extensions;
|
||||
using Gress;
|
||||
using Gress.Completable;
|
||||
using PowerKit;
|
||||
using PowerKit.Extensions;
|
||||
|
||||
namespace DiscordChatExporter.Gui.ViewModels.Components;
|
||||
|
||||
@@ -29,7 +28,7 @@ public partial class DashboardViewModel : ViewModelBase
|
||||
private readonly DialogManager _dialogManager;
|
||||
private readonly SettingsService _settingsService;
|
||||
|
||||
private readonly DisposableCollector _eventRoot = new();
|
||||
private readonly IDisposable _eventSubscription;
|
||||
private readonly AutoResetProgressMuxer _progressMuxer;
|
||||
|
||||
private DiscordClient? _discord;
|
||||
@@ -50,14 +49,11 @@ public partial class DashboardViewModel : ViewModelBase
|
||||
|
||||
_progressMuxer = Progress.CreateMuxer().WithAutoReset();
|
||||
|
||||
_eventRoot.Add(
|
||||
_eventSubscription = Disposable.Merge(
|
||||
Progress.WatchProperty(
|
||||
o => o.Current,
|
||||
_ => OnPropertyChanged(nameof(IsProgressIndeterminate))
|
||||
)
|
||||
);
|
||||
|
||||
_eventRoot.Add(
|
||||
),
|
||||
SelectedChannels.WatchProperty(
|
||||
o => o.Count,
|
||||
_ => ExportCommand.NotifyCanExecuteChanged()
|
||||
@@ -332,7 +328,7 @@ public partial class DashboardViewModel : ViewModelBase
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_eventRoot.Dispose();
|
||||
_eventSubscription.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
|
||||
@@ -10,10 +10,10 @@ using DiscordChatExporter.Core.Discord.Data;
|
||||
using DiscordChatExporter.Core.Exporting;
|
||||
using DiscordChatExporter.Core.Exporting.Filtering;
|
||||
using DiscordChatExporter.Core.Exporting.Partitioning;
|
||||
using DiscordChatExporter.Core.Utils.Extensions;
|
||||
using DiscordChatExporter.Gui.Framework;
|
||||
using DiscordChatExporter.Gui.Localization;
|
||||
using DiscordChatExporter.Gui.Services;
|
||||
using PowerKit.Extensions;
|
||||
|
||||
namespace DiscordChatExporter.Gui.ViewModels.Dialogs;
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DiscordChatExporter.Core.Discord;
|
||||
using DiscordChatExporter.Core.Utils.Extensions;
|
||||
using DiscordChatExporter.Gui.Framework;
|
||||
using DiscordChatExporter.Gui.Localization;
|
||||
using DiscordChatExporter.Gui.Models;
|
||||
using DiscordChatExporter.Gui.Services;
|
||||
using DiscordChatExporter.Gui.Utils;
|
||||
using DiscordChatExporter.Gui.Utils.Extensions;
|
||||
using PowerKit;
|
||||
using PowerKit.Extensions;
|
||||
|
||||
namespace DiscordChatExporter.Gui.ViewModels.Dialogs;
|
||||
|
||||
@@ -15,7 +14,7 @@ public class SettingsViewModel : DialogViewModelBase
|
||||
{
|
||||
private readonly SettingsService _settingsService;
|
||||
|
||||
private readonly DisposableCollector _eventRoot = new();
|
||||
private readonly IDisposable _eventSubscription;
|
||||
|
||||
public SettingsViewModel(
|
||||
SettingsService settingsService,
|
||||
@@ -25,7 +24,9 @@ public class SettingsViewModel : DialogViewModelBase
|
||||
_settingsService = settingsService;
|
||||
LocalizationManager = localizationManager;
|
||||
|
||||
_eventRoot.Add(_settingsService.WatchAllProperties(OnAllPropertiesChanged));
|
||||
_eventSubscription = Disposable.Merge(
|
||||
_settingsService.WatchAllProperties(OnAllPropertiesChanged)
|
||||
);
|
||||
}
|
||||
|
||||
public LocalizationManager LocalizationManager { get; }
|
||||
@@ -140,7 +141,7 @@ public class SettingsViewModel : DialogViewModelBase
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_eventRoot.Dispose();
|
||||
_eventSubscription.Dispose();
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
|
||||
@@ -7,6 +7,7 @@ using DiscordChatExporter.Gui.Localization;
|
||||
using DiscordChatExporter.Gui.Services;
|
||||
using DiscordChatExporter.Gui.Utils.Extensions;
|
||||
using DiscordChatExporter.Gui.ViewModels.Components;
|
||||
using PowerKit.Extensions;
|
||||
|
||||
namespace DiscordChatExporter.Gui.ViewModels;
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using DiscordChatExporter.Core.Discord.Data;
|
||||
using DiscordChatExporter.Gui.Framework;
|
||||
using DiscordChatExporter.Gui.Utils.Extensions;
|
||||
using DiscordChatExporter.Gui.ViewModels.Components;
|
||||
using PowerKit.Extensions;
|
||||
|
||||
namespace DiscordChatExporter.Gui.Views.Components;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.Windows.Input;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using DiscordChatExporter.Gui.Utils.Extensions;
|
||||
using PowerKit.Extensions;
|
||||
|
||||
namespace DiscordChatExporter.Gui.Views.Controls;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user