1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-13 19:04:06 +08:00

Merge pull request #18181 from jai-x/new-chat-visibility-behaviour

Update channel visibilty behaviour in new chat overlay
This commit is contained in:
Dean Herbert 2022-05-12 15:35:48 +09:00 committed by GitHub
commit 26d4237ff4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 65 additions and 89 deletions

View File

@ -25,7 +25,6 @@ namespace osu.Game.Tests.Visual.Online
[Cached] [Cached]
private readonly Bindable<Channel> selected = new Bindable<Channel>(); private readonly Bindable<Channel> selected = new Bindable<Channel>();
private OsuSpriteText selectorText;
private OsuSpriteText selectedText; private OsuSpriteText selectedText;
private OsuSpriteText leaveText; private OsuSpriteText leaveText;
private ChannelList channelList; private ChannelList channelList;
@ -43,21 +42,12 @@ namespace osu.Game.Tests.Visual.Online
Height = 0.7f, Height = 0.7f,
RowDimensions = new[] RowDimensions = new[]
{ {
new Dimension(GridSizeMode.Absolute, 20),
new Dimension(GridSizeMode.Absolute, 20), new Dimension(GridSizeMode.Absolute, 20),
new Dimension(GridSizeMode.Absolute, 20), new Dimension(GridSizeMode.Absolute, 20),
new Dimension(), new Dimension(),
}, },
Content = new[] Content = new[]
{ {
new Drawable[]
{
selectorText = new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
},
},
new Drawable[] new Drawable[]
{ {
selectedText = new OsuSpriteText selectedText = new OsuSpriteText
@ -89,7 +79,6 @@ namespace osu.Game.Tests.Visual.Online
channelList.OnRequestSelect += channel => channelList.OnRequestSelect += channel =>
{ {
channelList.SelectorActive.Value = false;
selected.Value = channel; selected.Value = channel;
}; };
@ -101,12 +90,6 @@ namespace osu.Game.Tests.Visual.Online
channelList.RemoveChannel(channel); channelList.RemoveChannel(channel);
}; };
channelList.SelectorActive.BindValueChanged(change =>
{
selectorText.Text = $"Channel Selector Active: {change.NewValue}";
selected.Value = null;
}, true);
selected.BindValueChanged(change => selected.BindValueChanged(change =>
{ {
selectedText.Text = $"Selected Channel: {change.NewValue?.Name ?? "[null]"}"; selectedText.Text = $"Selected Channel: {change.NewValue?.Name ?? "[null]"}";

View File

@ -121,6 +121,19 @@ namespace osu.Game.Tests.Visual.Online
}); });
} }
[Test]
public void TestBasic()
{
AddStep("Show overlay with channel", () =>
{
chatOverlay.Show();
Channel joinedChannel = channelManager.JoinChannel(testChannel1);
channelManager.CurrentChannel.Value = joinedChannel;
});
AddAssert("Overlay is visible", () => chatOverlay.State.Value == Visibility.Visible);
AddUntilStep("Channel is visible", () => channelIsVisible && currentDrawableChannel.Channel == testChannel1);
}
[Test] [Test]
public void TestShowHide() public void TestShowHide()
{ {
@ -158,20 +171,17 @@ namespace osu.Game.Tests.Visual.Online
public void TestChannelSelection() public void TestChannelSelection()
{ {
AddStep("Show overlay", () => chatOverlay.Show()); AddStep("Show overlay", () => chatOverlay.Show());
AddAssert("Listing is visible", () => listingVisibility == Visibility.Visible); AddAssert("Listing is visible", () => listingIsVisible);
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("Listing is hidden", () => listingVisibility == Visibility.Hidden); AddUntilStep("Channel 1 is visible", () => channelIsVisible && currentDrawableChannel.Channel == testChannel1);
AddAssert("Loading is hidden", () => loadingVisibility == Visibility.Hidden);
AddAssert("Current channel is correct", () => channelManager.CurrentChannel.Value == testChannel1);
AddAssert("DrawableChannel is correct", () => currentDrawableChannel.Channel == testChannel1);
} }
[Test] [Test]
public void TestSearchInListing() public void TestSearchInListing()
{ {
AddStep("Show overlay", () => chatOverlay.Show()); AddStep("Show overlay", () => chatOverlay.Show());
AddAssert("Listing is visible", () => listingVisibility == Visibility.Visible); AddAssert("Listing is visible", () => listingIsVisible);
AddStep("Search for 'number 2'", () => chatOverlayTextBox.Text = "number 2"); AddStep("Search for 'number 2'", () => chatOverlayTextBox.Text = "number 2");
AddUntilStep("Only channel 2 visibile", () => AddUntilStep("Only channel 2 visibile", () =>
{ {
@ -263,6 +273,7 @@ namespace osu.Game.Tests.Visual.Online
}); });
}); });
AddStep("Highlight message", () => chatOverlay.HighlightMessage(message, testChannel1)); AddStep("Highlight message", () => chatOverlay.HighlightMessage(message, testChannel1));
AddUntilStep("Channel 1 is visible", () => channelIsVisible && currentDrawableChannel.Channel == testChannel1);
} }
[Test] [Test]
@ -285,8 +296,7 @@ namespace osu.Game.Tests.Visual.Online
}); });
}); });
AddStep("Highlight message", () => chatOverlay.HighlightMessage(message, testChannel2)); AddStep("Highlight message", () => chatOverlay.HighlightMessage(message, testChannel2));
AddAssert("Channel 2 is selected", () => channelManager.CurrentChannel.Value == testChannel2); AddUntilStep("Channel 2 is visible", () => channelIsVisible && currentDrawableChannel.Channel == testChannel2);
AddAssert("Channel 2 is visible", () => currentDrawableChannel.Channel == testChannel2);
} }
[Test] [Test]
@ -310,8 +320,7 @@ namespace osu.Game.Tests.Visual.Online
}); });
AddStep("Leave channel 2", () => channelManager.LeaveChannel(testChannel2)); AddStep("Leave channel 2", () => channelManager.LeaveChannel(testChannel2));
AddStep("Highlight message", () => chatOverlay.HighlightMessage(message, testChannel2)); AddStep("Highlight message", () => chatOverlay.HighlightMessage(message, testChannel2));
AddAssert("Channel 2 is selected", () => channelManager.CurrentChannel.Value == testChannel2); AddUntilStep("Channel 2 is visible", () => channelIsVisible && currentDrawableChannel.Channel == testChannel2);
AddAssert("Channel 2 is visible", () => currentDrawableChannel.Channel == testChannel2);
} }
[Test] [Test]
@ -331,6 +340,7 @@ namespace osu.Game.Tests.Visual.Online
}); });
}); });
AddStep("Highlight message", () => chatOverlay.HighlightMessage(message, testChannel1)); AddStep("Highlight message", () => chatOverlay.HighlightMessage(message, testChannel1));
AddUntilStep("Channel 1 is visible", () => channelIsVisible && currentDrawableChannel.Channel == testChannel1);
} }
[Test] [Test]
@ -351,6 +361,7 @@ namespace osu.Game.Tests.Visual.Online
}); });
AddStep("Set null channel", () => channelManager.CurrentChannel.Value = null); AddStep("Set null channel", () => channelManager.CurrentChannel.Value = null);
AddStep("Highlight message", () => chatOverlay.HighlightMessage(message, testChannel1)); AddStep("Highlight message", () => chatOverlay.HighlightMessage(message, testChannel1));
AddUntilStep("Channel 1 is visible", () => channelIsVisible && currentDrawableChannel.Channel == testChannel1);
} }
[Test] [Test]
@ -365,7 +376,7 @@ namespace osu.Game.Tests.Visual.Online
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(chatOverlay.ChildrenOfType<DrawableChannel>().Single())); AddStep("Click drawable channel", () => clickDrawable(currentDrawableChannel));
AddAssert("TextBox is focused", () => InputManager.FocusedDrawable == chatOverlayTextBox); 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);
@ -375,14 +386,17 @@ namespace osu.Game.Tests.Visual.Online
AddAssert("TextBox is not focused", () => InputManager.FocusedDrawable == null); AddAssert("TextBox is not focused", () => InputManager.FocusedDrawable == null);
} }
private Visibility listingVisibility => private bool listingIsVisible =>
chatOverlay.ChildrenOfType<ChannelListing>().Single().State.Value; chatOverlay.ChildrenOfType<ChannelListing>().Single().State.Value == Visibility.Visible;
private Visibility loadingVisibility => private bool loadingIsVisible =>
chatOverlay.ChildrenOfType<LoadingLayer>().Single().State.Value; chatOverlay.ChildrenOfType<LoadingLayer>().Single().State.Value == Visibility.Visible;
private bool channelIsVisible =>
!listingIsVisible && !loadingIsVisible;
private DrawableChannel currentDrawableChannel => private DrawableChannel currentDrawableChannel =>
chatOverlay.ChildrenOfType<Container<DrawableChannel>>().Single().Child; chatOverlay.ChildrenOfType<DrawableChannel>().Single();
private ChannelListItem getChannelListItem(Channel channel) => private ChannelListItem getChannelListItem(Channel channel) =>
chatOverlay.ChildrenOfType<ChannelListItem>().Single(item => item.Channel == channel); chatOverlay.ChildrenOfType<ChannelListItem>().Single(item => item.Channel == channel);

View File

@ -420,10 +420,11 @@ namespace osu.Game.Online.Chat
/// Joins a channel if it has not already been joined. Must be called from the update thread. /// Joins a channel if it has not already been joined. Must be called from the update thread.
/// </summary> /// </summary>
/// <param name="channel">The channel to join.</param> /// <param name="channel">The channel to join.</param>
/// <param name="setCurrent">Set the channel to join as the current channel if the current channel is null.</param>
/// <returns>The joined channel. Note that this may not match the parameter channel as it is a backed object.</returns> /// <returns>The joined channel. Note that this may not match the parameter channel as it is a backed object.</returns>
public Channel JoinChannel(Channel channel) => joinChannel(channel, true); public Channel JoinChannel(Channel channel, bool setCurrent = true) => joinChannel(channel, true, setCurrent);
private Channel joinChannel(Channel channel, bool fetchInitialMessages = false) private Channel joinChannel(Channel channel, bool fetchInitialMessages = false, bool setCurrent = true)
{ {
if (channel == null) return null; if (channel == null) return null;
@ -439,7 +440,7 @@ namespace osu.Game.Online.Chat
case ChannelType.Multiplayer: case ChannelType.Multiplayer:
// join is implicit. happens when you join a multiplayer game. // join is implicit. happens when you join a multiplayer game.
// this will probably change in the future. // this will probably change in the future.
joinChannel(channel, fetchInitialMessages); joinChannel(channel, fetchInitialMessages, setCurrent);
return channel; return channel;
case ChannelType.PM: case ChannelType.PM:
@ -460,7 +461,7 @@ namespace osu.Game.Online.Chat
default: default:
var req = new JoinChannelRequest(channel); var req = new JoinChannelRequest(channel);
req.Success += () => joinChannel(channel, fetchInitialMessages); req.Success += () => joinChannel(channel, fetchInitialMessages, setCurrent);
req.Failure += ex => LeaveChannel(channel); req.Failure += ex => LeaveChannel(channel);
api.Queue(req); api.Queue(req);
return channel; return channel;
@ -472,6 +473,7 @@ namespace osu.Game.Online.Chat
this.fetchInitialMessages(channel); this.fetchInitialMessages(channel);
} }
if (setCurrent)
CurrentChannel.Value ??= channel; CurrentChannel.Value ??= channel;
return channel; return channel;

View File

@ -6,7 +6,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -19,11 +18,9 @@ namespace osu.Game.Overlays.Chat.ChannelList
{ {
public class ChannelList : Container public class ChannelList : Container
{ {
public Action<Channel>? OnRequestSelect; public Action<Channel?>? OnRequestSelect;
public Action<Channel>? OnRequestLeave; public Action<Channel>? OnRequestLeave;
public readonly BindableBool SelectorActive = new BindableBool();
private readonly Dictionary<Channel, ChannelListItem> channelMap = new Dictionary<Channel, ChannelListItem>(); private readonly Dictionary<Channel, ChannelListItem> channelMap = new Dictionary<Channel, ChannelListItem>();
private ChannelListItemFlow publicChannelFlow = null!; private ChannelListItemFlow publicChannelFlow = null!;
@ -56,7 +53,7 @@ namespace osu.Game.Overlays.Chat.ChannelList
new ChannelListSelector new ChannelListSelector
{ {
Margin = new MarginPadding { Bottom = 10 }, Margin = new MarginPadding { Bottom = 10 },
SelectorActive = { BindTarget = SelectorActive }, Action = () => OnRequestSelect?.Invoke(null),
}, },
privateChannelFlow = new ChannelListItemFlow("DIRECT MESSAGES"), privateChannelFlow = new ChannelListItemFlow("DIRECT MESSAGES"),
}, },
@ -73,7 +70,6 @@ namespace osu.Game.Overlays.Chat.ChannelList
ChannelListItem item = new ChannelListItem(channel); ChannelListItem item = new ChannelListItem(channel);
item.OnRequestSelect += chan => OnRequestSelect?.Invoke(chan); item.OnRequestSelect += chan => OnRequestSelect?.Invoke(chan);
item.OnRequestLeave += chan => OnRequestLeave?.Invoke(chan); item.OnRequestLeave += chan => OnRequestLeave?.Invoke(chan);
item.SelectorActive.BindTarget = SelectorActive;
ChannelListItemFlow flow = getFlowForChannel(channel); ChannelListItemFlow flow = getFlowForChannel(channel);
channelMap.Add(channel, item); channelMap.Add(channel, item);

View File

@ -31,8 +31,6 @@ namespace osu.Game.Overlays.Chat.ChannelList
public readonly BindableBool Unread = new BindableBool(); public readonly BindableBool Unread = new BindableBool();
public readonly BindableBool SelectorActive = new BindableBool();
private Box hoverBox = null!; private Box hoverBox = null!;
private Box selectBox = null!; private Box selectBox = null!;
private OsuSpriteText text = null!; private OsuSpriteText text = null!;
@ -127,7 +125,6 @@ namespace osu.Game.Overlays.Chat.ChannelList
base.LoadComplete(); base.LoadComplete();
selectedChannel.BindValueChanged(_ => updateState(), true); selectedChannel.BindValueChanged(_ => updateState(), true);
SelectorActive.BindValueChanged(_ => updateState(), true);
Unread.BindValueChanged(_ => updateState(), true); Unread.BindValueChanged(_ => updateState(), true);
} }
@ -163,7 +160,7 @@ namespace osu.Game.Overlays.Chat.ChannelList
private void updateState() private void updateState()
{ {
bool selected = selectedChannel.Value == Channel && !SelectorActive.Value; bool selected = selectedChannel.Value == Channel;
if (selected) if (selected)
selectBox.FadeIn(300, Easing.OutQuint); selectBox.FadeIn(300, Easing.OutQuint);

View File

@ -12,17 +12,19 @@ using osu.Framework.Input.Events;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat;
namespace osu.Game.Overlays.Chat.ChannelList namespace osu.Game.Overlays.Chat.ChannelList
{ {
public class ChannelListSelector : OsuClickableContainer public class ChannelListSelector : OsuClickableContainer
{ {
public readonly BindableBool SelectorActive = new BindableBool();
private Box hoverBox = null!; private Box hoverBox = null!;
private Box selectBox = null!; private Box selectBox = null!;
private OsuSpriteText text = null!; private OsuSpriteText text = null!;
[Resolved]
private Bindable<Channel> currentChannel { get; set; } = null!;
[Resolved] [Resolved]
private OverlayColourProvider colourProvider { get; set; } = null!; private OverlayColourProvider colourProvider { get; set; } = null!;
@ -69,9 +71,11 @@ namespace osu.Game.Overlays.Chat.ChannelList
{ {
base.LoadComplete(); base.LoadComplete();
SelectorActive.BindValueChanged(selector => currentChannel.BindValueChanged(channel =>
{ {
if (selector.NewValue) // This logic should be handled by the chat overlay rather than this component.
// Selected state should be moved to an abstract class and shared with ChannelListItem.
if (channel.NewValue == null)
{ {
text.FadeColour(colourProvider.Content1, 300, Easing.OutQuint); text.FadeColour(colourProvider.Content1, 300, Easing.OutQuint);
selectBox.FadeIn(300, Easing.OutQuint); selectBox.FadeIn(300, Easing.OutQuint);
@ -82,8 +86,6 @@ namespace osu.Game.Overlays.Chat.ChannelList
selectBox.FadeOut(200, Easing.OutQuint); selectBox.FadeOut(200, Easing.OutQuint);
} }
}, true); }, true);
Action = () => SelectorActive.Value = true;
} }
protected override bool OnHover(HoverEvent e) protected override bool OnHover(HoverEvent e)

View File

@ -50,8 +50,6 @@ namespace osu.Game.Overlays
private const float side_bar_width = 190; private const float side_bar_width = 190;
private const float chat_bar_height = 60; private const float chat_bar_height = 60;
private readonly BindableBool selectorActive = new BindableBool();
[Resolved] [Resolved]
private OsuConfigManager config { get; set; } = null!; private OsuConfigManager config { get; set; } = null!;
@ -100,7 +98,6 @@ namespace osu.Game.Overlays
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
Width = side_bar_width, Width = side_bar_width,
Padding = new MarginPadding { Top = top_bar_height }, Padding = new MarginPadding { Top = top_bar_height },
SelectorActive = { BindTarget = selectorActive },
}, },
new Container new Container
{ {
@ -137,7 +134,6 @@ namespace osu.Game.Overlays
Anchor = Anchor.BottomRight, Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight, Origin = Anchor.BottomRight,
Padding = new MarginPadding { Left = side_bar_width }, Padding = new MarginPadding { Left = side_bar_width },
ShowSearch = { BindTarget = selectorActive },
}, },
}; };
} }
@ -146,8 +142,6 @@ namespace osu.Game.Overlays
{ {
base.LoadComplete(); base.LoadComplete();
loading.Show();
config.BindWith(OsuSetting.ChatDisplayHeight, chatHeight); config.BindWith(OsuSetting.ChatDisplayHeight, chatHeight);
chatHeight.BindValueChanged(height => { Height = height.NewValue; }, true); chatHeight.BindValueChanged(height => { Height = height.NewValue; }, true);
@ -157,21 +151,14 @@ namespace osu.Game.Overlays
channelManager.JoinedChannels.BindCollectionChanged(joinedChannelsChanged, true); channelManager.JoinedChannels.BindCollectionChanged(joinedChannelsChanged, true);
channelManager.AvailableChannels.BindCollectionChanged(availableChannelsChanged, true); channelManager.AvailableChannels.BindCollectionChanged(availableChannelsChanged, true);
channelList.OnRequestSelect += channel => channelList.OnRequestSelect += channel => channelManager.CurrentChannel.Value = channel;
{
// Manually selecting a channel should dismiss the selector
selectorActive.Value = false;
channelManager.CurrentChannel.Value = channel;
};
channelList.OnRequestLeave += channel => channelManager.LeaveChannel(channel); channelList.OnRequestLeave += channel => channelManager.LeaveChannel(channel);
channelListing.OnRequestJoin += channel => channelManager.JoinChannel(channel); channelListing.OnRequestJoin += channel => channelManager.JoinChannel(channel, false);
channelListing.OnRequestLeave += channel => channelManager.LeaveChannel(channel); channelListing.OnRequestLeave += channel => channelManager.LeaveChannel(channel);
textBar.OnSearchTermsChanged += searchTerms => channelListing.SearchTerm = searchTerms; textBar.OnSearchTermsChanged += searchTerms => channelListing.SearchTerm = searchTerms;
textBar.OnChatMessageCommitted += handleChatMessage; textBar.OnChatMessageCommitted += handleChatMessage;
selectorActive.BindValueChanged(v => channelListing.State.Value = v.NewValue ? Visibility.Visible : Visibility.Hidden, true);
} }
/// <summary> /// <summary>
@ -191,8 +178,6 @@ namespace osu.Game.Overlays
channelManager.CurrentChannel.Value = channel; channelManager.CurrentChannel.Value = channel;
} }
selectorActive.Value = false;
channel.HighlightedMessage.Value = message; channel.HighlightedMessage.Value = message;
Show(); Show();
@ -252,22 +237,18 @@ namespace osu.Game.Overlays
{ {
Channel? newChannel = channel.NewValue; Channel? newChannel = channel.NewValue;
loading.Show();
// Channel is null when leaving the currently selected channel
if (newChannel == null) if (newChannel == null)
{ {
// Find another channel to switch to // null channel denotes that we should be showing the listing.
newChannel = channelManager.JoinedChannels.FirstOrDefault(c => c != channel.OldValue); channelListing.State.Value = Visibility.Visible;
textBar.ShowSearch.Value = true;
if (newChannel == null)
selectorActive.Value = true;
else
currentChannel.Value = newChannel;
return;
} }
else
{
channelListing.State.Value = Visibility.Hidden;
textBar.ShowSearch.Value = false;
loading.Show();
LoadComponentAsync(new DrawableChannel(newChannel), loaded => LoadComponentAsync(new DrawableChannel(newChannel), loaded =>
{ {
currentChannelContainer.Clear(); currentChannelContainer.Clear();
@ -275,6 +256,7 @@ namespace osu.Game.Overlays
loading.Hide(); loading.Hide();
}); });
} }
}
private void joinedChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) private void joinedChannelsChanged(object sender, NotifyCollectionChangedEventArgs args)
{ {