mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2026-02-10 20:02:31 +00:00
Make use of C# 14 features
This commit is contained in:
@@ -6,28 +6,31 @@ namespace DiscordChatExporter.Gui.Utils.Extensions;
|
||||
|
||||
internal static class AvaloniaExtensions
|
||||
{
|
||||
public static Window? TryGetMainWindow(this IApplicationLifetime lifetime) =>
|
||||
lifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime
|
||||
? desktopLifetime.MainWindow
|
||||
: null;
|
||||
|
||||
public static TopLevel? TryGetTopLevel(this IApplicationLifetime lifetime) =>
|
||||
lifetime.TryGetMainWindow()
|
||||
?? (lifetime as ISingleViewApplicationLifetime)?.MainView?.GetVisualRoot() as TopLevel;
|
||||
|
||||
public static bool TryShutdown(this IApplicationLifetime lifetime, int exitCode = 0)
|
||||
extension(IApplicationLifetime lifetime)
|
||||
{
|
||||
if (lifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime)
|
||||
{
|
||||
return desktopLifetime.TryShutdown(exitCode);
|
||||
}
|
||||
public Window? TryGetMainWindow() =>
|
||||
lifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime
|
||||
? desktopLifetime.MainWindow
|
||||
: null;
|
||||
|
||||
if (lifetime is IControlledApplicationLifetime controlledLifetime)
|
||||
{
|
||||
controlledLifetime.Shutdown(exitCode);
|
||||
return true;
|
||||
}
|
||||
public TopLevel? TryGetTopLevel() =>
|
||||
lifetime.TryGetMainWindow()
|
||||
?? (lifetime as ISingleViewApplicationLifetime)?.MainView?.GetVisualRoot() as TopLevel;
|
||||
|
||||
return false;
|
||||
public bool TryShutdown(int exitCode = 0)
|
||||
{
|
||||
if (lifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime)
|
||||
{
|
||||
return desktopLifetime.TryShutdown(exitCode);
|
||||
}
|
||||
|
||||
if (lifetime is IControlledApplicationLifetime controlledLifetime)
|
||||
{
|
||||
controlledLifetime.Shutdown(exitCode);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,23 +6,26 @@ namespace DiscordChatExporter.Gui.Utils.Extensions;
|
||||
|
||||
internal static class DisposableExtensions
|
||||
{
|
||||
public static void DisposeAll(this IEnumerable<IDisposable> disposables)
|
||||
extension(IEnumerable<IDisposable> disposables)
|
||||
{
|
||||
var exceptions = default(List<Exception>);
|
||||
|
||||
foreach (var disposable in disposables)
|
||||
public void DisposeAll()
|
||||
{
|
||||
try
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
(exceptions ??= []).Add(ex);
|
||||
}
|
||||
}
|
||||
var exceptions = default(List<Exception>);
|
||||
|
||||
if (exceptions?.Any() == true)
|
||||
throw new AggregateException(exceptions);
|
||||
foreach (var disposable in disposables)
|
||||
{
|
||||
try
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
(exceptions ??= []).Add(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (exceptions?.Any() == true)
|
||||
throw new AggregateException(exceptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,50 +7,47 @@ namespace DiscordChatExporter.Gui.Utils.Extensions;
|
||||
|
||||
internal static class NotifyPropertyChangedExtensions
|
||||
{
|
||||
public static IDisposable WatchProperty<TOwner, TProperty>(
|
||||
this TOwner owner,
|
||||
Expression<Func<TOwner, TProperty>> propertyExpression,
|
||||
Action callback,
|
||||
bool watchInitialValue = false
|
||||
)
|
||||
extension<TOwner>(TOwner owner)
|
||||
where TOwner : INotifyPropertyChanged
|
||||
{
|
||||
var memberExpression = propertyExpression.Body as MemberExpression;
|
||||
if (memberExpression?.Member is not PropertyInfo property)
|
||||
throw new ArgumentException("Provided expression must reference a property.");
|
||||
|
||||
void OnPropertyChanged(object? sender, PropertyChangedEventArgs args)
|
||||
public IDisposable WatchProperty<TProperty>(
|
||||
Expression<Func<TOwner, TProperty>> propertyExpression,
|
||||
Action callback,
|
||||
bool watchInitialValue = false
|
||||
)
|
||||
{
|
||||
if (
|
||||
string.IsNullOrWhiteSpace(args.PropertyName)
|
||||
|| string.Equals(args.PropertyName, property.Name, StringComparison.Ordinal)
|
||||
)
|
||||
var memberExpression = propertyExpression.Body as MemberExpression;
|
||||
if (memberExpression?.Member is not PropertyInfo property)
|
||||
throw new ArgumentException("Provided expression must reference a property.");
|
||||
|
||||
void OnPropertyChanged(object? sender, PropertyChangedEventArgs args)
|
||||
{
|
||||
callback();
|
||||
if (
|
||||
string.IsNullOrWhiteSpace(args.PropertyName)
|
||||
|| string.Equals(args.PropertyName, property.Name, StringComparison.Ordinal)
|
||||
)
|
||||
{
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
owner.PropertyChanged += OnPropertyChanged;
|
||||
|
||||
if (watchInitialValue)
|
||||
callback();
|
||||
|
||||
return Disposable.Create(() => owner.PropertyChanged -= OnPropertyChanged);
|
||||
}
|
||||
|
||||
owner.PropertyChanged += OnPropertyChanged;
|
||||
public IDisposable WatchAllProperties(Action callback, bool watchInitialValues = false)
|
||||
{
|
||||
void OnPropertyChanged(object? sender, PropertyChangedEventArgs args) => callback();
|
||||
owner.PropertyChanged += OnPropertyChanged;
|
||||
|
||||
if (watchInitialValue)
|
||||
callback();
|
||||
if (watchInitialValues)
|
||||
callback();
|
||||
|
||||
return Disposable.Create(() => owner.PropertyChanged -= OnPropertyChanged);
|
||||
}
|
||||
|
||||
public static IDisposable WatchAllProperties<TOwner>(
|
||||
this TOwner owner,
|
||||
Action callback,
|
||||
bool watchInitialValues = false
|
||||
)
|
||||
where TOwner : INotifyPropertyChanged
|
||||
{
|
||||
void OnPropertyChanged(object? sender, PropertyChangedEventArgs args) => callback();
|
||||
owner.PropertyChanged += OnPropertyChanged;
|
||||
|
||||
if (watchInitialValues)
|
||||
callback();
|
||||
|
||||
return Disposable.Create(() => owner.PropertyChanged -= OnPropertyChanged);
|
||||
return Disposable.Create(() => owner.PropertyChanged -= OnPropertyChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
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 { FileName = path, UseShellExecute = true };
|
||||
|
||||
process.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace DiscordChatExporter.Gui.Utils;
|
||||
|
||||
internal static class ProcessEx
|
||||
{
|
||||
public static void StartShellExecute(string path)
|
||||
{
|
||||
using var process = new Process();
|
||||
process.StartInfo = new ProcessStartInfo { FileName = path, UseShellExecute = true };
|
||||
|
||||
process.Start();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -102,7 +103,7 @@ public partial class DashboardViewModel : ViewModelBase
|
||||
await _dialogManager.ShowDialogAsync(_viewModelManager.CreateSettingsViewModel());
|
||||
|
||||
[RelayCommand]
|
||||
private void ShowHelp() => ProcessEx.StartShellExecute(Program.ProjectDocumentationUrl);
|
||||
private void ShowHelp() => Process.StartShellExecute(Program.ProjectDocumentationUrl);
|
||||
|
||||
private bool CanPullGuilds() => !IsBusy && !string.IsNullOrWhiteSpace(Token);
|
||||
|
||||
@@ -322,11 +323,11 @@ public partial class DashboardViewModel : ViewModelBase
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenDiscord() => ProcessEx.StartShellExecute("https://discord.com/app");
|
||||
private void OpenDiscord() => Process.StartShellExecute("https://discord.com/app");
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenDiscordDeveloperPortal() =>
|
||||
ProcessEx.StartShellExecute("https://discord.com/developers/applications");
|
||||
Process.StartShellExecute("https://discord.com/developers/applications");
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,6 @@ using Avalonia;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using DiscordChatExporter.Gui.Framework;
|
||||
using DiscordChatExporter.Gui.Services;
|
||||
using DiscordChatExporter.Gui.Utils;
|
||||
using DiscordChatExporter.Gui.Utils.Extensions;
|
||||
using DiscordChatExporter.Gui.ViewModels.Components;
|
||||
|
||||
@@ -44,7 +43,7 @@ public partial class MainViewModel(
|
||||
settingsService.Save();
|
||||
|
||||
if (await dialogManager.ShowDialogAsync(dialog) == true)
|
||||
ProcessEx.StartShellExecute("https://tyrrrz.me/ukraine?source=discordchatexporter");
|
||||
Process.StartShellExecute("https://tyrrrz.me/ukraine?source=discordchatexporter");
|
||||
}
|
||||
|
||||
private async Task ShowDevelopmentBuildMessageAsync()
|
||||
@@ -70,7 +69,7 @@ public partial class MainViewModel(
|
||||
);
|
||||
|
||||
if (await dialogManager.ShowDialogAsync(dialog) == true)
|
||||
ProcessEx.StartShellExecute(Program.ProjectReleasesUrl);
|
||||
Process.StartShellExecute(Program.ProjectReleasesUrl);
|
||||
}
|
||||
|
||||
private async Task CheckForUpdatesAsync()
|
||||
|
||||
Reference in New Issue
Block a user