diff --git a/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingChatDisplay.cs b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingChatDisplay.cs new file mode 100644 index 0000000000..d8e42cd946 --- /dev/null +++ b/osu.Game.Tests/Visual/Matchmaking/TestSceneMatchmakingChatDisplay.cs @@ -0,0 +1,49 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Online.Rooms; +using osu.Game.Overlays; +using osu.Game.Screens; +using osu.Game.Screens.OnlinePlay.Matchmaking.Match; +using osuTK; + +namespace osu.Game.Tests.Visual.Matchmaking +{ + public partial class TestSceneMatchmakingChatDisplay : ScreenTestScene + { + private MatchmakingChatDisplay? chat; + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("add chat", () => + { + chat?.Expire(); + + ScreenFooter.Add(chat = new MatchmakingChatDisplay(new Room()) + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Size = new Vector2(700, 130), + Margin = new MarginPadding { Bottom = 10, Right = WaveOverlayContainer.WIDTH_PADDING - OsuScreen.HORIZONTAL_OVERFLOW_PADDING }, + Alpha = 0 + }); + }); + + AddStep("show footer", () => ScreenFooter.Show()); + } + + [Test] + public void TestAppearDisappear() + { + AddStep("appear", () => chat!.Appear()); + AddWaitStep("wait for animation", 3); + + AddStep("disappear", () => chat!.Disappear()); + AddWaitStep("wait for animation", 3); + } + } +} diff --git a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs index d7f79d3e30..877dc7eaac 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneStandAloneChatDisplay.cs @@ -471,7 +471,7 @@ namespace osu.Game.Tests.Visual.Online public DrawableChannel DrawableChannel => InternalChildren.OfType().First(); - public ChannelScrollContainer ScrollContainer => (ChannelScrollContainer)((Container)DrawableChannel.Child).Child; + public ChannelScrollContainer ScrollContainer => DrawableChannel.ChildrenOfType().Single(); public FillFlowContainer FillFlow => (FillFlowContainer)ScrollContainer.Child; diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 2f0461eb40..ad327f4b28 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -12,7 +12,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Graphics.Cursor; using osu.Game.Online.Chat; using osuTK.Graphics; @@ -49,25 +48,20 @@ namespace osu.Game.Overlays.Chat [BackgroundDependencyLoader] private void load() { - Child = new OsuContextMenuContainer + Child = scroll = new ChannelScrollContainer { + ScrollbarVisible = scrollbarVisible, RelativeSizeAxes = Axes.Both, - Masking = true, - Child = scroll = new ChannelScrollContainer + // Some chat lines have effects that slightly protrude to the bottom, + // which we do not want to mask away, hence the padding. + Padding = new MarginPadding { Bottom = 5 }, + Child = ChatLineFlow = new FillFlowContainer { - ScrollbarVisible = scrollbarVisible, - RelativeSizeAxes = Axes.Both, - // Some chat lines have effects that slightly protrude to the bottom, - // which we do not want to mask away, hence the padding. - Padding = new MarginPadding { Bottom = 5 }, - Child = ChatLineFlow = new FillFlowContainer - { - Padding = new MarginPadding { Left = 3, Right = 10 }, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - } - }, + Padding = new MarginPadding { Left = 3, Right = 10 }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + } }; newMessagesArrived(Channel.Messages); diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 7f4ba3e2e2..e7422d6f86 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -19,6 +19,7 @@ using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Online; @@ -142,9 +143,13 @@ namespace osu.Game.Overlays new PopoverContainer { RelativeSizeAxes = Axes.Both, - Child = currentChannelContainer = new Container + Child = new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, + Child = currentChannelContainer = new Container + { + RelativeSizeAxes = Axes.Both, + } } }, loading = new LoadingLayer(true), diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingChatDisplay.cs index 4ff6a3cdf6..6a01642907 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/MatchmakingChatDisplay.cs @@ -2,6 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Transforms; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Input; @@ -66,5 +68,23 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match public void OnReleased(KeyBindingReleaseEvent e) { } + + public void Appear() + { + FinishTransforms(); + + this.MoveToY(150f) + .FadeOut() + .MoveToY(0f, 240, Easing.OutCubic) + .FadeIn(240, Easing.OutCubic); + } + + public TransformSequence Disappear() + { + FinishTransforms(); + + return this.FadeOut(240, Easing.InOutCubic) + .MoveToY(150f, 240, Easing.InOutCubic); + } } } diff --git a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs index 9292287c3c..95e3cb0236 100644 --- a/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs +++ b/osu.Game/Screens/OnlinePlay/Matchmaking/Match/ScreenMatchmaking.cs @@ -29,10 +29,10 @@ using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Overlays.Dialog; using osu.Game.Rulesets; -using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.OnlinePlay.Matchmaking.Match.Gameplay; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Users; +using osuTK; using osuTK.Input; namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match @@ -87,19 +87,27 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match private MusicController music { get; set; } = null!; private readonly MultiplayerRoom room; + private readonly MatchmakingChatDisplay chat; private Sample? sampleStart; private CancellationTokenSource? downloadCheckCancellation; private int? lastDownloadCheckedBeatmapId; - private MatchChatDisplay chat = null!; - public ScreenMatchmaking(MultiplayerRoom room) { this.room = room; Activity.Value = new UserActivity.InLobby(room); Padding = new MarginPadding { Horizontal = -HORIZONTAL_OVERFLOW_PADDING }; + + chat = new MatchmakingChatDisplay(new Room(room)) + { + Anchor = Anchor.BottomRight, + Origin = Anchor.BottomRight, + Size = new Vector2(700, 130), + Margin = new MarginPadding { Bottom = 10, Right = WaveOverlayContainer.WIDTH_PADDING - HORIZONTAL_OVERFLOW_PADDING }, + Alpha = 0 + }; } [BackgroundDependencyLoader] @@ -156,13 +164,8 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Width = 700, - Height = 130, - Padding = new MarginPadding { Bottom = row_padding }, - Child = chat = new MatchmakingChatDisplay(new Room(room)) - { - RelativeSizeAxes = Axes.Both, - } + Size = new Vector2(700, 130), + Margin = new MarginPadding { Bottom = row_padding } } ] } @@ -183,7 +186,7 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match beatmapAvailabilityTracker.Availability.BindValueChanged(onBeatmapAvailabilityChanged, true); - Footer!.Add(chat.CreateProxy()); + Footer?.Add(new ChatContainer(chat)); } private void onRoomUpdated() @@ -326,12 +329,16 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match public override void OnEntering(ScreenTransitionEvent e) { base.OnEntering(e); + + chat.Appear(); beginHandlingTrack(); } public override void OnSuspending(ScreenTransitionEvent e) { - onLeaving(); + chat.Disappear(); + endHandlingTrack(); + base.OnSuspending(e); } @@ -347,7 +354,9 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match return true; } - onLeaving(); + chat.Disappear().Expire(); + endHandlingTrack(); + client.LeaveRoom().FireAndForget(); return false; } @@ -370,6 +379,8 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match public override void OnResuming(ScreenTransitionEvent e) { base.OnResuming(e); + + chat.Appear(); beginHandlingTrack(); if (e.Last is not MultiplayerPlayerLoader playerLoader) @@ -384,11 +395,6 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match client.ChangeState(MultiplayerUserState.Idle); } - private void onLeaving() - { - endHandlingTrack(); - } - /// /// Handles changes in the track to keep it looping while active. /// @@ -439,5 +445,32 @@ namespace osu.Game.Screens.OnlinePlay.Matchmaking.Match client.LoadRequested -= onLoadRequested; } } + + // Contains the chat display and a context menu container for it. Shared lifetime with the chat display (expires along with it). + private partial class ChatContainer : CompositeDrawable + { + public override double LifetimeStart => chat.LifetimeStart; + public override double LifetimeEnd => chat.LifetimeEnd; + + private readonly MatchmakingChatDisplay chat; + + public ChatContainer(MatchmakingChatDisplay chat) + { + this.chat = chat; + + Anchor = Anchor.BottomRight; + Origin = Anchor.BottomRight; + + // This component is added to the screen footer which is only about 50px high. + // Therefore, it's given a large absolute size to give the context menu enough space to display correctly. + Size = new Vector2(700); + + InternalChild = new OsuContextMenuContainer + { + RelativeSizeAxes = Axes.Both, + Child = chat + }; + } + } } }