Cleanup GUI

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

@ -7,7 +7,7 @@
<ItemGroup>
<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" />
</ItemGroup>

@ -7,7 +7,7 @@
<ItemGroup>
<PackageReference Include="Gress" Version="2.0.1" />
<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="Superpower" Version="3.0.0" />
</ItemGroup>

@ -47,6 +47,21 @@
<Setter Property="Minimum" Value="0" />
</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 MaterialDesignComboBox}" TargetType="{x:Type ComboBox}" />
@ -90,6 +105,10 @@
</Style.Triggers>
</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) -->
<Style BasedOn="{StaticResource MaterialDesignExpander}" TargetType="{x:Type Expander}">
<Setter Property="Template">

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

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

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

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

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

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

@ -11,6 +11,8 @@ internal static class ProcessEx
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? 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 MessageBoxViewModel CreateMessageBoxViewModel(
this IViewModelFactory factory,
string title,
string message)
string title, string message,
string? okButtonText, string? cancelButtonText)
{
var viewModel = factory.CreateMessageBoxViewModel();
viewModel.Title = title;
viewModel.Message = message;
viewModel.IsOkButtonVisible = !string.IsNullOrWhiteSpace(okButtonText);
viewModel.OkButtonText = okButtonText;
viewModel.IsCancelButtonVisible = !string.IsNullOrWhiteSpace(cancelButtonText);
viewModel.CancelButtonText = cancelButtonText;
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));
}
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()
{
try
@ -97,6 +114,12 @@ public class RootViewModel : Screen
Notifications.Enqueue("Failed to perform application update");
}
}
// This is a custom event that fires when the dialog host is loaded
public async void OnViewFullyLoaded()
{
await ShowWarInUkraineMessageAsync();
}
protected override async void OnViewLoaded()
{
@ -118,19 +141,6 @@ public class RootViewModel : Screen
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();
}

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

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

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

Loading…
Cancel
Save