feat(desktop): add basic targeting window
This commit is contained in:
parent
98e7889844
commit
2807f695ae
|
@ -217,9 +217,8 @@ namespace XIVChat_Desktop {
|
||||||
// tell the server our preferences
|
// tell the server our preferences
|
||||||
var preferences = new ClientPreferences {
|
var preferences = new ClientPreferences {
|
||||||
Preferences = new Dictionary<ClientPreference, object> {
|
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);
|
await SecretMessage.SendSecretMessage(stream, handshake.Keys.tx, preferences, this.cancel.Token);
|
||||||
|
@ -418,16 +417,24 @@ namespace XIVChat_Desktop {
|
||||||
case ServerOperation.PlayerList:
|
case ServerOperation.PlayerList:
|
||||||
var playerList = ServerPlayerList.Decode(payload);
|
var playerList = ServerPlayerList.Decode(payload);
|
||||||
|
|
||||||
if (playerList.Type == PlayerListType.Friend) {
|
switch (playerList.Type) {
|
||||||
var players = playerList.Players
|
case PlayerListType.Friend: {
|
||||||
.OrderBy(player => !player.HasStatus(PlayerStatus.Online));
|
var players = playerList.Players
|
||||||
|
.OrderBy(player => !player.HasStatus(PlayerStatus.Online));
|
||||||
|
|
||||||
this.app.Dispatch(() => {
|
this.app.Dispatch(() => {
|
||||||
this.app.Window.FriendList.Clear();
|
this.app.Window.FriendList.Clear();
|
||||||
foreach (var player in players) {
|
foreach (var player in players) {
|
||||||
this.app.Window.FriendList.Add(player);
|
this.app.Window.FriendList.Add(player);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PlayerListType.Targeting:
|
||||||
|
this.app.Dispatch(() => {
|
||||||
|
this.app.Window.UpdateTargeting(playerList.Players);
|
||||||
|
});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -51,7 +51,7 @@ namespace XIVChat_Desktop {
|
||||||
|
|
||||||
public class SenderPlayerConverter : IValueConverter {
|
public class SenderPlayerConverter : IValueConverter {
|
||||||
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ namespace XIVChat_Desktop {
|
||||||
if (worldName != null) {
|
if (worldName != null) {
|
||||||
s.Append(" (");
|
s.Append(" (");
|
||||||
s.Append(worldName);
|
s.Append(worldName);
|
||||||
s.Append(")");
|
s.Append(')');
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.ToString();
|
return s.ToString();
|
||||||
|
@ -100,11 +100,11 @@ namespace XIVChat_Desktop {
|
||||||
|
|
||||||
public class NotConverter : IValueConverter {
|
public class NotConverter : IValueConverter {
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
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) {
|
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 T FalseValue { get; set; } = default!;
|
||||||
|
|
||||||
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
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) {
|
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);
|
return EqualityComparer<T>.Default.Equals(val, this.TrueValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,8 @@
|
||||||
WindowChrome.IsHitTestVisibleInChrome="{Binding App.Config.CompactMode}">
|
WindowChrome.IsHitTestVisibleInChrome="{Binding App.Config.CompactMode}">
|
||||||
<MenuItem Header="Friend list"
|
<MenuItem Header="Friend list"
|
||||||
Click="FriendList_Click" />
|
Click="FriendList_Click" />
|
||||||
|
<MenuItem Header="Targeting"
|
||||||
|
Click="Targeting_Click" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</Menu>
|
</Menu>
|
||||||
<TabControl x:Name="Tabs"
|
<TabControl x:Name="Tabs"
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -163,6 +164,7 @@ namespace XIVChat_Desktop {
|
||||||
|
|
||||||
public List<ServerMessage> Messages { get; } = new();
|
public List<ServerMessage> Messages { get; } = new();
|
||||||
public ObservableCollection<Player> FriendList { get; } = new();
|
public ObservableCollection<Player> FriendList { get; } = new();
|
||||||
|
public List<TargetingPlayer> Targeting { get; set; } = new();
|
||||||
|
|
||||||
private bool ShowMessageForNoUpdate { get; set; }
|
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) {
|
private void Connect_Click(object sender, RoutedEventArgs e) {
|
||||||
new ConnectDialog(this).ShowDialog();
|
new ConnectDialog(this).ShowDialog();
|
||||||
}
|
}
|
||||||
|
@ -518,5 +545,27 @@ namespace XIVChat_Desktop {
|
||||||
private void TabGrid_OnInitialized(object? sender, EventArgs e) {
|
private void TabGrid_OnInitialized(object? sender, EventArgs e) {
|
||||||
this.CalculateCompactMargins();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
66
XIVChat Desktop/Targeting.xaml
Normal file
66
XIVChat Desktop/Targeting.xaml
Normal 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>
|
14
XIVChat Desktop/Targeting.xaml.cs
Normal file
14
XIVChat Desktop/Targeting.xaml.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user