1
0
mirror of https://github.com/chylex/Discord-History-Tracker.git synced 2025-01-30 14:46:03 +01:00

Compare commits

...

5 Commits

Author SHA1 Message Date
e11db62015
Update Avalonia to 11.2.3 2024-12-31 10:30:18 +01:00
bfac9b91d9
Release v44.0 2024-12-31 09:23:17 +01:00
4215dc76f4
Add main menu button to check for updates
Closes #165
2024-12-31 08:58:56 +01:00
86adda610b
Fix wrong reaction handling in messages with polls
Closes #259
2024-12-31 04:59:33 +01:00
f1c4cd040e
Tweak tracking script for easier debugging 2024-12-31 04:55:53 +01:00
14 changed files with 142 additions and 79 deletions

View File

@ -0,0 +1,9 @@
using System.Diagnostics;
namespace DHT.Desktop.Common;
static class SystemUtils {
public static void OpenUrl(string url) {
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
}
}

View File

@ -15,14 +15,14 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.11" /> <PackageReference Include="Avalonia" Version="11.2.3" />
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.0.11" /> <PackageReference Include="Avalonia.Controls.DataGrid" Version="11.2.3" />
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.11" /> <PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.1.5" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.11" /> <PackageReference Include="Avalonia.Desktop" Version="11.2.3" />
<PackageReference Include="Avalonia.Diagnostics" Version="11.0.11" Condition=" '$(Configuration)' == 'Debug' " /> <PackageReference Include="Avalonia.Diagnostics" Version="11.2.3" Condition=" '$(Configuration)' == 'Debug' " />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.11" /> <PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.3" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.11" /> <PackageReference Include="Avalonia.ReactiveUI" Version="11.2.3" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.11" /> <PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.3" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="999.0.0-build.0.g0d941a6a62" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="999.0.0-build.0.g0d941a6a62" />
</ItemGroup> </ItemGroup>

View File

@ -1,45 +1,41 @@
using System.Diagnostics; using DHT.Desktop.Common;
namespace DHT.Desktop.Main; namespace DHT.Desktop.Main;
sealed class AboutWindowModel { sealed class AboutWindowModel {
public void ShowOfficialWebsite() { public void ShowOfficialWebsite() {
OpenUrl("https://dht.chylex.com"); SystemUtils.OpenUrl(Program.Website);
} }
public void ShowIssueTracker() { public void ShowIssueTracker() {
OpenUrl("https://github.com/chylex/Discord-History-Tracker/issues"); SystemUtils.OpenUrl("https://github.com/chylex/Discord-History-Tracker/issues");
} }
public void ShowSourceCode() { public void ShowSourceCode() {
OpenUrl("https://github.com/chylex/Discord-History-Tracker"); SystemUtils.OpenUrl("https://github.com/chylex/Discord-History-Tracker");
} }
public void ShowLibraryNetCore() { public void ShowLibraryNetCore() {
OpenUrl("https://github.com/dotnet/core"); SystemUtils.OpenUrl("https://github.com/dotnet/core");
} }
public void ShowLibraryAvalonia() { public void ShowLibraryAvalonia() {
OpenUrl("https://www.nuget.org/packages/Avalonia"); SystemUtils.OpenUrl("https://www.nuget.org/packages/Avalonia");
} }
public void ShowLibraryCommunityToolkit() { public void ShowLibraryCommunityToolkit() {
OpenUrl("https://github.com/CommunityToolkit/dotnet"); SystemUtils.OpenUrl("https://github.com/CommunityToolkit/dotnet");
} }
public void ShowLibrarySqlite() { public void ShowLibrarySqlite() {
OpenUrl("https://www.sqlite.org"); SystemUtils.OpenUrl("https://www.sqlite.org");
} }
public void ShowLibrarySqliteAdoNet() { public void ShowLibrarySqliteAdoNet() {
OpenUrl("https://www.nuget.org/packages/Microsoft.Data.Sqlite"); SystemUtils.OpenUrl("https://www.nuget.org/packages/Microsoft.Data.Sqlite");
} }
public void ShowLibraryRxNet() { public void ShowLibraryRxNet() {
OpenUrl("https://github.com/dotnet/reactive"); SystemUtils.OpenUrl("https://github.com/dotnet/reactive");
}
private static void OpenUrl(string url) {
Process.Start(new ProcessStartInfo { FileName = url, UseShellExecute = true });
} }
} }

View File

@ -16,6 +16,10 @@
<Setter Property="FontFamily" Value="Consolas,Courier" /> <Setter Property="FontFamily" Value="Consolas,Courier" />
<Setter Property="FontSize" Value="15" /> <Setter Property="FontSize" Value="15" />
</Style> </Style>
<Style Selector="Label">
<Setter Property="Margin" Value="0 5" />
<Setter Property="Padding" Value="0" />
</Style>
<Style Selector="WrapPanel > StackPanel"> <Style Selector="WrapPanel > StackPanel">
<Setter Property="Orientation" Value="Vertical" /> <Setter Property="Orientation" Value="Vertical" />
<Setter Property="Margin" Value="0 0 10 10" /> <Setter Property="Margin" Value="0 0 10 10" />

View File

@ -16,6 +16,10 @@
<Setter Property="FontFamily" Value="Consolas,Courier" /> <Setter Property="FontFamily" Value="Consolas,Courier" />
<Setter Property="FontSize" Value="15" /> <Setter Property="FontSize" Value="15" />
</Style> </Style>
<Style Selector="Label">
<Setter Property="Margin" Value="0 5" />
<Setter Property="Padding" Value="0" />
</Style>
<Style Selector="WrapPanel > StackPanel"> <Style Selector="WrapPanel > StackPanel">
<Setter Property="Orientation" Value="Vertical" /> <Setter Property="Orientation" Value="Vertical" />
<Setter Property="Margin" Value="0 0 10 10" /> <Setter Property="Margin" Value="0 0 10 10" />

View File

@ -1,6 +1,5 @@
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
using Avalonia.Controls; using Avalonia.Controls;
@ -52,10 +51,7 @@ sealed partial class ViewerPageModel : ObservableObject, IDisposable {
string serverUrl = "http://127.0.0.1:" + ServerConfiguration.Port; string serverUrl = "http://127.0.0.1:" + ServerConfiguration.Port;
string serverToken = ServerConfiguration.Token; string serverToken = ServerConfiguration.Token;
string sessionId = state.ViewerSessions.Register(new ViewerSession(FilterModel.CreateFilter())).ToString(); string sessionId = state.ViewerSessions.Register(new ViewerSession(FilterModel.CreateFilter())).ToString();
SystemUtils.OpenUrl(serverUrl + "/viewer/?token=" + HttpUtility.UrlEncode(serverToken) + "&session=" + HttpUtility.UrlEncode(sessionId));
Process.Start(new ProcessStartInfo(serverUrl + "/viewer/?token=" + HttpUtility.UrlEncode(serverToken) + "&session=" + HttpUtility.UrlEncode(sessionId)) {
UseShellExecute = true
});
} catch (Exception e) { } catch (Exception e) {
await Dialog.ShowOk(window, "Open Viewer", "Could not open viewer: " + e.Message); await Dialog.ShowOk(window, "Open Viewer", "Could not open viewer: " + e.Message);
} }

View File

@ -40,13 +40,13 @@
<Style Selector="TabItem:pointerover /template/ Border"> <Style Selector="TabItem:pointerover /template/ Border">
<Setter Property="Background" Value="#455785" /> <Setter Property="Background" Value="#455785" />
</Style> </Style>
<Style Selector="TabItem:pointerover > TextBlock"> <Style Selector="TabItem:pointerover /template/ ContentPresenter">
<Setter Property="Foreground" Value="#E9E9E9" /> <Setter Property="Foreground" Value="#E9E9E9" />
</Style> </Style>
<Style Selector="TabItem:selected:pointerover /template/ Border"> <Style Selector="TabItem:selected:pointerover /template/ Border">
<Setter Property="Background" Value="#FFFFFF" /> <Setter Property="Background" Value="#FFFFFF" />
</Style> </Style>
<Style Selector="TabItem:selected:pointerover > TextBlock"> <Style Selector="TabItem:selected:pointerover /template/ ContentPresenter">
<Setter Property="Foreground" Value="#1A2234" /> <Setter Property="Foreground" Value="#1A2234" />
</Style> </Style>
<Style Selector="TabItem:selected"> <Style Selector="TabItem:selected">
@ -56,9 +56,11 @@
<Style Selector="TabItem:selected /template/ Border#PART_SelectedPipe"> <Style Selector="TabItem:selected /template/ Border#PART_SelectedPipe">
<Setter Property="IsVisible" Value="False" /> <Setter Property="IsVisible" Value="False" />
</Style> </Style>
<Style Selector="TabItem:disabled > TextBlock"> <Style Selector="TabItem:disabled /template/ ContentPresenter">
<Setter Property="Foreground" Value="#B2B2B2" /> <Setter Property="Foreground" Value="#B2B2B2" />
<Setter Property="TextDecorations" Value="Strikethrough" /> </Style>
<Style Selector="TabItem:disabled /template/ ContentPresenter">
<Setter Property="AccessText.TextDecorations" Value="Strikethrough" />
</Style> </Style>
<Style Selector="TabItem.first"> <Style Selector="TabItem.first">
<Setter Property="Margin" Value="0 13 0 0" /> <Setter Property="Margin" Value="0 13 0 0" />

View File

@ -22,20 +22,21 @@
<Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" />
</Style> </Style>
<Style Selector="Button"> <Style Selector="Grid#ButtonPanel > Button">
<Setter Property="Margin" Value="5 0" /> <Setter Property="HorizontalAlignment" Value="Stretch" />
</Style> </Style>
</UserControl.Styles> </UserControl.Styles>
<Panel Name="RootPanel"> <Panel Name="RootPanel">
<StackPanel Margin="42"> <StackPanel Margin="42 30">
<TextBlock Text="{Binding Version, StringFormat=Discord History Tracker v{0}}" FontSize="25" Margin="0 0 0 30" HorizontalAlignment="Center" /> <TextBlock Text="{Binding Version, StringFormat=Discord History Tracker v{0}}" FontSize="25" Margin="0 0 0 25" HorizontalAlignment="Center" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <Grid Name="ButtonPanel" RowDefinitions="Auto,12,Auto,12,Auto" ColumnDefinitions="*,12,*" Margin="12 0" HorizontalAlignment="Stretch">
<Button Command="{Binding OpenOrCreateDatabase}" IsEnabled="{Binding IsOpenOrCreateDatabaseButtonEnabled}">Open or Create Database</Button> <Button Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Command="{Binding OpenOrCreateDatabase}" IsEnabled="{Binding IsOpenOrCreateDatabaseButtonEnabled}">Open or Create Database</Button>
<Button Command="{Binding ShowAboutDialog}">About</Button> <Button Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Command="{Binding CheckUpdates}">Check For Updates</Button>
<Button Command="{Binding Exit}">Exit</Button> <Button Grid.Row="4" Grid.Column="0" Command="{Binding ShowAboutDialog}">About</Button>
</StackPanel> <Button Grid.Row="4" Grid.Column="2" Command="{Binding Exit}">Exit</Button>
</Grid>
</StackPanel> </StackPanel>
</Panel> </Panel>
</UserControl> </UserControl>

View File

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls; using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
@ -10,10 +12,13 @@ using DHT.Desktop.Dialogs.Progress;
using DHT.Server.Data.Settings; using DHT.Server.Data.Settings;
using DHT.Server.Database; using DHT.Server.Database;
using DHT.Server.Database.Sqlite.Schema; using DHT.Server.Database.Sqlite.Schema;
using DHT.Utils.Logging;
namespace DHT.Desktop.Main.Screens; namespace DHT.Desktop.Main.Screens;
sealed partial class WelcomeScreenModel : ObservableObject { sealed partial class WelcomeScreenModel : ObservableObject {
private static readonly Log Log = Log.ForType<WelcomeScreenModel>();
public string Version => Program.Version; public string Version => Program.Version;
[ObservableProperty(Setter = Access.Private)] [ObservableProperty(Setter = Access.Private)]
@ -61,13 +66,7 @@ sealed partial class WelcomeScreenModel : ObservableObject {
DatabaseSelected?.Invoke(this, db); DatabaseSelected?.Invoke(this, db);
} }
private sealed class SchemaUpgradeCallbacks : ISchemaUpgradeCallbacks { private sealed class SchemaUpgradeCallbacks(Window window) : ISchemaUpgradeCallbacks {
private readonly Window window;
public SchemaUpgradeCallbacks(Window window) {
this.window = window;
}
public async Task<bool> CanUpgrade() { public async Task<bool> CanUpgrade() {
return DialogResult.YesNo.Yes == await DatabaseGui.ShowCanUpgradeDatabaseDialog(window); return DialogResult.YesNo.Yes == await DatabaseGui.ShowCanUpgradeDatabaseDialog(window);
} }
@ -84,17 +83,9 @@ sealed partial class WelcomeScreenModel : ObservableObject {
await new ProgressDialog { DataContext = new ProgressDialogModel("Upgrading Database", StartUpgrade, progressItems: 3) }.ShowProgressDialog(window); await new ProgressDialog { DataContext = new ProgressDialogModel("Upgrading Database", StartUpgrade, progressItems: 3) }.ShowProgressDialog(window);
} }
private sealed class ProgressReporter : ISchemaUpgradeCallbacks.IProgressReporter { private sealed class ProgressReporter(int versionSteps, IReadOnlyList<IProgressCallback> callbacks) : ISchemaUpgradeCallbacks.IProgressReporter {
private readonly IReadOnlyList<IProgressCallback> callbacks;
private readonly int versionSteps;
private int versionProgress = 0; private int versionProgress = 0;
public ProgressReporter(int versionSteps, IReadOnlyList<IProgressCallback> callbacks) {
this.callbacks = callbacks;
this.versionSteps = versionSteps;
}
public async Task NextVersion() { public async Task NextVersion() {
await callbacks[0].Update("Upgrading schema version...", versionProgress++, versionSteps); await callbacks[0].Update("Upgrading schema version...", versionProgress++, versionSteps);
await HideChildren(0); await HideChildren(0);
@ -118,6 +109,53 @@ sealed partial class WelcomeScreenModel : ObservableObject {
} }
} }
public async Task CheckUpdates() {
Version? latestVersion = await ProgressDialog.ShowIndeterminate<Version?>(window, "Check Updates", "Checking for updates...", async _ => {
var client = new HttpClient(new SocketsHttpHandler {
AutomaticDecompression = DecompressionMethods.None,
AllowAutoRedirect = false,
UseCookies = false
});
client.Timeout = TimeSpan.FromSeconds(30);
client.MaxResponseContentBufferSize = 1024;
client.DefaultRequestHeaders.UserAgent.ParseAdd("DiscordHistoryTracker/" + Program.Version);
string response;
try {
response = await client.GetStringAsync(Program.Website + "/version");
} catch (TaskCanceledException e) when (e.InnerException is TimeoutException) {
await Dialog.ShowOk(window, "Check Updates", "Request timed out.");
return null;
} catch (Exception e) {
Log.Error(e);
await Dialog.ShowOk(window, "Check Updates", "Error checking for updates: " + e.Message);
return null;
}
if (!System.Version.TryParse(response, out var latestVersion)) {
await Dialog.ShowOk(window, "Check Updates", "Server returned an invalid response.");
return null;
}
return latestVersion;
});
if (latestVersion == null) {
return;
}
if (Program.AssemblyVersion >= latestVersion) {
await Dialog.ShowOk(window, "Check Updates", "You are using the latest version.");
return;
}
if (await Dialog.ShowYesNo(window, "Check Updates", "A newer version is available: v" + Program.VersionToString(latestVersion) + "\nVisit the official website and close the app?") == DialogResult.YesNo.Yes) {
SystemUtils.OpenUrl(Program.Website);
Exit();
}
}
public async Task ShowAboutDialog() { public async Task ShowAboutDialog() {
await new AboutWindow { DataContext = new AboutWindowModel() }.ShowDialog(window); await new AboutWindow { DataContext = new AboutWindowModel() }.ShowDialog(window);
} }

View File

@ -9,17 +9,18 @@ namespace DHT.Desktop;
static class Program { static class Program {
public static string Version { get; } public static string Version { get; }
public static Version AssemblyVersion { get; }
public static CultureInfo Culture { get; } public static CultureInfo Culture { get; }
public static ResourceLoader Resources { get; } public static ResourceLoader Resources { get; }
public static Arguments Arguments { get; } public static Arguments Arguments { get; }
public const string Website = "https://dht.chylex.com";
static Program() { static Program() {
var assembly = Assembly.GetExecutingAssembly(); var assembly = Assembly.GetExecutingAssembly();
Version = assembly.GetName().Version?.ToString() ?? ""; AssemblyVersion = assembly.GetName().Version ?? new Version(0, 0, 0, 0);
while (Version.EndsWith(".0")) { Version = VersionToString(AssemblyVersion);
Version = Version[..^2];
}
Culture = CultureInfo.CurrentCulture; Culture = CultureInfo.CurrentCulture;
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
@ -31,6 +32,16 @@ static class Program {
Arguments = new Arguments(Environment.GetCommandLineArgs()); Arguments = new Arguments(Environment.GetCommandLineArgs());
} }
public static string VersionToString(Version version) {
string versionStr = version.ToString();
while (versionStr.EndsWith(".0")) {
versionStr = versionStr[..^2];
}
return versionStr;
}
public static void Main(string[] args) { public static void Main(string[] args) {
if (Arguments.Console && OperatingSystem.IsWindows()) { if (Arguments.Console && OperatingSystem.IsWindows()) {
WindowsConsole.AllocConsole(); WindowsConsole.AllocConsole();

View File

@ -117,24 +117,25 @@ class DISCORD {
} }
} }
static getMessagesFromSelectedChannel() {
const channelId = this.#getCurrentlySelectedChannelId();
return channelId ? this.#getMessages(channelId) : null;
}
/** /**
* Calls the provided function with a list of messages whenever the currently loaded messages change. * Calls the provided function with a list of messages whenever the currently loaded messages change.
* @param callback {function(server: ?DiscordGuild, channel: DiscordChannel, messages: Array<DiscordMessage>, hasMoreBefore: boolean)}
*/ */
static setupMessageCallback(callback) { static setupMessageCallback(callback) {
const previousMessages = new Set(); const previousMessages = new Set();
const onMessageElementsChanged = force => { const onMessageElementsChanged = force => {
const channelId = this.#getCurrentlySelectedChannelId(); const messages = this.getMessagesFromSelectedChannel();
if (!channelId) {
return false;
}
const messages = this.#getMessages(channelId);
if (!messages || !messages.ready || messages.loadingMore) { if (!messages || !messages.ready || messages.loadingMore) {
return false; return false;
} }
const channel = this.#channelStore.getChannel(channelId); const channel = this.#channelStore.getChannel(messages.channelId);
if (!channel) { if (!channel) {
return false; return false;
} }

View File

@ -286,7 +286,7 @@ const STATE = (function() {
} }
if (msg.reactions.length > 0) { if (msg.reactions.length > 0) {
obj.reactions = msg.reactions.map(reaction => { obj.reactions = msg.reactions.filter(reaction => reaction.count > 0).map(reaction => {
const emoji = reaction.emoji; const emoji = reaction.emoji;
const mapped = { const mapped = {

View File

@ -73,6 +73,7 @@
/** /**
* @name MessageData * @name MessageData
* @type {Object} * @type {Object}
* @property {String} channelId
* @property {Boolean} ready * @property {Boolean} ready
* @property {Boolean} loadingMore * @property {Boolean} loadingMore
* @property {Boolean} hasMoreAfter * @property {Boolean} hasMoreAfter

View File

@ -8,5 +8,5 @@ using DHT.Utils;
namespace DHT.Utils; namespace DHT.Utils;
static class Version { static class Version {
public const string Tag = "43.1.0.0"; public const string Tag = "44.0.0.0";
} }