mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2025-05-23 19:26:57 -04:00
parent
e5e9d4c9ff
commit
d7345e91d3
18 changed files with 157 additions and 133 deletions
|
@ -148,7 +148,6 @@
|
||||||
<Compile Include="Models\Guild.cs" />
|
<Compile Include="Models\Guild.cs" />
|
||||||
<Compile Include="Models\Message.cs" />
|
<Compile Include="Models\Message.cs" />
|
||||||
<Compile Include="Models\MessageGroup.cs" />
|
<Compile Include="Models\MessageGroup.cs" />
|
||||||
<Compile Include="Models\Theme.cs" />
|
|
||||||
<Compile Include="Models\User.cs" />
|
<Compile Include="Models\User.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Services\DataService.cs" />
|
<Compile Include="Services\DataService.cs" />
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
{
|
{
|
||||||
public enum ExportFormat
|
public enum ExportFormat
|
||||||
{
|
{
|
||||||
Text,
|
PlainText,
|
||||||
Html
|
HtmlDark,
|
||||||
|
HtmlLight
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +1,31 @@
|
||||||
namespace DiscordChatExporter.Models
|
using System;
|
||||||
|
|
||||||
|
namespace DiscordChatExporter.Models
|
||||||
{
|
{
|
||||||
public static class Extensions
|
public static class Extensions
|
||||||
{
|
{
|
||||||
public static string GetFileExtension(this ExportFormat format)
|
public static string GetFileExtension(this ExportFormat format)
|
||||||
{
|
{
|
||||||
if (format == ExportFormat.Text)
|
if (format == ExportFormat.PlainText)
|
||||||
return "txt";
|
return "txt";
|
||||||
if (format == ExportFormat.Html)
|
if (format == ExportFormat.HtmlDark)
|
||||||
return "html";
|
return "html";
|
||||||
return null;
|
if (format == ExportFormat.HtmlLight)
|
||||||
|
return "html";
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetDisplayName(this ExportFormat format)
|
||||||
|
{
|
||||||
|
if (format == ExportFormat.PlainText)
|
||||||
|
return "Plain Text";
|
||||||
|
if (format == ExportFormat.HtmlDark)
|
||||||
|
return "HTML (Dark)";
|
||||||
|
if (format == ExportFormat.HtmlLight)
|
||||||
|
return "HTML (Light)";
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +0,0 @@
|
||||||
namespace DiscordChatExporter.Models
|
|
||||||
{
|
|
||||||
public enum Theme
|
|
||||||
{
|
|
||||||
Dark,
|
|
||||||
Light
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Resources;
|
||||||
using AmmySidekick;
|
using AmmySidekick;
|
||||||
|
|
||||||
namespace DiscordChatExporter
|
namespace DiscordChatExporter
|
||||||
|
@ -15,5 +18,19 @@ namespace DiscordChatExporter
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetResourceString(string resourcePath)
|
||||||
|
{
|
||||||
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
|
var stream = assembly.GetManifestResourceStream(resourcePath);
|
||||||
|
if (stream == null)
|
||||||
|
throw new MissingManifestResourceException("Could not find resource");
|
||||||
|
|
||||||
|
using (stream)
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
return reader.ReadToEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -71,7 +71,8 @@ namespace DiscordChatExporter.Services
|
||||||
return channels;
|
return channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IReadOnlyList<Message>> GetChannelMessagesAsync(string token, string channelId, DateTime? from, DateTime? to)
|
public async Task<IReadOnlyList<Message>> GetChannelMessagesAsync(string token, string channelId,
|
||||||
|
DateTime? from, DateTime? to)
|
||||||
{
|
{
|
||||||
var result = new List<Message>();
|
var result = new List<Message>();
|
||||||
|
|
||||||
|
@ -100,10 +101,12 @@ namespace DiscordChatExporter.Services
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no messages - break
|
// If no messages - break
|
||||||
if (currentMessageId == null) break;
|
if (currentMessageId == null)
|
||||||
|
break;
|
||||||
|
|
||||||
// If last message is older than from date - break
|
// If last message is older than from date - break
|
||||||
if (from != null && result.Last().TimeStamp < from) break;
|
if (from != null && result.Last().TimeStamp < from)
|
||||||
|
break;
|
||||||
|
|
||||||
// Otherwise offset the next request
|
// Otherwise offset the next request
|
||||||
beforeId = currentMessageId;
|
beforeId = currentMessageId;
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Reflection;
|
|
||||||
using System.Resources;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -20,7 +18,7 @@ namespace DiscordChatExporter.Services
|
||||||
_settingsService = settingsService;
|
_settingsService = settingsService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ExportAsTextAsync(string filePath, ChannelChatLog log)
|
private async Task ExportAsTextAsync(string filePath, ChannelChatLog log)
|
||||||
{
|
{
|
||||||
var dateFormat = _settingsService.DateFormat;
|
var dateFormat = _settingsService.DateFormat;
|
||||||
|
|
||||||
|
@ -66,9 +64,8 @@ namespace DiscordChatExporter.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ExportAsHtmlAsync(string filePath, ChannelChatLog log, Theme theme)
|
private async Task ExportAsHtmlAsync(string filePath, ChannelChatLog log, string css)
|
||||||
{
|
{
|
||||||
var themeCss = GetThemeCss(theme);
|
|
||||||
var dateFormat = _settingsService.DateFormat;
|
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))
|
||||||
|
@ -85,7 +82,7 @@ namespace DiscordChatExporter.Services
|
||||||
await writer.WriteLineAsync($"<title>{log.Guild} - {log.Channel}</title>");
|
await writer.WriteLineAsync($"<title>{log.Guild} - {log.Channel}</title>");
|
||||||
await writer.WriteLineAsync("<meta charset=\"utf-8\" />");
|
await writer.WriteLineAsync("<meta charset=\"utf-8\" />");
|
||||||
await writer.WriteLineAsync("<meta name=\"viewport\" content=\"width=device-width\" />");
|
await writer.WriteLineAsync("<meta name=\"viewport\" content=\"width=device-width\" />");
|
||||||
await writer.WriteLineAsync($"<style>{themeCss}</style>");
|
await writer.WriteLineAsync($"<style>{css}</style>");
|
||||||
await writer.WriteLineAsync("</head>");
|
await writer.WriteLineAsync("</head>");
|
||||||
|
|
||||||
// Body start
|
// Body start
|
||||||
|
@ -173,26 +170,30 @@ namespace DiscordChatExporter.Services
|
||||||
await writer.WriteLineAsync("</html>");
|
await writer.WriteLineAsync("</html>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task ExportAsync(ExportFormat format, string filePath, ChannelChatLog log)
|
||||||
|
{
|
||||||
|
if (format == ExportFormat.PlainText)
|
||||||
|
{
|
||||||
|
return ExportAsTextAsync(filePath, log);
|
||||||
|
}
|
||||||
|
if (format == ExportFormat.HtmlDark)
|
||||||
|
{
|
||||||
|
var css = Program.GetResourceString("DiscordChatExporter.Resources.ExportService.DarkTheme.css");
|
||||||
|
return ExportAsHtmlAsync(filePath, log, css);
|
||||||
|
}
|
||||||
|
if (format == ExportFormat.HtmlLight)
|
||||||
|
{
|
||||||
|
var css = Program.GetResourceString("DiscordChatExporter.Resources.ExportService.LightTheme.css");
|
||||||
|
return ExportAsHtmlAsync(filePath, log, css);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class ExportService
|
public partial class ExportService
|
||||||
{
|
{
|
||||||
private static string GetThemeCss(Theme theme)
|
|
||||||
{
|
|
||||||
var resourcePath = $"DiscordChatExporter.Resources.ExportService.{theme}Theme.css";
|
|
||||||
|
|
||||||
var assembly = Assembly.GetExecutingAssembly();
|
|
||||||
var stream = assembly.GetManifestResourceStream(resourcePath);
|
|
||||||
if (stream == null)
|
|
||||||
throw new MissingManifestResourceException("Could not find style resource");
|
|
||||||
|
|
||||||
using (stream)
|
|
||||||
using (var reader = new StreamReader(stream))
|
|
||||||
{
|
|
||||||
return reader.ReadToEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string HtmlEncode(string str)
|
private static string HtmlEncode(string str)
|
||||||
{
|
{
|
||||||
return WebUtility.HtmlEncode(str);
|
return WebUtility.HtmlEncode(str);
|
||||||
|
|
|
@ -5,7 +5,6 @@ namespace DiscordChatExporter.Services
|
||||||
{
|
{
|
||||||
public interface IExportService
|
public interface IExportService
|
||||||
{
|
{
|
||||||
Task ExportAsTextAsync(string filePath, ChannelChatLog log);
|
Task ExportAsync(ExportFormat format, string filePath, ChannelChatLog log);
|
||||||
Task ExportAsHtmlAsync(string filePath, ChannelChatLog log, Theme theme);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,6 @@ namespace DiscordChatExporter.Services
|
||||||
{
|
{
|
||||||
public interface ISettingsService
|
public interface ISettingsService
|
||||||
{
|
{
|
||||||
Theme Theme { get; set; }
|
|
||||||
string DateFormat { get; set; }
|
string DateFormat { get; set; }
|
||||||
int MessageGroupLimit { get; set; }
|
int MessageGroupLimit { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,11 @@ namespace DiscordChatExporter.Services
|
||||||
{
|
{
|
||||||
public class SettingsService : SettingsManager, ISettingsService
|
public class SettingsService : SettingsManager, ISettingsService
|
||||||
{
|
{
|
||||||
public Theme Theme { get; set; }
|
|
||||||
public string DateFormat { get; set; } = "dd-MMM-yy hh:mm tt";
|
public string DateFormat { get; set; } = "dd-MMM-yy hh:mm tt";
|
||||||
public int MessageGroupLimit { get; set; } = 20;
|
public int MessageGroupLimit { get; set; } = 20;
|
||||||
|
|
||||||
public string LastToken { get; set; }
|
public string LastToken { get; set; }
|
||||||
public ExportFormat LastExportFormat { get; set; } = ExportFormat.Html;
|
public ExportFormat LastExportFormat { get; set; } = ExportFormat.HtmlDark;
|
||||||
|
|
||||||
public SettingsService()
|
public SettingsService()
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,7 +39,15 @@ namespace DiscordChatExporter.ViewModels
|
||||||
public ExportFormat SelectedFormat
|
public ExportFormat SelectedFormat
|
||||||
{
|
{
|
||||||
get => _format;
|
get => _format;
|
||||||
set => Set(ref _format, value);
|
set
|
||||||
|
{
|
||||||
|
Set(ref _format, value);
|
||||||
|
|
||||||
|
// Replace extension in path
|
||||||
|
var newExt = value.GetFileExtension();
|
||||||
|
if (FilePath != null && !FilePath.EndsWith(newExt))
|
||||||
|
FilePath = FilePath.SubstringUntilLast(".") + "." + newExt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime? From
|
public DateTime? From
|
||||||
|
@ -82,7 +90,10 @@ namespace DiscordChatExporter.ViewModels
|
||||||
|
|
||||||
private void Export()
|
private void Export()
|
||||||
{
|
{
|
||||||
|
// Save format
|
||||||
_settingsService.LastExportFormat = SelectedFormat;
|
_settingsService.LastExportFormat = SelectedFormat;
|
||||||
|
|
||||||
|
// Start export
|
||||||
MessengerInstance.Send(new StartExportMessage(Channel, FilePath, SelectedFormat, From, To));
|
MessengerInstance.Send(new StartExportMessage(Channel, FilePath, SelectedFormat, From, To));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
using System.Collections.Generic;
|
namespace DiscordChatExporter.ViewModels
|
||||||
using DiscordChatExporter.Models;
|
|
||||||
|
|
||||||
namespace DiscordChatExporter.ViewModels
|
|
||||||
{
|
{
|
||||||
public interface ISettingsViewModel
|
public interface ISettingsViewModel
|
||||||
{
|
{
|
||||||
IReadOnlyList<Theme> AvailableThemes { get; }
|
|
||||||
Theme Theme { get; set; }
|
|
||||||
string DateFormat { get; set; }
|
string DateFormat { get; set; }
|
||||||
int MessageGroupLimit { get; set; }
|
int MessageGroupLimit { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,10 @@ namespace DiscordChatExporter.ViewModels
|
||||||
private readonly Dictionary<Guild, IReadOnlyList<Channel>> _guildChannelsMap;
|
private readonly Dictionary<Guild, IReadOnlyList<Channel>> _guildChannelsMap;
|
||||||
|
|
||||||
private bool _isBusy;
|
private bool _isBusy;
|
||||||
|
private string _token;
|
||||||
private IReadOnlyList<Guild> _availableGuilds;
|
private IReadOnlyList<Guild> _availableGuilds;
|
||||||
private Guild _selectedGuild;
|
private Guild _selectedGuild;
|
||||||
private IReadOnlyList<Channel> _availableChannels;
|
private IReadOnlyList<Channel> _availableChannels;
|
||||||
private string _cachedToken;
|
|
||||||
|
|
||||||
public bool IsBusy
|
public bool IsBusy
|
||||||
{
|
{
|
||||||
|
@ -43,13 +43,13 @@ namespace DiscordChatExporter.ViewModels
|
||||||
|
|
||||||
public string Token
|
public string Token
|
||||||
{
|
{
|
||||||
get => _settingsService.LastToken;
|
get => _token;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
// Remove invalid chars
|
// Remove invalid chars
|
||||||
value = value?.Trim('"');
|
value = value?.Trim('"');
|
||||||
|
|
||||||
_settingsService.LastToken = value;
|
Set(ref _token, value);
|
||||||
PullDataCommand.RaiseCanExecuteChanged();
|
PullDataCommand.RaiseCanExecuteChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,12 +107,20 @@ namespace DiscordChatExporter.ViewModels
|
||||||
{
|
{
|
||||||
Export(m.Channel, m.FilePath, m.Format, m.From, m.To);
|
Export(m.Channel, m.FilePath, m.Format, m.From, m.To);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Defaults
|
||||||
|
_token = _settingsService.LastToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void PullData()
|
private async void PullData()
|
||||||
{
|
{
|
||||||
IsBusy = true;
|
IsBusy = true;
|
||||||
_cachedToken = Token;
|
|
||||||
|
// Copy token so it doesn't get mutated
|
||||||
|
var token = Token;
|
||||||
|
|
||||||
|
// Save token
|
||||||
|
_settingsService.LastToken = token;
|
||||||
|
|
||||||
// Clear existing
|
// Clear existing
|
||||||
_guildChannelsMap.Clear();
|
_guildChannelsMap.Clear();
|
||||||
|
@ -121,17 +129,17 @@ namespace DiscordChatExporter.ViewModels
|
||||||
{
|
{
|
||||||
// Get DM channels
|
// Get DM channels
|
||||||
{
|
{
|
||||||
var channels = await _dataService.GetDirectMessageChannelsAsync(_cachedToken);
|
var channels = await _dataService.GetDirectMessageChannelsAsync(token);
|
||||||
var guild = new Guild("@me", "Direct Messages", null);
|
var guild = new Guild("@me", "Direct Messages", null);
|
||||||
_guildChannelsMap[guild] = channels.ToArray();
|
_guildChannelsMap[guild] = channels.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get guild channels
|
// Get guild channels
|
||||||
{
|
{
|
||||||
var guilds = await _dataService.GetGuildsAsync(_cachedToken);
|
var guilds = await _dataService.GetGuildsAsync(token);
|
||||||
foreach (var guild in guilds)
|
foreach (var guild in guilds)
|
||||||
{
|
{
|
||||||
var channels = await _dataService.GetGuildChannelsAsync(_cachedToken, guild.Id);
|
var channels = await _dataService.GetGuildChannelsAsync(token, guild.Id);
|
||||||
_guildChannelsMap[guild] = channels.Where(c => c.Type == ChannelType.GuildTextChat).ToArray();
|
_guildChannelsMap[guild] = channels.Where(c => c.Type == ChannelType.GuildTextChat).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,22 +179,22 @@ namespace DiscordChatExporter.ViewModels
|
||||||
{
|
{
|
||||||
IsBusy = true;
|
IsBusy = true;
|
||||||
|
|
||||||
|
// Get last used token
|
||||||
|
var token = _settingsService.LastToken;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Get messages
|
// Get messages
|
||||||
var messages = await _dataService.GetChannelMessagesAsync(_cachedToken, channel.Id, from, to);
|
var messages = await _dataService.GetChannelMessagesAsync(token, channel.Id, from, to);
|
||||||
|
|
||||||
// Group them
|
// Group them
|
||||||
var messageGroups = _messageGroupService.GroupMessages(messages);
|
var messageGroups = _messageGroupService.GroupMessages(messages);
|
||||||
|
|
||||||
// Create log
|
// Create log
|
||||||
var chatLog = new ChannelChatLog(SelectedGuild, channel, messageGroups, messages.Count);
|
var log = new ChannelChatLog(SelectedGuild, channel, messageGroups, messages.Count);
|
||||||
|
|
||||||
// Export
|
// Export
|
||||||
if (format == ExportFormat.Text)
|
await _exportService.ExportAsync(format, filePath, log);
|
||||||
await _exportService.ExportAsTextAsync(filePath, chatLog);
|
|
||||||
else if (format == ExportFormat.Html)
|
|
||||||
await _exportService.ExportAsHtmlAsync(filePath, chatLog, _settingsService.Theme);
|
|
||||||
|
|
||||||
// Notify completion
|
// Notify completion
|
||||||
MessengerInstance.Send(new ShowExportDoneMessage(filePath));
|
MessengerInstance.Send(new ShowExportDoneMessage(filePath));
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
using System;
|
using DiscordChatExporter.Services;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using DiscordChatExporter.Models;
|
|
||||||
using DiscordChatExporter.Services;
|
|
||||||
using GalaSoft.MvvmLight;
|
using GalaSoft.MvvmLight;
|
||||||
using Tyrrrz.Extensions;
|
using Tyrrrz.Extensions;
|
||||||
|
|
||||||
|
@ -12,14 +8,6 @@ namespace DiscordChatExporter.ViewModels
|
||||||
{
|
{
|
||||||
private readonly ISettingsService _settingsService;
|
private readonly ISettingsService _settingsService;
|
||||||
|
|
||||||
public IReadOnlyList<Theme> AvailableThemes { get; }
|
|
||||||
|
|
||||||
public Theme Theme
|
|
||||||
{
|
|
||||||
get => _settingsService.Theme;
|
|
||||||
set => _settingsService.Theme = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string DateFormat
|
public string DateFormat
|
||||||
{
|
{
|
||||||
get => _settingsService.DateFormat;
|
get => _settingsService.DateFormat;
|
||||||
|
@ -35,9 +23,6 @@ namespace DiscordChatExporter.ViewModels
|
||||||
public SettingsViewModel(ISettingsService settingsService)
|
public SettingsViewModel(ISettingsService settingsService)
|
||||||
{
|
{
|
||||||
_settingsService = settingsService;
|
_settingsService = settingsService;
|
||||||
|
|
||||||
// Defaults
|
|
||||||
AvailableThemes = Enum.GetValues(typeof(Theme)).Cast<Theme>().ToArray();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
using MaterialDesignThemes.Wpf
|
using DiscordChatExporter.Models
|
||||||
|
using MaterialDesignThemes.Wpf
|
||||||
|
|
||||||
UserControl "DiscordChatExporter.Views.ExportSetupDialog" {
|
UserControl "DiscordChatExporter.Views.ExportSetupDialog" {
|
||||||
DataContext: bind ExportSetupViewModel from $resource Container
|
DataContext: bind ExportSetupViewModel from $resource Container
|
||||||
Width: 350
|
Width: 325
|
||||||
|
|
||||||
StackPanel {
|
StackPanel {
|
||||||
// File path
|
// File path
|
||||||
|
@ -15,13 +16,29 @@ UserControl "DiscordChatExporter.Views.ExportSetupDialog" {
|
||||||
set [ UpdateSourceTrigger: PropertyChanged ]
|
set [ UpdateSourceTrigger: PropertyChanged ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format
|
||||||
|
ComboBox {
|
||||||
|
Margin: "16 8 16 8"
|
||||||
|
HintAssist.Hint: "Export format"
|
||||||
|
HintAssist.IsFloating: true
|
||||||
|
IsReadOnly: true
|
||||||
|
ItemsSource: bind AvailableFormats
|
||||||
|
ItemTemplate: DataTemplate {
|
||||||
|
TextBlock {
|
||||||
|
Text: bind
|
||||||
|
convert (ExportFormat f) => Extensions.GetDisplayName(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SelectedItem: bind SelectedFormat
|
||||||
|
}
|
||||||
|
|
||||||
// Date range
|
// Date range
|
||||||
Grid {
|
Grid {
|
||||||
#TwoColumns("*", "*")
|
#TwoColumns("*", "*")
|
||||||
|
|
||||||
DatePicker {
|
DatePicker {
|
||||||
Grid.Column: 0
|
Grid.Column: 0
|
||||||
Margin: "16 16 8 8"
|
Margin: "16 20 8 8"
|
||||||
HintAssist.Hint: "From"
|
HintAssist.Hint: "From"
|
||||||
HintAssist.IsFloating: true
|
HintAssist.IsFloating: true
|
||||||
SelectedDate: bind From
|
SelectedDate: bind From
|
||||||
|
@ -29,7 +46,7 @@ UserControl "DiscordChatExporter.Views.ExportSetupDialog" {
|
||||||
|
|
||||||
DatePicker {
|
DatePicker {
|
||||||
Grid.Column: 1
|
Grid.Column: 1
|
||||||
Margin: "8 16 16 8"
|
Margin: "8 20 16 8"
|
||||||
HintAssist.Hint: "To"
|
HintAssist.Hint: "To"
|
||||||
HintAssist.IsFloating: true
|
HintAssist.IsFloating: true
|
||||||
SelectedDate: bind To
|
SelectedDate: bind To
|
||||||
|
@ -40,6 +57,14 @@ UserControl "DiscordChatExporter.Views.ExportSetupDialog" {
|
||||||
@StackPanelHorizontal {
|
@StackPanelHorizontal {
|
||||||
HorizontalAlignment: Right
|
HorizontalAlignment: Right
|
||||||
|
|
||||||
|
// Browse
|
||||||
|
Button "BrowseButton" {
|
||||||
|
Click: BrowseButton_Click
|
||||||
|
Content: "BROWSE"
|
||||||
|
Margin: 8
|
||||||
|
Style: resource dyn "MaterialDesignFlatButton"
|
||||||
|
}
|
||||||
|
|
||||||
// Export
|
// Export
|
||||||
Button "ExportButton" {
|
Button "ExportButton" {
|
||||||
Click: ExportButton_Click
|
Click: ExportButton_Click
|
||||||
|
@ -49,14 +74,6 @@ UserControl "DiscordChatExporter.Views.ExportSetupDialog" {
|
||||||
Style: resource dyn "MaterialDesignFlatButton"
|
Style: resource dyn "MaterialDesignFlatButton"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Browse
|
|
||||||
Button "BrowseButton" {
|
|
||||||
Click: BrowseButton_Click
|
|
||||||
Content: "BROWSE"
|
|
||||||
Margin: 8
|
|
||||||
Style: resource dyn "MaterialDesignFlatButton"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel
|
// Cancel
|
||||||
Button {
|
Button {
|
||||||
Command: DialogHost.CloseDialogCommand
|
Command: DialogHost.CloseDialogCommand
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Windows;
|
||||||
using System.Windows;
|
|
||||||
using DiscordChatExporter.Models;
|
using DiscordChatExporter.Models;
|
||||||
using DiscordChatExporter.ViewModels;
|
using DiscordChatExporter.ViewModels;
|
||||||
using MaterialDesignThemes.Wpf;
|
using MaterialDesignThemes.Wpf;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using Tyrrrz.Extensions;
|
|
||||||
|
|
||||||
namespace DiscordChatExporter.Views
|
namespace DiscordChatExporter.Views
|
||||||
{
|
{
|
||||||
|
@ -17,39 +15,30 @@ namespace DiscordChatExporter.Views
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetFilter()
|
public void BrowseButton_Click(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
var filters = new List<string>();
|
// Get file extension of the selected format
|
||||||
foreach (var format in ViewModel.AvailableFormats)
|
var ext = ViewModel.SelectedFormat.GetFileExtension();
|
||||||
{
|
|
||||||
var ext = format.GetFileExtension();
|
|
||||||
filters.Add($"{format} (*.{ext})|*.{ext}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return filters.JoinToString("|");
|
// 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)
|
public void ExportButton_Click(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
DialogHost.CloseDialogCommand.Execute(null, null);
|
DialogHost.CloseDialogCommand.Execute(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BrowseButton_Click(object sender, RoutedEventArgs args)
|
|
||||||
{
|
|
||||||
var sfd = new SaveFileDialog
|
|
||||||
{
|
|
||||||
FileName = ViewModel.FilePath,
|
|
||||||
Filter = GetFilter(),
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -46,6 +46,8 @@ Window "DiscordChatExporter.Views.MainWindow" {
|
||||||
FontSize: 16
|
FontSize: 16
|
||||||
Text: bind Token
|
Text: bind Token
|
||||||
set [ UpdateSourceTrigger: PropertyChanged ]
|
set [ UpdateSourceTrigger: PropertyChanged ]
|
||||||
|
TextFieldAssist.DecorationVisibility: Hidden
|
||||||
|
TextFieldAssist.TextBoxViewMargin: "0 0 2 0"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit
|
// Submit
|
||||||
|
|
|
@ -5,19 +5,9 @@ UserControl "DiscordChatExporter.Views.SettingsDialog" {
|
||||||
Width: 250
|
Width: 250
|
||||||
|
|
||||||
StackPanel {
|
StackPanel {
|
||||||
// Theme
|
|
||||||
ComboBox {
|
|
||||||
Margin: "16 16 16 8"
|
|
||||||
HintAssist.Hint: "Theme"
|
|
||||||
HintAssist.IsFloating: true
|
|
||||||
IsReadOnly: true
|
|
||||||
ItemsSource: bind AvailableThemes
|
|
||||||
SelectedItem: bind Theme
|
|
||||||
}
|
|
||||||
|
|
||||||
// Date format
|
// Date format
|
||||||
TextBox {
|
TextBox {
|
||||||
Margin: "16 8 16 8"
|
Margin: "16 16 16 8"
|
||||||
HintAssist.Hint: "Date format"
|
HintAssist.Hint: "Date format"
|
||||||
HintAssist.IsFloating: true
|
HintAssist.IsFloating: true
|
||||||
Text: bind DateFormat
|
Text: bind DateFormat
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue