Add GUI (#7)
* 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 * Refactorpull/17/head
parent
d8bbe8c8c8
commit
6d7a8ae063
@ -0,0 +1,69 @@
|
||||
Application "DiscordChatExporter.App" {
|
||||
StartupUri: "Views/MainWindow.g.xaml"
|
||||
Startup: App_Startup
|
||||
Exit: App_Exit
|
||||
|
||||
Resources: ResourceDictionary {
|
||||
// Material Design
|
||||
#MergeDictionary("pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml")
|
||||
#MergeDictionary("pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml")
|
||||
|
||||
// Colors
|
||||
Color Key="PrimaryColor" { "#343838" }
|
||||
Color Key="PrimaryLightColor" { "#5E6262" }
|
||||
Color Key="PrimaryDarkColor" { "#0D1212" }
|
||||
Color Key="AccentColor" { "#F9A825" }
|
||||
Color Key="TextColor" { "#000000" }
|
||||
Color Key="InverseTextColor" { "#FFFFFF" }
|
||||
|
||||
// Brushes
|
||||
SolidColorBrush Key="PrimaryHueLightBrush" { Color: resource dyn "PrimaryLightColor" }
|
||||
SolidColorBrush Key="PrimaryHueLightForegroundBrush" { Color: resource dyn "InverseTextColor" }
|
||||
SolidColorBrush Key="PrimaryHueMidBrush" { Color: resource dyn "PrimaryColor" }
|
||||
SolidColorBrush Key="PrimaryHueMidForegroundBrush" { Color: resource dyn "InverseTextColor" }
|
||||
SolidColorBrush Key="PrimaryHueDarkBrush" { Color: resource dyn "PrimaryDarkColor" }
|
||||
SolidColorBrush Key="PrimaryHueDarkForegroundBrush" { Color: resource dyn "InverseTextColor" }
|
||||
SolidColorBrush Key="SecondaryAccentBrush" { Color: resource dyn "AccentColor" }
|
||||
SolidColorBrush Key="SecondaryAccentForegroundBrush" { Color: resource dyn "TextColor" }
|
||||
SolidColorBrush Key="PrimaryTextBrush" { Color: resource dyn "TextColor", Opacity: 0.87 }
|
||||
SolidColorBrush Key="SecondaryTextBrush" { Color: resource dyn "TextColor", Opacity: 0.64 }
|
||||
SolidColorBrush Key="DimTextBrush" { Color: resource dyn "TextColor", Opacity: 0.45 }
|
||||
SolidColorBrush Key="PrimaryInverseTextBrush" { Color: resource dyn "InverseTextColor", Opacity: 1 }
|
||||
SolidColorBrush Key="SecondaryInverseTextBrush" { Color: resource dyn "InverseTextColor", Opacity: 0.7 }
|
||||
SolidColorBrush Key="DimInverseTextBrush" { Color: resource dyn "InverseTextColor", Opacity: 0.52 }
|
||||
SolidColorBrush Key="AccentTextBrush" { Color: resource dyn "AccentColor", Opacity: 1 }
|
||||
SolidColorBrush Key="DividerBrush" { Color: resource dyn "TextColor", Opacity: 0.12 }
|
||||
SolidColorBrush Key="InverseDividerBrush" { Color: resource dyn "InverseTextColor", Opacity: 0.12 }
|
||||
|
||||
// Styles
|
||||
Style {
|
||||
TargetType: "Image"
|
||||
#Setter("RenderOptions.BitmapScalingMode", "HighQuality")
|
||||
}
|
||||
|
||||
Style {
|
||||
TargetType: "ProgressBar"
|
||||
BasedOn: resource "MaterialDesignLinearProgressBar"
|
||||
#Setter("Foreground", resource dyn "SecondaryAccentBrush")
|
||||
#Setter("Height", 2)
|
||||
#Setter("Minimum", 0)
|
||||
#Setter("Maximum", 1)
|
||||
#Setter("BorderThickness", 0)
|
||||
}
|
||||
|
||||
Style {
|
||||
TargetType: "TextBox"
|
||||
BasedOn: resource "MaterialDesignTextBox"
|
||||
#Setter("Foreground", resource dyn "PrimaryTextBrush")
|
||||
}
|
||||
|
||||
Style {
|
||||
TargetType: "ComboBox"
|
||||
BasedOn: resource "MaterialDesignComboBox"
|
||||
#Setter("Foreground", resource dyn "PrimaryTextBrush")
|
||||
}
|
||||
|
||||
// Locator
|
||||
Locator Key="Locator" { }
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
|
||||
</startup>
|
||||
</configuration>
|
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
@ -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: ""token""
|
||||
Foreground: resource dyn "PrimaryTextBrush"
|
||||
}
|
||||
Run {
|
||||
Text: "under key and copy the value"
|
||||
}
|
||||
LineBreak { }
|
||||
Run {
|
||||
Text: "7. Paste the value in the textbox above"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,238 @@
|
||||
mixin TwoColumns (one = "*", two = "*") for Grid {
|
||||
combine ColumnDefinitions: [
|
||||
ColumnDefinition { Width: $one }
|
||||
ColumnDefinition { Width: $two }
|
||||
]
|
||||
}
|
||||
|
||||
mixin ThreeColumns (one = none, two = none, three = none) for Grid {
|
||||
#TwoColumns($one, $two)
|
||||
combine ColumnDefinitions: ColumnDefinition { Width: $three }
|
||||
}
|
||||
|
||||
mixin FourColumns (one = none, two = none, three = none, four = none) for Grid {
|
||||
#ThreeColumns($one, $two, $three)
|
||||
combine ColumnDefinitions: ColumnDefinition { Width: $four }
|
||||
}
|
||||
|
||||
mixin FiveColumns (one = none, two = none, three = none, four = none, five = none) for Grid {
|
||||
#FourColumns($one, $two, $three, $four)
|
||||
combine ColumnDefinitions: ColumnDefinition { Width: $five }
|
||||
}
|
||||
|
||||
mixin TwoRows (one = none, two = none) for Grid
|
||||
{
|
||||
combine RowDefinitions: [
|
||||
RowDefinition { Height: $one }
|
||||
RowDefinition { Height: $two }
|
||||
]
|
||||
}
|
||||
|
||||
mixin ThreeRows (one = none, two = none, three = none) for Grid
|
||||
{
|
||||
#TwoRows($one, $two)
|
||||
combine RowDefinitions: RowDefinition { Height: $three }
|
||||
}
|
||||
|
||||
mixin FourRows (one = none, two = none, three = none, four = none) for Grid
|
||||
{
|
||||
#ThreeRows($one, $two, $three)
|
||||
combine RowDefinitions: RowDefinition { Height: $four }
|
||||
}
|
||||
|
||||
mixin FiveRows (one = none, two = none, three = none, four = none, five = none) for Grid
|
||||
{
|
||||
#FourRows($one, $two, $three, $four)
|
||||
combine RowDefinitions: RowDefinition { Height: $five }
|
||||
}
|
||||
|
||||
mixin Cell (row = none, column = none, rowSpan = none, columnSpan = none) for FrameworkElement {
|
||||
Grid.Row: $row
|
||||
Grid.Column: $column
|
||||
Grid.RowSpan: $rowSpan
|
||||
Grid.ColumnSpan: $columnSpan
|
||||
}
|
||||
|
||||
alias ImageCached(source) {
|
||||
Image {
|
||||
Source: BitmapImage {
|
||||
UriCachePolicy: "Revalidate"
|
||||
UriSource: $source
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mixin Setter(property, value, targetName=none) for Style {
|
||||
Setter { Property: $property, Value: $value, TargetName: $targetName }
|
||||
}
|
||||
|
||||
/*
|
||||
mixin AddSetter(property, value, targetName=none) for Style {
|
||||
combine Setters: #Setter($property, $value, $targetName) {}
|
||||
}*/
|
||||
|
||||
alias DataTrigger(binding, bindingValue) {
|
||||
DataTrigger { Binding: $binding, Value: $bindingValue }
|
||||
}
|
||||
|
||||
alias Trigger(property, value) {
|
||||
Trigger { Property: $property, Value: $value }
|
||||
}
|
||||
|
||||
alias EventTrigger(event, sourceName=none) {
|
||||
EventTrigger { RoutedEvent: $event, SourceName: $sourceName }
|
||||
}
|
||||
|
||||
alias DataTrigger_SetProperty(binding, bindingValue, property, propertyValue) {
|
||||
@DataTrigger ($binding, $bindingValue) {
|
||||
#Setter($property, $propertyValue)
|
||||
}
|
||||
}
|
||||
|
||||
alias Trigger_SetProperty(triggerProperty, triggerValue, property, propertyValue) {
|
||||
@Trigger ($triggerProperty, $triggerValue) {
|
||||
#Setter($property, $propertyValue)
|
||||
}
|
||||
}
|
||||
|
||||
alias EventTrigger_SetProperty(event, property, propertyValue) {
|
||||
@EventTrigger ($event) {
|
||||
#Setter($property, $propertyValue)
|
||||
}
|
||||
}
|
||||
alias VisibleIf_DataTrigger(binding, valueForVisible) {
|
||||
@DataTrigger_SetProperty($binding, $valueForVisible, "Visibility", "Visible") {}
|
||||
}
|
||||
|
||||
alias CollapsedIf_DataTrigger(binding, valueForCollapsed) {
|
||||
@DataTrigger_SetProperty($binding, $valueForCollapsed, "Visibility", "Collapsed") {}
|
||||
}
|
||||
|
||||
alias StackPanelHorizontal() {
|
||||
StackPanel {
|
||||
Orientation: Horizontal
|
||||
}
|
||||
}
|
||||
|
||||
alias GridItemsControl() {
|
||||
ItemsControl {
|
||||
ScrollViewer.HorizontalScrollBarVisibility: Disabled,
|
||||
|
||||
ItemsPanel: ItemsPanelTemplate {
|
||||
WrapPanel {
|
||||
IsItemsHost: true
|
||||
Orientation: Horizontal
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////
|
||||
// Animations //
|
||||
////////////////
|
||||
|
||||
alias DoubleAnimation(property, frm = "0", to = "1", duration = "0:0:1", targetName=none, beginTime=none) {
|
||||
DoubleAnimation {
|
||||
Storyboard.TargetProperty: $property
|
||||
Storyboard.TargetName: $targetName
|
||||
From: $frm
|
||||
To: $to
|
||||
Duration: $duration
|
||||
BeginTime: $beginTime
|
||||
}
|
||||
}
|
||||
|
||||
alias DoubleAnimationStoryboard (property, frm = "0", to = "1", duration = "0:0:1", targetName=none) {
|
||||
BeginStoryboard {
|
||||
Storyboard {
|
||||
@DoubleAnimation($property, $frm, $to, $duration, $targetName) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mixin DoubleAnimation_PropertyTrigger(triggerProperty, triggerValue, animationProperty, frm, to, duration) for Style {
|
||||
combine Triggers: @Trigger ($triggerProperty, $triggerValue) {
|
||||
EnterActions: @DoubleAnimationStoryboard($animationProperty, $frm, $to, $duration) {}
|
||||
}
|
||||
}
|
||||
|
||||
mixin DoubleAnimation_PropertyTrigger_Toggle(triggerProperty, triggerValue, animationProperty, frm, to, duration) for Style {
|
||||
combine Triggers: @Trigger ($triggerProperty, $triggerValue) {
|
||||
EnterActions: @DoubleAnimationStoryboard($animationProperty, $frm, $to, $duration) {}
|
||||
ExitActions: @DoubleAnimationStoryboard($animationProperty, $to, $frm, $duration) {}
|
||||
}
|
||||
}
|
||||
|
||||
mixin DoubleAnimation_EventTrigger(triggerEvent, animationProperty, frm, to, duration) for Style {
|
||||
combine Triggers: EventTrigger {
|
||||
RoutedEvent: $triggerEvent
|
||||
@DoubleAnimationStoryboard($animationProperty, $frm, $to, $duration) {}
|
||||
}
|
||||
}
|
||||
|
||||
mixin DoubleAnimation_DataTrigger(binding, value, animationProperty, frm, to, duration) for Style {
|
||||
combine Triggers: DataTrigger {
|
||||
Binding: $binding
|
||||
Value: $value
|
||||
EnterActions: @DoubleAnimationStoryboard($animationProperty, $frm, $to, $duration) {}
|
||||
}
|
||||
}
|
||||
|
||||
mixin FadeIn_OnProperty(property, value, frm = "0", to = "1", duration = "0:0:1") for Style {
|
||||
#DoubleAnimation_PropertyTrigger($property, $value, "Opacity", $frm, $to, $duration)
|
||||
}
|
||||
|
||||
mixin FadeOut_OnProperty(property, value, frm = "1", to = "0", duration = "0:0:1") for Style {
|
||||
#DoubleAnimation_PropertyTrigger($property, $value, "Opacity", $frm, $to, $duration)
|
||||
}
|
||||
|
||||
mixin FadeIn_OnEvent(event, frm = "0", to = "1", duration = "0:0:1") for Style {
|
||||
#DoubleAnimation_EventTrigger($event, "Opacity", $frm, $to, $duration)
|
||||
}
|
||||
|
||||
mixin FadeOut_OnEvent(event, frm = "1", to = "0", duration = "0:0:1") for Style {
|
||||
#DoubleAnimation_EventTrigger($event, "Opacity", $frm, $to, $duration)
|
||||
}
|
||||
|
||||
mixin FadeIn_OnData(binding, value, from_ = "0", to = "1", duration = "0:0:1") for Style {
|
||||
#DoubleAnimation_DataTrigger($binding, $value, "Opacity", $from_, $to, $duration)
|
||||
}
|
||||
|
||||
mixin FadeOut_OnData(binding, value, from_ = "1", to = "0", duration = "0:0:1") for Style {
|
||||
#DoubleAnimation_DataTrigger($binding, $value, "Opacity", $from_, $to, $duration)
|
||||
}
|
||||
|
||||
mixin Property_OnBinding(binding, bindingValue, property, propertyValue, initialValue) for Style {
|
||||
#Setter("Visibility", $initialValue)
|
||||
combine Triggers: [
|
||||
@DataTrigger_SetProperty($binding, $bindingValue, $property, $propertyValue) {}
|
||||
]
|
||||
}
|
||||
|
||||
mixin Visibility_OnBinding(binding, bindingValue, visibilityValue="Visible", initialValue="Collapsed") for Style {
|
||||
#Property_OnBinding($binding, $bindingValue, "Visibility", $visibilityValue, $initialValue)
|
||||
}
|
||||
|
||||
mixin Fade_OnBinding(binding, bindingValue) for Style {
|
||||
#Setter("Visibility", "Visible")
|
||||
#Setter("Opacity", "0")
|
||||
|
||||
combine Triggers: [
|
||||
@DataTrigger($binding, $bindingValue) {
|
||||
EnterActions: [
|
||||
@DoubleAnimationStoryboard("Opacity", 0, 1, "0:0:0.5") {}
|
||||
]
|
||||
ExitActions: [
|
||||
@DoubleAnimationStoryboard("Opacity", 1, 0, "0:0:0.5") {}
|
||||
]
|
||||
#Setter("Opacity", 1)
|
||||
}
|
||||
@Trigger("Opacity", 0) {
|
||||
#Setter("Visibility", "Hidden")
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
mixin MergeDictionary (source) for ResourceDictionary {
|
||||
combine MergedDictionaries: ResourceDictionary { Source: $source }
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Ammy" version="1.2.87" targetFramework="net461" />
|
||||
<package id="Ammy.WPF" version="1.2.87" targetFramework="net461" />
|
||||
<package id="CommonServiceLocator" version="1.3" targetFramework="net461" />
|
||||
<package id="HtmlAgilityPack" version="1.5.5" targetFramework="net461" />
|
||||
<package id="MaterialDesignColors" version="1.1.3" targetFramework="net461" />
|
||||
<package id="MaterialDesignThemes" version="2.3.1.953" targetFramework="net461" />
|
||||
<package id="MvvmLightLibs" version="5.3.0.0" targetFramework="net461" />
|
||||
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
|
||||
<package id="Tyrrrz.Extensions" version="1.4.1" targetFramework="net461" />
|
||||
<package id="Tyrrrz.Settings" version="1.3.0" targetFramework="net461" />
|
||||
</packages>
|
Loading…
Reference in new issue