diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomPanel.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomPanel.cs index fee5e62958..037c5faae3 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomPanel.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomPanel.cs @@ -165,23 +165,75 @@ namespace osu.Game.Tests.Visual.Multiplayer Name = "A host-only room", QueueMode = QueueMode.HostOnly, Type = MatchType.HeadToHead, + RoomID = 1337, }), new MultiplayerRoomPanel(new Room { Name = "An all-players, team-versus room", QueueMode = QueueMode.AllPlayers, - Type = MatchType.TeamVersus + Type = MatchType.TeamVersus, + RoomID = 1338, }), new MultiplayerRoomPanel(new Room { Name = "A round-robin room", QueueMode = QueueMode.AllPlayersRoundRobin, - Type = MatchType.HeadToHead + Type = MatchType.HeadToHead, + RoomID = 1339, }), } }); } + [Test] + public void TestRoomWithLongTitle() + { + AddStep("create rooms", () => Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + Children = new[] + { + new MultiplayerRoomPanel(new Room + { + Name = "This room has a very very long title enough to make the external link button reach the participants list on the right side unless the test window is very wide, at which point I don't know, hi.", + QueueMode = QueueMode.HostOnly, + Type = MatchType.HeadToHead, + RoomID = 1337, + }), + } + }); + } + + [Test] + public void TestRoomWithUpdatedRoomID() + { + Room room = null!; + + AddStep("create rooms", () => Child = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Direction = FillDirection.Vertical, + Spacing = new Vector2(5), + Children = new[] + { + new MultiplayerRoomPanel(room = new Room + { + Name = "This room has a very very long title enough to make the external link button reach the participants list on the right side unless the test window is very wide, at which point I don't know, hi.", + QueueMode = QueueMode.HostOnly, + Type = MatchType.HeadToHead, + }), + } + }); + AddWaitStep("wait", 3); + AddStep("set room ID", () => room.RoomID = 1337); + AddWaitStep("wait", 3); + AddStep("clear room ID", () => room.RoomID = null); + } + private RoomPanel createLoungeRoom(Room room) { room.Host ??= new APIUser { Username = "peppy", Id = 2 }; diff --git a/osu.Game/Online/Rooms/RoomExtensions.cs b/osu.Game/Online/Rooms/RoomExtensions.cs new file mode 100644 index 0000000000..b7348e8997 --- /dev/null +++ b/osu.Game/Online/Rooms/RoomExtensions.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Game.Online.API; + +namespace osu.Game.Online.Rooms +{ + public static class RoomExtensions + { + /// + /// Get the room page URL, or null if unavailable. + /// + public static string? GetOnlineURL(this Room room, IAPIProvider api) + { + if (!room.RoomID.HasValue) + return null; + + return $@"{api.Endpoints.WebsiteUrl}/multiplayer/rooms/{room.RoomID.Value}"; + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomPanel.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomPanel.cs index acbf5d8462..b9f84b4fa4 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomPanel.cs @@ -17,6 +17,7 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Database; @@ -54,11 +55,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components protected readonly Bindable SelectedItem = new Bindable(); protected Container ButtonsContainer { get; private set; } = null!; + protected bool ShowExternalLink { get; init; } = true; + private DrawableRoomParticipantsList? drawableRoomParticipantsList; private RoomSpecialCategoryPill? specialCategoryPill; private PasswordProtectedIcon? passwordIcon; private EndDateInfo? endDateInfo; - private SpriteText? roomName; + private RoomNameLine? roomName; private DelayedLoadWrapper wrapper = null!; private CancellationTokenSource? beatmapLookupCancellation; @@ -204,11 +207,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Direction = FillDirection.Vertical, Children = new Drawable[] { - roomName = new TruncatingSpriteText - { - RelativeSizeAxes = Axes.X, - Font = OsuFont.GetFont(size: 28) - }, + roomName = new RoomNameLine(), new RoomStatusText(Room) { Beatmap = { BindTarget = currentBeatmap } @@ -279,6 +278,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components wrapper.FadeInFromZero(200); + updateRoomID(); updateRoomName(); updateRoomCategory(); updateRoomType(); @@ -292,6 +292,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { switch (e.PropertyName) { + case nameof(Room.RoomID): + updateRoomID(); + break; + case nameof(Room.Name): updateRoomName(); break; @@ -335,6 +339,12 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }), cancellationSource.Token); } + private void updateRoomID() + { + if (roomName != null && ShowExternalLink) + roomName.Link = Room.GetOnlineURL(api); + } + private void updateRoomName() { if (roomName != null) @@ -381,17 +391,17 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { var items = new List(); - if (Room.RoomID.HasValue) + string? url = Room.GetOnlineURL(api); + + if (url != null) { items.AddRange([ - new OsuMenuItem("View in browser", MenuItemType.Standard, () => game?.OpenUrlExternally(formatRoomUrl(Room.RoomID.Value))), - new OsuMenuItem("Copy link", MenuItemType.Standard, () => game?.CopyToClipboard(formatRoomUrl(Room.RoomID.Value))) + new OsuMenuItem("View in browser", MenuItemType.Standard, () => game?.OpenUrlExternally(url)), + new OsuMenuItem("Copy link", MenuItemType.Standard, () => game?.CopyToClipboard(url)) ]); } return items.ToArray(); - - string formatRoomUrl(long id) => $@"{api.Endpoints.WebsiteUrl}/multiplayer/rooms/{id}"; } } @@ -556,5 +566,71 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }; } } + + public partial class RoomNameLine : FillFlowContainer + { + private TruncatingSpriteText spriteText = null!; + private ExternalLinkButton linkButton = null!; + + public LocalisableString Text + { + get => spriteText.Text; + set => spriteText.Text = value; + } + + private string? link; + + public string? Link + { + get => link; + set + { + link = value; + updateLink(); + } + } + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Direction = FillDirection.Horizontal; + + Children = new Drawable[] + { + spriteText = new TruncatingSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Font = OsuFont.GetFont(size: 28), + }, + linkButton = new ExternalLinkButton + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Margin = new MarginPadding { Horizontal = 6, Bottom = 4 }, + Alpha = 0f, + }, + }; + } + + private void updateLink() + { + if (link == null) + linkButton.Hide(); + else + { + linkButton.Show(); + linkButton.Link = link; + } + } + + protected override void Update() + { + base.Update(); + spriteText.MaxWidth = DrawWidth - linkButton.LayoutSize.X; + } + } } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeRoomPanel.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeRoomPanel.cs index 3ff27a14bb..12b38a9677 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeRoomPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeRoomPanel.cs @@ -67,6 +67,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge public LoungeRoomPanel(Room room) : base(room) { + ShowExternalLink = false; } [BackgroundDependencyLoader]