From 28a67ab60dded9bcf3b34ddcd31963c4935d39cb Mon Sep 17 00:00:00 2001 From: Alexey Golub Date: Sat, 30 Sep 2017 22:22:28 +0300 Subject: [PATCH] Add export dialog and implement export as plain text --- DiscordChatExporter/Container.cs | 6 +- .../DiscordChatExporter.csproj | 15 ++++ .../Messages/ShowExportSetupMessage.cs | 17 +++++ .../Messages/StartExportMessage.cs | 20 +++++ DiscordChatExporter/Models/ExportFormat.cs | 8 ++ DiscordChatExporter/Models/Extensions.cs | 14 ++++ DiscordChatExporter/Services/ExportService.cs | 72 +++++++++++++++--- .../Services/IExportService.cs | 3 +- .../Services/ISettingsService.cs | 4 +- .../Services/SettingsService.cs | 4 +- .../ViewModels/ErrorViewModel.cs | 6 +- .../ViewModels/ExportDoneViewModel.cs | 8 +- .../ViewModels/ExportSetupViewModel.cs | 72 ++++++++++++++++++ .../ViewModels/IExportSetupViewModel.cs | 17 +++++ .../ViewModels/IMainViewModel.cs | 2 +- .../ViewModels/MainViewModel.cs | 75 +++++++++---------- DiscordChatExporter/Views/ErrorDialog.ammy.cs | 10 +-- .../Views/ExportDoneDialog.ammy | 3 +- .../Views/ExportDoneDialog.ammy.cs | 12 +-- .../Views/ExportSetupDialog.ammy | 58 ++++++++++++++ .../Views/ExportSetupDialog.ammy.cs | 55 ++++++++++++++ DiscordChatExporter/Views/MainWindow.ammy | 2 +- DiscordChatExporter/Views/MainWindow.ammy.cs | 3 +- 23 files changed, 409 insertions(+), 77 deletions(-) create mode 100644 DiscordChatExporter/Messages/ShowExportSetupMessage.cs create mode 100644 DiscordChatExporter/Messages/StartExportMessage.cs create mode 100644 DiscordChatExporter/Models/ExportFormat.cs create mode 100644 DiscordChatExporter/Models/Extensions.cs create mode 100644 DiscordChatExporter/ViewModels/ExportSetupViewModel.cs create mode 100644 DiscordChatExporter/ViewModels/IExportSetupViewModel.cs create mode 100644 DiscordChatExporter/Views/ExportSetupDialog.ammy create mode 100644 DiscordChatExporter/Views/ExportSetupDialog.ammy.cs diff --git a/DiscordChatExporter/Container.cs b/DiscordChatExporter/Container.cs index ddb24dac..459f6ec4 100644 --- a/DiscordChatExporter/Container.cs +++ b/DiscordChatExporter/Container.cs @@ -19,9 +19,10 @@ namespace DiscordChatExporter // View models SimpleIoc.Default.Register(true); + SimpleIoc.Default.Register(true); + SimpleIoc.Default.Register(true); SimpleIoc.Default.Register(true); SimpleIoc.Default.Register(true); - SimpleIoc.Default.Register(true); // Load settings ServiceLocator.Current.GetInstance().Load(); @@ -34,8 +35,9 @@ namespace DiscordChatExporter } public IErrorViewModel ErrorViewModel => ServiceLocator.Current.GetInstance(); + public IExportDoneViewModel ExportDoneViewModel => ServiceLocator.Current.GetInstance(); + public IExportSetupViewModel ExportSetupViewModel => ServiceLocator.Current.GetInstance(); public IMainViewModel MainViewModel => ServiceLocator.Current.GetInstance(); public ISettingsViewModel SettingsViewModel => ServiceLocator.Current.GetInstance(); - public IExportDoneViewModel ExportDoneViewModel => ServiceLocator.Current.GetInstance(); } } \ No newline at end of file diff --git a/DiscordChatExporter/DiscordChatExporter.csproj b/DiscordChatExporter/DiscordChatExporter.csproj index 5439cf5a..d76983dd 100644 --- a/DiscordChatExporter/DiscordChatExporter.csproj +++ b/DiscordChatExporter/DiscordChatExporter.csproj @@ -84,14 +84,20 @@ + + + + + + @@ -102,6 +108,9 @@ ExportDoneDialog.ammy + + ExportSetupDialog.ammy + SettingsDialog.ammy @@ -120,6 +129,11 @@ MSBuild:Compile ExportDoneDialog.ammy + + Designer + MSBuild:Compile + ExportSetupDialog.ammy + Designer MSBuild:Compile @@ -174,6 +188,7 @@ + diff --git a/DiscordChatExporter/Messages/ShowExportSetupMessage.cs b/DiscordChatExporter/Messages/ShowExportSetupMessage.cs new file mode 100644 index 00000000..827a075c --- /dev/null +++ b/DiscordChatExporter/Messages/ShowExportSetupMessage.cs @@ -0,0 +1,17 @@ +using DiscordChatExporter.Models; + +namespace DiscordChatExporter.Messages +{ + public class ShowExportSetupMessage + { + public Guild Guild { get; } + + public Channel Channel { get; } + + public ShowExportSetupMessage(Guild guild, Channel channel) + { + Guild = guild; + Channel = channel; + } + } +} \ No newline at end of file diff --git a/DiscordChatExporter/Messages/StartExportMessage.cs b/DiscordChatExporter/Messages/StartExportMessage.cs new file mode 100644 index 00000000..bf169271 --- /dev/null +++ b/DiscordChatExporter/Messages/StartExportMessage.cs @@ -0,0 +1,20 @@ +using DiscordChatExporter.Models; + +namespace DiscordChatExporter.Messages +{ + public class StartExportMessage + { + public Channel Channel { get; } + + public string FilePath { get; } + + public ExportFormat Format { get; } + + public StartExportMessage(Channel channel, string filePath, ExportFormat format) + { + Channel = channel; + FilePath = filePath; + Format = format; + } + } +} \ No newline at end of file diff --git a/DiscordChatExporter/Models/ExportFormat.cs b/DiscordChatExporter/Models/ExportFormat.cs new file mode 100644 index 00000000..b1447886 --- /dev/null +++ b/DiscordChatExporter/Models/ExportFormat.cs @@ -0,0 +1,8 @@ +namespace DiscordChatExporter.Models +{ + public enum ExportFormat + { + Text, + Html + } +} \ No newline at end of file diff --git a/DiscordChatExporter/Models/Extensions.cs b/DiscordChatExporter/Models/Extensions.cs new file mode 100644 index 00000000..83d0ff32 --- /dev/null +++ b/DiscordChatExporter/Models/Extensions.cs @@ -0,0 +1,14 @@ +namespace DiscordChatExporter.Models +{ + public static class Extensions + { + public static string GetFileExtension(this ExportFormat format) + { + if (format == ExportFormat.Text) + return "txt"; + if (format == ExportFormat.Html) + return "html"; + return null; + } + } +} \ No newline at end of file diff --git a/DiscordChatExporter/Services/ExportService.cs b/DiscordChatExporter/Services/ExportService.cs index 23be9982..e08ac602 100644 --- a/DiscordChatExporter/Services/ExportService.cs +++ b/DiscordChatExporter/Services/ExportService.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Net; using System.Reflection; using System.Resources; @@ -19,12 +20,53 @@ namespace DiscordChatExporter.Services _settingsService = settingsService; } - public async Task ExportAsync(string filePath, ChannelChatLog log, Theme theme) + public async Task ExportAsTextAsync(string filePath, ChannelChatLog log) + { + var dateFormat = _settingsService.DateFormat; + + using (var writer = new StreamWriter(filePath, false, Encoding.UTF8, 128 * 1024)) + { + // Guild and channel info + await writer.WriteLineAsync("=".Repeat(16)); + await writer.WriteLineAsync($"Guild: {log.Guild}"); + await writer.WriteLineAsync($"Channel: {log.Channel}"); + await writer.WriteLineAsync($"Messages: {log.TotalMessageCount:N0}"); + await writer.WriteLineAsync("=".Repeat(16)); + await writer.WriteLineAsync(); + + // Chat log + foreach (var group in log.MessageGroups) + { + var timeStampFormatted = group.TimeStamp.ToString(dateFormat); + await writer.WriteLineAsync($"{group.Author} [{timeStampFormatted}]"); + + // Messages + foreach (var message in group.Messages) + { + if (message.Content.IsNotBlank()) + { + var contentFormatted = message.Content.Replace("\n", Environment.NewLine); + await writer.WriteLineAsync(contentFormatted); + } + + // Attachments + foreach (var attachment in message.Attachments) + { + await writer.WriteLineAsync(attachment.Url); + } + } + + await writer.WriteLineAsync(); + } + } + } + + public async Task ExportAsHtmlAsync(string filePath, ChannelChatLog log, Theme theme) { var themeCss = GetThemeCss(theme); var dateFormat = _settingsService.DateFormat; - using (var writer = new StreamWriter(filePath, false, Encoding.UTF8, 128*1024)) + using (var writer = new StreamWriter(filePath, false, Encoding.UTF8, 128 * 1024)) { // Generation info await writer.WriteLineAsync(""); @@ -35,7 +77,7 @@ namespace DiscordChatExporter.Services // HEAD await writer.WriteLineAsync(""); - await writer.WriteLineAsync($"{log.Guild.Name} - {log.Channel.Name}"); + await writer.WriteLineAsync($"{log.Guild} - {log.Channel}"); await writer.WriteLineAsync(""); await writer.WriteLineAsync(""); await writer.WriteLineAsync($""); @@ -50,8 +92,8 @@ namespace DiscordChatExporter.Services await writer.WriteLineAsync($""); await writer.WriteLineAsync(""); // info-left await writer.WriteLineAsync("
"); - await writer.WriteLineAsync($"
{log.Guild.Name}
"); - await writer.WriteLineAsync($"
{log.Channel.Name}
"); + await writer.WriteLineAsync($"
{log.Guild}
"); + await writer.WriteLineAsync($"
{log.Channel}
"); await writer.WriteLineAsync($"
{log.TotalMessageCount:N0} messages
"); await writer.WriteLineAsync("
"); // info-right await writer.WriteLineAsync(""); // info @@ -66,18 +108,20 @@ namespace DiscordChatExporter.Services await writer.WriteLineAsync(""); await writer.WriteLineAsync("
"); - await writer.WriteLineAsync($"{HtmlEncode(group.Author.Name)}"); + await writer.WriteAsync($""); + await writer.WriteAsync(HtmlEncode(group.Author.Name)); + await writer.WriteLineAsync(""); var timeStampFormatted = HtmlEncode(group.TimeStamp.ToString(dateFormat)); await writer.WriteLineAsync($"{timeStampFormatted}"); - // Message + // Messages foreach (var message in group.Messages) { // Content if (message.Content.IsNotBlank()) { await writer.WriteLineAsync("
"); - var contentFormatted = FormatMessageContent(message.Content); + var contentFormatted = FormatMessageContentHtml(message.Content); await writer.WriteAsync(contentFormatted); // Edited timestamp @@ -99,7 +143,8 @@ namespace DiscordChatExporter.Services { await writer.WriteLineAsync(""); } @@ -148,6 +193,11 @@ namespace DiscordChatExporter.Services return WebUtility.HtmlEncode(str); } + private static string HtmlEncode(object obj) + { + return WebUtility.HtmlEncode(obj.ToString()); + } + private static string FormatFileSize(long fileSize) { string[] units = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}; @@ -163,7 +213,7 @@ namespace DiscordChatExporter.Services return $"{size:0.#} {units[unit]}"; } - private static string FormatMessageContent(string content) + private static string FormatMessageContentHtml(string content) { // Encode HTML content = HtmlEncode(content); diff --git a/DiscordChatExporter/Services/IExportService.cs b/DiscordChatExporter/Services/IExportService.cs index c92ee65d..7983d2f5 100644 --- a/DiscordChatExporter/Services/IExportService.cs +++ b/DiscordChatExporter/Services/IExportService.cs @@ -5,6 +5,7 @@ namespace DiscordChatExporter.Services { public interface IExportService { - Task ExportAsync(string filePath, ChannelChatLog log, Theme theme); + Task ExportAsTextAsync(string filePath, ChannelChatLog log); + Task ExportAsHtmlAsync(string filePath, ChannelChatLog log, Theme theme); } } \ No newline at end of file diff --git a/DiscordChatExporter/Services/ISettingsService.cs b/DiscordChatExporter/Services/ISettingsService.cs index 2c6bc0be..46f23701 100644 --- a/DiscordChatExporter/Services/ISettingsService.cs +++ b/DiscordChatExporter/Services/ISettingsService.cs @@ -4,11 +4,13 @@ namespace DiscordChatExporter.Services { public interface ISettingsService { - string Token { get; set; } Theme Theme { get; set; } string DateFormat { get; set; } int MessageGroupLimit { get; set; } + string LastToken { get; set; } + ExportFormat LastExportFormat { get; set; } + void Load(); void Save(); } diff --git a/DiscordChatExporter/Services/SettingsService.cs b/DiscordChatExporter/Services/SettingsService.cs index 998606a5..9b7762f8 100644 --- a/DiscordChatExporter/Services/SettingsService.cs +++ b/DiscordChatExporter/Services/SettingsService.cs @@ -5,11 +5,13 @@ namespace DiscordChatExporter.Services { public class SettingsService : SettingsManager, ISettingsService { - public string Token { get; set; } public Theme Theme { get; set; } public string DateFormat { get; set; } = "dd-MMM-yy hh:mm"; public int MessageGroupLimit { get; set; } = 20; + public string LastToken { get; set; } + public ExportFormat LastExportFormat { get; set; } = ExportFormat.Html; + public SettingsService() { Configuration.StorageSpace = StorageSpace.Instance; diff --git a/DiscordChatExporter/ViewModels/ErrorViewModel.cs b/DiscordChatExporter/ViewModels/ErrorViewModel.cs index 58d2738a..daac0cd0 100644 --- a/DiscordChatExporter/ViewModels/ErrorViewModel.cs +++ b/DiscordChatExporter/ViewModels/ErrorViewModel.cs @@ -9,7 +9,11 @@ namespace DiscordChatExporter.ViewModels public ErrorViewModel() { - MessengerInstance.Register(this, m => Message = m.Message); + // Messages + MessengerInstance.Register(this, m => + { + Message = m.Message; + }); } } } \ No newline at end of file diff --git a/DiscordChatExporter/ViewModels/ExportDoneViewModel.cs b/DiscordChatExporter/ViewModels/ExportDoneViewModel.cs index 27bd996f..0dc5fb69 100644 --- a/DiscordChatExporter/ViewModels/ExportDoneViewModel.cs +++ b/DiscordChatExporter/ViewModels/ExportDoneViewModel.cs @@ -14,10 +14,14 @@ namespace DiscordChatExporter.ViewModels public ExportDoneViewModel() { - MessengerInstance.Register(this, m => _filePath = m.FilePath); - // Commands OpenCommand = new RelayCommand(Open); + + // Messages + MessengerInstance.Register(this, m => + { + _filePath = m.FilePath; + }); } private void Open() diff --git a/DiscordChatExporter/ViewModels/ExportSetupViewModel.cs b/DiscordChatExporter/ViewModels/ExportSetupViewModel.cs new file mode 100644 index 00000000..7814000d --- /dev/null +++ b/DiscordChatExporter/ViewModels/ExportSetupViewModel.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using DiscordChatExporter.Messages; +using DiscordChatExporter.Models; +using DiscordChatExporter.Services; +using GalaSoft.MvvmLight; +using GalaSoft.MvvmLight.CommandWpf; +using Tyrrrz.Extensions; + +namespace DiscordChatExporter.ViewModels +{ + public class ExportSetupViewModel : ViewModelBase, IExportSetupViewModel + { + private readonly ISettingsService _settingsService; + + private string _filePath; + private ExportFormat _format; + + public Guild Guild { get; private set; } + + public Channel Channel { get; private set; } + + public string FilePath + { + get => _filePath; + set + { + Set(ref _filePath, value); + ExportCommand.RaiseCanExecuteChanged(); + } + } + + public IReadOnlyList AvailableFormats { get; } + + public ExportFormat SelectedFormat + { + get => _format; + set => Set(ref _format, value); + } + + // Commands + public RelayCommand ExportCommand { get; } + + public ExportSetupViewModel(ISettingsService settingsService) + { + _settingsService = settingsService; + + // Defaults + AvailableFormats = Enum.GetValues(typeof(ExportFormat)).Cast().ToArray(); + + // Commands + ExportCommand = new RelayCommand(Export, () => FilePath.IsNotBlank()); + + // Messages + MessengerInstance.Register(this, m => + { + Guild = m.Guild; + Channel = m.Channel; + SelectedFormat = _settingsService.LastExportFormat; + FilePath = Path.Combine($"{Guild} - {Channel}.{SelectedFormat.GetFileExtension()}"); + }); + } + + private void Export() + { + _settingsService.LastExportFormat = SelectedFormat; + MessengerInstance.Send(new StartExportMessage(Channel, FilePath, SelectedFormat)); + } + } +} \ No newline at end of file diff --git a/DiscordChatExporter/ViewModels/IExportSetupViewModel.cs b/DiscordChatExporter/ViewModels/IExportSetupViewModel.cs new file mode 100644 index 00000000..a21a8d1a --- /dev/null +++ b/DiscordChatExporter/ViewModels/IExportSetupViewModel.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using DiscordChatExporter.Models; +using GalaSoft.MvvmLight.CommandWpf; + +namespace DiscordChatExporter.ViewModels +{ + public interface IExportSetupViewModel + { + Guild Guild { get; } + Channel Channel { get; } + string FilePath { get; set; } + IReadOnlyList AvailableFormats { get; } + ExportFormat SelectedFormat { get; set; } + + RelayCommand ExportCommand { get; } + } +} \ No newline at end of file diff --git a/DiscordChatExporter/ViewModels/IMainViewModel.cs b/DiscordChatExporter/ViewModels/IMainViewModel.cs index d8d578ef..68d71efd 100644 --- a/DiscordChatExporter/ViewModels/IMainViewModel.cs +++ b/DiscordChatExporter/ViewModels/IMainViewModel.cs @@ -16,8 +16,8 @@ namespace DiscordChatExporter.ViewModels IReadOnlyList AvailableChannels { get; } RelayCommand PullDataCommand { get; } - RelayCommand ExportChannelCommand { get; } RelayCommand ShowSettingsCommand { get; } RelayCommand ShowAboutCommand { get; } + RelayCommand ShowExportSetupCommand { get; } } } \ No newline at end of file diff --git a/DiscordChatExporter/ViewModels/MainViewModel.cs b/DiscordChatExporter/ViewModels/MainViewModel.cs index 4fcbcea6..9bd348a2 100644 --- a/DiscordChatExporter/ViewModels/MainViewModel.cs +++ b/DiscordChatExporter/ViewModels/MainViewModel.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Linq; using System.Net; using DiscordChatExporter.Exceptions; @@ -9,7 +8,6 @@ using DiscordChatExporter.Models; using DiscordChatExporter.Services; using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.CommandWpf; -using Microsoft.Win32; using Tyrrrz.Extensions; namespace DiscordChatExporter.ViewModels @@ -36,7 +34,7 @@ namespace DiscordChatExporter.ViewModels { Set(ref _isBusy, value); PullDataCommand.RaiseCanExecuteChanged(); - ExportChannelCommand.RaiseCanExecuteChanged(); + ShowExportSetupCommand.RaiseCanExecuteChanged(); } } @@ -44,13 +42,13 @@ namespace DiscordChatExporter.ViewModels public string Token { - get => _settingsService.Token; + get => _settingsService.LastToken; set { // Remove invalid chars value = value?.Trim('"'); - _settingsService.Token = value; + _settingsService.LastToken = value; PullDataCommand.RaiseCanExecuteChanged(); } } @@ -72,7 +70,7 @@ namespace DiscordChatExporter.ViewModels { Set(ref _selectedGuild, value); AvailableChannels = value != null ? _guildChannelsMap[value] : new Channel[0]; - ExportChannelCommand.RaiseCanExecuteChanged(); + ShowExportSetupCommand.RaiseCanExecuteChanged(); } } @@ -83,9 +81,9 @@ namespace DiscordChatExporter.ViewModels } public RelayCommand PullDataCommand { get; } - public RelayCommand ExportChannelCommand { get; } public RelayCommand ShowSettingsCommand { get; } public RelayCommand ShowAboutCommand { get; } + public RelayCommand ShowExportSetupCommand { get; } public MainViewModel(ISettingsService settingsService, IDataService dataService, IMessageGroupService messageGroupService, IExportService exportService) @@ -99,9 +97,15 @@ namespace DiscordChatExporter.ViewModels // Commands PullDataCommand = new RelayCommand(PullData, () => Token.IsNotBlank() && !IsBusy); - ExportChannelCommand = new RelayCommand(ExportChannel, _ => !IsBusy); ShowSettingsCommand = new RelayCommand(ShowSettings); ShowAboutCommand = new RelayCommand(ShowAbout); + ShowExportSetupCommand = new RelayCommand(ShowExportSetup, _ => !IsBusy); + + // Messages + MessengerInstance.Register(this, m => + { + Export(m.Channel, m.FilePath, m.Format); + }); } private async void PullData() @@ -142,29 +146,25 @@ namespace DiscordChatExporter.ViewModels IsBusy = false; } - private async void ExportChannel(Channel channel) + private void ShowSettings() + { + MessengerInstance.Send(new ShowSettingsMessage()); + } + + private void ShowAbout() + { + Process.Start("https://github.com/Tyrrrz/DiscordChatExporter"); + } + + private void ShowExportSetup(Channel channel) + { + MessengerInstance.Send(new ShowExportSetupMessage(SelectedGuild, channel)); + } + + private async void Export(Channel channel, string filePath, ExportFormat format) { IsBusy = true; - - // Get safe file names - var safeGuildName = SelectedGuild.Name.Replace(Path.GetInvalidFileNameChars(), '_'); - var safeChannelName = channel.Name.Replace(Path.GetInvalidFileNameChars(), '_'); - // Ask for path - var sfd = new SaveFileDialog - { - FileName = $"{safeGuildName} - {safeChannelName}.html", - Filter = "HTML files (*.html)|*.html|All files (*.*)|*.*", - DefaultExt = "html", - AddExtension = true - }; - if (sfd.ShowDialog() != true) - { - IsBusy = false; - return; - } - - // Export try { // Get messages @@ -177,10 +177,13 @@ namespace DiscordChatExporter.ViewModels var chatLog = new ChannelChatLog(SelectedGuild, channel, messageGroups, messages.Count); // Export - await _exportService.ExportAsync(sfd.FileName, chatLog, _settingsService.Theme); + if (format == ExportFormat.Text) + await _exportService.ExportAsTextAsync(filePath, chatLog); + else if (format == ExportFormat.Html) + await _exportService.ExportAsHtmlAsync(filePath, chatLog, _settingsService.Theme); - // Show dialog - MessengerInstance.Send(new ShowExportDoneMessage(sfd.FileName)); + // Notify completion + MessengerInstance.Send(new ShowExportDoneMessage(filePath)); } catch (HttpErrorStatusCodeException ex) when (ex.StatusCode == HttpStatusCode.Forbidden) { @@ -190,15 +193,5 @@ namespace DiscordChatExporter.ViewModels IsBusy = false; } - - private void ShowSettings() - { - MessengerInstance.Send(new ShowSettingsMessage()); - } - - private void ShowAbout() - { - Process.Start("https://github.com/Tyrrrz/DiscordChatExporter"); - } } } \ No newline at end of file diff --git a/DiscordChatExporter/Views/ErrorDialog.ammy.cs b/DiscordChatExporter/Views/ErrorDialog.ammy.cs index a3538e7c..59675851 100644 --- a/DiscordChatExporter/Views/ErrorDialog.ammy.cs +++ b/DiscordChatExporter/Views/ErrorDialog.ammy.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace DiscordChatExporter.Views +namespace DiscordChatExporter.Views { public partial class ErrorDialog { @@ -13,4 +7,4 @@ namespace DiscordChatExporter.Views InitializeComponent(); } } -} +} \ No newline at end of file diff --git a/DiscordChatExporter/Views/ExportDoneDialog.ammy b/DiscordChatExporter/Views/ExportDoneDialog.ammy index b9979946..9f6436a9 100644 --- a/DiscordChatExporter/Views/ExportDoneDialog.ammy +++ b/DiscordChatExporter/Views/ExportDoneDialog.ammy @@ -18,7 +18,8 @@ UserControl "DiscordChatExporter.Views.ExportDoneDialog" { HorizontalAlignment: Right // Open - Button { + Button "OpenButton" { + Click: OpenButton_Click Command: bind OpenCommand Content: "OPEN IT" Margin: 8 diff --git a/DiscordChatExporter/Views/ExportDoneDialog.ammy.cs b/DiscordChatExporter/Views/ExportDoneDialog.ammy.cs index 21d3bc2b..22f9284e 100644 --- a/DiscordChatExporter/Views/ExportDoneDialog.ammy.cs +++ b/DiscordChatExporter/Views/ExportDoneDialog.ammy.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Windows; +using MaterialDesignThemes.Wpf; namespace DiscordChatExporter.Views { @@ -12,5 +9,10 @@ namespace DiscordChatExporter.Views { InitializeComponent(); } + + public void OpenButton_Click(object sender, RoutedEventArgs args) + { + DialogHost.CloseDialogCommand.Execute(null, null); + } } } diff --git a/DiscordChatExporter/Views/ExportSetupDialog.ammy b/DiscordChatExporter/Views/ExportSetupDialog.ammy new file mode 100644 index 00000000..c92e75cb --- /dev/null +++ b/DiscordChatExporter/Views/ExportSetupDialog.ammy @@ -0,0 +1,58 @@ +using MaterialDesignThemes.Wpf + +UserControl "DiscordChatExporter.Views.ExportSetupDialog" { + DataContext: bind ExportSetupViewModel from $resource Container + Width: 350 + + StackPanel { + // File path + Grid { + #TwoColumns("*", "Auto") + + TextBox { + Grid.Column: 0 + Margin: "16 16 4 8" + HintAssist.Hint: "Output file" + HintAssist.IsFloating: true + Text: bind FilePath + set [ UpdateSourceTrigger: PropertyChanged ] + } + + Button "LocateFilePathButton" { + Grid.Column: 1 + Margin: "4 16 16 8" + Padding: 4 + Click: LocateFilePathButton_Click + Style: resource dyn "MaterialDesignFlatButton" + + PackIcon { + Kind: PackIconKind.DotsHorizontal + Width: 24 + Height: 24 + } + } + } + + // Buttons + @StackPanelHorizontal { + HorizontalAlignment: Right + + // Export + Button "ExportButton" { + Click: ExportButton_Click + Command: bind ExportCommand + Content: "EXPORT" + Margin: 8 + Style: resource dyn "MaterialDesignFlatButton" + } + + // Cancel + Button { + Command: DialogHost.CloseDialogCommand + Content: "CANCEL" + Margin: 8 + Style: resource dyn "MaterialDesignFlatButton" + } + } + } +} \ No newline at end of file diff --git a/DiscordChatExporter/Views/ExportSetupDialog.ammy.cs b/DiscordChatExporter/Views/ExportSetupDialog.ammy.cs new file mode 100644 index 00000000..f732b953 --- /dev/null +++ b/DiscordChatExporter/Views/ExportSetupDialog.ammy.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Windows; +using DiscordChatExporter.Models; +using DiscordChatExporter.ViewModels; +using MaterialDesignThemes.Wpf; +using Microsoft.Win32; +using Tyrrrz.Extensions; + +namespace DiscordChatExporter.Views +{ + public partial class ExportSetupDialog + { + public ExportSetupDialog() + { + InitializeComponent(); + } + + private IExportSetupViewModel ViewModel => (IExportSetupViewModel) DataContext; + + private string GetOutputFileFilter() + { + var filters = new List(); + foreach (var format in ViewModel.AvailableFormats) + { + var ext = format.GetFileExtension(); + filters.Add($"{format} (*.{ext})|*.{ext}"); + } + + return filters.JoinToString("|"); + } + + public void LocateFilePathButton_Click(object sender, RoutedEventArgs args) + { + var sfd = new SaveFileDialog + { + FileName = ViewModel.FilePath, + Filter = GetOutputFileFilter(), + FilterIndex = ViewModel.AvailableFormats.IndexOf(ViewModel.SelectedFormat) + 1, + AddExtension = true, + Title = "Select output file" + }; + + if (sfd.ShowDialog() == true) + { + ViewModel.FilePath = sfd.FileName; + ViewModel.SelectedFormat = ViewModel.AvailableFormats[sfd.FilterIndex - 1]; + } + } + + public void ExportButton_Click(object sender, RoutedEventArgs args) + { + DialogHost.CloseDialogCommand.Execute(null, null); + } + } +} \ No newline at end of file diff --git a/DiscordChatExporter/Views/MainWindow.ammy b/DiscordChatExporter/Views/MainWindow.ammy index 503a1ad1..458a18fb 100644 --- a/DiscordChatExporter/Views/MainWindow.ammy +++ b/DiscordChatExporter/Views/MainWindow.ammy @@ -167,7 +167,7 @@ Window "DiscordChatExporter.Views.MainWindow" { Cursor: CursorType.Hand InputBindings: [ MouseBinding { - Command: bind DataContext.ExportChannelCommand from $ancestor + Command: bind DataContext.ShowExportSetupCommand from $ancestor CommandParameter: bind MouseAction: LeftClick } diff --git a/DiscordChatExporter/Views/MainWindow.ammy.cs b/DiscordChatExporter/Views/MainWindow.ammy.cs index 1b56ac9e..84338c45 100644 --- a/DiscordChatExporter/Views/MainWindow.ammy.cs +++ b/DiscordChatExporter/Views/MainWindow.ammy.cs @@ -18,8 +18,9 @@ namespace DiscordChatExporter.Views Title += $" v{Assembly.GetExecutingAssembly().GetName().Version}"; Messenger.Default.Register(this, m => DialogHost.Show(new ErrorDialog()).Forget()); - Messenger.Default.Register(this, m => DialogHost.Show(new SettingsDialog()).Forget()); Messenger.Default.Register(this, m => DialogHost.Show(new ExportDoneDialog()).Forget()); + Messenger.Default.Register(this, m => DialogHost.Show(new ExportSetupDialog()).Forget()); + Messenger.Default.Register(this, m => DialogHost.Show(new SettingsDialog()).Forget()); } public void TokenTextBox_KeyDown(object sender, KeyEventArgs e)