[GUI] Show error in a dialog when pull or export fails, instead of crashing the whole app

pull/678/head
Tyrrrz 3 years ago
parent 650c55bbd1
commit 2ab6773c17

@ -0,0 +1,27 @@
using DiscordChatExporter.Gui.ViewModels.Framework;
namespace DiscordChatExporter.Gui.ViewModels.Dialogs
{
public class MessageBoxViewModel : DialogScreen
{
public string? Title { get; set; }
public string? Message { get; set; }
}
public static class MessageBoxViewModelExtensions
{
public static MessageBoxViewModel CreateMessageBoxViewModel(
this IViewModelFactory factory,
string title,
string message)
{
var viewModel = factory.CreateMessageBoxViewModel();
viewModel.Title = title;
viewModel.Message = message;
return viewModel;
}
}
}

@ -7,6 +7,8 @@ namespace DiscordChatExporter.Gui.ViewModels.Framework
{
ExportSetupViewModel CreateExportSetupViewModel();
MessageBoxViewModel CreateMessageBoxViewModel();
SettingsViewModel CreateSettingsViewModel();
}
}

@ -178,6 +178,15 @@ namespace DiscordChatExporter.Gui.ViewModels
{
Notifications.Enqueue(ex.Message.TrimEnd('.'));
}
catch (Exception ex)
{
var dialog = _viewModelFactory.CreateMessageBoxViewModel(
"Error pulling guilds and channels",
ex.ToString()
);
await _dialogManager.ShowDialogAsync(dialog);
}
}
public bool CanExportChannels =>
@ -185,56 +194,68 @@ namespace DiscordChatExporter.Gui.ViewModels
public async void ExportChannels()
{
var token = _settingsService.LastToken;
if (token is null || SelectedGuild is null || SelectedChannels is null || !SelectedChannels.Any())
return;
var dialog = _viewModelFactory.CreateExportSetupViewModel(SelectedGuild, SelectedChannels);
if (await _dialogManager.ShowDialogAsync(dialog) != true)
return;
try
{
var token = _settingsService.LastToken;
if (token is null || SelectedGuild is null || SelectedChannels is null || !SelectedChannels.Any())
return;
var exporter = new ChannelExporter(token);
var dialog = _viewModelFactory.CreateExportSetupViewModel(SelectedGuild, SelectedChannels);
if (await _dialogManager.ShowDialogAsync(dialog) != true)
return;
var operations = ProgressManager.CreateOperations(dialog.Channels!.Count);
var successfulExportCount = 0;
var exporter = new ChannelExporter(token);
await dialog.Channels.Zip(operations).ParallelForEachAsync(async tuple =>
{
var (channel, operation) = tuple;
var operations = ProgressManager.CreateOperations(dialog.Channels!.Count);
var successfulExportCount = 0;
try
{
var request = new ExportRequest(
dialog.Guild!,
channel!,
dialog.OutputPath!,
dialog.SelectedFormat,
dialog.After?.Pipe(Snowflake.FromDate),
dialog.Before?.Pipe(Snowflake.FromDate),
dialog.PartitionLimit,
dialog.MessageFilter,
dialog.ShouldDownloadMedia,
_settingsService.ShouldReuseMedia,
_settingsService.DateFormat
);
await exporter.ExportChannelAsync(request, operation);
Interlocked.Increment(ref successfulExportCount);
}
catch (DiscordChatExporterException ex) when (!ex.IsCritical)
await dialog.Channels.Zip(operations).ParallelForEachAsync(async tuple =>
{
Notifications.Enqueue(ex.Message.TrimEnd('.'));
}
finally
{
operation.Dispose();
}
}, _settingsService.ParallelLimit.ClampMin(1));
var (channel, operation) = tuple;
try
{
var request = new ExportRequest(
dialog.Guild!,
channel!,
dialog.OutputPath!,
dialog.SelectedFormat,
dialog.After?.Pipe(Snowflake.FromDate),
dialog.Before?.Pipe(Snowflake.FromDate),
dialog.PartitionLimit,
dialog.MessageFilter,
dialog.ShouldDownloadMedia,
_settingsService.ShouldReuseMedia,
_settingsService.DateFormat
);
await exporter.ExportChannelAsync(request, operation);
Interlocked.Increment(ref successfulExportCount);
}
catch (DiscordChatExporterException ex) when (!ex.IsCritical)
{
Notifications.Enqueue(ex.Message.TrimEnd('.'));
}
finally
{
operation.Dispose();
}
}, _settingsService.ParallelLimit.ClampMin(1));
// Notify of overall completion
if (successfulExportCount > 0)
Notifications.Enqueue($"Successfully exported {successfulExportCount} channel(s)");
}
catch (Exception ex)
{
var dialog = _viewModelFactory.CreateMessageBoxViewModel(
"Error exporting channel(s)",
ex.ToString()
);
// Notify of overall completion
if (successfulExportCount > 0)
Notifications.Enqueue($"Successfully exported {successfulExportCount} channel(s)");
await _dialogManager.ShowDialogAsync(dialog);
}
}
}
}

@ -0,0 +1,49 @@
<UserControl
x:Class="DiscordChatExporter.Gui.Views.Dialogs.MessageBoxView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:dialogs="clr-namespace:DiscordChatExporter.Gui.ViewModels.Dialogs"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:s="https://github.com/canton7/Stylet"
MinWidth="500"
d:DataContext="{d:DesignInstance Type=dialogs:MessageBoxViewModel}"
d:DesignHeight="450"
d:DesignWidth="800"
Style="{DynamicResource MaterialDesignRoot}"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Title -->
<TextBlock
Grid.Row="0"
Margin="16"
FontSize="17"
Text="{Binding Title}"
TextTrimming="CharacterEllipsis"
ToolTip="{Binding Title}" />
<!-- Message -->
<TextBlock
Grid.Row="1"
Margin="16,0,16,16"
Text="{Binding Message}"
TextWrapping="Wrap" />
<!-- Close -->
<Button
Grid.Row="2"
Margin="8"
HorizontalAlignment="Right"
Command="{s:Action Close}"
Content="CLOSE"
IsCancel="True"
IsDefault="True"
Style="{DynamicResource MaterialDesignFlatButton}" />
</Grid>
</UserControl>

@ -0,0 +1,10 @@
namespace DiscordChatExporter.Gui.Views.Dialogs
{
public partial class MessageBoxView
{
public MessageBoxView()
{
InitializeComponent();
}
}
}
Loading…
Cancel
Save