mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 17:47:29 +08:00
Merge pull request #18246 from jai-x/new-chat-cache-loaded-channels
Add drawable channel caching to new chat overlay
This commit is contained in:
commit
d187ca2d8c
@ -5,6 +5,8 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
@ -31,7 +33,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneChatOverlayV2 : OsuManualInputManagerTestScene
|
public class TestSceneChatOverlayV2 : OsuManualInputManagerTestScene
|
||||||
{
|
{
|
||||||
private ChatOverlayV2 chatOverlay;
|
private TestChatOverlayV2 chatOverlay;
|
||||||
private ChannelManager channelManager;
|
private ChannelManager channelManager;
|
||||||
|
|
||||||
private APIUser testUser;
|
private APIUser testUser;
|
||||||
@ -61,7 +63,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
channelManager,
|
channelManager,
|
||||||
chatOverlay = new ChatOverlayV2 { RelativeSizeAxes = Axes.Both },
|
chatOverlay = new TestChatOverlayV2 { RelativeSizeAxes = Axes.Both },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -365,19 +367,19 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TextBoxRetainsFocus()
|
public void TestTextBoxRetainsFocus()
|
||||||
{
|
{
|
||||||
AddStep("Show overlay", () => chatOverlay.Show());
|
AddStep("Show overlay", () => chatOverlay.Show());
|
||||||
AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
|
AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
|
||||||
AddStep("Join channel 1", () => channelManager.JoinChannel(testChannel1));
|
AddStep("Join channel 1", () => channelManager.JoinChannel(testChannel1));
|
||||||
AddStep("Select channel 1", () => clickDrawable(getChannelListItem(testChannel1)));
|
AddStep("Select channel 1", () => clickDrawable(getChannelListItem(testChannel1)));
|
||||||
AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
|
AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
|
||||||
|
AddStep("Click drawable channel", () => clickDrawable(currentDrawableChannel));
|
||||||
|
AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
|
||||||
AddStep("Click selector", () => clickDrawable(chatOverlay.ChildrenOfType<ChannelListSelector>().Single()));
|
AddStep("Click selector", () => clickDrawable(chatOverlay.ChildrenOfType<ChannelListSelector>().Single()));
|
||||||
AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
|
AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
|
||||||
AddStep("Click listing", () => clickDrawable(chatOverlay.ChildrenOfType<ChannelListing>().Single()));
|
AddStep("Click listing", () => clickDrawable(chatOverlay.ChildrenOfType<ChannelListing>().Single()));
|
||||||
AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
|
AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
|
||||||
AddStep("Click drawable channel", () => clickDrawable(currentDrawableChannel));
|
|
||||||
AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
|
|
||||||
AddStep("Click channel list", () => clickDrawable(chatOverlay.ChildrenOfType<ChannelList>().Single()));
|
AddStep("Click channel list", () => clickDrawable(chatOverlay.ChildrenOfType<ChannelList>().Single()));
|
||||||
AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
|
AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox);
|
||||||
AddStep("Click top bar", () => clickDrawable(chatOverlay.ChildrenOfType<ChatOverlayTopBar>().Single()));
|
AddStep("Click top bar", () => clickDrawable(chatOverlay.ChildrenOfType<ChatOverlayTopBar>().Single()));
|
||||||
@ -386,6 +388,34 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddAssert("TextBox is not focused", () => InputManager.FocusedDrawable == null);
|
AddAssert("TextBox is not focused", () => InputManager.FocusedDrawable == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSlowLoadingChannel()
|
||||||
|
{
|
||||||
|
AddStep("Show overlay (slow-loading)", () =>
|
||||||
|
{
|
||||||
|
chatOverlay.Show();
|
||||||
|
chatOverlay.SlowLoading = true;
|
||||||
|
});
|
||||||
|
AddStep("Join channel 1", () => channelManager.JoinChannel(testChannel1));
|
||||||
|
AddAssert("Channel 1 loading", () => !channelIsVisible && chatOverlay.GetSlowLoadingChannel(testChannel1).LoadState == LoadState.Loading);
|
||||||
|
|
||||||
|
AddStep("Join channel 2", () => channelManager.JoinChannel(testChannel2));
|
||||||
|
AddStep("Select channel 2", () => clickDrawable(getChannelListItem(testChannel2)));
|
||||||
|
AddAssert("Channel 2 loading", () => !channelIsVisible && chatOverlay.GetSlowLoadingChannel(testChannel2).LoadState == LoadState.Loading);
|
||||||
|
|
||||||
|
AddStep("Finish channel 1 load", () => chatOverlay.GetSlowLoadingChannel(testChannel1).LoadEvent.Set());
|
||||||
|
AddAssert("Channel 1 ready", () => chatOverlay.GetSlowLoadingChannel(testChannel1).LoadState == LoadState.Ready);
|
||||||
|
AddAssert("Channel 1 not displayed", () => !channelIsVisible);
|
||||||
|
|
||||||
|
AddStep("Finish channel 2 load", () => chatOverlay.GetSlowLoadingChannel(testChannel2).LoadEvent.Set());
|
||||||
|
AddAssert("Channel 2 loaded", () => chatOverlay.GetSlowLoadingChannel(testChannel2).IsLoaded);
|
||||||
|
AddAssert("Channel 2 displayed", () => channelIsVisible && currentDrawableChannel.Channel == testChannel2);
|
||||||
|
|
||||||
|
AddStep("Select channel 1", () => clickDrawable(getChannelListItem(testChannel1)));
|
||||||
|
AddAssert("Channel 1 loaded", () => chatOverlay.GetSlowLoadingChannel(testChannel1).IsLoaded);
|
||||||
|
AddAssert("Channel 1 displayed", () => channelIsVisible && currentDrawableChannel.Channel == testChannel1);
|
||||||
|
}
|
||||||
|
|
||||||
private bool listingIsVisible =>
|
private bool listingIsVisible =>
|
||||||
chatOverlay.ChildrenOfType<ChannelListing>().Single().State.Value == Visibility.Visible;
|
chatOverlay.ChildrenOfType<ChannelListing>().Single().State.Value == Visibility.Visible;
|
||||||
|
|
||||||
@ -432,5 +462,35 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
Topic = $"We talk about the number {id} here",
|
Topic = $"We talk about the number {id} here",
|
||||||
Type = ChannelType.Public,
|
Type = ChannelType.Public,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private class TestChatOverlayV2 : ChatOverlayV2
|
||||||
|
{
|
||||||
|
public bool SlowLoading { get; set; }
|
||||||
|
|
||||||
|
public SlowLoadingDrawableChannel GetSlowLoadingChannel(Channel channel) => DrawableChannels.OfType<SlowLoadingDrawableChannel>().Single(c => c.Channel == channel);
|
||||||
|
|
||||||
|
protected override ChatOverlayDrawableChannel CreateDrawableChannel(Channel newChannel)
|
||||||
|
{
|
||||||
|
return SlowLoading
|
||||||
|
? new SlowLoadingDrawableChannel(newChannel)
|
||||||
|
: new ChatOverlayDrawableChannel(newChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SlowLoadingDrawableChannel : ChatOverlayDrawableChannel
|
||||||
|
{
|
||||||
|
public readonly ManualResetEventSlim LoadEvent = new ManualResetEventSlim();
|
||||||
|
|
||||||
|
public SlowLoadingDrawableChannel([NotNull] Channel channel)
|
||||||
|
: base(channel)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
LoadEvent.Wait(10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,8 +39,11 @@ namespace osu.Game.Overlays
|
|||||||
private ChatTextBar textBar = null!;
|
private ChatTextBar textBar = null!;
|
||||||
private Container<ChatOverlayDrawableChannel> currentChannelContainer = null!;
|
private Container<ChatOverlayDrawableChannel> currentChannelContainer = null!;
|
||||||
|
|
||||||
private readonly BindableFloat chatHeight = new BindableFloat();
|
private readonly Dictionary<Channel, ChatOverlayDrawableChannel> loadedChannels = new Dictionary<Channel, ChatOverlayDrawableChannel>();
|
||||||
|
|
||||||
|
protected IEnumerable<DrawableChannel> DrawableChannels => loadedChannels.Values;
|
||||||
|
|
||||||
|
private readonly BindableFloat chatHeight = new BindableFloat();
|
||||||
private bool isDraggingTopBar;
|
private bool isDraggingTopBar;
|
||||||
private float dragStartChatHeight;
|
private float dragStartChatHeight;
|
||||||
|
|
||||||
@ -173,7 +176,7 @@ namespace osu.Game.Overlays
|
|||||||
if (currentChannel.Value?.Id != channel.Id)
|
if (currentChannel.Value?.Id != channel.Id)
|
||||||
{
|
{
|
||||||
if (!channel.Joined.Value)
|
if (!channel.Joined.Value)
|
||||||
channel = channelManager.JoinChannel(channel);
|
channel = channelManager.JoinChannel(channel, false);
|
||||||
|
|
||||||
channelManager.CurrentChannel.Value = channel;
|
channelManager.CurrentChannel.Value = channel;
|
||||||
}
|
}
|
||||||
@ -240,38 +243,76 @@ namespace osu.Game.Overlays
|
|||||||
if (newChannel == null)
|
if (newChannel == null)
|
||||||
{
|
{
|
||||||
// null channel denotes that we should be showing the listing.
|
// null channel denotes that we should be showing the listing.
|
||||||
channelListing.State.Value = Visibility.Visible;
|
currentChannelContainer.Clear(false);
|
||||||
|
channelListing.Show();
|
||||||
textBar.ShowSearch.Value = true;
|
textBar.ShowSearch.Value = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
channelListing.State.Value = Visibility.Hidden;
|
channelListing.Hide();
|
||||||
textBar.ShowSearch.Value = false;
|
textBar.ShowSearch.Value = false;
|
||||||
|
|
||||||
loading.Show();
|
if (loadedChannels.ContainsKey(newChannel))
|
||||||
LoadComponentAsync(new ChatOverlayDrawableChannel(newChannel), loaded =>
|
|
||||||
{
|
{
|
||||||
currentChannelContainer.Clear();
|
currentChannelContainer.Clear(false);
|
||||||
currentChannelContainer.Add(loaded);
|
currentChannelContainer.Add(loadedChannels[newChannel]);
|
||||||
loading.Hide();
|
}
|
||||||
});
|
else
|
||||||
|
{
|
||||||
|
loading.Show();
|
||||||
|
|
||||||
|
// Ensure the drawable channel is stored before async load to prevent double loading
|
||||||
|
ChatOverlayDrawableChannel drawableChannel = CreateDrawableChannel(newChannel);
|
||||||
|
loadedChannels.Add(newChannel, drawableChannel);
|
||||||
|
|
||||||
|
LoadComponentAsync(drawableChannel, loadedDrawable =>
|
||||||
|
{
|
||||||
|
// Ensure the current channel hasn't changed by the time the load completes
|
||||||
|
if (currentChannel.Value != loadedDrawable.Channel)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Ensure the cached reference hasn't been removed from leaving the channel
|
||||||
|
if (!loadedChannels.ContainsKey(loadedDrawable.Channel))
|
||||||
|
return;
|
||||||
|
|
||||||
|
currentChannelContainer.Clear(false);
|
||||||
|
currentChannelContainer.Add(loadedDrawable);
|
||||||
|
loading.Hide();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual ChatOverlayDrawableChannel CreateDrawableChannel(Channel newChannel) => new ChatOverlayDrawableChannel(newChannel);
|
||||||
|
|
||||||
private void joinedChannelsChanged(object sender, NotifyCollectionChangedEventArgs args)
|
private void joinedChannelsChanged(object sender, NotifyCollectionChangedEventArgs args)
|
||||||
{
|
{
|
||||||
switch (args.Action)
|
switch (args.Action)
|
||||||
{
|
{
|
||||||
case NotifyCollectionChangedAction.Add:
|
case NotifyCollectionChangedAction.Add:
|
||||||
IEnumerable<Channel> joinedChannels = filterChannels(args.NewItems);
|
IEnumerable<Channel> joinedChannels = filterChannels(args.NewItems);
|
||||||
|
|
||||||
foreach (var channel in joinedChannels)
|
foreach (var channel in joinedChannels)
|
||||||
channelList.AddChannel(channel);
|
channelList.AddChannel(channel);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NotifyCollectionChangedAction.Remove:
|
case NotifyCollectionChangedAction.Remove:
|
||||||
IEnumerable<Channel> leftChannels = filterChannels(args.OldItems);
|
IEnumerable<Channel> leftChannels = filterChannels(args.OldItems);
|
||||||
|
|
||||||
foreach (var channel in leftChannels)
|
foreach (var channel in leftChannels)
|
||||||
|
{
|
||||||
channelList.RemoveChannel(channel);
|
channelList.RemoveChannel(channel);
|
||||||
|
|
||||||
|
if (loadedChannels.ContainsKey(channel))
|
||||||
|
{
|
||||||
|
ChatOverlayDrawableChannel loaded = loadedChannels[channel];
|
||||||
|
loadedChannels.Remove(channel);
|
||||||
|
// DrawableChannel removed from cache must be manually disposed
|
||||||
|
loaded.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user