Add command line interface and change solution structure (#26)

This commit is contained in:
Alexey Golub 2018-01-12 20:28:36 +01:00 committed by GitHub
parent 7da82f9ef4
commit 8515efe11b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
74 changed files with 508 additions and 218 deletions

View file

@ -0,0 +1,25 @@
using MaterialDesignThemes.Wpf
UserControl "DiscordChatExporter.Gui.Views.ErrorDialog" {
DataContext: bind ErrorViewModel from $resource Container
Width: 250
StackPanel {
// Message
TextBlock {
Margin: 16
FontSize: 16
TextWrapping: WrapWithOverflow
Text: bind Message
}
// OK
Button {
Margin: 8
Command: DialogHost.CloseDialogCommand
Content: "OK"
HorizontalAlignment: Right
Style: resource dyn "MaterialDesignFlatButton"
}
}
}

View file

@ -0,0 +1,10 @@
namespace DiscordChatExporter.Gui.Views
{
public partial class ErrorDialog
{
public ErrorDialog()
{
InitializeComponent();
}
}
}

View file

@ -0,0 +1,38 @@
using MaterialDesignThemes.Wpf
UserControl "DiscordChatExporter.Gui.Views.ExportDoneDialog" {
DataContext: bind ExportDoneViewModel from $resource Container
Width: 250
StackPanel {
// Message
TextBlock {
Margin: 16
FontSize: 16
TextWrapping: WrapWithOverflow
Text: "Finished exporting chat log"
}
// Buttons
@StackPanelHorizontal {
HorizontalAlignment: Right
// Open
Button "OpenButton" {
Margin: 8
Click: OpenButton_Click
Command: bind OpenCommand
Content: "OPEN IT"
Style: resource dyn "MaterialDesignFlatButton"
}
// Dismiss
Button {
Margin: 8
Command: DialogHost.CloseDialogCommand
Content: "DISMISS"
Style: resource dyn "MaterialDesignFlatButton"
}
}
}
}

View file

@ -0,0 +1,18 @@
using System.Windows;
using MaterialDesignThemes.Wpf;
namespace DiscordChatExporter.Gui.Views
{
public partial class ExportDoneDialog
{
public ExportDoneDialog()
{
InitializeComponent();
}
public void OpenButton_Click(object sender, RoutedEventArgs args)
{
DialogHost.CloseDialogCommand.Execute(null, null);
}
}
}

View file

@ -0,0 +1,88 @@
using DiscordChatExporter.Core.Models
using MaterialDesignThemes.Wpf
UserControl "DiscordChatExporter.Gui.Views.ExportSetupDialog" {
DataContext: bind ExportSetupViewModel from $resource Container
Width: 325
StackPanel {
// File path
TextBox {
Margin: [16, 16, 16, 8]
HintAssist.Hint: "Output file"
HintAssist.IsFloating: true
IsReadOnly: true
Text: bind FilePath
set [ UpdateSourceTrigger: PropertyChanged ]
}
// Format
ComboBox {
Margin: [16, 8, 16, 8]
HintAssist.Hint: "Export format"
HintAssist.IsFloating: true
IsReadOnly: true
ItemsSource: bind AvailableFormats
SelectedItem: bind SelectedFormat
ItemTemplate: DataTemplate {
TextBlock {
Text: bind
convert (ExportFormat f) => Extensions.GetDisplayName(f)
}
}
}
// Date range
Grid {
#TwoColumns("*", "*")
DatePicker {
#Cell(0, 0)
Margin: [16, 20, 8, 8]
HintAssist.Hint: "From (optional)"
HintAssist.IsFloating: true
SelectedDate: bind From
}
DatePicker {
#Cell(0, 1)
Margin: [8, 20, 16, 8]
HintAssist.Hint: "To (optional)"
HintAssist.IsFloating: true
SelectedDate: bind To
}
}
// Buttons
@StackPanelHorizontal {
HorizontalAlignment: Right
// Browse
Button "BrowseButton" {
Margin: 8
Click: BrowseButton_Click
Content: "BROWSE"
Style: resource dyn "MaterialDesignFlatButton"
}
// Export
Button "ExportButton" {
Margin: 8
Click: ExportButton_Click
Command: bind ExportCommand
Content: "EXPORT"
IsDefault: true
Style: resource dyn "MaterialDesignFlatButton"
}
// Cancel
Button {
Margin: 8
Command: DialogHost.CloseDialogCommand
Content: "CANCEL"
Style: resource dyn "MaterialDesignFlatButton"
}
}
}
}

View file

@ -0,0 +1,44 @@
using System.Windows;
using DiscordChatExporter.Core.Models;
using DiscordChatExporter.Gui.ViewModels;
using MaterialDesignThemes.Wpf;
using Microsoft.Win32;
namespace DiscordChatExporter.Gui.Views
{
public partial class ExportSetupDialog
{
private IExportSetupViewModel ViewModel => (IExportSetupViewModel) DataContext;
public ExportSetupDialog()
{
InitializeComponent();
}
public void BrowseButton_Click(object sender, RoutedEventArgs args)
{
// Get file extension of the selected format
var ext = ViewModel.SelectedFormat.GetFileExtension();
// Open dialog
var sfd = new SaveFileDialog
{
FileName = ViewModel.FilePath,
Filter = $"{ext.ToUpperInvariant()} Files|*.{ext}|All Files|*.*",
AddExtension = true,
Title = "Select output file"
};
// Assign new file path if dialog was successful
if (sfd.ShowDialog() == true)
{
ViewModel.FilePath = sfd.FileName;
}
}
public void ExportButton_Click(object sender, RoutedEventArgs args)
{
DialogHost.CloseDialogCommand.Execute(null, null);
}
}
}

View file

@ -0,0 +1,271 @@
using MaterialDesignThemes.Wpf
using MaterialDesignThemes.Wpf.Transitions
Window "DiscordChatExporter.Gui.Views.MainWindow" {
Title: "DiscordChatExporter"
Width: 600
Height: 550
Background: resource dyn "MaterialDesignPaper"
DataContext: bind MainViewModel from $resource Container
FocusManager.FocusedElement: bind from "TokenTextBox"
FontFamily: resource dyn "MaterialDesignFont"
Icon: "/DiscordChatExporter;component/favicon.ico"
SnapsToDevicePixels: true
TextElement.FontSize: 13
TextElement.FontWeight: Regular
TextElement.Foreground: resource dyn "SecondaryTextBrush"
TextOptions.TextFormattingMode: Ideal
TextOptions.TextRenderingMode: Auto
UseLayoutRounding: true
WindowStartupLocation: CenterScreen
DialogHost {
DockPanel {
IsEnabled: bind IsBusy
convert (bool b) => b ? false : true
// Toolbar
Border {
DockPanel.Dock: Top
Background: resource dyn "PrimaryHueMidBrush"
TextElement.Foreground: resource dyn "SecondaryInverseTextBrush"
StackPanel {
Grid {
#TwoColumns("*", "Auto")
Card {
#Cell(0, 0)
Margin: [6, 6, 0, 6]
Grid {
#TwoColumns("*", "Auto")
// Token
TextBox "TokenTextBox" {
#Cell(0, 0)
Margin: 6
BorderThickness: 0
HintAssist.Hint: "Token"
FontSize: 16
Text: bind Token
set [ UpdateSourceTrigger: PropertyChanged ]
TextFieldAssist.DecorationVisibility: Hidden
TextFieldAssist.TextBoxViewMargin: [0, 0, 2, 0]
}
// Submit
Button {
#Cell(0, 1)
Margin: [0, 6, 6, 6]
Padding: 4
Command: bind PullDataCommand
IsDefault: true
Style: resource dyn "MaterialDesignFlatButton"
PackIcon {
Width: 24
Height: 24
Kind: PackIconKind.ArrowRight
}
}
}
}
// Popup menu
PopupBox {
#Cell(0, 1)
Foreground: resource dyn "PrimaryHueMidForegroundBrush"
PlacementMode: LeftAndAlignTopEdges
StackPanel {
Button {
Command: bind ShowSettingsCommand
Content: "Settings"
}
Button {
Command: bind ShowAboutCommand
Content: "About"
}
}
}
}
// Progress
ProgressBar {
Background: Transparent
IsIndeterminate: true
Visibility: bind IsBusy
convert (bool b) => b ? Visibility.Visible : Visibility.Hidden
}
}
}
// Content
Grid {
DockPanel {
Background: resource dyn "MaterialDesignCardBackground"
Visibility: bind IsDataAvailable
convert (bool b) => b ? Visibility.Visible : Visibility.Hidden
// Guilds
Border {
DockPanel.Dock: Left
BorderBrush: resource dyn "DividerBrush"
BorderThickness: "0 0 1 0"
ListBox {
ItemsSource: bind AvailableGuilds
ScrollViewer.VerticalScrollBarVisibility: Hidden
SelectedItem: bind SelectedGuild
VirtualizingStackPanel.IsVirtualizing: false
ItemTemplate: DataTemplate {
TransitioningContent {
OpeningEffect: TransitionEffect {
Duration: "0:0:0.3"
Kind: SlideInFromLeft
}
Border {
Margin: -8
Background: Transparent
Cursor: CursorType.Hand
Image {
Margin: [12, 4, 12, 4]
Width: 48
Height: 48
Source: bind IconUrl
ToolTip: bind Name
OpacityMask: RadialGradientBrush {
GradientStops: [
GradientStop { Color: "#FF000000", Offset: 0 }
GradientStop { Color: "#FF000000", Offset: 0.96 }
GradientStop { Color: "#00000000", Offset: 1 }
]
}
}
}
}
}
}
}
// Channels
Border {
ListBox {
ItemsSource: bind AvailableChannels
HorizontalContentAlignment: Stretch
VirtualizingStackPanel.IsVirtualizing: false
ItemTemplate: DataTemplate {
TransitioningContent {
OpeningEffect: TransitionEffect {
Duration: "0:0:0.3"
Kind: SlideInFromLeft
}
@StackPanelHorizontal {
Margin: -8
Background: Transparent
Cursor: CursorType.Hand
InputBindings: [
MouseBinding {
Command: bind DataContext.ShowExportSetupCommand from $ancestor<ItemsControl>
CommandParameter: bind
MouseAction: LeftClick
}
]
PackIcon {
Margin: [16, 7, 0, 6]
Kind: PackIconKind.Pound
VerticalAlignment: Center
}
TextBlock {
Margin: [3, 8, 8, 8]
FontSize: 14
Text: bind Name
VerticalAlignment: Center
}
}
}
}
}
}
}
// Content placeholder
StackPanel {
Margin: [32, 32, 8, 8]
Visibility: bind IsDataAvailable
convert (bool b) => b ? Visibility.Hidden : Visibility.Visible
TextBlock {
FontSize: 18
Text: "DiscordChatExporter needs your authorization token to work."
}
TextBlock {
Margin: [0, 8, 0, 0]
FontSize: 16
Text: "To obtain it, follow these steps:"
}
TextBlock {
Margin: [8, 0, 0, 0]
FontSize: 14
Run {
Text: "1. Open the Discord app"
}
LineBreak { }
Run {
Text: "2. Log in if you haven't"
}
LineBreak { }
Run {
Text: "3. Press"
}
Run {
Text: "Ctrl+Shift+I"
Foreground: resource dyn "PrimaryTextBrush"
}
LineBreak { }
Run {
Text: "4. Navigate to"
}
Run {
Text: "Application"
Foreground: resource dyn "PrimaryTextBrush"
}
Run { Text: "tab" }
LineBreak { }
Run {
Text: "5. Expand"
}
Run {
Text: "Storage > Local Storage > https://discordapp.com"
Foreground: resource dyn "PrimaryTextBrush"
}
LineBreak { }
Run {
Text: "6. Find"
}
Run {
Text: "&quot;token&quot;"
Foreground: resource dyn "PrimaryTextBrush"
}
Run {
Text: "under key and copy the value"
}
LineBreak { }
Run {
Text: "7. Paste the value in the textbox above"
}
}
}
}
}
}
}

View file

@ -0,0 +1,27 @@
using System.Reflection;
using DiscordChatExporter.Gui.Messages;
using GalaSoft.MvvmLight.Messaging;
using MaterialDesignThemes.Wpf;
using Tyrrrz.Extensions;
namespace DiscordChatExporter.Gui.Views
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Title += $" v{Assembly.GetExecutingAssembly().GetName().Version}";
// Dialogs
Messenger.Default.Register<ShowErrorMessage>(this,
m => DialogHost.Show(new ErrorDialog()).Forget());
Messenger.Default.Register<ShowExportDoneMessage>(this,
m => DialogHost.Show(new ExportDoneDialog()).Forget());
Messenger.Default.Register<ShowExportSetupMessage>(this,
m => DialogHost.Show(new ExportSetupDialog()).Forget());
Messenger.Default.Register<ShowSettingsMessage>(this,
m => DialogHost.Show(new SettingsDialog()).Forget());
}
}
}

View file

@ -0,0 +1,33 @@
using MaterialDesignThemes.Wpf
UserControl "DiscordChatExporter.Gui.Views.SettingsDialog" {
DataContext: bind SettingsViewModel from $resource Container
Width: 250
StackPanel {
// Date format
TextBox {
Margin: [16, 16, 16, 8]
HintAssist.Hint: "Date format"
HintAssist.IsFloating: true
Text: bind DateFormat
}
// Group limit
TextBox {
Margin: [16, 8, 16, 8]
HintAssist.Hint: "Message group limit"
HintAssist.IsFloating: true
Text: bind MessageGroupLimit
}
// Save
Button {
Margin: 8
Command: DialogHost.CloseDialogCommand
Content: "SAVE"
HorizontalAlignment: Right
Style: resource dyn "MaterialDesignFlatButton"
}
}
}

View file

@ -0,0 +1,10 @@
namespace DiscordChatExporter.Gui.Views
{
public partial class SettingsDialog
{
public SettingsDialog()
{
InitializeComponent();
}
}
}