feat(desktop): add basic targeting window

This commit is contained in:
Anna 2021-07-04 21:12:36 -04:00
parent 98e7889844
commit 2807f695ae
6 changed files with 156 additions and 18 deletions

View File

@ -217,9 +217,8 @@ namespace XIVChat_Desktop {
// tell the server our preferences
var preferences = new ClientPreferences {
Preferences = new Dictionary<ClientPreference, object> {
{
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;

View File

@ -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<T>.Default.Equals(val, this.TrueValue);
}
}

View File

@ -63,6 +63,8 @@
WindowChrome.IsHitTestVisibleInChrome="{Binding App.Config.CompactMode}">
<MenuItem Header="Friend list"
Click="FriendList_Click" />
<MenuItem Header="Targeting"
Click="Targeting_Click" />
</MenuItem>
</Menu>
<TabControl x:Name="Tabs"

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using System.Text;
@ -163,6 +164,7 @@ namespace XIVChat_Desktop {
public List<ServerMessage> Messages { get; } = new();
public ObservableCollection<Player> FriendList { get; } = new();
public List<TargetingPlayer> Targeting { get; set; } = new();
private bool ShowMessageForNoUpdate { get; set; }
@ -349,6 +351,31 @@ namespace XIVChat_Desktop {
}
}
internal void UpdateTargeting(IEnumerable<Player> 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;
}
}
}

View File

@ -0,0 +1,66 @@
<local:XivChatWindow x:Class="XIVChat_Desktop.Targeting"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:XIVChat_Desktop"
xmlns:ui="http://schemas.modernwpf.com/2019"
ui:WindowHelper.UseModernWindowStyle="True"
WindowStartupLocation="CenterOwner"
mc:Ignorable="d"
Title="Targeting"
Height="225"
Width="250"
WindowStyle="ToolWindow"
d:DataContext="{d:DesignInstance local:Targeting}">
<Grid Margin="8">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DataGrid Grid.Row="0"
ItemsSource="{Binding App.Window.Targeting, UpdateSourceTrigger=PropertyChanged}"
AutoGenerateColumns="False"
RowHeaderWidth="0"
IsReadOnly="True"
SelectionUnit="FullRow"
SelectionMode="Single"
CanUserReorderColumns="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Name"
Binding="{Binding Player.Name}"
d:DataContext="{d:DesignInstance local:TargetingPlayer}">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}"
BasedOn="{StaticResource DefaultDataGridCellStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding Current}"
Value="False">
<Setter Property="Opacity"
Value="0.75" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Timestamp"
Binding="{Binding UiTimestamp}"
d:DataContext="{d:DesignInstance local:TargetingPlayer}">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}"
BasedOn="{StaticResource DefaultDataGridCellStyle}">
<Style.Triggers>
<DataTrigger Binding="{Binding Current}"
Value="False">
<Setter Property="Opacity"
Value="0.75" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</local:XivChatWindow>

View File

@ -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();
}
}
}