Cleanup GUI

pull/826/head
Oleksii Holub 3 years ago
parent 3a2b119618
commit 1daff4178d

@ -7,7 +7,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CliFx" Version="2.2.2" /> <PackageReference Include="CliFx" Version="2.2.2" />
<PackageReference Include="Spectre.Console" Version="0.43.0" /> <PackageReference Include="Spectre.Console" Version="0.44.0" />
<PackageReference Include="Gress" Version="2.0.1" /> <PackageReference Include="Gress" Version="2.0.1" />
</ItemGroup> </ItemGroup>

@ -7,7 +7,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Gress" Version="2.0.1" /> <PackageReference Include="Gress" Version="2.0.1" />
<PackageReference Include="JsonExtensions" Version="1.2.0" /> <PackageReference Include="JsonExtensions" Version="1.2.0" />
<PackageReference Include="MiniRazor.CodeGen" Version="2.2.0" /> <PackageReference Include="MiniRazor.CodeGen" Version="2.2.1" />
<PackageReference Include="Polly" Version="7.2.3" /> <PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="Superpower" Version="3.0.0" /> <PackageReference Include="Superpower" Version="3.0.0" />
</ItemGroup> </ItemGroup>

@ -47,6 +47,21 @@
<Setter Property="Minimum" Value="0" /> <Setter Property="Minimum" Value="0" />
</Style> </Style>
<Style BasedOn="{StaticResource MaterialDesignBody1Hyperlink}" TargetType="{x:Type Hyperlink}">
<Setter Property="TextDecorations" Value="Underline" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsEnabled" Value="True" />
<Condition Property="IsMouseOver" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Foreground" Value="{DynamicResource SecondaryHueMidBrush}" />
</MultiTrigger>
</Style.Triggers>
</Style>
<Style BasedOn="{StaticResource MaterialDesignTextBox}" TargetType="{x:Type TextBox}" /> <Style BasedOn="{StaticResource MaterialDesignTextBox}" TargetType="{x:Type TextBox}" />
<Style BasedOn="{StaticResource MaterialDesignComboBox}" TargetType="{x:Type ComboBox}" /> <Style BasedOn="{StaticResource MaterialDesignComboBox}" TargetType="{x:Type ComboBox}" />
@ -90,6 +105,10 @@
</Style.Triggers> </Style.Triggers>
</Style> </Style>
<Style BasedOn="{StaticResource MaterialDesignContextMenu}" TargetType="{x:Type ContextMenu}">
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}" />
</Style>
<!-- Default MD Expander is incredibly slow (https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/issues/1307) --> <!-- Default MD Expander is incredibly slow (https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/issues/1307) -->
<Style BasedOn="{StaticResource MaterialDesignExpander}" TargetType="{x:Type Expander}"> <Style BasedOn="{StaticResource MaterialDesignExpander}" TargetType="{x:Type Expander}">
<Setter Property="Template"> <Setter Property="Template">

@ -9,11 +9,16 @@ namespace DiscordChatExporter.Gui.Behaviors;
public class MultiSelectionListBoxBehavior<T> : Behavior<ListBox> public class MultiSelectionListBoxBehavior<T> : Behavior<ListBox>
{ {
public static readonly DependencyProperty SelectedItemsProperty = public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register(
DependencyProperty.Register(nameof(SelectedItems), typeof(IList), nameof(SelectedItems),
typeof(IList),
typeof(MultiSelectionListBoxBehavior<T>), typeof(MultiSelectionListBoxBehavior<T>),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new FrameworkPropertyMetadata(
OnSelectedItemsChanged)); null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
OnSelectedItemsChanged
)
);
private static void OnSelectedItemsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) private static void OnSelectedItemsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{ {

@ -9,19 +9,13 @@ public class DateTimeOffsetToDateTimeConverter : IValueConverter
{ {
public static DateTimeOffsetToDateTimeConverter Instance { get; } = new(); public static DateTimeOffsetToDateTimeConverter Instance { get; } = new();
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
{ value is DateTimeOffset dateTimeOffsetValue
if (value is DateTimeOffset dateTimeOffsetValue) ? dateTimeOffsetValue.DateTime
return dateTimeOffsetValue.DateTime; : default(DateTime?);
return default(DateTime?); public object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
} value is DateTime dateTimeValue
? new DateTimeOffset(dateTimeValue)
public object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) : default(DateTimeOffset?);
{
if (value is DateTime dateTimeValue)
return new DateTimeOffset(dateTimeValue);
return default(DateTimeOffset?);
}
} }

@ -10,13 +10,10 @@ public class ExportFormatToStringConverter : IValueConverter
{ {
public static ExportFormatToStringConverter Instance { get; } = new(); public static ExportFormatToStringConverter Instance { get; } = new();
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
{ value is ExportFormat exportFormatValue
if (value is ExportFormat exportFormatValue) ? exportFormatValue.GetDisplayName()
return exportFormatValue.GetDisplayName(); : default;
return default(string?);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
throw new NotSupportedException(); throw new NotSupportedException();

@ -9,19 +9,9 @@ public class InverseBoolConverter : IValueConverter
{ {
public static InverseBoolConverter Instance { get; } = new(); public static InverseBoolConverter Instance { get; } = new();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
{ value is false;
if (value is bool boolValue)
return !boolValue;
return default(bool); public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
} value is false;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool boolValue)
return !boolValue;
return default(bool);
}
} }

@ -9,19 +9,13 @@ public class TimeSpanToDateTimeConverter : IValueConverter
{ {
public static TimeSpanToDateTimeConverter Instance { get; } = new(); public static TimeSpanToDateTimeConverter Instance { get; } = new();
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
{ value is TimeSpan timeSpanValue
if (value is TimeSpan timeSpanValue) ? DateTime.Today.Add(timeSpanValue)
return DateTime.Today.Add(timeSpanValue); : default(DateTime?);
return default(DateTime?); public object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
} value is DateTime dateTimeValue
? dateTimeValue.TimeOfDay
public object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) : default(TimeSpan?);
{
if (value is DateTime dateTimeValue)
return dateTimeValue.TimeOfDay;
return default(TimeSpan?);
}
} }

@ -14,8 +14,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Gress" Version="2.0.1" /> <PackageReference Include="Gress" Version="2.0.1" />
<PackageReference Include="MaterialDesignColors" Version="2.0.4" /> <PackageReference Include="MaterialDesignColors" Version="2.0.5" />
<PackageReference Include="MaterialDesignThemes" Version="4.3.0" /> <PackageReference Include="MaterialDesignThemes" Version="4.4.0" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" /> <PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" /> <PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
<PackageReference Include="Onova" Version="2.6.2" /> <PackageReference Include="Onova" Version="2.6.2" />

@ -11,6 +11,8 @@ internal static class ProcessEx
UseShellExecute = true UseShellExecute = true
}; };
using (Process.Start(startInfo)) {} using (Process.Start(startInfo))
{
}
} }
} }

@ -7,20 +7,41 @@ public class MessageBoxViewModel : DialogScreen
public string? Title { get; set; } public string? Title { get; set; }
public string? Message { get; set; } public string? Message { get; set; }
public bool IsOkButtonVisible { get; set; } = true;
public string? OkButtonText { get; set; }
public bool IsCancelButtonVisible { get; set; }
public string? CancelButtonText { get; set; }
public int ButtonsCount =>
(IsOkButtonVisible ? 1 : 0) +
(IsCancelButtonVisible ? 1 : 0);
} }
public static class MessageBoxViewModelExtensions public static class MessageBoxViewModelExtensions
{ {
public static MessageBoxViewModel CreateMessageBoxViewModel( public static MessageBoxViewModel CreateMessageBoxViewModel(
this IViewModelFactory factory, this IViewModelFactory factory,
string title, string title, string message,
string message) string? okButtonText, string? cancelButtonText)
{ {
var viewModel = factory.CreateMessageBoxViewModel(); var viewModel = factory.CreateMessageBoxViewModel();
viewModel.Title = title; viewModel.Title = title;
viewModel.Message = message; viewModel.Message = message;
viewModel.IsOkButtonVisible = !string.IsNullOrWhiteSpace(okButtonText);
viewModel.OkButtonText = okButtonText;
viewModel.IsCancelButtonVisible = !string.IsNullOrWhiteSpace(cancelButtonText);
viewModel.CancelButtonText = cancelButtonText;
return viewModel; return viewModel;
} }
public static MessageBoxViewModel CreateMessageBoxViewModel(
this IViewModelFactory factory,
string title, string message) =>
factory.CreateMessageBoxViewModel(title, message, "CLOSE", null);
} }

@ -71,6 +71,23 @@ public class RootViewModel : Screen
Progress.Bind(o => o.Current, (_, _) => NotifyOfPropertyChange(() => IsProgressIndeterminate)); Progress.Bind(o => o.Current, (_, _) => NotifyOfPropertyChange(() => IsProgressIndeterminate));
} }
private async Task ShowWarInUkraineMessageAsync()
{
var dialog = _viewModelFactory.CreateMessageBoxViewModel(
"Ukraine is at war!", @"
My country, Ukraine, has been invaded by Russian military forces in an act of aggression that can only be described as genocide.
Be on the right side of history! Consider supporting Ukraine in its fight for freedom.
Press LEARN MORE to find ways that you can help.".Trim(),
"LEARN MORE", "CLOSE"
);
if (await _dialogManager.ShowDialogAsync(dialog) == true)
{
ProcessEx.StartShellExecute("https://tyrrrz.me");
}
}
private async ValueTask CheckForUpdatesAsync() private async ValueTask CheckForUpdatesAsync()
{ {
try try
@ -98,6 +115,12 @@ public class RootViewModel : Screen
} }
} }
// This is a custom event that fires when the dialog host is loaded
public async void OnViewFullyLoaded()
{
await ShowWarInUkraineMessageAsync();
}
protected override async void OnViewLoaded() protected override async void OnViewLoaded()
{ {
base.OnViewLoaded(); base.OnViewLoaded();
@ -118,19 +141,6 @@ public class RootViewModel : Screen
App.SetLightTheme(); App.SetLightTheme();
} }
// War in Ukraine message
Notifications.Enqueue(
"⚠ Ukraine is at war! Support my country in its fight for freedom",
"LEARN MORE", _ =>
{
ProcessEx.StartShellExecute("https://tyrrrz.me");
},
null,
true,
true,
TimeSpan.FromMinutes(1)
);
await CheckForUpdatesAsync(); await CheckForUpdatesAsync();
} }

@ -1,10 +1,7 @@
<UserControl <UserControl
Style="{DynamicResource MaterialDesignRoot}"
Width="380"
d:DataContext="{d:DesignInstance Type=dialogs:ExportSetupViewModel}"
mc:Ignorable="d"
x:Class="DiscordChatExporter.Gui.Views.Dialogs.ExportSetupView" x:Class="DiscordChatExporter.Gui.Views.Dialogs.ExportSetupView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:DiscordChatExporter.Gui.Converters" xmlns:converters="clr-namespace:DiscordChatExporter.Gui.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:dialogs="clr-namespace:DiscordChatExporter.Gui.ViewModels.Dialogs" xmlns:dialogs="clr-namespace:DiscordChatExporter.Gui.ViewModels.Dialogs"
@ -12,7 +9,10 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:s="https://github.com/canton7/Stylet" xmlns:s="https://github.com/canton7/Stylet"
xmlns:utils="clr-namespace:DiscordChatExporter.Gui.Utils" xmlns:utils="clr-namespace:DiscordChatExporter.Gui.Utils"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> Width="380"
d:DataContext="{d:DesignInstance Type=dialogs:ExportSetupViewModel}"
Style="{DynamicResource MaterialDesignRoot}"
mc:Ignorable="d">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@ -30,21 +30,21 @@
<!-- Guild icon --> <!-- Guild icon -->
<Ellipse <Ellipse
Grid.Column="0" Grid.Column="0"
Height="32" Width="32"
Width="32"> Height="32">
<Ellipse.Fill> <Ellipse.Fill>
<ImageBrush ImageSource="{Binding Guild.IconUrl}" /> <ImageBrush ImageSource="{Binding Guild.IconUrl}" />
</Ellipse.Fill> </Ellipse.Fill>
</Ellipse> </Ellipse>
<!-- Placeholder (for multiple channels) --> <!-- Channel count (for multiple channels) -->
<TextBlock <TextBlock
FontSize="19"
FontWeight="Light"
Grid.Column="1" Grid.Column="1"
Margin="8,0,0,0" Margin="8,0,0,0"
TextTrimming="CharacterEllipsis"
VerticalAlignment="Center" VerticalAlignment="Center"
FontSize="19"
FontWeight="Light"
TextTrimming="CharacterEllipsis"
Visibility="{Binding IsSingleChannel, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}}"> Visibility="{Binding IsSingleChannel, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}}">
<Run Text="{Binding Channels.Count, Mode=OneWay}" /> <Run Text="{Binding Channels.Count, Mode=OneWay}" />
<Run Text="channels selected" /> <Run Text="channels selected" />
@ -52,12 +52,12 @@
<!-- Category and channel name (for single channel) --> <!-- Category and channel name (for single channel) -->
<TextBlock <TextBlock
FontSize="19"
FontWeight="Light"
Grid.Column="1" Grid.Column="1"
Margin="8,0,0,0" Margin="8,0,0,0"
TextTrimming="CharacterEllipsis"
VerticalAlignment="Center" VerticalAlignment="Center"
FontSize="19"
FontWeight="Light"
TextTrimming="CharacterEllipsis"
Visibility="{Binding IsSingleChannel, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"> Visibility="{Binding IsSingleChannel, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<Run Text="{Binding Channels[0].Category.Name, Mode=OneWay}" ToolTip="{Binding Channels[0].Category.Name, Mode=OneWay}" /> <Run Text="{Binding Channels[0].Category.Name, Mode=OneWay}" ToolTip="{Binding Channels[0].Category.Name, Mode=OneWay}" />
<Run Text="/" /> <Run Text="/" />
@ -69,21 +69,21 @@
</Grid> </Grid>
<Border <Border
BorderBrush="{DynamicResource MaterialDesignDivider}"
BorderThickness="0,1"
Grid.Row="1" Grid.Row="1"
Padding="0,8"> Padding="0,8"
BorderBrush="{DynamicResource MaterialDesignDivider}"
BorderThickness="0,1">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<StackPanel> <StackPanel>
<!-- Format --> <!-- Format -->
<ComboBox <ComboBox
Margin="16,8"
materialDesign:HintAssist.Hint="Format"
materialDesign:HintAssist.IsFloating="True"
IsReadOnly="True" IsReadOnly="True"
ItemsSource="{Binding AvailableFormats}" ItemsSource="{Binding AvailableFormats}"
Margin="16,8"
SelectedItem="{Binding SelectedFormat}" SelectedItem="{Binding SelectedFormat}"
Style="{DynamicResource MaterialDesignOutlinedComboBox}" Style="{DynamicResource MaterialDesignOutlinedComboBox}">
materialDesign:HintAssist.Hint="Format"
materialDesign:HintAssist.IsFloating="True">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<TextBlock Text="{Binding Converter={x:Static converters:ExportFormatToStringConverter.Instance}}" /> <TextBlock Text="{Binding Converter={x:Static converters:ExportFormatToStringConverter.Instance}}" />
@ -105,66 +105,66 @@
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<DatePicker <DatePicker
DisplayDateEnd="{Binding BeforeDate, Converter={x:Static converters:DateTimeOffsetToDateTimeConverter.Instance}}"
Grid.Column="0"
Grid.Row="0" Grid.Row="0"
Grid.Column="0"
Margin="16,8,16,4" Margin="16,8,16,4"
materialDesign:HintAssist.Hint="After (date)"
materialDesign:HintAssist.IsFloating="True"
DisplayDateEnd="{Binding BeforeDate, Converter={x:Static converters:DateTimeOffsetToDateTimeConverter.Instance}}"
SelectedDate="{Binding AfterDate, Converter={x:Static converters:DateTimeOffsetToDateTimeConverter.Instance}}" SelectedDate="{Binding AfterDate, Converter={x:Static converters:DateTimeOffsetToDateTimeConverter.Instance}}"
Style="{DynamicResource MaterialDesignOutlinedDatePicker}" Style="{DynamicResource MaterialDesignOutlinedDatePicker}"
ToolTip="Only include messages sent after this date" ToolTip="Only include messages sent after this date" />
materialDesign:HintAssist.Hint="After (date)"
materialDesign:HintAssist.IsFloating="True" />
<DatePicker <DatePicker
DisplayDateStart="{Binding AfterDate, Converter={x:Static converters:DateTimeOffsetToDateTimeConverter.Instance}}"
Grid.Column="1"
Grid.Row="0" Grid.Row="0"
Grid.Column="1"
Margin="16,8,16,4" Margin="16,8,16,4"
materialDesign:HintAssist.Hint="Before (date)"
materialDesign:HintAssist.IsFloating="True"
DisplayDateStart="{Binding AfterDate, Converter={x:Static converters:DateTimeOffsetToDateTimeConverter.Instance}}"
SelectedDate="{Binding BeforeDate, Converter={x:Static converters:DateTimeOffsetToDateTimeConverter.Instance}}" SelectedDate="{Binding BeforeDate, Converter={x:Static converters:DateTimeOffsetToDateTimeConverter.Instance}}"
Style="{DynamicResource MaterialDesignOutlinedDatePicker}" Style="{DynamicResource MaterialDesignOutlinedDatePicker}"
ToolTip="Only include messages sent before this date" ToolTip="Only include messages sent before this date" />
materialDesign:HintAssist.Hint="Before (date)"
materialDesign:HintAssist.IsFloating="True" />
<materialDesign:TimePicker <materialDesign:TimePicker
Grid.Column="0"
Grid.Row="1" Grid.Row="1"
Grid.Column="0"
Margin="16,4,16,8"
materialDesign:HintAssist.Hint="After (time)"
materialDesign:HintAssist.IsFloating="True"
Is24Hours="{x:Static utils:Internationalization.Is24Hours}" Is24Hours="{x:Static utils:Internationalization.Is24Hours}"
IsEnabled="{Binding IsAfterDateSet}" IsEnabled="{Binding IsAfterDateSet}"
Margin="16,4,16,8"
SelectedTime="{Binding AfterTime, Converter={x:Static converters:TimeSpanToDateTimeConverter.Instance}}" SelectedTime="{Binding AfterTime, Converter={x:Static converters:TimeSpanToDateTimeConverter.Instance}}"
Style="{DynamicResource MaterialDesignOutlinedTimePicker}" Style="{DynamicResource MaterialDesignOutlinedTimePicker}"
ToolTip="Only include messages sent after this time" ToolTip="Only include messages sent after this time" />
materialDesign:HintAssist.Hint="After (time)"
materialDesign:HintAssist.IsFloating="True" />
<materialDesign:TimePicker <materialDesign:TimePicker
Grid.Column="1"
Grid.Row="1" Grid.Row="1"
Grid.Column="1"
Margin="16,4,16,8"
materialDesign:HintAssist.Hint="Before (time)"
materialDesign:HintAssist.IsFloating="True"
Is24Hours="{x:Static utils:Internationalization.Is24Hours}" Is24Hours="{x:Static utils:Internationalization.Is24Hours}"
IsEnabled="{Binding IsBeforeDateSet}" IsEnabled="{Binding IsBeforeDateSet}"
Margin="16,4,16,8"
SelectedTime="{Binding BeforeTime, Converter={x:Static converters:TimeSpanToDateTimeConverter.Instance}}" SelectedTime="{Binding BeforeTime, Converter={x:Static converters:TimeSpanToDateTimeConverter.Instance}}"
Style="{DynamicResource MaterialDesignOutlinedTimePicker}" Style="{DynamicResource MaterialDesignOutlinedTimePicker}"
ToolTip="Only include messages sent before this time" ToolTip="Only include messages sent before this time" />
materialDesign:HintAssist.Hint="Before (time)"
materialDesign:HintAssist.IsFloating="True" />
</Grid> </Grid>
<!-- Partitioning --> <!-- Partitioning -->
<TextBox <TextBox
Margin="16,8" Margin="16,8"
materialDesign:HintAssist.Hint="Partition limit"
materialDesign:HintAssist.IsFloating="True"
Style="{DynamicResource MaterialDesignOutlinedTextBox}" Style="{DynamicResource MaterialDesignOutlinedTextBox}"
Text="{Binding PartitionLimitValue}" Text="{Binding PartitionLimitValue}"
ToolTip="Split output into partitions, each limited to this number of messages (e.g. '100') or file size (e.g. '10mb')" ToolTip="Split output into partitions, each limited to this number of messages (e.g. '100') or file size (e.g. '10mb')" />
materialDesign:HintAssist.Hint="Partition limit"
materialDesign:HintAssist.IsFloating="True" />
<!-- Filtering --> <!-- Filtering -->
<TextBox <TextBox
Margin="16,8" Margin="16,8"
materialDesign:HintAssist.Hint="Message filter"
materialDesign:HintAssist.IsFloating="True"
Style="{DynamicResource MaterialDesignOutlinedTextBox}" Style="{DynamicResource MaterialDesignOutlinedTextBox}"
Text="{Binding MessageFilterValue}" Text="{Binding MessageFilterValue}"
ToolTip="Only include messages that satisfy this filter (e.g. 'from:foo#1234' or 'has:image')." ToolTip="Only include messages that satisfy this filter (e.g. 'from:foo#1234' or 'has:image')." />
materialDesign:HintAssist.Hint="Message filter"
materialDesign:HintAssist.IsFloating="True" />
<!-- Download media --> <!-- Download media -->
<Grid Margin="16,16" ToolTip="Download referenced media content (user avatars, attached files, embedded images, etc)"> <Grid Margin="16,16" ToolTip="Download referenced media content (user avatars, attached files, embedded images, etc)">
@ -175,13 +175,13 @@
<TextBlock <TextBlock
Grid.Column="0" Grid.Column="0"
Text="Download media" VerticalAlignment="Center"
VerticalAlignment="Center" /> Text="Download media" />
<ToggleButton <ToggleButton
Grid.Column="1" Grid.Column="1"
HorizontalAlignment="Right" HorizontalAlignment="Right"
IsChecked="{Binding ShouldDownloadMedia}" VerticalAlignment="Center"
VerticalAlignment="Center" /> IsChecked="{Binding ShouldDownloadMedia}" />
</Grid> </Grid>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
@ -198,8 +198,8 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Button <Button
Command="{s:Action ToggleAdvancedSection}"
Grid.Column="0" Grid.Column="0"
Command="{s:Action ToggleAdvancedSection}"
IsDefault="True" IsDefault="True"
ToolTip="Toggle advanced options"> ToolTip="Toggle advanced options">
<Button.Style> <Button.Style>
@ -217,17 +217,17 @@
</Button> </Button>
<Button <Button
Grid.Column="2"
Command="{s:Action Confirm}" Command="{s:Action Confirm}"
Content="EXPORT" Content="EXPORT"
Grid.Column="2"
IsDefault="True" IsDefault="True"
Style="{DynamicResource MaterialDesignOutlinedButton}" /> Style="{DynamicResource MaterialDesignOutlinedButton}" />
<Button <Button
Grid.Column="3"
Margin="8,0,0,0"
Command="{s:Action Close}" Command="{s:Action Close}"
Content="CANCEL" Content="CANCEL"
Grid.Column="3"
IsCancel="True" IsCancel="True"
Margin="8,0,0,0"
Style="{DynamicResource MaterialDesignOutlinedButton}" /> Style="{DynamicResource MaterialDesignOutlinedButton}" />
</Grid> </Grid>
</Grid> </Grid>

@ -6,6 +6,7 @@
xmlns:dialogs="clr-namespace:DiscordChatExporter.Gui.ViewModels.Dialogs" xmlns:dialogs="clr-namespace:DiscordChatExporter.Gui.ViewModels.Dialogs"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:s="https://github.com/canton7/Stylet" xmlns:s="https://github.com/canton7/Stylet"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
MinWidth="500" MinWidth="500"
d:DataContext="{d:DesignInstance Type=dialogs:MessageBoxViewModel}" d:DataContext="{d:DesignInstance Type=dialogs:MessageBoxViewModel}"
Style="{DynamicResource MaterialDesignRoot}" Style="{DynamicResource MaterialDesignRoot}"
@ -41,15 +42,32 @@
</ScrollViewer> </ScrollViewer>
</Border> </Border>
<!-- Close --> <UniformGrid
<Button
Grid.Row="2" Grid.Row="2"
Margin="16" Margin="16"
HorizontalAlignment="Right"
Columns="{Binding ButtonsCount}">
<!-- OK -->
<Button
Command="{s:Action Close}"
Content="{Binding OkButtonText}"
IsDefault="True"
Style="{DynamicResource MaterialDesignOutlinedButton}"
Visibility="{Binding IsOkButtonVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<Button.CommandParameter>
<system:Boolean>True</system:Boolean>
</Button.CommandParameter>
</Button>
<!-- Cancel -->
<Button
Margin="8,0,0,0"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
Command="{s:Action Close}" Command="{s:Action Close}"
Content="CLOSE" Content="{Binding CancelButtonText}"
IsCancel="True" IsCancel="True"
IsDefault="True" Style="{DynamicResource MaterialDesignOutlinedButton}"
Style="{DynamicResource MaterialDesignOutlinedButton}" /> Visibility="{Binding IsCancelButtonVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
</UniformGrid>
</Grid> </Grid>
</UserControl> </UserControl>

@ -1,16 +1,7 @@
<Window <Window
Background="{DynamicResource MaterialDesignPaper}"
FocusManager.FocusedElement="{Binding ElementName=TokenValueTextBox}"
Height="550"
Icon="/DiscordChatExporter;component/favicon.ico"
MinWidth="325"
Style="{DynamicResource MaterialDesignRoot}"
Width="600"
WindowStartupLocation="CenterScreen"
d:DataContext="{d:DesignInstance Type=viewModels:RootViewModel}"
mc:Ignorable="d"
x:Class="DiscordChatExporter.Gui.Views.RootView" x:Class="DiscordChatExporter.Gui.Views.RootView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:behaviors="clr-namespace:DiscordChatExporter.Gui.Behaviors" xmlns:behaviors="clr-namespace:DiscordChatExporter.Gui.Behaviors"
xmlns:componentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase" xmlns:componentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
xmlns:converters="clr-namespace:DiscordChatExporter.Gui.Converters" xmlns:converters="clr-namespace:DiscordChatExporter.Gui.Converters"
@ -20,12 +11,21 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:s="https://github.com/canton7/Stylet" xmlns:s="https://github.com/canton7/Stylet"
xmlns:viewModels="clr-namespace:DiscordChatExporter.Gui.ViewModels" xmlns:viewModels="clr-namespace:DiscordChatExporter.Gui.ViewModels"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> Width="600"
Height="550"
MinWidth="325"
d:DataContext="{d:DesignInstance Type=viewModels:RootViewModel}"
Background="{DynamicResource MaterialDesignPaper}"
FocusManager.FocusedElement="{Binding ElementName=TokenValueTextBox}"
Icon="/DiscordChatExporter;component/favicon.ico"
Style="{DynamicResource MaterialDesignRoot}"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Window.TaskbarItemInfo> <Window.TaskbarItemInfo>
<TaskbarItemInfo ProgressState="Normal" ProgressValue="{Binding Progress.Current.Fraction}" /> <TaskbarItemInfo ProgressState="Normal" ProgressValue="{Binding Progress.Current.Fraction}" />
</Window.TaskbarItemInfo> </Window.TaskbarItemInfo>
<Window.Resources> <Window.Resources>
<CollectionViewSource Source="{Binding AvailableChannels, Mode=OneWay}" x:Key="AvailableChannelsViewSource"> <CollectionViewSource x:Key="AvailableChannelsViewSource" Source="{Binding AvailableChannels, Mode=OneWay}">
<CollectionViewSource.GroupDescriptions> <CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Category.Name" /> <PropertyGroupDescription PropertyName="Category.Name" />
</CollectionViewSource.GroupDescriptions> </CollectionViewSource.GroupDescriptions>
@ -36,7 +36,10 @@
</CollectionViewSource> </CollectionViewSource>
</Window.Resources> </Window.Resources>
<materialDesign:DialogHost SnackbarMessageQueue="{Binding Notifications}" Style="{DynamicResource MaterialDesignEmbeddedDialogHost}"> <materialDesign:DialogHost
Loaded="{s:Action OnViewFullyLoaded}"
SnackbarMessageQueue="{Binding Notifications}"
Style="{DynamicResource MaterialDesignEmbeddedDialogHost}">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@ -46,7 +49,7 @@
</Grid.RowDefinitions> </Grid.RowDefinitions>
<!-- Toolbar --> <!-- Toolbar -->
<Grid Background="{DynamicResource MaterialDesignDarkBackground}" Grid.Row="0"> <Grid Grid.Row="0" Background="{DynamicResource MaterialDesignDarkBackground}">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@ -54,8 +57,8 @@
<!-- Token and pull data button --> <!-- Token and pull data button -->
<materialDesign:Card <materialDesign:Card
Grid.Column="0"
Grid.Row="0" Grid.Row="0"
Grid.Column="0"
Margin="12,12,0,12"> Margin="12,12,0,12">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
@ -66,74 +69,74 @@
<!-- Token icon --> <!-- Token icon -->
<materialDesign:PackIcon <materialDesign:PackIcon
Foreground="{DynamicResource PrimaryHueMidBrush}"
Grid.Column="0" Grid.Column="0"
Width="24"
Height="24" Height="24"
Kind="Password"
Margin="8" Margin="8"
VerticalAlignment="Center" VerticalAlignment="Center"
Width="24" /> Foreground="{DynamicResource PrimaryHueMidBrush}"
Kind="Password" />
<!-- Token value --> <!-- Token value -->
<TextBox <TextBox
BorderThickness="0" x:Name="TokenValueTextBox"
FontSize="16"
Grid.Column="1" Grid.Column="1"
Margin="0,6,6,8" Margin="0,6,6,8"
Text="{Binding Token, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Bottom" VerticalAlignment="Bottom"
materialDesign:HintAssist.Hint="Token" materialDesign:HintAssist.Hint="Token"
materialDesign:TextFieldAssist.DecorationVisibility="Hidden" materialDesign:TextFieldAssist.DecorationVisibility="Hidden"
materialDesign:TextFieldAssist.TextBoxViewMargin="0,0,2,0" materialDesign:TextFieldAssist.TextBoxViewMargin="0,0,2,0"
x:Name="TokenValueTextBox" /> BorderThickness="0"
FontSize="16"
Text="{Binding Token, UpdateSourceTrigger=PropertyChanged}" />
<!-- Pull data button --> <!-- Pull data button -->
<Button <Button
Command="{s:Action PopulateGuildsAndChannels}"
Grid.Column="2" Grid.Column="2"
IsDefault="True"
Margin="0,6,6,6" Margin="0,6,6,6"
Padding="4" Padding="4"
Command="{s:Action PopulateGuildsAndChannels}"
IsDefault="True"
Style="{DynamicResource MaterialDesignFlatButton}" Style="{DynamicResource MaterialDesignFlatButton}"
ToolTip="Pull available guilds and channels (Enter)"> ToolTip="Pull available guilds and channels (Enter)">
<materialDesign:PackIcon <materialDesign:PackIcon
Width="24"
Height="24" Height="24"
Kind="ArrowRight" Kind="ArrowRight" />
Width="24" />
</Button> </Button>
</Grid> </Grid>
</materialDesign:Card> </materialDesign:Card>
<!-- Settings button --> <!-- Settings button -->
<Button <Button
Command="{s:Action ShowSettings}"
Foreground="{DynamicResource MaterialDesignDarkForeground}"
Grid.Column="1" Grid.Column="1"
Margin="6" Margin="6"
Padding="4" Padding="4"
Command="{s:Action ShowSettings}"
Foreground="{DynamicResource MaterialDesignDarkForeground}"
Style="{DynamicResource MaterialDesignFlatButton}" Style="{DynamicResource MaterialDesignFlatButton}"
ToolTip="Settings"> ToolTip="Settings">
<Button.Resources> <Button.Resources>
<SolidColorBrush Color="#4C4C4C" x:Key="MaterialDesignFlatButtonClick" /> <SolidColorBrush x:Key="MaterialDesignFlatButtonClick" Color="#4C4C4C" />
</Button.Resources> </Button.Resources>
<materialDesign:PackIcon <materialDesign:PackIcon
Width="24"
Height="24" Height="24"
Kind="Settings" Kind="Settings" />
Width="24" />
</Button> </Button>
</Grid> </Grid>
<!-- Progress bar --> <!-- Progress bar -->
<ProgressBar <ProgressBar
Background="{DynamicResource MaterialDesignDarkBackground}"
Grid.Row="1" Grid.Row="1"
Background="{DynamicResource MaterialDesignDarkBackground}"
IsIndeterminate="{Binding IsProgressIndeterminate}" IsIndeterminate="{Binding IsProgressIndeterminate}"
Value="{Binding Progress.Current.Fraction, Mode=OneWay}" /> Value="{Binding Progress.Current.Fraction, Mode=OneWay}" />
<!-- Content --> <!-- Content -->
<Grid <Grid
Background="{DynamicResource MaterialDesignCardBackground}"
Grid.Row="2" Grid.Row="2"
Background="{DynamicResource MaterialDesignCardBackground}"
IsEnabled="{Binding IsBusy, Converter={x:Static converters:InverseBoolConverter.Instance}}"> IsEnabled="{Binding IsBusy, Converter={x:Static converters:InverseBoolConverter.Instance}}">
<Grid.Resources> <Grid.Resources>
<Style TargetType="TextBlock"> <Style TargetType="TextBlock">
@ -143,7 +146,7 @@
<!-- Placeholder / usage instructions --> <!-- Placeholder / usage instructions -->
<Grid Visibility="{Binding AvailableGuilds, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}}"> <Grid Visibility="{Binding AvailableGuilds, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}}">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<TextBlock FontSize="14" Margin="32,16"> <TextBlock Margin="32,16" FontSize="14">
<Run FontSize="18" Text="Please provide authentication token to continue" /> <Run FontSize="18" Text="Please provide authentication token to continue" />
<LineBreak /> <LineBreak />
<LineBreak /> <LineBreak />
@ -151,9 +154,9 @@
<!-- User token --> <!-- User token -->
<InlineUIContainer> <InlineUIContainer>
<materialDesign:PackIcon <materialDesign:PackIcon
Margin="1,0,0,-2"
Foreground="{DynamicResource PrimaryHueMidBrush}" Foreground="{DynamicResource PrimaryHueMidBrush}"
Kind="Account" Kind="Account" />
Margin="1,0,0,-2" />
</InlineUIContainer> </InlineUIContainer>
<Run FontSize="16" Text="Authenticate using your personal account" /> <Run FontSize="16" Text="Authenticate using your personal account" />
<LineBreak /> <LineBreak />
@ -199,11 +202,11 @@
<!-- Bot token --> <!-- Bot token -->
<InlineUIContainer> <InlineUIContainer>
<materialDesign:PackIcon <materialDesign:PackIcon
Margin="1,0,0,-2"
Foreground="{DynamicResource PrimaryHueMidBrush}" Foreground="{DynamicResource PrimaryHueMidBrush}"
Kind="Robot" Kind="Robot" />
Margin="1,0,0,-2" />
</InlineUIContainer> </InlineUIContainer>
<Run FontSize="16" Text="Authenticate as a bot" /> <Run FontSize="16" Text="Authenticate using a bot account" />
<LineBreak /> <LineBreak />
<Run Text="1. Open Discord developer portal" /> <Run Text="1. Open Discord developer portal" />
<LineBreak /> <LineBreak />
@ -235,9 +238,9 @@
<!-- Guilds --> <!-- Guilds -->
<Border <Border
Grid.Column="0"
BorderBrush="{DynamicResource MaterialDesignDivider}" BorderBrush="{DynamicResource MaterialDesignDivider}"
BorderThickness="0,0,1,0" BorderThickness="0,0,1,0">
Grid.Column="0">
<ListBox <ListBox
ItemsSource="{Binding AvailableGuilds}" ItemsSource="{Binding AvailableGuilds}"
ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Hidden"
@ -246,24 +249,24 @@
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<Grid <Grid
Margin="-8"
Background="Transparent" Background="Transparent"
Cursor="Hand" Cursor="Hand"
Margin="-8"
ToolTip="{Binding Name}"> ToolTip="{Binding Name}">
<!-- Guild icon placeholder --> <!-- Guild icon placeholder -->
<Ellipse <Ellipse
Fill="{DynamicResource MaterialDesignDivider}" Width="48"
Height="48" Height="48"
Margin="12,4,12,4" Margin="12,4,12,4"
Width="48" /> Fill="{DynamicResource MaterialDesignDivider}" />
<!-- Guild icon --> <!-- Guild icon -->
<Ellipse <Ellipse
Width="48"
Height="48" Height="48"
Margin="12,4,12,4" Margin="12,4,12,4"
Stroke="{DynamicResource MaterialDesignDivider}" Stroke="{DynamicResource MaterialDesignDivider}"
StrokeThickness="1" StrokeThickness="1">
Width="48">
<Ellipse.Fill> <Ellipse.Fill>
<ImageBrush ImageSource="{Binding IconUrl}" /> <ImageBrush ImageSource="{Binding IconUrl}" />
</Ellipse.Fill> </Ellipse.Fill>
@ -293,13 +296,13 @@
<Setter.Value> <Setter.Value>
<ControlTemplate d:DataContext="{x:Type CollectionViewGroup}"> <ControlTemplate d:DataContext="{x:Type CollectionViewGroup}">
<Expander <Expander
Margin="0"
Padding="0"
Background="Transparent" Background="Transparent"
BorderBrush="{DynamicResource MaterialDesignDivider}" BorderBrush="{DynamicResource MaterialDesignDivider}"
BorderThickness="0,0,0,1" BorderThickness="0,0,0,1"
Header="{Binding Name}" Header="{Binding Name}"
IsExpanded="False" IsExpanded="False">
Margin="0"
Padding="0">
<ItemsPresenter /> <ItemsPresenter />
</Expander> </Expander>
</ControlTemplate> </ControlTemplate>
@ -311,7 +314,7 @@
</ListBox.GroupStyle> </ListBox.GroupStyle>
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<Grid Background="Transparent" Margin="-8"> <Grid Margin="-8" Background="Transparent">
<Grid.InputBindings> <Grid.InputBindings>
<MouseBinding Command="{s:Action ExportChannels}" MouseAction="LeftDoubleClick" /> <MouseBinding Command="{s:Action ExportChannels}" MouseAction="LeftDoubleClick" />
</Grid.InputBindings> </Grid.InputBindings>
@ -324,27 +327,27 @@
<!-- Channel icon --> <!-- Channel icon -->
<materialDesign:PackIcon <materialDesign:PackIcon
Grid.Column="0" Grid.Column="0"
Kind="Pound"
Margin="16,7,0,6" Margin="16,7,0,6"
VerticalAlignment="Center" /> VerticalAlignment="Center"
Kind="Pound" />
<!-- Channel name --> <!-- Channel name -->
<TextBlock <TextBlock
FontSize="14"
Grid.Column="1" Grid.Column="1"
Margin="3,8,8,8" Margin="3,8,8,8"
Text="{Binding Name, Mode=OneWay}" VerticalAlignment="Center"
VerticalAlignment="Center" /> FontSize="14"
Text="{Binding Name, Mode=OneWay}" />
<!-- Is selected checkmark --> <!-- Is selected checkmark -->
<materialDesign:PackIcon <materialDesign:PackIcon
Grid.Column="2" Grid.Column="2"
Width="24"
Height="24" Height="24"
Kind="Check"
Margin="8,0" Margin="8,0"
VerticalAlignment="Center" VerticalAlignment="Center"
Visibility="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" Kind="Check"
Width="24" /> Visibility="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
</Grid> </Grid>
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
@ -354,16 +357,16 @@
<!-- Export button --> <!-- Export button -->
<Button <Button
Command="{s:Action ExportChannels}"
HorizontalAlignment="Right"
Margin="32,24" Margin="32,24"
Style="{DynamicResource MaterialDesignFloatingActionAccentButton}" HorizontalAlignment="Right"
VerticalAlignment="Bottom" VerticalAlignment="Bottom"
Command="{s:Action ExportChannels}"
Style="{DynamicResource MaterialDesignFloatingActionAccentButton}"
Visibility="{Binding CanExportChannels, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"> Visibility="{Binding CanExportChannels, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<materialDesign:PackIcon <materialDesign:PackIcon
Width="32"
Height="32" Height="32"
Kind="Download" Kind="Download" />
Width="32" />
</Button> </Button>
<!-- Notifications snackbar --> <!-- Notifications snackbar -->

Loading…
Cancel
Save