diff --git a/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallenge.cs b/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallenge.cs index 46a951dcff..e05f5f13ae 100644 --- a/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallenge.cs +++ b/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallenge.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge } }, EndDate = { Value = DateTimeOffset.Now.AddHours(12) }, - Category = { Value = RoomCategory.DailyChallenge } + Category = RoomCategory.DailyChallenge }; AddStep("add room", () => API.Perform(new CreateRoomRequest(room))); @@ -73,7 +73,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge } }, EndDate = { Value = DateTimeOffset.Now.AddHours(12) }, - Category = { Value = RoomCategory.DailyChallenge } + Category = RoomCategory.DailyChallenge }; AddStep("add room", () => API.Perform(new CreateRoomRequest(room))); @@ -102,7 +102,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge } }, EndDate = { Value = DateTimeOffset.Now.AddHours(12) }, - Category = { Value = RoomCategory.DailyChallenge } + Category = RoomCategory.DailyChallenge }; AddStep("add room", () => API.Perform(new CreateRoomRequest(room))); diff --git a/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallengeIntro.cs b/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallengeIntro.cs index 7b3595b064..33be952e20 100644 --- a/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallengeIntro.cs +++ b/osu.Game.Tests/Visual/DailyChallenge/TestSceneDailyChallengeIntro.cs @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge }, StartDate = { Value = DateTimeOffset.Now }, EndDate = { Value = DateTimeOffset.Now.AddHours(24) }, - Category = { Value = RoomCategory.DailyChallenge } + Category = RoomCategory.DailyChallenge })); }); AddStep("signal client", () => metadataClient.DailyChallengeUpdated(new DailyChallengeInfo { RoomID = roomId })); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index 17c0a159e9..07e557fe36 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -110,13 +110,13 @@ namespace osu.Game.Tests.Visual.Multiplayer { Name = "Spotlight room", Status = { Value = new RoomStatusOpen() }, - Category = { Value = RoomCategory.Spotlight }, + Category = RoomCategory.Spotlight, }), createLoungeRoom(new Room { Name = "Featured artist room", Status = { Value = new RoomStatusOpen() }, - Category = { Value = RoomCategory.FeaturedArtist }, + Category = RoomCategory.FeaturedArtist, }), } }; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs index 112fdfd9ab..8654fe1f11 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs @@ -55,20 +55,20 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("has 5 rooms", () => container.Rooms.Count == 5); AddAssert("all spotlights at top", () => container.Rooms - .SkipWhile(r => r.Room.Category.Value == RoomCategory.Spotlight) - .All(r => r.Room.Category.Value == RoomCategory.Normal)); + .SkipWhile(r => r.Room.Category == RoomCategory.Spotlight) + .All(r => r.Room.Category == RoomCategory.Normal)); AddStep("remove first room", () => RoomManager.RemoveRoom(RoomManager.Rooms.First(r => r.RoomID == 0))); AddAssert("has 4 rooms", () => container.Rooms.Count == 4); AddAssert("first room removed", () => container.Rooms.All(r => r.Room.RoomID != 0)); AddStep("select first room", () => container.Rooms.First().TriggerClick()); - AddAssert("first spotlight selected", () => checkRoomSelected(RoomManager.Rooms.First(r => r.Category.Value == RoomCategory.Spotlight))); + AddAssert("first spotlight selected", () => checkRoomSelected(RoomManager.Rooms.First(r => r.Category == RoomCategory.Spotlight))); AddStep("remove last room", () => RoomManager.RemoveRoom(RoomManager.Rooms.MinBy(r => r.RoomID))); - AddAssert("first spotlight still selected", () => checkRoomSelected(RoomManager.Rooms.First(r => r.Category.Value == RoomCategory.Spotlight))); + AddAssert("first spotlight still selected", () => checkRoomSelected(RoomManager.Rooms.First(r => r.Category == RoomCategory.Spotlight))); - AddStep("remove spotlight room", () => RoomManager.RemoveRoom(RoomManager.Rooms.Single(r => r.Category.Value == RoomCategory.Spotlight))); + AddStep("remove spotlight room", () => RoomManager.RemoveRoom(RoomManager.Rooms.Single(r => r.Category == RoomCategory.Spotlight))); AddAssert("selection vacated", () => checkRoomSelected(null)); } diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index 48282ba5e9..1a7a3f73e8 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -39,12 +39,24 @@ namespace osu.Game.Online.Rooms set => SetField(ref name, value); } + /// + /// The room host. Will be null while the room has not yet been created. + /// public APIUser? Host { get => host; set => SetField(ref host, value); } + /// + /// The room category. + /// + public RoomCategory Category + { + get => category; + set => SetField(ref category, value); + } + /// /// Represents the current item selected within the room. /// @@ -66,6 +78,10 @@ namespace osu.Game.Online.Rooms [JsonProperty("host")] private APIUser? host; + [JsonProperty("category")] + [JsonConverter(typeof(SnakeCaseStringEnumConverter))] + private RoomCategory category; + [JsonProperty("current_playlist_item")] private PlaylistItem? currentPlaylistItem; @@ -85,18 +101,6 @@ namespace osu.Game.Online.Rooms [Cached] public readonly Bindable DifficultyRange = new Bindable(); - [Cached] - public readonly Bindable Category = new Bindable(); - - // Todo: osu-framework bug (https://github.com/ppy/osu-framework/issues/4106) - [JsonProperty("category")] - [JsonConverter(typeof(SnakeCaseStringEnumConverter))] - private RoomCategory category - { - get => Category.Value; - set => Category.Value = value; - } - [Cached] public readonly Bindable MaxAttempts = new Bindable(); @@ -220,7 +224,7 @@ namespace osu.Game.Online.Rooms RoomID = other.RoomID; Name = other.Name; - Category.Value = other.Category.Value; + Category = other.Category; if (other.Host != null && Host?.Id != other.Host.Id) Host = other.Host; diff --git a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs index 0020a7dfb6..67c3586a35 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.OnlinePlay.Components req.Success += result => { - result = result.Where(r => r.Category.Value != RoomCategory.DailyChallenge).ToList(); + result = result.Where(r => r.Category != RoomCategory.DailyChallenge).ToList(); foreach (var existing in RoomManager.Rooms.ToArray()) { diff --git a/osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs b/osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs index ed39021a73..90127dc961 100644 --- a/osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Components/StatusColouredContainer.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -17,13 +15,13 @@ namespace osu.Game.Screens.OnlinePlay.Components private readonly double transitionDuration; [Resolved(typeof(Room), nameof(Room.Status))] - private Bindable status { get; set; } + private Bindable status { get; set; } = null!; - [Resolved(typeof(Room), nameof(Room.Category))] - private Bindable category { get; set; } + private readonly Room room; - public StatusColouredContainer(double transitionDuration = 100) + public StatusColouredContainer(Room room, double transitionDuration = 100) { + this.room = room; this.transitionDuration = transitionDuration; } @@ -32,7 +30,7 @@ namespace osu.Game.Screens.OnlinePlay.Components { status.BindValueChanged(s => { - this.FadeColour(colours.ForRoomCategory(category.Value) ?? s.NewValue.GetAppropriateColour(colours), transitionDuration); + this.FadeColour(colours.ForRoomCategory(room.Category) ?? s.NewValue.GetAppropriateColour(colours), transitionDuration); }, true); } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 99809a2a50..8b2f2bfe4a 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -164,7 +164,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft }, - specialCategoryPill = new RoomSpecialCategoryPill + specialCategoryPill = new RoomSpecialCategoryPill(Room) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft @@ -259,15 +259,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components wrapper.FadeInFromZero(200); - roomCategory.BindTo(Room.Category); - roomCategory.BindValueChanged(c => - { - if (c.NewValue > RoomCategory.Normal) - specialCategoryPill.Show(); - else - specialCategoryPill.Hide(); - }, true); - roomType.BindTo(Room.Type); roomType.BindValueChanged(t => { @@ -278,6 +269,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components hasPassword.BindValueChanged(v => passwordIcon.Alpha = v.NewValue ? 1 : 0, true); updateRoomName(); + updateRoomCategory(); }; SelectedItem.BindValueChanged(item => background.Beatmap.Value = item.NewValue?.Beatmap, true); @@ -285,8 +277,16 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e) { - if (e.PropertyName == nameof(Room.Name)) - updateRoomName(); + switch (e.PropertyName) + { + case nameof(Room.Name): + updateRoomName(); + break; + + case nameof(Room.Category): + updateRoomCategory(); + break; + } } private void updateRoomName() @@ -295,6 +295,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components roomName.Text = Room.Name; } + private void updateRoomCategory() + { + if (Room.Category > RoomCategory.Normal) + specialCategoryPill?.Show(); + else + specialCategoryPill?.Hide(); + } + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { return new CachedModelDependencyContainer(base.CreateChildDependencies(parent)) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomSpecialCategoryPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomSpecialCategoryPill.cs index 9b8954bb33..9bb3a59d0c 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomSpecialCategoryPill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomSpecialCategoryPill.cs @@ -1,21 +1,30 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.ComponentModel; using osu.Framework.Allocation; using osu.Framework.Extensions; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; +using osu.Game.Online.Rooms; using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public partial class RoomSpecialCategoryPill : OnlinePlayPill { + private readonly Room room; + [Resolved] private OsuColour colours { get; set; } = null!; protected override FontUsage Font => base.Font.With(weight: FontWeight.SemiBold); + public RoomSpecialCategoryPill(Room room) + { + this.room = room; + } + protected override void LoadComplete() { base.LoadComplete(); @@ -23,11 +32,26 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Pill.Background.Alpha = 1; TextFlow.Colour = Color4.Black; - Category.BindValueChanged(c => - { - TextFlow.Text = c.NewValue.GetLocalisableDescription(); - Pill.Background.Colour = colours.ForRoomCategory(c.NewValue) ?? colours.Pink; - }, true); + room.PropertyChanged += onRoomPropertyChanged; + updateRoomCategory(); + } + + private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(Room.Category)) + updateRoomCategory(); + } + + private void updateRoomCategory() + { + TextFlow.Text = room.Category.GetLocalisableDescription(); + Pill.Background.Colour = colours.ForRoomCategory(room.Category) ?? colours.Pink; + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + room.PropertyChanged -= onRoomPropertyChanged; } } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index 3d9b7a46d0..f197a7d018 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -169,7 +169,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { foreach (var room in roomFlow) { - roomFlow.SetLayoutPosition(room, room.Room.Category.Value > RoomCategory.Normal + roomFlow.SetLayoutPosition(room, room.Room.Category > RoomCategory.Normal // Always show spotlight playlists at the top of the listing. ? float.MinValue : -(room.Room.RoomID ?? 0)); diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs index a277b3771b..1fc177ce0b 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -66,7 +66,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge AddRangeInternal(new Drawable[] { - new StatusColouredContainer(transition_duration) + new StatusColouredContainer(Room, transition_duration) { RelativeSizeAxes = Axes.Both, Child = selectionBox = new Container diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs index 4c614bba8f..0a51dcc8eb 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs @@ -31,9 +31,6 @@ namespace osu.Game.Screens.OnlinePlay [Resolved(typeof(Room))] protected Bindable DifficultyRange { get; private set; } = null!; - [Resolved(typeof(Room))] - protected Bindable Category { get; private set; } = null!; - [Resolved(typeof(Room))] protected BindableList RecentParticipants { get; private set; } = null!; diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs index b0f91ca0b9..07dd57eb68 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs @@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay Name = $@"Room {currentRoomId}", Host = new APIUser { Username = @"Host" }, EndDate = { Value = DateTimeOffset.Now + TimeSpan.FromSeconds(10) }, - Category = { Value = withSpotlightRooms && i % 2 == 0 ? RoomCategory.Spotlight : RoomCategory.Normal }, + Category = withSpotlightRooms && i % 2 == 0 ? RoomCategory.Spotlight : RoomCategory.Normal, }; if (withPassword)