1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-19 01:03:02 +08:00
osu-lazer/osu.Game/Online/Chat/Channel.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

212 lines
6.7 KiB
C#
Raw Normal View History

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2018-04-13 17:19:50 +08:00
2022-06-17 15:37:17 +08:00
#nullable disable
using System;
2016-08-31 18:49:34 +08:00
using System.Collections.Generic;
using System.Collections.ObjectModel;
2017-04-19 17:46:26 +08:00
using System.Linq;
2016-08-31 18:49:34 +08:00
using Newtonsoft.Json;
2019-02-21 18:04:31 +08:00
using osu.Framework.Bindables;
2017-04-19 17:46:26 +08:00
using osu.Framework.Lists;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Chat;
2018-04-13 17:19:50 +08:00
2016-08-31 18:49:34 +08:00
namespace osu.Game.Online.Chat
{
public class Channel
{
public const int MAX_HISTORY = 300;
/// <summary>
/// Contains every joined user except the current logged in user. Currently only returned for PM channels.
/// </summary>
public readonly ObservableCollection<APIUser> Users = new ObservableCollection<APIUser>();
[JsonProperty(@"users")]
private int[] userIds
{
set
{
foreach (int id in value)
Users.Add(new APIUser { Id = id });
}
}
/// <summary>
/// Contains all the messages send in the channel.
/// </summary>
public readonly SortedList<Message> Messages = new SortedList<Message>(Comparer<Message>.Default);
2020-01-03 00:07:28 +08:00
/// <summary>
/// Contains all the messages that weren't read by the user.
/// </summary>
public IEnumerable<Message> UnreadMessages => Messages.Where(m => LastReadId < m.Id);
/// <summary>
/// Contains all the messages that are still pending for submission to the server.
/// </summary>
private readonly List<LocalEchoMessage> pendingMessages = new List<LocalEchoMessage>();
/// <summary>
/// An event that fires when new messages arrived.
/// </summary>
public event Action<IEnumerable<Message>> NewMessagesArrived;
/// <summary>
/// An event that fires when a pending message gets resolved.
/// </summary>
public event Action<LocalEchoMessage, Message> PendingMessageResolved;
/// <summary>
/// An event that fires when a pending message gets removed.
/// </summary>
public event Action<Message> MessageRemoved;
2020-05-05 09:31:11 +08:00
public bool ReadOnly => false; // todo: not yet used.
public override string ToString() => Name;
2016-08-31 18:49:34 +08:00
[JsonProperty(@"name")]
public string Name;
2018-04-13 17:19:50 +08:00
2016-08-31 18:49:34 +08:00
[JsonProperty(@"description")]
public string Topic;
2018-04-13 17:19:50 +08:00
2016-08-31 18:49:34 +08:00
[JsonProperty(@"type")]
public ChannelType Type;
2018-04-13 17:19:50 +08:00
2016-08-31 18:49:34 +08:00
[JsonProperty(@"channel_id")]
public long Id;
2018-04-13 17:19:50 +08:00
[JsonProperty(@"last_message_id")]
public long? LastMessageId;
2020-01-03 00:07:28 +08:00
[JsonProperty(@"last_read_id")]
public long? LastReadId;
/// <summary>
/// Signals if the current user joined this channel or not. Defaults to false.
/// Note that this does not guarantee a join has completed. Check Id > 0 for confirmation.
/// </summary>
2017-05-26 14:38:52 +08:00
public Bindable<bool> Joined = new Bindable<bool>();
2018-04-13 17:19:50 +08:00
/// <summary>
/// Signals if there is a message to highlight.
/// This is automatically cleared by the associated <see cref="DrawableChannel"/> after highlighting.
/// </summary>
public Bindable<Message> HighlightedMessage = new Bindable<Message>();
2016-08-31 18:49:34 +08:00
[JsonConstructor]
public Channel()
{
}
2018-04-13 17:19:50 +08:00
/// <summary>
/// Create a private messaging channel with the specified user.
/// </summary>
/// <param name="user">The user to create the private conversation with.</param>
public Channel(APIUser user)
{
Type = ChannelType.PM;
Users.Add(user);
Name = user.Username;
}
/// <summary>
/// Adds the argument message as a local echo. When this local echo is resolved <see cref="PendingMessageResolved"/> will get called.
/// </summary>
/// <param name="message"></param>
2017-08-21 16:43:26 +08:00
public void AddLocalEcho(LocalEchoMessage message)
{
pendingMessages.Add(message);
Messages.Add(message);
2018-04-13 17:19:50 +08:00
2017-08-21 16:43:26 +08:00
NewMessagesArrived?.Invoke(new[] { message });
}
2018-04-13 17:19:50 +08:00
public bool MessagesLoaded;
/// <summary>
/// Adds new messages to the channel and purges old messages. Triggers the <see cref="NewMessagesArrived"/> event.
/// </summary>
/// <param name="messages"></param>
public void AddNewMessages(params Message[] messages)
{
foreach (var m in messages)
{
LocalEchoMessage localEcho = pendingMessages.FirstOrDefault(local => local.Uuid == m.Uuid);
if (localEcho != null)
ReplaceMessage(localEcho, m);
}
messages = messages.Except(Messages).ToArray();
2018-04-13 17:19:50 +08:00
if (messages.Length == 0) return;
2017-08-21 17:51:14 +08:00
Messages.AddRange(messages);
long? maxMessageId = messages.Max(m => m.Id);
if (maxMessageId > LastMessageId)
LastMessageId = maxMessageId;
2018-04-13 17:19:50 +08:00
purgeOldMessages();
2018-04-13 17:19:50 +08:00
NewMessagesArrived?.Invoke(messages);
}
2018-04-13 17:19:50 +08:00
2022-11-02 16:00:47 +08:00
public void RemoveMessagesFromUser(int userId)
{
for (int i = 0; i < Messages.Count; i++)
{
var message = Messages[i];
if (message.SenderId == userId)
{
Messages.RemoveAt(i--);
MessageRemoved?.Invoke(message);
}
}
}
2017-08-21 16:43:26 +08:00
/// <summary>
/// Replace or remove a message from the channel.
/// </summary>
/// <param name="echo">The local echo message (client-side).</param>
/// <param name="final">The response message, or null if the message became invalid.</param>
public void ReplaceMessage(LocalEchoMessage echo, Message final)
{
if (!pendingMessages.Remove(echo))
2017-08-21 22:34:08 +08:00
throw new InvalidOperationException("Attempted to remove echo that wasn't present");
2018-04-13 17:19:50 +08:00
2017-08-21 16:43:26 +08:00
Messages.Remove(echo);
2018-04-13 17:19:50 +08:00
2017-08-21 16:43:26 +08:00
if (final == null)
{
MessageRemoved?.Invoke(echo);
return;
}
2018-04-13 17:19:50 +08:00
2017-08-21 16:43:26 +08:00
if (Messages.Contains(final))
throw new InvalidOperationException("Attempted to add the same message again");
2018-04-13 17:19:50 +08:00
2017-08-21 16:43:26 +08:00
Messages.Add(final);
2022-11-11 13:55:41 +08:00
if (final.Id > LastMessageId)
LastMessageId = final.Id;
2017-08-21 16:43:26 +08:00
PendingMessageResolved?.Invoke(echo, final);
}
2018-04-13 17:19:50 +08:00
private void purgeOldMessages()
{
// never purge local echos
int messageCount = Messages.Count - pendingMessages.Count;
if (messageCount > MAX_HISTORY)
Messages.RemoveRange(0, messageCount - MAX_HISTORY);
}
2016-08-31 18:49:34 +08:00
}
}