feat: add better relay support to desktop

This commit is contained in:
Anna 2021-01-24 17:59:47 -05:00
parent 6d95b0d850
commit 617f9717a2
Signed by: anna
GPG Key ID: 0B391D8F06FCD9E0
10 changed files with 261 additions and 280 deletions

View File

@ -30,16 +30,7 @@ namespace XIVChat_Desktop {
public string? LastHost { get; set; }
private Connection? connection;
public Connection? Connection {
get => this.connection;
set {
this.connection = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Connection)));
this.ConnectionStatusChanged();
}
}
public Connection? Connection { get; set; }
public bool Connected => this.Connection != null;
@ -125,16 +116,12 @@ namespace XIVChat_Desktop {
};
}
private void ConnectionStatusChanged() {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Connected)));
}
public void Connect(string host, ushort port, string? relayAuth, string? relayTarget) {
public void Connect(string host, ushort port) {
if (this.Connected) {
return;
}
this.Connection = new Connection(this, host, port, relayAuth, relayTarget);
this.Connection = new Connection(this, host, port);
this.Connection.ReceiveMessage += this.OnReceiveMessage;
Task.Run(this.Connection.Connect);
}

View File

@ -9,7 +9,6 @@ using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using XIVChatCommon.Message;
using XIVChatCommon.Message.Server;
@ -30,56 +29,20 @@ namespace XIVChat_Desktop {
public bool AlwaysOnTop { get; set; }
private double fontSize = 14d;
public double FontSize {
get => this.fontSize;
set {
this.fontSize = value;
this.OnPropertyChanged(nameof(this.FontSize));
}
}
public double FontSize { get; set; } = 14d;
public ushort BacklogMessages { get; set; } = 500;
public uint LocalBacklogMessages { get; set; } = 10_000;
private double opacity = 1.0;
public double Opacity { get; set; } = 1.0;
public double Opacity {
get => this.opacity;
set {
this.opacity = value;
this.OnPropertyChanged(nameof(this.Opacity));
}
}
public bool CompactMode { get; set; }
private bool compactMode;
public bool CompactMode {
get => this.compactMode;
set {
this.compactMode = value;
this.OnPropertyChanged(nameof(this.CompactMode));
}
}
private Theme theme = Theme.System;
public Theme Theme {
get => this.theme;
set {
this.theme = value;
this.OnPropertyChanged(nameof(this.Theme));
}
}
public Theme Theme { get; set; } = Theme.System;
public ObservableCollection<Notification> Notifications { get; set; } = new ObservableCollection<Notification>();
private void OnPropertyChanged(string propName) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
#region io
private static string FilePath() => Path.Join(
@ -98,6 +61,7 @@ namespace XIVChat_Desktop {
using var json = new JsonTextReader(reader);
var serializer = new JsonSerializer {
TypeNameHandling = TypeNameHandling.Auto,
ObjectCreationHandling = ObjectCreationHandling.Replace,
};
return serializer.Deserialize<Configuration>(json);
@ -113,81 +77,39 @@ namespace XIVChat_Desktop {
using var file = File.CreateText(path);
using var json = new JsonTextWriter(file);
var serialiser = new JsonSerializer();
var serialiser = new JsonSerializer {
TypeNameHandling = TypeNameHandling.Auto,
};
serialiser.Serialize(json, this);
}
#endregion
}
[JsonObject]
public class SavedServer : INotifyPropertyChanged {
private string _name;
private string _host;
private ushort _port;
private string? _relayAuth;
private string? _relayTarget;
public string Name {
get => this._name;
set {
this._name = value;
this.OnPropertyChanged(nameof(this.Name));
}
}
public string Host {
get => this._host;
set {
this._host = value;
this.OnPropertyChanged(nameof(this.Host));
}
}
public ushort Port {
get => this._port;
set {
this._port = value;
this.OnPropertyChanged(nameof(this.Port));
}
}
public string? RelayAuth {
get => this._relayAuth;
set {
this._relayAuth = value;
this.OnPropertyChanged(nameof(this.RelayAuth));
}
}
public string? RelayTarget {
get => this._relayTarget;
set {
this._relayTarget = value;
this.OnPropertyChanged(nameof(this.RelayTarget));
}
}
public abstract class SavedServer : INotifyPropertyChanged {
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public string Name { get; set; }
}
[JsonObject]
public class DirectServer : SavedServer {
public string Host { get; set; }
public ushort Port { get; set; }
public DirectServer(string name, string host, ushort port) {
this.Name = name;
this.Host = host;
this.Port = port;
}
public SavedServer(string name, string host, ushort port, string? relayAuth, string? relayTarget) {
this._name = name;
this._host = host;
this._port = port;
this._relayAuth = relayAuth;
this._relayTarget = relayTarget;
}
protected bool Equals(SavedServer other) {
protected bool Equals(DirectServer other) {
return this.Name == other.Name && this.Host == other.Host && this.Port == other.Port;
}
public override bool Equals(object? obj) {
if (obj is null) {
if (ReferenceEquals(null, obj)) {
return false;
}
@ -195,12 +117,47 @@ namespace XIVChat_Desktop {
return true;
}
return obj.GetType() == this.GetType() && this.Equals((SavedServer)obj);
return obj.GetType() == this.GetType() && this.Equals((DirectServer) obj);
}
[SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")]
public override int GetHashCode() {
return HashCode.Combine(this.Name, this.Host, this.Port);
unchecked {
return (this.Host.GetHashCode() * 397) ^ this.Port.GetHashCode();
}
}
}
[JsonObject]
public class RelayServer : SavedServer {
public string RelayAuth { get; set; }
public string RelayTarget { get; set; }
public RelayServer(string name, string relayAuth, string relayTarget) {
this.Name = name;
this.RelayAuth = relayAuth;
this.RelayTarget = relayTarget;
}
protected bool Equals(RelayServer other) {
return this.Name == other.Name && this.RelayAuth == other.RelayAuth && this.RelayTarget == other.RelayTarget;
}
public override bool Equals(object? obj) {
if (ReferenceEquals(null, obj)) {
return false;
}
if (ReferenceEquals(this, obj)) {
return true;
}
return obj.GetType() == this.GetType() && this.Equals((RelayServer) obj);
}
public override int GetHashCode() {
unchecked {
return (this.RelayAuth.GetHashCode() * 397) ^ this.RelayTarget.GetHashCode();
}
}
}
@ -223,34 +180,19 @@ namespace XIVChat_Desktop {
[JsonObject]
public class Tab : IEnumerable<ServerMessage>, INotifyCollectionChanged, INotifyPropertyChanged {
private string name;
private bool processMarkdown;
public Tab(string name) {
this.name = name;
}
public string Name {
get => this.name;
set {
this.name = value;
this.OnPropertyChanged(nameof(this.Name));
}
}
public string Name { get; set; }
public Filter Filter { get; set; } = new Filter();
public bool ProcessMarkdown {
get => this.processMarkdown;
set {
this.processMarkdown = value;
this.OnPropertyChanged(nameof(this.ProcessMarkdown));
}
}
public bool ProcessMarkdown { get; set; }
[JsonIgnore]
public List<ServerMessage> Messages { get; } = new List<ServerMessage>();
public Tab(string name) {
this.Name = name;
}
private void NotifyReset() {
this.CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
@ -278,21 +220,21 @@ namespace XIVChat_Desktop {
this.NotifyReset();
}
private int lastSequence = -1;
private int insertAt;
private int _lastSequence = -1;
private int _insertAt;
public void AddReversedChunk(ServerMessage[] messages, int sequence, Configuration config) {
if (sequence != this.lastSequence) {
this.lastSequence = sequence;
this.insertAt = this.Messages.Count;
if (sequence != this._lastSequence) {
this._lastSequence = sequence;
this._insertAt = this.Messages.Count;
}
var filtered = messages
.Where(msg => msg.Channel == 0 || this.Filter.Allowed(msg))
.ToList();
this.Messages.InsertRange(this.insertAt, filtered);
this.NotifyAddItemsAt(filtered, this.insertAt);
this.Messages.InsertRange(this._insertAt, filtered);
this.NotifyAddItemsAt(filtered, this._insertAt);
this.Prune(config);
}
@ -314,8 +256,8 @@ namespace XIVChat_Desktop {
return;
}
var removed = this.Messages.Take((int)diff).ToList();
this.Messages.RemoveRange(0, (int)diff);
var removed = this.Messages.Take((int) diff).ToList();
this.Messages.RemoveRange(0, (int) diff);
this.NotifyRemoveItemsAt(removed, 0);
}
@ -365,10 +307,6 @@ namespace XIVChat_Desktop {
public event NotifyCollectionChangedEventHandler? CollectionChanged;
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
[JsonObject]
@ -376,7 +314,7 @@ namespace XIVChat_Desktop {
public HashSet<FilterType> Types { get; set; } = new HashSet<FilterType>();
public virtual bool Allowed(ServerMessage message) {
var code = new ChatCode((ushort)message.Channel);
var code = new ChatCode((ushort) message.Channel);
return this.Types.Any(type => type.Allowed(code));
}
}
@ -388,7 +326,7 @@ namespace XIVChat_Desktop {
public List<ChatType> Channels { get; set; } = new List<ChatType>();
public List<string> Substrings { get; set; } = new List<string>();
private IReadOnlyCollection<String> regexes = new List<string>();
private IReadOnlyCollection<string> regexes = new List<string>();
public IReadOnlyCollection<string> Regexes {
get => this.regexes;

View File

@ -31,7 +31,9 @@ namespace XIVChat_Desktop {
return;
}
this.App.Connect(server.Host, server.Port, server.RelayAuth, server.RelayTarget);
if (server is DirectServer direct) {
this.App.Connect(direct.Host, direct.Port);
}
this.Close();
}

View File

@ -10,9 +10,11 @@ using System.Threading.Channels;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using MessagePack;
using XIVChatCommon;
using XIVChatCommon.Message;
using XIVChatCommon.Message.Client;
using XIVChatCommon.Message.Relay;
using XIVChatCommon.Message.Server;
namespace XIVChat_Desktop {
@ -58,23 +60,18 @@ namespace XIVChat_Desktop {
public event PropertyChangedEventHandler? PropertyChanged;
public string? CurrentChannel { get; private set; }
private bool available;
public bool Available { get; set; }
public bool Available {
get => this.available;
private set {
this.available = value;
this.OnPropertyChanged(nameof(this.Available));
}
}
public Connection(App app, string host, ushort port, string? relayAuth = null, string? relayTarget = null) {
public Connection(App app, string host, ushort port) {
this.app = app;
this.host = host;
this.port = port;
this.relayAuth = relayAuth;
this.relayTarget = relayTarget;
}
// ReSharper disable once UnusedMember.Local
private void OnAvailableChanged() {
this.app.Window.OnPropertyChanged(nameof(MainWindow.InputPlaceholder));
}
public void SendMessage(string message) {
@ -112,39 +109,47 @@ namespace XIVChat_Desktop {
var stream = this.client.GetStream();
switch (usingRelay) {
// do relay auth before connecting if necessary
case true: {
var relayHandshake = await KeyExchange.ClientHandshake(this.app.Config.KeyPair, stream);
// write the magic bytes
await stream.WriteAsync(new byte[] {
14, 20, 67,
});
// ensure the relay's public key is what we expect
if (!relayHandshake.RemotePublicKey.SequenceEqual(RelayPublicKey)) {
this.app.Dispatch(() => {
MessageBox.Show("Unexpected relay public key.");
});
return;
}
// authenticate with relay if necessary
if (usingRelay) {
var relayHandshake = await KeyExchange.ClientHandshake(this.app.Config.KeyPair, stream);
// send auth token
var authBytes = Encoding.UTF8.GetBytes(this.relayAuth!);
await SecretMessage.SendSecretMessage(stream, relayHandshake.Keys.tx, authBytes);
// TODO: receive response
// send the public key of the server
var pk = Util.StringToByteArray(this.relayTarget!);
await SecretMessage.SendSecretMessage(stream, relayHandshake.Keys.tx, pk);
// TODO: receive response
break;
}
// only send magic bytes if not using the relay
case false:
// write the magic bytes
await stream.WriteAsync(new byte[] {
14, 20, 67,
// ensure the relay's public key is what we expect
if (!relayHandshake.RemotePublicKey.SequenceEqual(RelayPublicKey)) {
this.app.Dispatch(() => {
MessageBox.Show("Unexpected relay public key.");
});
break;
return;
}
async Task<RelaySuccess> ReadSuccess() {
var response = await SecretMessage.ReadSecretMessage(stream, relayHandshake.Keys.rx);
return MessagePackSerializer.Deserialize<RelaySuccess>(response);
}
// send auth token
var authBytes = Encoding.UTF8.GetBytes(this.relayAuth!);
await SecretMessage.SendSecretMessage(stream, relayHandshake.Keys.tx, authBytes);
var authSuccess = await ReadSuccess();
if (!authSuccess.Success) {
this.app.Dispatch(() => MessageBox.Show($"Relay rejected authentication code:\n{authSuccess.Info}"));
return;
}
// send the public key of the server
var pk = Util.StringToByteArray(this.relayTarget!);
await SecretMessage.SendSecretMessage(stream, relayHandshake.Keys.tx, pk);
var targetSuccess = await ReadSuccess();
if (!targetSuccess.Success) {
this.app.Dispatch(() => MessageBox.Show($"Relay rejected server public key:\n{targetSuccess.Info}"));
return;
}
}
// do the handshake
@ -360,11 +365,7 @@ namespace XIVChat_Desktop {
case ServerOperation.Channel:
var channel = ServerChannel.Decode(payload);
this.CurrentChannel = channel.name;
this.app.Dispatch(() => {
this.OnPropertyChanged(nameof(this.CurrentChannel));
});
this.app.Dispatch(() => this.CurrentChannel = channel.name);
break;
case ServerOperation.Backlog:
var backlog = ServerBacklog.Decode(payload);
@ -421,22 +422,5 @@ namespace XIVChat_Desktop {
window.Location.Visibility = visibility;
});
}
private void OnPropertyChanged(string prop) {
Action action;
if (prop == nameof(this.Available)) {
action = () => {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Available)));
this.app.Window.OnPropertyChanged(nameof(MainWindow.InputPlaceholder));
};
} else {
action = () => {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
};
}
this.app.Dispatch(action);
}
}
}

View File

@ -11,13 +11,13 @@ namespace XIVChat_Desktop.Controls {
private Window Window => Window.GetWindow(this)!;
public IEnumerable<SavedServer> ItemsSource {
get { return (IEnumerable<SavedServer>)this.GetValue(ItemsSourceProperty); }
set { this.SetValue(ItemsSourceProperty, value); }
get => (IEnumerable<SavedServer>)this.GetValue(ItemsSourceProperty);
set => this.SetValue(ItemsSourceProperty, value);
}
public Visibility ControlsVisibility {
get { return (Visibility)this.GetValue(ControlsVisibilityProperty); }
set { this.SetValue(ControlsVisibilityProperty, value); }
get => (Visibility)this.GetValue(ControlsVisibilityProperty);
set => this.SetValue(ControlsVisibilityProperty, value);
}
public SavedServer? SelectedServer {

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<PropertyChanged />
</Weavers>

View File

@ -10,6 +10,7 @@
WindowStartupLocation="CenterOwner"
SizeToContent="WidthAndHeight"
Title="Manage server"
Initialized="ManageServer_OnInitialized"
d:DataContext="{d:DesignInstance local:ManageServer}">
<Grid Margin="8">
<Grid.RowDefinitions>
@ -18,8 +19,6 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
@ -32,8 +31,10 @@
Grid.Column="0">
Server type
</Label>
<ComboBox Grid.Row="0"
<ComboBox x:Name="TypeBox"
Grid.Row="0"
Grid.Column="1"
SelectionChanged="TypeBox_OnSelectionChanged"
SelectedIndex="0">
<ComboBoxItem>Direct</ComboBoxItem>
<ComboBoxItem>Relay</ComboBoxItem>
@ -50,7 +51,8 @@
x:Name="ServerName"
Text="{Binding Server.Name, Mode=OneTime}" />
<Label VerticalAlignment="Center"
<Label x:Name="ServerHostLabel"
VerticalAlignment="Center"
Grid.Row="2"
Grid.Column="0">
IP Address
@ -61,7 +63,8 @@
x:Name="ServerHost"
Text="{Binding Server.Host, Mode=OneTime}" />
<Label VerticalAlignment="Center"
<Label x:Name="ServerPortLabel"
VerticalAlignment="Center"
Grid.Row="3"
Grid.Column="0">
Port
@ -73,32 +76,34 @@
Text="{Binding Server.Port, Mode=OneTime}"
ui:ControlHelper.PlaceholderText="14777" />
<Label VerticalAlignment="Center"
Grid.Row="4"
<Label x:Name="RelayAuthLabel"
VerticalAlignment="Center"
Grid.Row="2"
Grid.Column="0">
Relay auth
</Label>
<TextBox Margin="4,4,0,0"
Grid.Row="4"
Grid.Row="2"
Grid.Column="1"
x:Name="RelayAuth"
Text="{Binding Server.RelayAuth, Mode=OneTime}"
ui:ControlHelper.PlaceholderText="Optional (only enter if using relay)" />
ui:ControlHelper.PlaceholderText="Your authentication code" />
<Label VerticalAlignment="Center"
Grid.Row="5"
<Label x:Name="RelayTargetLabel"
VerticalAlignment="Center"
Grid.Row="3"
Grid.Column="0">
Server public key
</Label>
<TextBox Margin="4,4,0,0"
Grid.Row="5"
Grid.Row="3"
Grid.Column="1"
x:Name="RelayTarget"
Text="{Binding Server.RelayTarget, Mode=OneTime}"
ui:ControlHelper.PlaceholderText="Optional (only enter if using relay)" />
ui:ControlHelper.PlaceholderText="AABBCCDD..." />
<WrapPanel Margin="0,8,0,0"
Grid.Row="6"
Grid.Row="4"
Grid.ColumnSpan="2"
Grid.Column="0"
HorizontalAlignment="Right">

View File

@ -1,4 +1,6 @@
using System.Windows;
using System;
using System.Windows;
using System.Windows.Controls;
namespace XIVChat_Desktop {
/// <summary>
@ -8,17 +10,19 @@ namespace XIVChat_Desktop {
public App App => (App) Application.Current;
public SavedServer? Server { get; private set; }
private readonly bool isNewServer;
private bool IsDirect => this.TypeBox.SelectedIndex == 0;
private readonly bool _isNewServer;
public ManageServer(Window owner, SavedServer? server) {
this.Owner = owner;
this.Server = server;
this.isNewServer = server == null;
this._isNewServer = server == null;
this.InitializeComponent();
this.DataContext = this;
if (this.isNewServer) {
if (this._isNewServer) {
this.Title = "Add server";
}
}
@ -26,7 +30,7 @@ namespace XIVChat_Desktop {
public ManageServer(Window owner, SavedServer server, bool isNewServer) {
this.Owner = owner;
this.Server = server;
this.isNewServer = isNewServer;
this._isNewServer = isNewServer;
this.InitializeComponent();
this.DataContext = this;
@ -34,49 +38,55 @@ namespace XIVChat_Desktop {
private void Save_Click(object sender, RoutedEventArgs e) {
var serverName = this.ServerName.Text;
var serverHost = this.ServerHost.Text;
var relayAuth = this.RelayAuth.Text.Trim();
var relayTarget = this.RelayTarget.Text.Trim();
if (relayAuth.Length == 0) {
relayAuth = null;
}
if (relayTarget.Length == 0) {
relayTarget = null;
}
if (serverName.Length == 0 || serverHost.Length == 0) {
MessageBox.Show("Server must have a name and host.");
if (serverName.Length == 0) {
MessageBox.Show("Server must have a name.");
return;
}
ushort port;
if (this.ServerPort.Text.Length == 0) {
port = 14777;
} else {
if (!ushort.TryParse(this.ServerPort.Text, out port) || port < 1) {
MessageBox.Show("Port was not valid. It must be a number between 1 and 65535.");
if (this.IsDirect) {
var serverHost = this.ServerHost.Text.Trim();
if (serverHost.Length == 0) {
MessageBox.Show("Server must have a host.");
return;
}
}
if (this.isNewServer) {
this.Server = new SavedServer(
serverName,
serverHost,
port,
relayAuth,
relayTarget
);
ushort port;
if (this.ServerPort.Text.Length == 0) {
port = 14777;
} else {
if (!ushort.TryParse(this.ServerPort.Text, out port) || port < 1) {
MessageBox.Show("Port was not valid. It must be a number between 1 and 65535.");
return;
}
}
this.App.Config.Servers.Add(this.Server);
if (this._isNewServer) {
this.Server = new DirectServer(serverName, serverHost, port);
this.App.Config.Servers.Add(this.Server);
} else if (this.Server is DirectServer direct) {
this.Server!.Name = serverName;
direct.Host = serverHost;
direct.Port = port;
}
} else {
this.Server!.Name = serverName;
this.Server.Host = serverHost;
this.Server.Port = port;
this.Server.RelayAuth = relayAuth;
this.Server.RelayTarget = relayTarget;
var relayAuth = this.RelayAuth.Text.Trim();
var relayTarget = this.RelayTarget.Text.Trim();
if (relayAuth.Length == 0 || relayTarget.Length == 0) {
MessageBox.Show("Server must have an auth code and public key.");
return;
}
if (this._isNewServer) {
this.Server = new RelayServer(serverName, relayAuth, relayTarget);
this.App.Config.Servers.Add(this.Server);
} else if (this.Server is RelayServer relay) {
this.Server!.Name = serverName;
relay.RelayAuth = relayAuth;
relay.RelayTarget = relayTarget;
}
}
this.App.Config.Save();
@ -87,5 +97,49 @@ namespace XIVChat_Desktop {
private void Cancel_Click(object sender, RoutedEventArgs e) {
this.Close();
}
private void TypeBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e) {
this.CalcVisibility();
}
private void CalcVisibility() {
try {
if (this.IsDirect) {
this.ServerHostLabel.Visibility = Visibility.Visible;
this.ServerHost.Visibility = Visibility.Visible;
this.ServerPortLabel.Visibility = Visibility.Visible;
this.ServerPort.Visibility = Visibility.Visible;
this.RelayAuthLabel.Visibility = Visibility.Collapsed;
this.RelayAuth.Visibility = Visibility.Collapsed;
this.RelayTargetLabel.Visibility = Visibility.Collapsed;
this.RelayTarget.Visibility = Visibility.Collapsed;
} else {
this.ServerHostLabel.Visibility = Visibility.Collapsed;
this.ServerHost.Visibility = Visibility.Collapsed;
this.ServerPortLabel.Visibility = Visibility.Collapsed;
this.ServerPort.Visibility = Visibility.Collapsed;
this.RelayAuthLabel.Visibility = Visibility.Visible;
this.RelayAuth.Visibility = Visibility.Visible;
this.RelayTargetLabel.Visibility = Visibility.Visible;
this.RelayTarget.Visibility = Visibility.Visible;
}
} catch (NullReferenceException) {
// ignored
}
}
private void ManageServer_OnInitialized(object? sender, EventArgs e) {
this.TypeBox.SelectedIndex = this.Server switch {
RelayServer _ => 1,
DirectServer _ => 0,
_ => this.TypeBox.SelectedIndex,
};
if (this.Server != null) {
this.TypeBox.IsEnabled = false;
}
this.CalcVisibility();
}
}
}

View File

@ -72,7 +72,7 @@ namespace XIVChat_Desktop {
continue;
}
var saved = new SavedServer(server.playerName, server.address, server.port, null, null);
var saved = new DirectServer(server.playerName, server.address, server.port);
if (this.Servers.Contains(saved)) {
continue;
}

View File

@ -51,11 +51,18 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Fody" Version="6.3.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.0.8" />
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="6.1.1" />
<PackageReference Include="ModernWpfUI" Version="0.9.2" />
<PackageReference Include="ModernWpfUI.MahApps" Version="0.9.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="PropertyChanged.Fody" Version="3.3.1">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Sodium.Core" Version="1.2.3" />
<PackageReference Include="System.Drawing.Common" Version="5.0.0" />
</ItemGroup>