diff --git a/XIVChat Desktop/Connection.cs b/XIVChat Desktop/Connection.cs index 4d9c6ee..f9f50e5 100644 --- a/XIVChat Desktop/Connection.cs +++ b/XIVChat Desktop/Connection.cs @@ -217,9 +217,8 @@ namespace XIVChat_Desktop { // tell the server our preferences var preferences = new ClientPreferences { Preferences = new Dictionary { - { - ClientPreference.BacklogNewestMessagesFirst, true - }, + [ClientPreference.BacklogNewestMessagesFirst] = true, + [ClientPreference.TargetingListSupport] = true, }, }; await SecretMessage.SendSecretMessage(stream, handshake.Keys.tx, preferences, this.cancel.Token); @@ -418,16 +417,24 @@ namespace XIVChat_Desktop { case ServerOperation.PlayerList: var playerList = ServerPlayerList.Decode(payload); - if (playerList.Type == PlayerListType.Friend) { - var players = playerList.Players - .OrderBy(player => !player.HasStatus(PlayerStatus.Online)); + switch (playerList.Type) { + case PlayerListType.Friend: { + var players = playerList.Players + .OrderBy(player => !player.HasStatus(PlayerStatus.Online)); - this.app.Dispatch(() => { - this.app.Window.FriendList.Clear(); - foreach (var player in players) { - this.app.Window.FriendList.Add(player); - } - }); + this.app.Dispatch(() => { + this.app.Window.FriendList.Clear(); + foreach (var player in players) { + this.app.Window.FriendList.Add(player); + } + }); + break; + } + case PlayerListType.Targeting: + this.app.Dispatch(() => { + this.app.Window.UpdateTargeting(playerList.Players); + }); + break; } break; diff --git a/XIVChat Desktop/Converters.cs b/XIVChat Desktop/Converters.cs index fb1120e..ac94555 100644 --- a/XIVChat Desktop/Converters.cs +++ b/XIVChat Desktop/Converters.cs @@ -51,7 +51,7 @@ namespace XIVChat_Desktop { public class SenderPlayerConverter : IValueConverter { public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) { - if (!(value is ServerMessage.SenderPlayer sender)) { + if (value is not ServerMessage.SenderPlayer sender) { return null; } @@ -63,7 +63,7 @@ namespace XIVChat_Desktop { if (worldName != null) { s.Append(" ("); s.Append(worldName); - s.Append(")"); + s.Append(')'); } return s.ToString(); @@ -100,11 +100,11 @@ namespace XIVChat_Desktop { public class NotConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return !((bool)value); + return !(bool) value; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - return !((bool)value); + return !(bool) value; } } @@ -113,11 +113,11 @@ namespace XIVChat_Desktop { public T FalseValue { get; set; } = default!; public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) { - return (bool)value ? this.TrueValue : this.FalseValue; + return (bool) value ? this.TrueValue : this.FalseValue; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - var val = (T)value; + var val = (T) value; return EqualityComparer.Default.Equals(val, this.TrueValue); } } diff --git a/XIVChat Desktop/MainWindow.xaml b/XIVChat Desktop/MainWindow.xaml index 2a13482..4b42d37 100644 --- a/XIVChat Desktop/MainWindow.xaml +++ b/XIVChat Desktop/MainWindow.xaml @@ -63,6 +63,8 @@ WindowChrome.IsHitTestVisibleInChrome="{Binding App.Config.CompactMode}"> + Messages { get; } = new(); public ObservableCollection FriendList { get; } = new(); + public List Targeting { get; set; } = new(); private bool ShowMessageForNoUpdate { get; set; } @@ -349,6 +351,31 @@ namespace XIVChat_Desktop { } } + internal void UpdateTargeting(IEnumerable players) { + var now = DateTime.UtcNow; + var data = players as Player[] ?? players.ToArray(); + + var newPlayers = data + .Where(player => this.Targeting.All(t => t.Player.Name != player.Name && t.Player.HomeWorld != player.HomeWorld)) + .Select(player => new TargetingPlayer(player, true, now)); + + var oldPlayers = this.Targeting + .Select(t => { + var timestamp = t.Timestamp; + var current = data.Any(current => current.Name == t.Player.Name && current.HomeWorld == t.Player.HomeWorld); + if (current || t.Current) { + timestamp = now; + } + + return new TargetingPlayer(t.Player, current, timestamp); + }) + .Concat(newPlayers) + .OrderByDescending(t => t.Current) + .ThenByDescending(t => t.Timestamp); + + this.Targeting = oldPlayers.ToList(); + } + private void Connect_Click(object sender, RoutedEventArgs e) { new ConnectDialog(this).ShowDialog(); } @@ -518,5 +545,27 @@ namespace XIVChat_Desktop { private void TabGrid_OnInitialized(object? sender, EventArgs e) { this.CalculateCompactMargins(); } + + private void Targeting_Click(object sender, RoutedEventArgs e) { + new Targeting(this).Show(); + } + } + + public class TargetingPlayer { + public Player Player { get; } + public bool Current { get; } + public DateTime Timestamp { get; } + + public string UiTimestamp => this.Current + ? "Now" + : DateTime.UtcNow - this.Timestamp >= TimeSpan.FromDays(1) + ? this.Timestamp.ToLocalTime().ToString("dd/MM") + : this.Timestamp.ToLocalTime().ToString("t"); + + public TargetingPlayer(Player player, bool current, DateTime timestamp) { + this.Player = player; + this.Current = current; + this.Timestamp = timestamp; + } } } diff --git a/XIVChat Desktop/Targeting.xaml b/XIVChat Desktop/Targeting.xaml new file mode 100644 index 0000000..5abf075 --- /dev/null +++ b/XIVChat Desktop/Targeting.xaml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/XIVChat Desktop/Targeting.xaml.cs b/XIVChat Desktop/Targeting.xaml.cs new file mode 100644 index 0000000..a0e7c44 --- /dev/null +++ b/XIVChat Desktop/Targeting.xaml.cs @@ -0,0 +1,14 @@ +using System.Windows; + +namespace XIVChat_Desktop { + public partial class Targeting { + public App App => (App) Application.Current; + + public Targeting(Window owner) { + this.Owner = owner; + this.DataContext = this; + + this.InitializeComponent(); + } + } +}