1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 19:22:54 +08:00

Merge branch 'master' into fix-skin-layout-editor-crash

This commit is contained in:
Bartłomiej Dach 2021-10-24 12:58:56 +02:00
commit d24fbc6ade
No known key found for this signature in database
GPG Key ID: BCECCD4FA41F6497
16 changed files with 393 additions and 255 deletions

View File

@ -0,0 +1,167 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Rooms;
using osu.Game.Overlays;
using osu.Game.Screens.OnlinePlay.Lounge;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneDrawableLoungeRoom : OsuManualInputManagerTestScene
{
private readonly Room room = new Room
{
HasPassword = { Value = true }
};
[Cached]
protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Pink);
private DrawableLoungeRoom drawableRoom;
private SearchTextBox searchTextBox;
private readonly ManualResetEventSlim allowResponseCallback = new ManualResetEventSlim();
[BackgroundDependencyLoader]
private void load()
{
var mockLounge = new Mock<LoungeSubScreen>();
mockLounge
.Setup(l => l.Join(It.IsAny<Room>(), It.IsAny<string>(), It.IsAny<Action<Room>>(), It.IsAny<Action<string>>()))
.Callback<Room, string, Action<Room>, Action<string>>((a, b, c, d) =>
{
Task.Run(() =>
{
allowResponseCallback.Wait();
allowResponseCallback.Reset();
Schedule(() => d?.Invoke("Incorrect password"));
});
});
Dependencies.CacheAs(mockLounge.Object);
}
[SetUpSteps]
public void SetUpSteps()
{
AddStep("create drawable", () =>
{
Child = new PopoverContainer
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
searchTextBox = new SearchTextBox
{
HoldFocus = true,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Margin = new MarginPadding(50),
Width = 500,
Depth = float.MaxValue
},
drawableRoom = new DrawableLoungeRoom(room)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}
}
};
});
}
[Test]
public void TestFocusViaKeyboardCommit()
{
DrawableLoungeRoom.PasswordEntryPopover popover = null;
AddAssert("search textbox has focus", () => checkFocus(searchTextBox));
AddStep("click room twice", () =>
{
InputManager.MoveMouseTo(drawableRoom);
InputManager.Click(MouseButton.Left);
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for popover", () => (popover = InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().SingleOrDefault()) != null);
AddAssert("textbox has focus", () => checkFocus(popover.ChildrenOfType<OsuPasswordTextBox>().Single()));
AddStep("enter password", () => popover.ChildrenOfType<OsuPasswordTextBox>().Single().Text = "password");
AddStep("commit via enter", () => InputManager.Key(Key.Enter));
AddAssert("popover has focus", () => checkFocus(popover));
AddStep("attempt another enter", () => InputManager.Key(Key.Enter));
AddAssert("popover still has focus", () => checkFocus(popover));
AddStep("unblock response", () => allowResponseCallback.Set());
AddUntilStep("wait for textbox refocus", () => checkFocus(popover.ChildrenOfType<OsuPasswordTextBox>().Single()));
AddStep("press escape", () => InputManager.Key(Key.Escape));
AddStep("press escape", () => InputManager.Key(Key.Escape));
AddUntilStep("search textbox has focus", () => checkFocus(searchTextBox));
}
[Test]
public void TestFocusViaMouseCommit()
{
DrawableLoungeRoom.PasswordEntryPopover popover = null;
AddAssert("search textbox has focus", () => checkFocus(searchTextBox));
AddStep("click room twice", () =>
{
InputManager.MoveMouseTo(drawableRoom);
InputManager.Click(MouseButton.Left);
InputManager.Click(MouseButton.Left);
});
AddUntilStep("wait for popover", () => (popover = InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().SingleOrDefault()) != null);
AddAssert("textbox has focus", () => checkFocus(popover.ChildrenOfType<OsuPasswordTextBox>().Single()));
AddStep("enter password", () => popover.ChildrenOfType<OsuPasswordTextBox>().Single().Text = "password");
AddStep("commit via click button", () =>
{
var button = popover.ChildrenOfType<OsuButton>().Single();
InputManager.MoveMouseTo(button);
InputManager.Click(MouseButton.Left);
});
AddAssert("popover has focus", () => checkFocus(popover));
AddStep("attempt another click", () => InputManager.Click(MouseButton.Left));
AddAssert("popover still has focus", () => checkFocus(popover));
AddStep("unblock response", () => allowResponseCallback.Set());
AddUntilStep("wait for textbox refocus", () => checkFocus(popover.ChildrenOfType<OsuPasswordTextBox>().Single()));
AddStep("click away", () =>
{
InputManager.MoveMouseTo(searchTextBox);
InputManager.Click(MouseButton.Left);
});
AddUntilStep("search textbox has focus", () => checkFocus(searchTextBox));
}
private bool checkFocus(Drawable expected) =>
InputManager.FocusedDrawable == expected;
}
}

View File

@ -5,6 +5,7 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Testing;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Catch;
@ -25,12 +26,18 @@ namespace osu.Game.Tests.Visual.Multiplayer
[SetUp]
public new void Setup() => Schedule(() =>
{
Child = container = new RoomsContainer
Child = new PopoverContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Width = 0.5f,
SelectedRoom = { BindTarget = SelectedRoom }
Child = container = new RoomsContainer
{
SelectedRoom = { BindTarget = SelectedRoom }
}
};
});

View File

@ -107,27 +107,15 @@ namespace osu.Game.Beatmaps
[NotMapped]
[JsonIgnore]
public DateTimeOffset Submitted
{
get => OnlineInfo.Submitted;
set => OnlineInfo.Submitted = value;
}
public DateTimeOffset Submitted => OnlineInfo.Submitted;
[NotMapped]
[JsonIgnore]
public DateTimeOffset? Ranked
{
get => OnlineInfo.Ranked;
set => OnlineInfo.Ranked = value;
}
public DateTimeOffset? Ranked => OnlineInfo.Ranked;
[NotMapped]
[JsonIgnore]
public DateTimeOffset? LastUpdated
{
get => OnlineInfo.LastUpdated;
set => OnlineInfo.LastUpdated = value;
}
public DateTimeOffset? LastUpdated => OnlineInfo.LastUpdated;
[NotMapped]
[JsonIgnore]
@ -135,107 +123,55 @@ namespace osu.Game.Beatmaps
[NotMapped]
[JsonIgnore]
public bool HasExplicitContent
{
get => OnlineInfo.HasExplicitContent;
set => OnlineInfo.HasExplicitContent = value;
}
public bool HasExplicitContent => OnlineInfo.HasExplicitContent;
[NotMapped]
[JsonIgnore]
public bool HasVideo
{
get => OnlineInfo.HasVideo;
set => OnlineInfo.HasVideo = value;
}
public bool HasVideo => OnlineInfo.HasVideo;
[NotMapped]
[JsonIgnore]
public bool HasStoryboard
{
get => OnlineInfo.HasStoryboard;
set => OnlineInfo.HasStoryboard = value;
}
public bool HasStoryboard => OnlineInfo.HasStoryboard;
[NotMapped]
[JsonIgnore]
public BeatmapSetOnlineCovers Covers
{
get => OnlineInfo.Covers;
set => OnlineInfo.Covers = value;
}
public BeatmapSetOnlineCovers Covers => OnlineInfo.Covers;
[NotMapped]
[JsonIgnore]
public string Preview
{
get => OnlineInfo.Preview;
set => OnlineInfo.Preview = value;
}
public string Preview => OnlineInfo.Preview;
[NotMapped]
[JsonIgnore]
public double BPM
{
get => OnlineInfo.BPM;
set => OnlineInfo.BPM = value;
}
public double BPM => OnlineInfo.BPM;
[NotMapped]
[JsonIgnore]
public int PlayCount
{
get => OnlineInfo.PlayCount;
set => OnlineInfo.PlayCount = value;
}
public int PlayCount => OnlineInfo.PlayCount;
[NotMapped]
[JsonIgnore]
public int FavouriteCount
{
get => OnlineInfo.FavouriteCount;
set => OnlineInfo.FavouriteCount = value;
}
public int FavouriteCount => OnlineInfo.FavouriteCount;
[NotMapped]
[JsonIgnore]
public bool HasFavourited
{
get => OnlineInfo.HasFavourited;
set => OnlineInfo.HasFavourited = value;
}
public bool HasFavourited => OnlineInfo.HasFavourited;
[NotMapped]
[JsonIgnore]
public BeatmapSetOnlineAvailability Availability
{
get => OnlineInfo.Availability;
set => OnlineInfo.Availability = value;
}
public BeatmapSetOnlineAvailability Availability => OnlineInfo.Availability;
[NotMapped]
[JsonIgnore]
public BeatmapSetOnlineGenre Genre
{
get => OnlineInfo.Genre;
set => OnlineInfo.Genre = value;
}
public BeatmapSetOnlineGenre Genre => OnlineInfo.Genre;
[NotMapped]
[JsonIgnore]
public BeatmapSetOnlineLanguage Language
{
get => OnlineInfo.Language;
set => OnlineInfo.Language = value;
}
public BeatmapSetOnlineLanguage Language => OnlineInfo.Language;
[NotMapped]
[JsonIgnore]
public int? TrackId
{
get => OnlineInfo.TrackId;
set => OnlineInfo.TrackId = value;
}
public int? TrackId => OnlineInfo?.TrackId;
#endregion
}

View File

@ -15,87 +15,87 @@ namespace osu.Game.Beatmaps
/// <summary>
/// The date this beatmap set was submitted to the online listing.
/// </summary>
DateTimeOffset Submitted { get; set; }
DateTimeOffset Submitted { get; }
/// <summary>
/// The date this beatmap set was ranked.
/// </summary>
DateTimeOffset? Ranked { get; set; }
DateTimeOffset? Ranked { get; }
/// <summary>
/// The date this beatmap set was last updated.
/// </summary>
DateTimeOffset? LastUpdated { get; set; }
DateTimeOffset? LastUpdated { get; }
/// <summary>
/// The status of this beatmap set.
/// </summary>
BeatmapSetOnlineStatus Status { get; set; }
BeatmapSetOnlineStatus Status { get; }
/// <summary>
/// Whether or not this beatmap set has explicit content.
/// </summary>
bool HasExplicitContent { get; set; }
bool HasExplicitContent { get; }
/// <summary>
/// Whether or not this beatmap set has a background video.
/// </summary>
bool HasVideo { get; set; }
bool HasVideo { get; }
/// <summary>
/// Whether or not this beatmap set has a storyboard.
/// </summary>
bool HasStoryboard { get; set; }
bool HasStoryboard { get; }
/// <summary>
/// The different sizes of cover art for this beatmap set.
/// </summary>
BeatmapSetOnlineCovers Covers { get; set; }
BeatmapSetOnlineCovers Covers { get; }
/// <summary>
/// A small sample clip of this beatmap set's song.
/// </summary>
string Preview { get; set; }
string Preview { get; }
/// <summary>
/// The beats per minute of this beatmap set's song.
/// </summary>
double BPM { get; set; }
double BPM { get; }
/// <summary>
/// The amount of plays this beatmap set has.
/// </summary>
int PlayCount { get; set; }
int PlayCount { get; }
/// <summary>
/// The amount of people who have favourited this beatmap set.
/// </summary>
int FavouriteCount { get; set; }
int FavouriteCount { get; }
/// <summary>
/// Whether this beatmap set has been favourited by the current user.
/// </summary>
bool HasFavourited { get; set; }
bool HasFavourited { get; }
/// <summary>
/// The availability of this beatmap set.
/// </summary>
BeatmapSetOnlineAvailability Availability { get; set; }
BeatmapSetOnlineAvailability Availability { get; }
/// <summary>
/// The song genre of this beatmap set.
/// </summary>
BeatmapSetOnlineGenre Genre { get; set; }
BeatmapSetOnlineGenre Genre { get; }
/// <summary>
/// The song language of this beatmap set.
/// </summary>
BeatmapSetOnlineLanguage Language { get; set; }
BeatmapSetOnlineLanguage Language { get; }
/// <summary>
/// The track ID of this beatmap set.
/// Non-null only if the track is linked to a featured artist track entry.
/// </summary>
int? TrackId { get; set; }
int? TrackId { get; }
}
}

View File

@ -218,7 +218,9 @@ namespace osu.Game.Configuration
rawValue: skinName,
name: SkinSettingsStrings.SkinSectionHeader,
value: skinName,
shortcut: $"{GlobalActionKeyBindingStrings.RandomSkin}: {LookupKeyBindings(GlobalAction.RandomSkin)}"
shortcut: new TranslatableString(@"_", @"{0}: {1}",
GlobalActionKeyBindingStrings.RandomSkin,
LookupKeyBindings(GlobalAction.RandomSkin))
);
}),
new TrackedSetting<float>(OsuSetting.UIScale, scale => new SettingDescription(

View File

@ -10,7 +10,7 @@ using osu.Game.Rulesets;
namespace osu.Game.Online.API.Requests.Responses
{
public class APIBeatmap : BeatmapMetadata, IBeatmapInfo
public class APIBeatmap : IBeatmapInfo
{
[JsonProperty(@"id")]
public int OnlineID { get; set; }
@ -24,6 +24,9 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty("checksum")]
public string Checksum { get; set; } = string.Empty;
[JsonProperty(@"user_id")]
public int AuthorID { get; set; }
[JsonProperty(@"beatmapset")]
public APIBeatmapSet? BeatmapSet { get; set; }
@ -51,8 +54,10 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"accuracy")]
private float overallDifficulty { get; set; }
public double Length => lengthInSeconds * 1000;
[JsonProperty(@"total_length")]
public double Length { get; set; }
private double lengthInSeconds { get; set; }
[JsonProperty(@"count_circles")]
private int circleCount { get; set; }
@ -75,7 +80,7 @@ namespace osu.Game.Online.API.Requests.Responses
return new BeatmapInfo
{
Metadata = set?.Metadata ?? this,
Metadata = set?.Metadata ?? new BeatmapMetadata(),
Ruleset = rulesets.GetRuleset(RulesetID),
StarDifficulty = StarRating,
OnlineBeatmapID = OnlineID,
@ -106,7 +111,7 @@ namespace osu.Game.Online.API.Requests.Responses
#region Implementation of IBeatmapInfo
public IBeatmapMetadataInfo Metadata => this;
public IBeatmapMetadataInfo Metadata => (BeatmapSet as IBeatmapSetInfo)?.Metadata ?? new BeatmapMetadata();
public IBeatmapDifficultyInfo Difficulty => new BeatmapDifficulty
{

View File

@ -8,12 +8,13 @@ using Newtonsoft.Json;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Rulesets;
using osu.Game.Users;
#nullable enable
namespace osu.Game.Online.API.Requests.Responses
{
public class APIBeatmapSet : BeatmapMetadata, IBeatmapSetOnlineInfo, IBeatmapSetInfo
public class APIBeatmapSet : IBeatmapSetOnlineInfo, IBeatmapSetInfo
{
[JsonProperty(@"covers")]
public BeatmapSetOnlineCovers Covers { get; set; }
@ -63,10 +64,44 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"track_id")]
public int? TrackId { get; set; }
public string Title { get; set; } = string.Empty;
[JsonProperty("title_unicode")]
public string TitleUnicode { get; set; } = string.Empty;
public string Artist { get; set; } = string.Empty;
[JsonProperty("artist_unicode")]
public string ArtistUnicode { get; set; } = string.Empty;
public User? Author = new User();
/// <summary>
/// Helper property to deserialize a username to <see cref="User"/>.
/// </summary>
[JsonProperty(@"user_id")]
private int creatorId
public int AuthorID
{
set => Author.Id = value;
get => Author?.Id ?? 1;
set
{
Author ??= new User();
Author.Id = value;
}
}
/// <summary>
/// Helper property to deserialize a username to <see cref="User"/>.
/// </summary>
[JsonProperty(@"creator")]
public string AuthorString
{
get => Author?.Username ?? string.Empty;
set
{
Author ??= new User();
Author.Username = value;
}
}
[JsonProperty(@"availability")]
@ -78,6 +113,11 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"language")]
public BeatmapSetOnlineLanguage Language { get; set; }
public string Source { get; set; } = string.Empty;
[JsonProperty(@"tags")]
public string Tags { get; set; } = string.Empty;
[JsonProperty(@"beatmaps")]
private IEnumerable<APIBeatmap> beatmaps { get; set; } = Array.Empty<APIBeatmap>();
@ -86,7 +126,7 @@ namespace osu.Game.Online.API.Requests.Responses
var beatmapSet = new BeatmapSetInfo
{
OnlineBeatmapSetID = OnlineID,
Metadata = this,
Metadata = metadata,
Status = Status,
Metrics = new BeatmapSetMetrics { Ratings = ratings },
OnlineInfo = this
@ -103,11 +143,23 @@ namespace osu.Game.Online.API.Requests.Responses
return beatmapSet;
}
private BeatmapMetadata metadata => new BeatmapMetadata
{
Title = Title,
TitleUnicode = TitleUnicode,
Artist = Artist,
ArtistUnicode = ArtistUnicode,
AuthorID = AuthorID,
Author = Author,
Source = Source,
Tags = Tags,
};
#region Implementation of IBeatmapSetInfo
IEnumerable<IBeatmapInfo> IBeatmapSetInfo.Beatmaps => beatmaps;
IBeatmapMetadataInfo IBeatmapSetInfo.Metadata => this;
IBeatmapMetadataInfo IBeatmapSetInfo.Metadata => metadata;
DateTimeOffset IBeatmapSetInfo.DateAdded => throw new NotImplementedException();
IEnumerable<INamedFileUsage> IBeatmapSetInfo.Files => throw new NotImplementedException();

View File

@ -2,8 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using Newtonsoft.Json;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
namespace osu.Game.Online.API.Requests.Responses
{
@ -16,17 +14,19 @@ namespace osu.Game.Online.API.Requests.Responses
public int PlayCount { get; set; }
[JsonProperty("beatmap")]
private BeatmapInfo beatmapInfo { get; set; }
private APIBeatmap beatmap { get; set; }
[JsonProperty]
private APIBeatmapSet beatmapSet { get; set; }
public BeatmapInfo GetBeatmapInfo(RulesetStore rulesets)
public APIBeatmap BeatmapInfo
{
BeatmapSetInfo setInfo = beatmapSet.ToBeatmapSet(rulesets);
beatmapInfo.BeatmapSet = setInfo;
beatmapInfo.Metadata = setInfo.Metadata;
return beatmapInfo;
get
{
// old osu-web code doesn't nest set.
beatmap.BeatmapSet = BeatmapSet;
return beatmap;
}
}
[JsonProperty("beatmapset")]
public APIBeatmapSet BeatmapSet { get; set; }
}
}

View File

@ -15,9 +15,9 @@ namespace osu.Game.Overlays.Profile.Sections
/// </summary>
public abstract class BeatmapMetadataContainer : OsuHoverContainer
{
private readonly BeatmapInfo beatmapInfo;
private readonly IBeatmapInfo beatmapInfo;
protected BeatmapMetadataContainer(BeatmapInfo beatmapInfo)
protected BeatmapMetadataContainer(IBeatmapInfo beatmapInfo)
: base(HoverSampleSet.Submit)
{
this.beatmapInfo = beatmapInfo;
@ -30,10 +30,7 @@ namespace osu.Game.Overlays.Profile.Sections
{
Action = () =>
{
if (beatmapInfo.OnlineBeatmapID != null)
beatmapSetOverlay?.FetchAndShowBeatmap(beatmapInfo.OnlineBeatmapID.Value);
else if (beatmapInfo.BeatmapSet?.OnlineBeatmapSetID != null)
beatmapSetOverlay?.FetchAndShowBeatmapSet(beatmapInfo.BeatmapSet.OnlineBeatmapSetID.Value);
beatmapSetOverlay?.FetchAndShowBeatmap(beatmapInfo.OnlineID);
};
Child = new FillFlowContainer
@ -43,6 +40,6 @@ namespace osu.Game.Overlays.Profile.Sections
};
}
protected abstract Drawable[] CreateText(BeatmapInfo beatmapInfo);
protected abstract Drawable[] CreateText(IBeatmapInfo beatmapInfo);
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -13,6 +14,7 @@ using osu.Game.Graphics.Sprites;
using osuTK;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Localisation;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Resources.Localisation.Web;
namespace osu.Game.Overlays.Profile.Sections.Historical
@ -22,13 +24,11 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
private const int cover_width = 100;
private const int corner_radius = 6;
private readonly BeatmapInfo beatmapInfo;
private readonly int playCount;
private readonly APIUserMostPlayedBeatmap mostPlayed;
public DrawableMostPlayedBeatmap(BeatmapInfo beatmapInfo, int playCount)
public DrawableMostPlayedBeatmap(APIUserMostPlayedBeatmap mostPlayed)
{
this.beatmapInfo = beatmapInfo;
this.playCount = playCount;
this.mostPlayed = mostPlayed;
RelativeSizeAxes = Axes.X;
Height = 50;
@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
{
RelativeSizeAxes = Axes.Y,
Width = cover_width,
BeatmapSet = beatmapInfo.BeatmapSet,
BeatmapSet = mostPlayed.BeatmapSet,
},
new Container
{
@ -77,7 +77,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
new MostPlayedBeatmapMetadataContainer(beatmapInfo),
new MostPlayedBeatmapMetadataContainer(mostPlayed.BeatmapInfo),
new LinkFlowContainer(t =>
{
t.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular);
@ -89,11 +89,11 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
}.With(d =>
{
d.AddText("mapped by ");
d.AddUserLink(beatmapInfo.Metadata.Author);
d.AddUserLink(mostPlayed.BeatmapSet.Author);
}),
}
},
new PlayCountText(playCount)
new PlayCountText(mostPlayed.PlayCount)
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight
@ -120,26 +120,41 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
private class MostPlayedBeatmapMetadataContainer : BeatmapMetadataContainer
{
public MostPlayedBeatmapMetadataContainer(BeatmapInfo beatmapInfo)
public MostPlayedBeatmapMetadataContainer(IBeatmapInfo beatmapInfo)
: base(beatmapInfo)
{
}
protected override Drawable[] CreateText(BeatmapInfo beatmapInfo) => new Drawable[]
protected override Drawable[] CreateText(IBeatmapInfo beatmapInfo)
{
new OsuSpriteText
var metadata = beatmapInfo.Metadata;
Debug.Assert(metadata != null);
return new Drawable[]
{
Text = new RomanisableString(
$"{beatmapInfo.Metadata.TitleUnicode ?? beatmapInfo.Metadata.Title} [{beatmapInfo.Version}] ",
$"{beatmapInfo.Metadata.Title ?? beatmapInfo.Metadata.TitleUnicode} [{beatmapInfo.Version}] "),
Font = OsuFont.GetFont(weight: FontWeight.Bold)
},
new OsuSpriteText
{
Text = "by " + new RomanisableString(beatmapInfo.Metadata.ArtistUnicode, beatmapInfo.Metadata.Artist),
Font = OsuFont.GetFont(weight: FontWeight.Regular)
},
};
new OsuSpriteText
{
Text = new RomanisableString(metadata.TitleUnicode, metadata.Title),
Font = OsuFont.GetFont(weight: FontWeight.Bold)
},
new OsuSpriteText
{
Text = $" [{beatmapInfo.DifficultyName}]",
Font = OsuFont.GetFont(weight: FontWeight.Bold)
},
new OsuSpriteText
{
Text = " by ",
Font = OsuFont.GetFont(weight: FontWeight.Regular)
},
new OsuSpriteText
{
Text = new RomanisableString(metadata.ArtistUnicode, metadata.Artist),
Font = OsuFont.GetFont(weight: FontWeight.Regular)
},
};
}
}
private class PlayCountText : CompositeDrawable, IHasTooltip

View File

@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
protected override APIRequest<List<APIUserMostPlayedBeatmap>> CreateRequest() =>
new GetUserMostPlayedBeatmapsRequest(User.Value.Id, VisiblePages++, ItemsPerPage);
protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap model) =>
new DrawableMostPlayedBeatmap(model.GetBeatmapInfo(Rulesets), model.PlayCount);
protected override Drawable CreateDrawableItem(APIUserMostPlayedBeatmap mostPlayed) =>
new DrawableMostPlayedBeatmap(mostPlayed);
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
@ -245,30 +246,42 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
private class ScoreBeatmapMetadataContainer : BeatmapMetadataContainer
{
public ScoreBeatmapMetadataContainer(BeatmapInfo beatmapInfo)
public ScoreBeatmapMetadataContainer(IBeatmapInfo beatmapInfo)
: base(beatmapInfo)
{
}
protected override Drawable[] CreateText(BeatmapInfo beatmapInfo) => new Drawable[]
protected override Drawable[] CreateText(IBeatmapInfo beatmapInfo)
{
new OsuSpriteText
var metadata = beatmapInfo.Metadata;
Debug.Assert(metadata != null);
return new Drawable[]
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Text = new RomanisableString(
$"{beatmapInfo.Metadata.TitleUnicode ?? beatmapInfo.Metadata.Title} ",
$"{beatmapInfo.Metadata.Title ?? beatmapInfo.Metadata.TitleUnicode} "),
Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold, italics: true)
},
new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Text = "by " + new RomanisableString(beatmapInfo.Metadata.ArtistUnicode, beatmapInfo.Metadata.Artist),
Font = OsuFont.GetFont(size: 12, italics: true)
},
};
new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Text = new RomanisableString(metadata.TitleUnicode, metadata.Title),
Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold, italics: true)
},
new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Text = " by ",
Font = OsuFont.GetFont(size: 12, italics: true)
},
new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Text = new RomanisableString(metadata.ArtistUnicode, metadata.Artist),
Font = OsuFont.GetFont(size: 12, italics: true)
},
};
}
}
}
}

View File

@ -1,72 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osuTK;
namespace osu.Game.Screens.OnlinePlay.Components
{
public class BeatmapTypeInfo : OnlinePlayComposite
{
private LinkFlowContainer beatmapAuthor;
public BeatmapTypeInfo()
{
AutoSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load()
{
InternalChild = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
LayoutDuration = 100,
Spacing = new Vector2(5, 0),
Children = new Drawable[]
{
new ModeTypeInfo(),
new Container
{
AutoSizeAxes = Axes.X,
Height = 30,
Margin = new MarginPadding { Left = 5 },
Children = new Drawable[]
{
new BeatmapTitle(),
beatmapAuthor = new LinkFlowContainer(s => s.Font = s.Font.With(size: 14))
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
AutoSizeAxes = Axes.Both
},
},
},
}
};
Playlist.CollectionChanged += (_, __) => updateInfo();
updateInfo();
}
private void updateInfo()
{
beatmapAuthor.Clear();
var beatmap = Playlist.FirstOrDefault()?.Beatmap;
if (beatmap != null)
{
beatmapAuthor.AddText("mapped by ", s => s.Colour = OsuColour.Gray(0.8f));
beatmapAuthor.AddUserLink(beatmap.Value.Metadata.Author);
}
}
}
}

View File

@ -103,7 +103,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
public IEnumerable<string> FilterTerms => new[] { Room.Name.Value };
private bool matchingFilter;
private bool matchingFilter = true;
public bool MatchingFilter
{
@ -181,6 +181,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
[Resolved(canBeNull: true)]
private LoungeSubScreen lounge { get; set; }
public override bool HandleNonPositionalInput => true;
protected override bool BlockNonPositionalInput => true;
public PasswordEntryPopover(Room room)
{
this.room = room;
@ -200,6 +204,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
Spacing = new Vector2(5),
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
LayoutDuration = 500,
LayoutEasing = Easing.OutQuint,
Children = new Drawable[]
{
new FillFlowContainer
@ -230,10 +236,24 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
sampleJoinFail = audio.Samples.Get(@"UI/password-fail");
joinButton.Action = () => lounge?.Join(room, passwordTextbox.Text, null, joinFailed);
joinButton.Action = performJoin;
}
private void joinFailed(string error)
protected override void LoadComplete()
{
base.LoadComplete();
Schedule(() => GetContainingInputManager().ChangeFocus(passwordTextbox));
passwordTextbox.OnCommit += (_, __) => performJoin();
}
private void performJoin()
{
lounge?.Join(room, passwordTextbox.Text, null, joinFailed);
GetContainingInputManager().TriggerFocusContention(passwordTextbox);
}
private void joinFailed(string error) => Schedule(() =>
{
passwordTextbox.Text = string.Empty;
@ -249,15 +269,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
Body.Shake();
sampleJoinFail?.Play();
}
protected override void LoadComplete()
{
base.LoadComplete();
Schedule(() => GetContainingInputManager().ChangeFocus(passwordTextbox));
passwordTextbox.OnCommit += (_, __) => lounge?.Join(room, passwordTextbox.Text, null, joinFailed);
}
});
}
}
}

View File

@ -289,7 +289,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
popoverContainer.HidePopover();
}
public void Join(Room room, string password, Action<Room> onSuccess = null, Action<string> onFailure = null) => Schedule(() =>
public virtual void Join(Room room, string password, Action<Room> onSuccess = null, Action<string> onFailure = null) => Schedule(() =>
{
if (joiningRoomOperation != null)
return;

View File

@ -106,6 +106,7 @@ namespace osu.Game.Screens.Play
this.TransformBindableTo(trackFreq, 0, duration).OnComplete(_ =>
{
RemoveFilters();
OnComplete?.Invoke();
});
@ -137,6 +138,9 @@ namespace osu.Game.Screens.Play
public void RemoveFilters()
{
if (filters.Parent == null)
return;
RemoveInternal(filters);
filters.Dispose();