feat(desktop): add very basic friend list
This commit is contained in:
parent
c169c8099f
commit
bc0b8d73d7
|
@ -17,6 +17,7 @@
|
|||
<local:BoolToVisibility x:Key="InverseBoolToVisibilityConverter"
|
||||
TrueValue="Collapsed"
|
||||
FalseValue="Visible" />
|
||||
<local:TitleCaseConverter x:Key="TitleCaseConverter" />
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ui:ThemeResources AccentColor="#02ccee" />
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace XIVChat_Desktop {
|
|||
private TcpClient? client;
|
||||
|
||||
private readonly Channel<string> outgoing = Channel.CreateUnbounded<string>();
|
||||
private readonly Channel<byte[]> outgoingMessages = Channel.CreateUnbounded<byte[]>();
|
||||
private readonly Channel<byte[]> incoming = Channel.CreateUnbounded<byte[]>();
|
||||
private readonly Channel<byte> cancelChannel = Channel.CreateBounded<byte>(2);
|
||||
|
||||
|
@ -49,6 +50,13 @@ namespace XIVChat_Desktop {
|
|||
this.outgoing.Writer.TryWrite(message);
|
||||
}
|
||||
|
||||
public void RequestFriendList() {
|
||||
var msg = new ClientPlayerList {
|
||||
Type = PlayerListType.Friend,
|
||||
};
|
||||
this.outgoingMessages.Writer.TryWrite(msg.Encode());
|
||||
}
|
||||
|
||||
public void Disconnect() {
|
||||
this.cancel.Cancel();
|
||||
for (var i = 0; i < 2; i++) {
|
||||
|
@ -156,11 +164,12 @@ namespace XIVChat_Desktop {
|
|||
|
||||
var incoming = this.incoming.Reader.ReadAsync().AsTask();
|
||||
var outgoing = this.outgoing.Reader.ReadAsync().AsTask();
|
||||
var outgoingMessage = this.outgoingMessages.Reader.ReadAsync().AsTask();
|
||||
var cancel = this.cancelChannel.Reader.ReadAsync().AsTask();
|
||||
|
||||
// listen for incoming and outgoing messages and cancel requests
|
||||
while (!this.cancel.IsCancellationRequested) {
|
||||
var result = await Task.WhenAny(incoming, outgoing, cancel);
|
||||
var result = await Task.WhenAny(incoming, outgoing, outgoingMessage, cancel);
|
||||
if (result == incoming) {
|
||||
if (this.incoming.Reader.Completion.IsCompleted) {
|
||||
break;
|
||||
|
@ -186,6 +195,21 @@ namespace XIVChat_Desktop {
|
|||
});
|
||||
break;
|
||||
}
|
||||
} else if (result == outgoingMessage) {
|
||||
var toSend = await outgoingMessage;
|
||||
outgoingMessage = this.outgoingMessages.Reader.ReadAsync().AsTask();
|
||||
|
||||
try {
|
||||
await SecretMessage.SendSecretMessage(stream, handshake.Keys.tx, toSend, this.cancel.Token);
|
||||
} catch (Exception ex) {
|
||||
this.app.Dispatch(() => {
|
||||
this.app.Window.AddSystemMessage("Error sending message.");
|
||||
// ReSharper disable once LocalizableElement
|
||||
Console.WriteLine($"Error sending message: {ex.Message}");
|
||||
Console.WriteLine(ex.StackTrace);
|
||||
});
|
||||
break;
|
||||
}
|
||||
} else if (result == cancel) {
|
||||
try {
|
||||
// NOTE: purposely not including cancellation token because it will already be cancelled here
|
||||
|
@ -276,6 +300,17 @@ namespace XIVChat_Desktop {
|
|||
|
||||
break;
|
||||
case ServerOperation.PlayerList:
|
||||
var playerList = ServerPlayerList.Decode(payload);
|
||||
|
||||
if (playerList.Type == PlayerListType.Friend) {
|
||||
this.app.Dispatch(() => {
|
||||
this.app.Window.FriendList.Clear();
|
||||
foreach (var player in playerList.Players) {
|
||||
this.app.Window.FriendList.Add(player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
case ServerOperation.LinkshellList:
|
||||
break;
|
||||
|
|
|
@ -4,7 +4,6 @@ using System.Globalization;
|
|||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using XIVChatCommon;
|
||||
|
||||
namespace XIVChat_Desktop {
|
||||
|
@ -75,6 +74,30 @@ namespace XIVChat_Desktop {
|
|||
}
|
||||
}
|
||||
|
||||
public class TitleCaseConverter : IValueConverter {
|
||||
public object? Convert(object? value, Type targetType, object parameter, CultureInfo culture) {
|
||||
var s = value?.ToString();
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var lastWasSpace = true;
|
||||
var newString = new StringBuilder();
|
||||
|
||||
foreach (var c in s.ToCharArray()) {
|
||||
newString.Append(lastWasSpace ? char.ToUpperInvariant(c) : c);
|
||||
|
||||
lastWasSpace = c.IsWhitespace();
|
||||
}
|
||||
|
||||
return newString.ToString();
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public class NotConverter : IValueConverter {
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
|
||||
return !((bool)value);
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
<Window x:Class="XIVChat_Desktop.FriendList"
|
||||
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"
|
||||
mc:Ignorable="d"
|
||||
Title="Friend list"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Height="400"
|
||||
Width="700"
|
||||
Closed="FriendList_OnClosed"
|
||||
d:DataContext="{d:DesignInstance local:FriendList}">
|
||||
<Grid Margin="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ProgressBar Grid.Row="0"
|
||||
IsIndeterminate="True"
|
||||
Visibility="{Binding Waiting, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<DataGrid Grid.Row="0"
|
||||
ItemsSource="{Binding App.Window.FriendList}"
|
||||
AutoGenerateColumns="False"
|
||||
SelectionUnit="FullRow"
|
||||
SelectionMode="Single"
|
||||
IsReadOnly="True"
|
||||
CanUserReorderColumns="True"
|
||||
Visibility="{Binding Waiting, Converter={StaticResource InverseBoolToVisibilityConverter}}">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Name"
|
||||
Binding="{Binding Name}" />
|
||||
<DataGridTextColumn Header="Job"
|
||||
Binding="{Binding JobName, Converter={StaticResource TitleCaseConverter}}" />
|
||||
<DataGridTextColumn Header="Location"
|
||||
Binding="{Binding TerritoryName}" />
|
||||
<DataGridTextColumn Header="FC"
|
||||
Binding="{Binding FreeCompany}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
<!-- <ListView Grid.Row="0" -->
|
||||
<!-- ItemsSource="{Binding App.Window.FriendList}" -->
|
||||
<!-- Visibility="{Binding Waiting, Converter={StaticResource InverseBoolToVisibilityConverter}}"> -->
|
||||
<!-- <ListView.View> -->
|
||||
<!-- <GridView> -->
|
||||
<!-- <GridViewColumn Header="Name" -->
|
||||
<!-- DisplayMemberBinding="{Binding Name}" /> -->
|
||||
<!-- <GridViewColumn Header="Job" -->
|
||||
<!-- DisplayMemberBinding="{Binding JobName}" /> -->
|
||||
<!-- <GridViewColumn Header="Location" -->
|
||||
<!-- DisplayMemberBinding="{Binding TerritoryName}" /> -->
|
||||
<!-- <GridViewColumn Header="FC" -->
|
||||
<!-- DisplayMemberBinding="{Binding FreeCompany}" /> -->
|
||||
<!-- </GridView> -->
|
||||
<!-- </ListView.View> -->
|
||||
<!-- </ListView> -->
|
||||
<Button Grid.Row="1"
|
||||
IsEnabled="{Binding App.Connected}"
|
||||
Content="Refresh"
|
||||
Margin="0,8,0,0"
|
||||
Click="Refresh_Click" />
|
||||
</Grid>
|
||||
</Window>
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
|
||||
namespace XIVChat_Desktop {
|
||||
public partial class FriendList : INotifyPropertyChanged {
|
||||
public App App => (App)Application.Current;
|
||||
|
||||
private bool waiting;
|
||||
|
||||
public bool Waiting {
|
||||
get => this.waiting;
|
||||
set {
|
||||
this.waiting = value;
|
||||
this.OnPropertyChanged(nameof(this.Waiting));
|
||||
}
|
||||
}
|
||||
|
||||
public FriendList(Window owner) {
|
||||
this.Owner = owner;
|
||||
|
||||
this.InitializeComponent();
|
||||
this.DataContext = this;
|
||||
|
||||
this.App.Window.FriendList.CollectionChanged += this.OnFriendListChanged;
|
||||
}
|
||||
|
||||
private void Refresh_Click(object sender, RoutedEventArgs e) {
|
||||
var conn = this.App.Connection;
|
||||
if (conn == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.Waiting = true;
|
||||
conn.RequestFriendList();
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
private void OnPropertyChanged([CallerMemberName] string? propertyName = null) {
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
private void OnFriendListChanged(object sender, NotifyCollectionChangedEventArgs e) {
|
||||
this.Waiting = false;
|
||||
}
|
||||
|
||||
private void FriendList_OnClosed(object? sender, EventArgs e) {
|
||||
this.App.Window.FriendList.CollectionChanged -= this.OnFriendListChanged;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -52,6 +52,11 @@
|
|||
<MenuItem Header="Manage"
|
||||
Click="ManageTabs_Click" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="Players"
|
||||
WindowChrome.IsHitTestVisibleInChrome="{Binding App.Config.CompactMode}">
|
||||
<MenuItem Header="Friend list"
|
||||
Click="FriendList_Click" />
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<TabControl x:Name="Tabs"
|
||||
Margin="8,0,8,8"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
@ -17,6 +18,7 @@ namespace XIVChat_Desktop {
|
|||
public App App => (App)Application.Current;
|
||||
|
||||
public List<ServerMessage> Messages { get; } = new List<ServerMessage>();
|
||||
public ObservableCollection<Player> FriendList { get; } = new ObservableCollection<Player>();
|
||||
|
||||
public string InputPlaceholder => this.App.Connection?.Available == true ? "Send a message..." : "Chat is currently unavailable";
|
||||
|
||||
|
@ -79,7 +81,7 @@ namespace XIVChat_Desktop {
|
|||
this.insertAt = this.Messages.Count;
|
||||
}
|
||||
|
||||
// detect if scroller is at the bottom
|
||||
// detect iFriendList_Click the bottom
|
||||
var scroller = this.FindElementByName<ScrollViewer>(this.Tabs, "scroller");
|
||||
var wasAtBottom = Math.Abs(scroller!.VerticalOffset - scroller.ScrollableHeight) < .0001;
|
||||
|
||||
|
@ -194,5 +196,9 @@ namespace XIVChat_Desktop {
|
|||
this.Close();
|
||||
this.App.Shutdown();
|
||||
}
|
||||
|
||||
private void FriendList_Click(object sender, RoutedEventArgs e) {
|
||||
new FriendList(this).Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue