* Create a dummy WPF project

* Set up Ammy placeholders

* Don't track autogenerated files

* Basic layout

* Add Program.cs

* Implement basic workflow

* Autofocus token textbox and add Enter key handler

* Strip double quotes from token

* AmmyUI converters are slightly dumb :(

* Use CanExecute

* Add file path select and theme select, also refactor

* Persist token

* Trying to improve UI/UX - 1

* Rename stuff

* Finish improving UI/UX

* Remove data placeholder

* Remove border on middle grid

* Ok now i'm done

* Improve Discord API layer

* Add lots of stuff

* Show filesizes in export

* Improve export

* Animations

* Update readme

* Improving gui again

* Improve UI again

* Refactor
This commit is contained in:
Alexey Golub
2017-09-28 01:24:45 +03:00
committed by GitHub
parent d8bbe8c8c8
commit 6d7a8ae063
44 changed files with 1937 additions and 478 deletions

View File

@@ -0,0 +1,261 @@
using MaterialDesignThemes.Wpf
using MaterialDesignThemes.Wpf.Transitions
Window "DiscordChatExporter.Views.MainWindow" {
Title: "DiscordChatExporter"
Width: 600
Height: 550
Background: resource dyn "MaterialDesignPaper"
DataContext: bind MainViewModel from $resource Locator
FocusManager.FocusedElement: bind from "TokenTextBox"
FontFamily: resource dyn "MaterialDesignFont"
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 {
Grid.Column: 0
Margin: "6 6 0 6"
Grid {
#TwoColumns("*", "Auto")
// Token
TextBox "TokenTextBox" {
Grid.Column: 0
Margin: 6
BorderThickness: 0
HintAssist.Hint: "Token"
KeyDown: TokenTextBox_KeyDown
FontSize: 16
Text: bind Token
set [ UpdateSourceTrigger: PropertyChanged ]
}
// Submit
Button {
Grid.Column: 1
Margin: "0 6 6 6"
Padding: 4
Command: bind PullDataCommand
Style: resource dyn "MaterialDesignFlatButton"
PackIcon {
Width: 24
Height: 24
Kind: PackIconKind.ArrowRight
}
}
}
}
// Popup menu
PopupBox {
Grid.Column: 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: SlideInFromRight
}
Border {
Margin: -8
Background: Transparent
Cursor: CursorType.Hand
Image {
Margin: 6
Width: 48
Height: 48
Source: bind IconUrl
ToolTip: bind Name
}
}
}
}
}
}
// 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.ExportChannelCommand from $ancestor<ItemsControl>
CommandParameter: bind
MouseAction: LeftClick
}
]
PackIcon {
Margin: "4 7 0 6"
Kind: PackIconKind.Pound
VerticalAlignment: Center
}
TextBlock {
Margin: "3 6 6 6"
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,32 @@
using System.Reflection;
using System.Windows.Input;
using DiscordChatExporter.Messages;
using DiscordChatExporter.ViewModels;
using GalaSoft.MvvmLight.Messaging;
using MaterialDesignThemes.Wpf;
using Tyrrrz.Extensions;
namespace DiscordChatExporter.Views
{
public partial class MainWindow
{
private IMainViewModel ViewModel => (IMainViewModel) DataContext;
public MainWindow()
{
InitializeComponent();
Title += $" v{Assembly.GetExecutingAssembly().GetName().Version}";
Messenger.Default.Register<ShowSettingsMessage>(this, m => DialogHost.Show(new SettingsDialog()).Forget());
}
public void TokenTextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
// Execute command
ViewModel.PullDataCommand.Execute(null);
}
}
}
}

View File

@@ -0,0 +1,26 @@
using MaterialDesignThemes.Wpf
UserControl "DiscordChatExporter.Views.SettingsDialog" {
DataContext: bind SettingsViewModel from $resource Locator
Width: 250
StackPanel {
// Theme
ComboBox {
HintAssist.Hint: "Theme"
HintAssist.IsFloating: true
Margin: 8
IsReadOnly: true
ItemsSource: bind AvailableThemes
SelectedItem: bind Theme
}
// Save
Button {
Command: DialogHost.CloseDialogCommand
Content: "SAVE"
Margin: 8
Style: resource dyn "MaterialDesignFlatButton"
}
}
}

View File

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