1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-20 05:03:20 +08:00

Rename everything into channel and remove everything chat

This commit is contained in:
miterosan 2018-04-11 20:01:57 +02:00
parent 39ecc3d31d
commit 3860594f40
20 changed files with 232 additions and 310 deletions

View File

@ -55,9 +55,9 @@ namespace osu.Game.Tests.Visual
{
linkColour = colours.Blue;
var chatManager = new ChatManager(Scheduler);
chatManager.AvailableChannels.Add(new ChannelChat { Name = "#english"});
chatManager.AvailableChannels.Add(new ChannelChat { Name = "#japanese" });
var chatManager = new ChannelManager(Scheduler);
chatManager.AvailableChannels.Add(new Channel { Name = "#english"});
chatManager.AvailableChannels.Add(new Channel { Name = "#japanese" });
dependencies.Cache(chatManager);
dependencies.Cache(new ChatOverlay());

View File

@ -78,7 +78,7 @@ namespace osu.Game.Tests.Visual
private void addUser(long id, string name)
{
chatTabControl.AddItem(new UserChat(new User
chatTabControl.AddItem(new Channel(new User
{
Id = id,
Username = name
@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual
private void addChannel(string name)
{
this.chatTabControl.AddItem(new ChannelChat
this.chatTabControl.AddItem(new Channel
{
Name = name
});

View File

@ -23,11 +23,11 @@ namespace osu.Game.Graphics.Containers
public override bool HandleMouseInput => true;
private OsuGame game;
private ChatManager chatManager;
private ChannelManager chatManager;
private Action showNotImplementedError;
[BackgroundDependencyLoader(true)]
private void load(OsuGame game, NotificationOverlay notifications, ChatManager chatManager)
private void load(OsuGame game, NotificationOverlay notifications, ChannelManager chatManager)
{
// will be null in tests
this.game = game;
@ -82,7 +82,7 @@ namespace osu.Game.Graphics.Containers
case LinkAction.OpenChannel:
var channel = chatManager.AvailableChannels.FirstOrDefault(c => c.Name == linkArgument);
if (channel != null)
chatManager.CurrentChat.Value = channel;
chatManager.CurrentChannel.Value = channel;
break;
case LinkAction.OpenEditorTimestamp:
case LinkAction.JoinMultiplayerMatch:

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.IO.Network;
@ -10,11 +11,16 @@ namespace osu.Game.Online.API.Requests
{
public class GetChannelMessagesRequest : APIRequest<List<Message>>
{
private readonly IEnumerable<ChannelChat> channels;
private readonly IEnumerable<Channel> channels;
private long? since;
public GetChannelMessagesRequest(IEnumerable<ChannelChat> channels, long? sinceId)
public GetChannelMessagesRequest(IEnumerable<Channel> channels, long? sinceId)
{
if (channels == null)
throw new ArgumentNullException(nameof(channels));
if (channels.Any(c => c.Target != TargetType.Channel))
throw new ArgumentException("All channels in the argument channels must have the targettype Channel");
this.channels = channels;
since = sinceId;
}

View File

@ -6,7 +6,7 @@ using osu.Game.Online.Chat;
namespace osu.Game.Online.API.Requests
{
public class ListChannelsRequest : APIRequest<List<ChannelChat>>
public class ListChannelsRequest : APIRequest<List<Channel>>
{
protected override string Target => @"chat/channels";
}

View File

@ -1,22 +1,55 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Newtonsoft.Json;
using osu.Framework.Configuration;
using osu.Framework.Lists;
using osu.Game.Users;
namespace osu.Game.Online.Chat
{
public abstract class ChatBase
public class Channel
{
public const int MAX_HISTORY = 300;
public bool ReadOnly { get; } = false;
public abstract TargetType Target { get; }
public abstract long ChatID { get; }
public Bindable<bool> Joined = new Bindable<bool>();
[JsonProperty(@"name")]
public string Name;
[JsonProperty(@"description")]
public string Topic;
[JsonProperty(@"type")]
public string Type;
[JsonProperty(@"channel_id")]
public long Id;
[JsonConstructor]
public Channel()
{
}
/// <summary>
/// Contructs a privatechannel
/// TODO this class needs to be serialized from something like channels/private, instead of creating from a contructor
/// </summary>
/// <param name="user">The user </param>
public Channel(User user)
{
Target = TargetType.User;
Name = user.Username;
Id = user.Id;
JoinedUsers.Add(user);
}
/// <summary>
/// Contains every joined user except yourself
/// </summary>
public ObservableCollection<User> JoinedUsers = new ObservableCollection<User>();
public readonly SortedList<Message> Messages = new SortedList<Message>(Comparer<Message>.Default);
private readonly List<LocalEchoMessage> pendingMessages = new List<LocalEchoMessage>();
@ -24,6 +57,10 @@ namespace osu.Game.Online.Chat
public event Action<LocalEchoMessage, Message> PendingMessageResolved;
public event Action<Message> MessageRemoved;
public Bindable<bool> Joined = new Bindable<bool>();
public TargetType Target { get; set; }
public bool ReadOnly { get; set; }
public void AddLocalEcho(LocalEchoMessage message)
{
pendingMessages.Add(message);
@ -43,16 +80,8 @@ namespace osu.Game.Online.Chat
NewMessagesArrived?.Invoke(messages);
}
private void purgeOldMessages()
{
// never purge local echos
int messageCount = Messages.Count - pendingMessages.Count;
if (messageCount > MAX_HISTORY)
Messages.RemoveRange(0, messageCount - MAX_HISTORY);
}
/// <summary>
/// Replace or remove a message from the chat.
/// 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>
@ -81,5 +110,14 @@ namespace osu.Game.Online.Chat
PendingMessageResolved?.Invoke(echo, final);
}
private void purgeOldMessages()
{
// never purge local echos
int messageCount = Messages.Count - pendingMessages.Count;
if (messageCount > MAX_HISTORY)
Messages.RemoveRange(0, messageCount - MAX_HISTORY);
}
public override string ToString() => Name;
}
}

View File

@ -1,31 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Newtonsoft.Json;
namespace osu.Game.Online.Chat
{
public class ChannelChat : ChatBase
{
[JsonProperty(@"name")]
public string Name;
[JsonProperty(@"description")]
public string Topic;
[JsonProperty(@"type")]
public string Type;
[JsonProperty(@"channel_id")]
public int Id;
[JsonConstructor]
public ChannelChat()
{
}
public override string ToString() => Name;
public override long ChatID => Id;
public override TargetType Target => TargetType.Channel;
}
}

View File

@ -17,9 +17,9 @@ using osu.Game.Users;
namespace osu.Game.Online.Chat
{
/// <summary>
/// Manages everything chat related
/// Manages everything channel related
/// </summary>
public class ChatManager : Component, IOnlineComponent
public class ChannelManager : Component, IOnlineComponent
{
/// <summary>
/// The channels the player joins on startup
@ -30,21 +30,17 @@ namespace osu.Game.Online.Chat
};
/// <summary>
/// The currently opened chat
/// The currently opened channel
/// </summary>
public Bindable<ChatBase> CurrentChat { get; } = new Bindable<ChatBase>();
public Bindable<Channel> CurrentChannel { get; } = new Bindable<Channel>();
/// <summary>
/// The Channels the player has joined
/// </summary>
public ObservableCollection<ChannelChat> JoinedChannels { get; } = new ObservableCollection<ChannelChat>();
public ObservableCollection<Channel> JoinedChannels { get; } = new ObservableCollection<Channel>();
/// <summary>
/// The channels available for the player to join
/// </summary>
public ObservableCollection<ChannelChat> AvailableChannels { get; } = new ObservableCollection<ChannelChat>();
/// <summary>
/// The user chats opened.
/// </summary>
public ObservableCollection<UserChat> OpenedUserChats { get; } = new ObservableCollection<UserChat>();
public ObservableCollection<Channel> AvailableChannels { get; } = new ObservableCollection<Channel>();
private APIAccess api;
private readonly Scheduler scheduler;
@ -54,68 +50,49 @@ namespace osu.Game.Online.Chat
private long? lastChannelMsgId;
private long? lastUserMsgId;
public void OpenChannelChat(string name)
public void OpenChannel(string name)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
CurrentChat.Value = AvailableChannels.FirstOrDefault(c => c.Name == name)
CurrentChannel.Value = AvailableChannels.FirstOrDefault(c => c.Name == name)
?? throw new ArgumentException($"Channel {name} was not found.");
}
public void OpenUserChat(long userId)
{
var chat = OpenedUserChats.FirstOrDefault(c => c.ChatID == userId);
if (chat == null)
{
chat = new UserChat(new User
{
Id = userId
});
chat.RequestDetails(api);
}
CurrentChat.Value = chat;
}
public void OpenUserChat(User user)
public void OpenUserChannel(User user)
{
if (user == null)
throw new ArgumentNullException(nameof(user));
CurrentChat.Value = OpenedUserChats.FirstOrDefault(c => c.ChatID == user.Id)
?? new UserChat(user);
CurrentChannel.Value = JoinedChannels.FirstOrDefault(c => c.Target == TargetType.User && c.Id == user.Id)
?? new Channel(user);
}
public ChatManager(Scheduler scheduler)
public ChannelManager(Scheduler scheduler)
{
this.scheduler = scheduler ?? throw new ArgumentNullException(nameof(scheduler));
CurrentChat.ValueChanged += currentChatChanged;
CurrentChannel.ValueChanged += currentChannelChanged;
}
private void currentChatChanged(ChatBase chatBase)
private void currentChannelChanged(Channel channel)
{
if (chatBase is ChannelChat channel && !JoinedChannels.Contains(channel))
if (!JoinedChannels.Contains(channel))
JoinedChannels.Add(channel);
if (chatBase is UserChat userChat && !OpenedUserChats.Contains(userChat))
OpenedUserChats.Add(userChat);
}
/// <summary>
/// Posts a message to the currently opened chat.
/// Posts a message to the currently opened channel.
/// </summary>
/// <param name="text">The message text that is going to be posted</param>
/// <param name="isAction">Is true if the message is an action, e.g.: user is currently eating </param>
public void PostMessage(string text, bool isAction = false)
{
if (CurrentChat.Value == null)
if (CurrentChannel.Value == null)
return;
if (!api.IsLoggedIn)
{
CurrentChat.Value.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!"));
CurrentChannel.Value.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!"));
return;
}
@ -123,23 +100,23 @@ namespace osu.Game.Online.Chat
{
Sender = api.LocalUser.Value,
Timestamp = DateTimeOffset.Now,
TargetType = CurrentChat.Value.Target,
TargetId = CurrentChat.Value.ChatID,
TargetType = CurrentChannel.Value.Target,
TargetId = CurrentChannel.Value.Id,
IsAction = isAction,
Content = text
};
CurrentChat.Value.AddLocalEcho(message);
CurrentChannel.Value.AddLocalEcho(message);
var req = new PostMessageRequest(message);
req.Failure += e => CurrentChat.Value?.ReplaceMessage(message, null);
req.Success += m => CurrentChat.Value?.ReplaceMessage(message, m);
req.Failure += e => CurrentChannel.Value?.ReplaceMessage(message, null);
req.Success += m => CurrentChannel.Value?.ReplaceMessage(message, m);
api.Queue(req);
}
public void PostCommand(string text)
{
if (CurrentChat.Value == null)
if (CurrentChannel.Value == null)
return;
var parameters = text.Split(new[] { ' ' }, 2);
@ -151,18 +128,18 @@ namespace osu.Game.Online.Chat
case "me":
if (string.IsNullOrWhiteSpace(content))
{
CurrentChat.Value.AddNewMessages(new ErrorMessage("Usage: /me [action]"));
CurrentChannel.Value.AddNewMessages(new ErrorMessage("Usage: /me [action]"));
break;
}
PostMessage(content, true);
break;
case "help":
CurrentChat.Value.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action]"));
CurrentChannel.Value.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action]"));
break;
default:
CurrentChat.Value.AddNewMessages(new ErrorMessage($@"""/{command}"" is not supported! For a list of supported commands see /help"));
CurrentChannel.Value.AddNewMessages(new ErrorMessage($@"""/{command}"" is not supported! For a list of supported commands see /help"));
break;
}
}
@ -193,6 +170,8 @@ namespace osu.Game.Online.Chat
private void handleUserMessages(IEnumerable<Message> messages)
{
var joinedUserChannels = JoinedChannels.Where(c => c.Target == TargetType.User).ToList();
var outgoingMessages = messages.Where(m => m.Sender.Id == api.LocalUser.Value.Id);
var outgoingMessagesGroups = outgoingMessages.GroupBy(m => m.TargetId);
var incomingMessagesGroups = messages.Except(outgoingMessages).GroupBy(m => m.UserId);
@ -200,35 +179,43 @@ namespace osu.Game.Online.Chat
foreach (var messageGroup in incomingMessagesGroups)
{
var targetUser = messageGroup.First().Sender;
var chat = OpenedUserChats.FirstOrDefault(c => c.User.Id == targetUser.Id);
var channel = joinedUserChannels.FirstOrDefault(c => c.Id == targetUser.Id);
if (chat == null)
if (channel == null)
{
chat = new UserChat(targetUser);
OpenedUserChats.Add(chat);
channel = new Channel(targetUser);
JoinedChannels.Add(channel);
joinedUserChannels.Add(channel);
}
chat.AddNewMessages(messageGroup.ToArray());
channel.AddNewMessages(messageGroup.ToArray());
var outgoingTargetMessages = outgoingMessagesGroups.FirstOrDefault(g => g.Key == targetUser.Id);
if (outgoingTargetMessages != null)
chat.AddNewMessages(outgoingTargetMessages.ToArray());
channel.AddNewMessages(outgoingTargetMessages.ToArray());
}
var withoutReplyGroups = outgoingMessagesGroups.Where(g => OpenedUserChats.All(m => m.ChatID != g.Key));
var withoutReplyGroups = outgoingMessagesGroups.Where(g => joinedUserChannels.All(m => m.Id != g.Key));
foreach (var withoutReplyGroup in withoutReplyGroups)
{
var chat = new UserChat(new User { Id = withoutReplyGroup.First().TargetId });
var userReq = new GetUserRequest(withoutReplyGroup.First().TargetId);
chat.AddNewMessages(withoutReplyGroup.ToArray());
OpenedUserChats.Add(chat);
chat.RequestDetails(api);
userReq.Failure += exception => Logger.Error(exception, "Failed to get user informations.");
userReq.Success += user =>
{
var channel = new Channel(user);
channel.AddNewMessages(withoutReplyGroup.ToArray());
JoinedChannels.Add(channel);
};
api.Queue(userReq);
}
}
private void fetchNewChannelMessages()
{
fetchChannelMsgReq = new GetChannelMessagesRequest(JoinedChannels, lastChannelMsgId);
fetchChannelMsgReq = new GetChannelMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId);
fetchChannelMsgReq.Success += messages =>
{
@ -257,22 +244,24 @@ namespace osu.Game.Online.Chat
req.Success += channels =>
{
channels.Where(channel => AvailableChannels.All(c => c.ChatID != channel.ChatID))
channels.Where(channel => AvailableChannels.All(c => c.Id != channel.Id))
.ForEach(channel => AvailableChannels.Add(channel));
channels.Where(channel => defaultChannels.Contains(channel.Name))
.Where(channel => JoinedChannels.All(c => c.ChatID != channel.ChatID))
.Where(channel => JoinedChannels.All(c => c.Id != channel.Id))
.ForEach(channel =>
{
JoinedChannels.Add(channel);
var fetchInitialMsgReq = new GetChannelMessagesRequest(new[] {channel}, null);
fetchInitialMsgReq.Success += handleChannelMessages;
fetchInitialMsgReq.Failure += exception => Logger.Error(exception, "Failed to fetch inital messages.");
api.Queue(fetchInitialMsgReq);
});
fetchNewMessages();
};
req.Failure += error => Logger.Error(error, "Fetching channels failed");
req.Failure += error => Logger.Error(error, "Fetching channel list failed");
api.Queue(req);
}

View File

@ -1,44 +0,0 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Logging;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Users;
namespace osu.Game.Online.Chat
{
public class UserChat : ChatBase
{
public User User { get; private set; }
public override TargetType Target => TargetType.User;
public override long ChatID => User.Id;
public Action<User> DetailsArrived;
public UserChat(User user, Message[] messages = null)
{
User = user ?? throw new ArgumentNullException(nameof(user));
if (messages != null) AddNewMessages(messages);
}
public void RequestDetails(IAPIProvider api)
{
if (api == null)
throw new ArgumentNullException(nameof(api));
var req = new GetUserRequest(User.Id);
req.Success += user =>
{
User = user;
DetailsArrived?.Invoke(user);
};
req.Failure += exception => Logger.Error(exception, $"Requesting details for user with Id:{User.Id} failed.");
api.Queue(req);
}
public override string ToString() => User.Username ?? User.Id.ToString();
}
}

View File

@ -113,7 +113,7 @@ namespace osu.Game
dependencies.Cache(api);
dependencies.CacheAs<IAPIProvider>(api);
var chatManager = new ChatManager(Scheduler);
var chatManager = new ChannelManager(Scheduler);
api.Register(chatManager);
dependencies.Cache(chatManager);

View File

@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Chat
private const float text_size = 15;
private const float transition_duration = 100;
private readonly ChannelChat channel;
private readonly Channel channel;
private readonly Bindable<bool> joinedBind = new Bindable<bool>();
private readonly OsuSpriteText name;
@ -44,10 +44,10 @@ namespace osu.Game.Overlays.Chat
}
}
public Action<ChannelChat> OnRequestJoin;
public Action<ChannelChat> OnRequestLeave;
public Action<Channel> OnRequestJoin;
public Action<Channel> OnRequestLeave;
public ChannelListItem(ChannelChat channel)
public ChannelListItem(Channel channel)
{
this.channel = channel;

View File

@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Chat
set { header.Text = value.ToUpper(); }
}
public IEnumerable<ChannelChat> Channels
public IEnumerable<Channel> Channels
{
set { ChannelFlow.ChildrenEnumerable = value.Select(c => new ChannelListItem(c)); }
}

View File

@ -32,8 +32,8 @@ namespace osu.Game.Overlays.Chat
private readonly SearchTextBox search;
private readonly SearchContainer<ChannelSection> sectionsFlow;
public Action<ChannelChat> OnRequestJoin;
public Action<ChannelChat> OnRequestLeave;
public Action<Channel> OnRequestJoin;
public Action<Channel> OnRequestLeave;
public IEnumerable<ChannelSection> Sections
{

View File

@ -21,11 +21,11 @@ using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Chat
{
public class ChannelTabControl : OsuTabControl<ChannelChat>
public class ChannelTabControl : OsuTabControl<Channel>
{
private const float shear_width = 10;
public Action<ChannelChat> OnRequestLeave;
public Action<Channel> OnRequestLeave;
public readonly Bindable<bool> ChannelSelectorActive = new Bindable<bool>();
@ -46,19 +46,12 @@ namespace osu.Game.Overlays.Chat
Margin = new MarginPadding(10),
});
AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new ChannelChat { Name = "+" }));
AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" }));
ChannelSelectorActive.BindTo(selectorTab.Active);
}
public void DeselectAll()
{
if (SelectedTab != null)
SelectedTab.Active.Value = false;
SelectedTab = null;
}
protected override void AddTabItem(TabItem<ChannelChat> item, bool addToDropdown = true)
protected override void AddTabItem(TabItem<Channel> item, bool addToDropdown = true)
{
if (item != selectorTab && TabContainer.GetLayoutPosition(selectorTab) < float.MaxValue)
// performTabSort might've made selectorTab's position wonky, fix it
@ -70,9 +63,9 @@ namespace osu.Game.Overlays.Chat
SelectTab(item);
}
protected override TabItem<ChannelChat> CreateTabItem(ChannelChat value) => new ChannelTabItem(value) { OnRequestClose = tabCloseRequested };
protected override TabItem<Channel> CreateTabItem(Channel value) => new ChannelTabItem(value) { OnRequestClose = tabCloseRequested };
protected override void SelectTab(TabItem<ChannelChat> tab)
protected override void SelectTab(TabItem<Channel> tab)
{
if (tab is ChannelTabItem.ChannelSelectorTabItem)
{
@ -85,7 +78,7 @@ namespace osu.Game.Overlays.Chat
base.SelectTab(tab);
}
private void tabCloseRequested(TabItem<ChannelChat> tab)
private void tabCloseRequested(TabItem<Channel> tab)
{
int totalTabs = TabContainer.Count - 1; // account for selectorTab
int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(tab), 1, totalTabs);
@ -100,7 +93,7 @@ namespace osu.Game.Overlays.Chat
OnRequestLeave?.Invoke(tab.Value);
}
private class ChannelTabItem : TabItem<ChannelChat>
private class ChannelTabItem : TabItem<Channel>
{
private Color4 backgroundInactive;
private Color4 backgroundHover;
@ -182,7 +175,7 @@ namespace osu.Game.Overlays.Chat
updateState();
}
public ChannelTabItem(ChannelChat value) : base(value)
public ChannelTabItem(Channel value) : base(value)
{
Width = 150;
@ -314,7 +307,7 @@ namespace osu.Game.Overlays.Chat
{
public override bool IsRemovable => false;
public ChannelSelectorTabItem(ChannelChat value) : base(value)
public ChannelSelectorTabItem(Channel value) : base(value)
{
Depth = float.MaxValue;
Width = 45;

View File

@ -82,7 +82,7 @@ namespace osu.Game.Overlays.Chat
Padding = new MarginPadding { Left = padding, Right = padding };
}
private ChatManager chatManager;
private ChannelManager chatManager;
private Message message;
private OsuSpriteText username;
@ -107,7 +107,7 @@ namespace osu.Game.Overlays.Chat
}
[BackgroundDependencyLoader(true)]
private void load(OsuColour colours, ChatManager chatManager)
private void load(OsuColour colours, ChannelManager chatManager)
{
this.chatManager = chatManager;
customUsernameColour = colours.ChatBlue;
@ -245,10 +245,10 @@ namespace osu.Game.Overlays.Chat
}
[BackgroundDependencyLoader(true)]
private void load(UserProfileOverlay profile, ChatManager chatManager)
private void load(UserProfileOverlay profile, ChannelManager chatManager)
{
Action = () => profile?.ShowUser(sender);
startChatAction = () => chatManager?.OpenUserChat(sender);
startChatAction = () => chatManager?.OpenUserChannel(sender);
}
public MenuItem[] ContextMenuItems => new MenuItem[]

View File

@ -1,4 +1,5 @@
using System;
using System.Linq;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -7,14 +8,13 @@ using osu.Game.Online.Chat;
namespace osu.Game.Overlays.Chat
{
public class ChatTabControl : Container, IHasCurrentValue<ChatBase>
public class ChatTabControl : Container, IHasCurrentValue<Channel>
{
public readonly ChannelTabControl channelTabControl;
private readonly UserTabControl userTabControl;
public readonly ChannelTabControl ChannelTabControl;
public readonly UserTabControl UserTabControl;
public Bindable<ChatBase> Current { get; } = new Bindable<ChatBase>();
public Action<ChatBase> OnRequestLeave;
public Action OnRequestChannelSelection;
public Bindable<Channel> Current { get; } = new Bindable<Channel>();
public Action<Channel> OnRequestLeave;
public ChatTabControl()
{
@ -22,76 +22,80 @@ namespace osu.Game.Overlays.Chat
Children = new Drawable[]
{
channelTabControl = new ChannelTabControl
ChannelTabControl = new ChannelTabControl
{
Width = 0.5f,
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.Both,
OnRequestLeave = chat => OnRequestLeave?.Invoke(chat)
OnRequestLeave = channel => OnRequestLeave?.Invoke(channel)
},
userTabControl = new UserTabControl
UserTabControl = new UserTabControl
{
Width = 0.5f,
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
RelativeSizeAxes = Axes.Both,
OnRequestLeave = chat => OnRequestLeave?.Invoke(chat)
OnRequestLeave = channel => OnRequestLeave?.Invoke(channel)
},
};
Current.ValueChanged += currentTabChanged;
channelTabControl.Current.ValueChanged += chat =>
ChannelTabControl.Current.ValueChanged += channel =>
{
if (chat != null)
Current.Value = chat;
if (channel != null)
Current.Value = channel;
};
userTabControl.Current.ValueChanged += chat =>
UserTabControl.Current.ValueChanged += channel =>
{
if (chat != null)
Current.Value = chat;
if (channel != null)
Current.Value = channel;
};
}
private void currentTabChanged(ChatBase tab)
private void currentTabChanged(Channel channel)
{
switch (tab)
switch (channel.Target)
{
case UserChat userChat:
userTabControl.Current.Value = userChat;
channelTabControl.Current.Value = null;
case TargetType.User:
UserTabControl.Current.Value = channel;
ChannelTabControl.Current.Value = null;
break;
case ChannelChat channelChat:
channelTabControl.Current.Value = channelChat;
userTabControl.Current.Value = null;
case TargetType.Channel:
ChannelTabControl.Current.Value = channel;
UserTabControl.Current.Value = null;
break;
}
}
public void AddItem(ChatBase chat)
public void AddItem(Channel channel)
{
switch (chat)
switch (channel.Target)
{
case UserChat userChat:
userTabControl.AddItem(userChat);
case TargetType.User:
UserTabControl.AddItem(channel);
break;
case ChannelChat channelChat:
channelTabControl.AddItem(channelChat);
case TargetType.Channel:
ChannelTabControl.AddItem(channel);
break;
}
}
public void RemoveItem(ChatBase chat)
public void RemoveItem(Channel channel)
{
switch (chat)
Channel nextSelectedChannel = null;
switch (channel.Target)
{
case UserChat userChat:
userTabControl.RemoveItem(userChat);
Current.Value = null;
case TargetType.User:
UserTabControl.RemoveItem(channel);
if (Current.Value == channel)
Current.Value = UserTabControl.Items.FirstOrDefault() ?? ChannelTabControl.Items.FirstOrDefault();
break;
case ChannelChat channelChat:
channelTabControl.RemoveItem(channelChat);
Current.Value = null;
case TargetType.Channel:
ChannelTabControl.RemoveItem(channel);
if (Current.Value == channel)
Current.Value = ChannelTabControl.Items.FirstOrDefault() ?? UserTabControl.Items.FirstOrDefault();
break;
}
}

View File

@ -17,11 +17,11 @@ namespace osu.Game.Overlays.Chat
{
public class DrawableChat : Container
{
public readonly ChatBase Chat;
public readonly Channel Chat;
private readonly ChatLineContainer flow;
private readonly ScrollContainer scroll;
public DrawableChat(ChatBase chat)
public DrawableChat(Channel chat)
{
Chat = chat;
@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Chat
private void newMessagesArrived(IEnumerable<Message> newMessages)
{
// Add up to last ChatBase.MAX_HISTORY messages
var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - ChatBase.MAX_HISTORY));
var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY));
flow.AddRange(displayMessages.Select(m => new ChatLine(m)));
@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Chat
scrollToEnd();
var staleMessages = flow.Children.Where(c => c.LifetimeEnd == double.MaxValue).ToArray();
int count = staleMessages.Length - ChatBase.MAX_HISTORY;
int count = staleMessages.Length - Channel.MAX_HISTORY;
for (int i = 0; i < count; i++)
{

View File

@ -10,13 +10,16 @@ using OpenTK;
namespace osu.Game.Overlays.Chat
{
public class UserTabControl : OsuTabControl<UserChat>
public class UserTabControl : OsuTabControl<Channel>
{
protected override TabItem<UserChat> CreateTabItem(UserChat value) => new UserTabItem(value) { OnRequestClose = tabCloseRequested };
protected override TabItem<Channel> CreateTabItem(Channel value)
{
if (value.Target != TargetType.User)
throw new ArgumentException("Argument value needs to have the targettype user.");
return new UserTabItem(value) { OnRequestClose = tabCloseRequested };
}
protected override Dropdown<UserChat> CreateDropdown() => null;
public Action<UserChat> OnRequestLeave;
public Action<Channel> OnRequestLeave;
public UserTabControl()
{
@ -28,7 +31,7 @@ namespace osu.Game.Overlays.Chat
};
}
protected override void AddTabItem(TabItem<UserChat> item, bool addToDropdown = true)
protected override void AddTabItem(TabItem<Channel> item, bool addToDropdown = true)
{
base.AddTabItem(item, addToDropdown);
@ -36,7 +39,7 @@ namespace osu.Game.Overlays.Chat
SelectTab(item);
}
private void tabCloseRequested(TabItem<UserChat> priv)
private void tabCloseRequested(TabItem<Channel> priv)
{
int totalTabs = TabContainer.Count -1; // account for selectorTab
int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(priv), 1, totalTabs);
@ -47,13 +50,5 @@ namespace osu.Game.Overlays.Chat
OnRequestLeave?.Invoke(priv.Value);
}
public void DeselectAll()
{
if (SelectedTab != null)
SelectedTab.Active.Value = false;
SelectedTab = null;
}
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@ -19,10 +20,10 @@ using OpenTK.Graphics;
namespace osu.Game.Overlays.Chat
{
public class UserTabItem : TabItem<UserChat>
public class UserTabItem : TabItem<Channel>
{
private static readonly Vector2 shear = new Vector2(1f / 5f, 0);
private readonly UserChat chat;
private readonly Channel channel;
public override bool IsRemovable => true;
private readonly Box highlightBox;
@ -32,10 +33,13 @@ namespace osu.Game.Overlays.Chat
private readonly Avatar avatarContainer;
private readonly ChatTabItemCloseButton closeButton;
public UserTabItem(UserChat value)
public UserTabItem(Channel value)
: base(value)
{
chat = value;
if (value.Target != TargetType.User)
throw new ArgumentException("Argument value needs to have the targettype user!");
channel = value;
AutoSizeAxes = Axes.X;
Height = 50;
Origin = Anchor.BottomRight;
@ -117,7 +121,7 @@ namespace osu.Game.Overlays.Chat
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Masking = true,
Child = new DelayedLoadWrapper(new Avatar(value.User)
Child = new DelayedLoadWrapper(new Avatar(value.JoinedUsers.First())
{
Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT),
OnLoadComplete = d => d.FadeInFromZero(300, Easing.OutQuint),
@ -132,7 +136,7 @@ namespace osu.Game.Overlays.Chat
{
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
Text = value.User.Username,
Text = value.Name,
Margin = new MarginPadding(1),
TextSize = 18,
},
@ -177,12 +181,14 @@ namespace osu.Game.Overlays.Chat
username.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint);
closeButton.ScaleTo(new Vector2(1, 1), activate_length, Easing.OutQuint);
closeButton.FadeIn(activate_length, Easing.OutQuint);
// TweenEdgeEffectTo(activateEdgeEffect, activate_length);
TweenEdgeEffectTo(activateEdgeEffect, activate_length);
}
private readonly EdgeEffectParameters deactivateEdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0.0f),
Type = EdgeEffectType.Shadow,
Radius = 10,
Colour = Color4.Black.Opacity(0.2f),
};
protected override void OnDeactivated()
@ -196,19 +202,15 @@ namespace osu.Game.Overlays.Chat
username.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint);
closeButton.FadeOut(deactivate_length, Easing.OutQuint);
closeButton.ScaleTo(new Vector2(0, 1), deactivate_length, Easing.OutQuint);
// TweenEdgeEffectTo(deactivateEdgeEffect, deactivate_length);
TweenEdgeEffectTo(deactivateEdgeEffect, deactivate_length);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, IAPIProvider api)
{
backgroundBox.Colour = Value.User.Colour != null ? OsuColour.FromHex(Value.User.Colour) : colours.BlueDark;
var user = Value.JoinedUsers.First();
if (chat.User.Username == null || chat.User.Id < 1)
{
chat.DetailsArrived += arrivedUser => { Scheduler.Add(() => { username.Text = arrivedUser.Username; }); };
chat.RequestDetails(api);
}
backgroundBox.Colour = user.Colour != null ? OsuColour.FromHex(user.Colour) : colours.BlueDark;
}
}
}

View File

@ -30,7 +30,7 @@ namespace osu.Game.Overlays
private const float textbox_height = 60;
private const float channel_selection_min_height = 0.3f;
private ChatManager chatManager;
private ChannelManager chatManager;
private readonly Container<DrawableChat> currentChatContainer;
private readonly List<DrawableChat> loadedChannels = new List<DrawableChat>();
@ -157,13 +157,7 @@ namespace osu.Game.Overlays
chatTabControl = new ChatTabControl
{
RelativeSizeAxes = Axes.Both,
OnRequestLeave = chat =>
{
if (chat is ChannelChat channelChat)
chatManager.JoinedChannels.Remove(channelChat);
if (chat is UserChat userChat)
chatManager.OpenedUserChats.Remove(userChat);
}
OnRequestLeave = channel => chatManager.JoinedChannels.Remove(channel)
}
}
},
@ -171,11 +165,11 @@ namespace osu.Game.Overlays
},
};
chatTabControl.Current.ValueChanged += chat => chatManager.CurrentChat.Value = chat;
chatTabControl.channelTabControl.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden;
chatTabControl.Current.ValueChanged += chat => chatManager.CurrentChannel.Value = chat;
chatTabControl.ChannelTabControl.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden;
channelSelection.StateChanged += state =>
{
chatTabControl.channelTabControl.ChannelSelectorActive.Value = state == Visibility.Visible;
chatTabControl.ChannelTabControl.ChannelSelectorActive.Value = state == Visibility.Visible;
if (state == Visibility.Visible)
{
@ -211,28 +205,24 @@ namespace osu.Game.Overlays
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (ChannelChat newChannel in args.NewItems)
foreach (Channel newChannel in args.NewItems)
{
chatTabControl.AddItem(newChannel);
newChannel.Joined.Value = true;
//if (chatManager.CurrentChat.Value == null)
// chatManager.CurrentChat.Value = newChannel;
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (ChannelChat removedChannel in args.OldItems)
foreach (Channel removedChannel in args.OldItems)
{
chatTabControl.RemoveItem(removedChannel);
loadedChannels.Remove(loadedChannels.Find(c => c.Chat == removedChannel ));
removedChannel.Joined.Value = false;
if (chatManager.CurrentChat.Value == removedChannel)
chatManager.CurrentChat.Value = null;
}
break;
}
}
private void currentChatChanged(ChatBase chat)
private void currentChatChanged(Channel chat)
{
if (chat == null)
{
@ -243,8 +233,9 @@ namespace osu.Game.Overlays
}
textbox.Current.Disabled = chat.ReadOnly;
Scheduler.Add(() => chatTabControl.Current.Value = chat);
if (chatTabControl.Current.Value != chat)
Scheduler.Add(() => chatTabControl.Current.Value = chat);
var loaded = loadedChannels.Find(d => d.Chat == chat);
if (loaded == null)
@ -337,7 +328,7 @@ namespace osu.Game.Overlays
}
[BackgroundDependencyLoader]
private void load(APIAccess api, OsuConfigManager config, OsuColour colours, ChatManager chatManager)
private void load(APIAccess api, OsuConfigManager config, OsuColour colours, ChannelManager chatManager)
{
api.Register(chatManager);
@ -354,30 +345,9 @@ namespace osu.Game.Overlays
loading.Show();
this.chatManager = chatManager;
chatManager.CurrentChat.ValueChanged += currentChatChanged;
chatManager.CurrentChannel.ValueChanged += currentChatChanged;
chatManager.JoinedChannels.CollectionChanged += joinedChannelsChanged;
chatManager.AvailableChannels.CollectionChanged += availableChannelsChanged;
chatManager.OpenedUserChats.CollectionChanged += openedUserChatsChanged;
}
private void openedUserChatsChanged(object sender, NotifyCollectionChangedEventArgs args)
{
switch (args.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (UserChat chat in args.NewItems)
{
chatTabControl.AddItem(args.NewItems[0] as UserChat);
if (chatManager.CurrentChat.Value == chat)
chatTabControl.Current.Value = chat;
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (UserChat chat in args.OldItems)
chatTabControl.RemoveItem(chat);
break;
}
}
private void postMessage(TextBox textbox, bool newText)