1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-06 06:17:23 +08:00

Merge branch 'master' into split-out-pulp-formations

This commit is contained in:
Dan Balasescu 2020-02-21 11:45:06 +09:00 committed by GitHub
commit 8d48008dd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
85 changed files with 1782 additions and 779 deletions

View File

@ -53,7 +53,7 @@
<Reference Include="Java.Interop" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.219.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.218.0" />
</ItemGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -38,9 +38,51 @@ namespace osu.Game.Rulesets.Catch.Tests
foreach (FruitVisualRepresentation rep in Enum.GetValues(typeof(FruitVisualRepresentation)))
AddStep($"show {rep}", () => SetContents(() => createDrawable(rep)));
AddStep("show droplet", () => SetContents(createDrawableDroplet));
AddStep("show tiny droplet", () => SetContents(createDrawableTinyDroplet));
}
private DrawableFruit createDrawable(FruitVisualRepresentation rep)
private Drawable createDrawableTinyDroplet()
{
var droplet = new TinyDroplet
{
StartTime = Clock.CurrentTime,
Scale = 1.5f,
};
return new DrawableTinyDroplet(droplet)
{
Anchor = Anchor.Centre,
RelativePositionAxes = Axes.None,
Position = Vector2.Zero,
Alpha = 1,
LifetimeStart = double.NegativeInfinity,
LifetimeEnd = double.PositiveInfinity,
};
}
private Drawable createDrawableDroplet()
{
var droplet = new Droplet
{
StartTime = Clock.CurrentTime,
Scale = 1.5f,
};
return new DrawableDroplet(droplet)
{
Anchor = Anchor.Centre,
RelativePositionAxes = Axes.None,
Position = Vector2.Zero,
Alpha = 1,
LifetimeStart = double.NegativeInfinity,
LifetimeEnd = double.PositiveInfinity,
};
}
private Drawable createDrawable(FruitVisualRepresentation rep)
{
Fruit fruit = new TestCatchFruit(rep)
{

View File

@ -16,10 +16,10 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
private Color4? colour;
protected override void UpdateComboColour(Color4 proposedColour, IReadOnlyList<Color4> comboColours)
protected override Color4 GetComboColour(IReadOnlyList<Color4> comboColours)
{
// override any external colour changes with banananana
AccentColour.Value = (colour ??= getBananaColour());
return colour ??= getBananaColour();
}
private Color4 getBananaColour()

View File

@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
public override bool CanBePlated => true;
protected Container ScaleContainer;
protected Container ScaleContainer { get; private set; }
protected PalpableCatchHitObject(TObject hitObject)
: base(hitObject)
@ -45,11 +45,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
ScaleContainer.Scale = new Vector2(HitObject.Scale);
}
protected override void UpdateComboColour(Color4 proposedColour, IReadOnlyList<Color4> comboColours)
{
// ignore the incoming combo colour as we use a custom lookup
AccentColour.Value = comboColours[(HitObject.IndexInBeatmap + 1) % comboColours.Count];
}
protected override Color4 GetComboColour(IReadOnlyList<Color4> comboColours) =>
comboColours[(HitObject.IndexInBeatmap + 1) % comboColours.Count];
}
public abstract class DrawableCatchHitObject<TObject> : DrawableCatchHitObject

View File

@ -2,9 +2,10 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Utils;
using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
using osu.Game.Skinning;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
@ -20,12 +21,22 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
[BackgroundDependencyLoader]
private void load()
{
ScaleContainer.Child = new SkinnableDrawable(
new CatchSkinComponent(CatchSkinComponents.Droplet), _ => new Pulp
{
Size = Size / 4,
AccentColour = { Value = Color4.White }
});
ScaleContainer.Child = new SkinnableDrawable(new CatchSkinComponent(CatchSkinComponents.Droplet), _ => new Pulp
{
Size = Size / 4,
AccentColour = { BindTarget = AccentColour }
});
}
protected override void UpdateInitialTransforms()
{
base.UpdateInitialTransforms();
// roughly matches osu-stable
float startRotation = RNG.NextSingle() * 20;
double duration = HitObject.TimePreempt + 2000;
this.RotateTo(startRotation).RotateTo(startRotation + 720, duration);
}
}
}

View File

@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
((DrawableCatchHitObject)o).CheckPosition = p => CheckPosition?.Invoke(p) ?? false);
}
return null;
throw new ArgumentException($"{nameof(hitObject)} must be of type {nameof(CatchHitObject)}.");
}
}
}

View File

@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
[BackgroundDependencyLoader]
private void load()
{
Scale /= 2;
ScaleContainer.Scale /= 2;
}
}
}

View File

@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Catch.Skinning
case CatchSkinComponents.FruitOrange:
case CatchSkinComponents.FruitGrapes:
case CatchSkinComponents.FruitPear:
var lookupName = catchSkinComponent.Component.ToString().Underscore().Hyphenate();
var lookupName = catchSkinComponent.Component.ToString().Kebaberize();
if (GetTexture(lookupName) != null)
return new LegacyFruitPiece(lookupName);

View File

@ -221,9 +221,9 @@ namespace osu.Game.Rulesets.Catch.UI
/// Add a caught fruit to the catcher's stack.
/// </summary>
/// <param name="fruit">The fruit that was caught.</param>
public void PlaceOnPlate(DrawableHitObject fruit)
public void PlaceOnPlate(DrawableCatchHitObject fruit)
{
float ourRadius = ((DrawableCatchHitObject)fruit).DisplayRadius;
float ourRadius = fruit.DisplayRadius;
float theirRadius = 0;
const float allowance = 6;

View File

@ -1,46 +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;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Skinning;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Mania.Tests
{
public abstract class SkinnableTestScene : OsuGridTestScene
{
private Skin defaultSkin;
protected SkinnableTestScene()
: base(1, 2)
{
}
[BackgroundDependencyLoader]
private void load(AudioManager audio, SkinManager skinManager)
{
defaultSkin = skinManager.GetSkin(DefaultLegacySkin.Info);
}
public void SetContents(Func<Drawable> creationFunction)
{
Cell(0).Child = createProvider(null, creationFunction);
Cell(1).Child = createProvider(defaultSkin, creationFunction);
}
private Drawable createProvider(Skin skin, Func<Drawable> creationFunction)
{
var mainProvider = new SkinProvidingContainer(skin);
return mainProvider
.WithChild(new SkinProvidingContainer(Ruleset.Value.CreateInstance().CreateLegacySkinProvider(mainProvider))
{
Child = creationFunction()
});
}
}
}

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Game.Tests.Visual;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;

View File

@ -1,13 +1,11 @@
// 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.Collections.Generic;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Graphics.Containers;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
@ -56,8 +54,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
}
}
protected override void UpdateComboColour(Color4 proposedColour, IReadOnlyList<Color4> comboColours) => AccentColour.Value = proposedColour;
protected override JudgementResult CreateResult(Judgement judgement) => new OsuJudgementResult(HitObject, judgement);
}
}

View File

@ -76,8 +76,6 @@ namespace osu.Game.Tests.Gameplay
: base(new TestHitObjectWithCombo())
{
}
protected override void UpdateComboColour(Color4 proposedColour, IReadOnlyList<Color4> comboColours) => AccentColour.Value = proposedColour;
}
private class TestHitObjectWithCombo : HitObject, IHasComboInformation

View File

@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
typeof(DrawableRoomPlaylistItem)
};
private DrawableRoomPlaylist playlist;
private TestPlaylist playlist;
[Test]
public void TestNonEditableNonSelectable()
@ -211,30 +211,45 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void assertDeleteButtonVisibility(int index, bool visible)
=> AddAssert($"delete button {index} {(visible ? "is" : "is not")} visible", () => (playlist.ChildrenOfType<IconButton>().ElementAt(2 + index * 2).Alpha > 0) == visible);
private void createPlaylist(bool allowEdit, bool allowSelection) => AddStep("create playlist", () =>
private void createPlaylist(bool allowEdit, bool allowSelection)
{
Child = playlist = new DrawableRoomPlaylist(allowEdit, allowSelection)
AddStep("create playlist", () =>
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500, 300)
};
for (int i = 0; i < 20; i++)
{
playlist.Items.Add(new PlaylistItem
Child = playlist = new TestPlaylist(allowEdit, allowSelection)
{
ID = i,
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RequiredMods =
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500, 300)
};
for (int i = 0; i < 20; i++)
{
playlist.Items.Add(new PlaylistItem
{
new OsuModHardRock(),
new OsuModDoubleTime(),
new OsuModAutoplay()
}
});
ID = i,
Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo },
Ruleset = { Value = new OsuRuleset().RulesetInfo },
RequiredMods =
{
new OsuModHardRock(),
new OsuModDoubleTime(),
new OsuModAutoplay()
}
});
}
});
AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded));
}
private class TestPlaylist : DrawableRoomPlaylist
{
public new IReadOnlyDictionary<PlaylistItem, RearrangeableListItem<PlaylistItem>> ItemMap => base.ItemMap;
public TestPlaylist(bool allowEdit, bool allowSelection)
: base(allowEdit, allowSelection)
{
}
});
}
}
}

View File

@ -0,0 +1,59 @@
// 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.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.RoomStatuses;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Users;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneLoungeRoomInfo : MultiplayerTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(RoomInfo)
};
[SetUp]
public void Setup() => Schedule(() =>
{
Room.CopyFrom(new Room());
Child = new RoomInfo
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Width = 500
};
});
public override void SetUpSteps()
{
// Todo: Temp
}
[Test]
public void TestNonSelectedRoom()
{
AddStep("set null room", () => Room.RoomID.Value = null);
}
[Test]
public void TestOpenRoom()
{
AddStep("set open room", () =>
{
Room.RoomID.Value = 0;
Room.Name.Value = "Room 0";
Room.Host.Value = new User { Username = "peppy", Id = 2 };
Room.EndDate.Value = DateTimeOffset.Now.AddMonths(1);
Room.Status.Value = new RoomStatusOpen();
});
}
}
}

View File

@ -1,27 +1,57 @@
// 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.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Screens.Multi.Components;
using osuTK;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneOverlinedParticipants : MultiplayerTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(OverlinedParticipants),
typeof(OverlinedDisplay),
typeof(ParticipantsList)
};
protected override bool UseOnlineAPI => true;
public TestSceneOverlinedParticipants()
{
Room.RoomID.Value = 7;
}
Add(new Container
[Test]
public void TestHorizontalLayout()
{
AddStep("create component", () =>
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500),
Child = new OverlinedParticipants()
Child = new OverlinedParticipants(Direction.Horizontal)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Width = 500,
AutoSizeAxes = Axes.Y,
};
});
}
[Test]
public void TestVerticalLayout()
{
AddStep("create component", () =>
{
Child = new OverlinedParticipants(Direction.Vertical)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500)
};
});
}
}

View File

@ -2,10 +2,9 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Screens.Multi.Components;
using osu.Game.Tests.Beatmaps;
using osuTK;
@ -27,12 +26,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
});
}
Add(new Container
Add(new OverlinedPlaylist(false)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(500),
Child = new OverlinedPlaylist(false)
});
}
}

View File

@ -0,0 +1,39 @@
// 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.Collections.Generic;
using osu.Game.Overlays;
using NUnit.Framework;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneBeatmapListingOverlay : OsuTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(BeatmapListingOverlay),
};
protected override bool UseOnlineAPI => true;
private readonly BeatmapListingOverlay overlay;
public TestSceneBeatmapListingOverlay()
{
Add(overlay = new BeatmapListingOverlay());
}
[Test]
public void TestShow()
{
AddStep("Show", overlay.Show);
}
[Test]
public void TestHide()
{
AddStep("Hide", overlay.Hide);
}
}
}

View File

@ -29,8 +29,8 @@ namespace osu.Game.Tests.Visual.Online
typeof(RankingsOverlayHeader)
};
[Cached]
private RankingsOverlay rankingsOverlay;
[Cached(typeof(RankingsOverlay))]
private readonly RankingsOverlay rankingsOverlay;
private readonly Bindable<Country> countryBindable = new Bindable<Country>();
private readonly Bindable<RankingsScope> scope = new Bindable<RankingsScope>();

View File

@ -195,6 +195,29 @@ namespace osu.Game.Tests.Visual.Online
Position = 1337,
};
var myBestScoreWithNullPosition = new APILegacyUserTopScoreInfo
{
Score = new APILegacyScoreInfo
{
User = new User
{
Id = 7151382,
Username = @"Mayuri Hana",
Country = new Country
{
FullName = @"Thailand",
FlagName = @"TH",
},
},
Rank = ScoreRank.D,
PP = 160,
MaxCombo = 1234,
TotalScore = 123456,
Accuracy = 0.6543,
},
Position = null,
};
var oneScore = new APILegacyScores
{
Scores = new List<APILegacyScoreInfo>
@ -250,6 +273,12 @@ namespace osu.Game.Tests.Visual.Online
allScores.UserScore = myBestScore;
scoresContainer.Scores = allScores;
});
AddStep("Load scores with null my best position", () =>
{
allScores.UserScore = myBestScoreWithNullPosition;
scoresContainer.Scores = allScores;
});
}
private class TestScoresContainer : ScoresContainer

View File

@ -59,6 +59,33 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep(@"None selected", () => leaderboard.SetRetrievalState(PlaceholderState.NoneSelected));
foreach (BeatmapSetOnlineStatus status in Enum.GetValues(typeof(BeatmapSetOnlineStatus)))
AddStep($"{status} beatmap", () => showBeatmapWithStatus(status));
AddStep("null personal best position", showPersonalBestWithNullPosition);
}
private void showPersonalBestWithNullPosition()
{
leaderboard.TopScore = new APILegacyUserTopScoreInfo
{
Position = null,
Score = new APILegacyScoreInfo
{
Rank = ScoreRank.XH,
Accuracy = 1,
MaxCombo = 244,
TotalScore = 1707827,
Mods = new[] { new OsuModHidden().Acronym, new OsuModHardRock().Acronym, },
User = new User
{
Id = 6602580,
Username = @"waaiiru",
Country = new Country
{
FullName = @"Spain",
FlagName = @"ES",
},
},
}
};
}
private void showPersonalBest()

View File

@ -502,6 +502,72 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("Selected beatmap has not changed", () => songSelect.Carousel.SelectedBeatmap.ID == previousID);
}
[Test]
public void TestDifficultyIconSelecting()
{
addRulesetImportStep(0);
createSongSelect();
DrawableCarouselBeatmapSet set = null;
AddStep("Find the DrawableCarouselBeatmapSet", () =>
{
set = songSelect.Carousel.ChildrenOfType<DrawableCarouselBeatmapSet>().First();
});
DrawableCarouselBeatmapSet.FilterableDifficultyIcon difficultyIcon = null;
AddStep("Find an icon", () =>
{
difficultyIcon = set.ChildrenOfType<DrawableCarouselBeatmapSet.FilterableDifficultyIcon>()
.First(icon => getDifficultyIconIndex(set, icon) != getCurrentBeatmapIndex());
});
AddStep("Click on a difficulty", () =>
{
InputManager.MoveMouseTo(difficultyIcon);
InputManager.PressButton(MouseButton.Left);
InputManager.ReleaseButton(MouseButton.Left);
});
AddAssert("Selected beatmap correct", () => getCurrentBeatmapIndex() == getDifficultyIconIndex(set, difficultyIcon));
double? maxBPM = null;
AddStep("Filter some difficulties", () => songSelect.Carousel.Filter(new FilterCriteria
{
BPM = new FilterCriteria.OptionalRange<double>
{
Min = maxBPM = songSelect.Carousel.SelectedBeatmapSet.MaxBPM,
IsLowerInclusive = true
}
}));
DrawableCarouselBeatmapSet.FilterableDifficultyIcon filteredIcon = null;
AddStep("Get filtered icon", () =>
{
var filteredBeatmap = songSelect.Carousel.SelectedBeatmapSet.Beatmaps.Find(b => b.BPM < maxBPM);
int filteredBeatmapIndex = getBeatmapIndex(filteredBeatmap.BeatmapSet, filteredBeatmap);
filteredIcon = set.ChildrenOfType<DrawableCarouselBeatmapSet.FilterableDifficultyIcon>().ElementAt(filteredBeatmapIndex);
});
int? previousID = null;
AddStep("Store current ID", () => previousID = songSelect.Carousel.SelectedBeatmap.ID);
AddStep("Click on a filtered difficulty", () =>
{
InputManager.MoveMouseTo(filteredIcon);
InputManager.PressButton(MouseButton.Left);
InputManager.ReleaseButton(MouseButton.Left);
});
AddAssert("Selected beatmap has not changed", () => songSelect.Carousel.SelectedBeatmap.ID == previousID);
}
private int getBeatmapIndex(BeatmapSetInfo set, BeatmapInfo info) => set.Beatmaps.FindIndex(b => b == info);
private int getCurrentBeatmapIndex() => getBeatmapIndex(songSelect.Carousel.SelectedBeatmapSet, songSelect.Carousel.SelectedBeatmap);
private int getDifficultyIconIndex(DrawableCarouselBeatmapSet set, DrawableCarouselBeatmapSet.FilterableDifficultyIcon icon)
{
return set.ChildrenOfType<DrawableCarouselBeatmapSet.FilterableDifficultyIcon>().ToList().FindIndex(i => i == icon);
}
private void addRulesetImportStep(int id) => AddStep($"import test map for ruleset {id}", () => importForRuleset(id));
private void importForRuleset(int id) => manager.Import(createTestBeatmapSet(getImportId(), rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())).Wait();

View File

@ -0,0 +1,86 @@
// 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 NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
{
public class TestSceneProcessingOverlay : OsuTestScene
{
private Drawable dimContent;
private ProcessingOverlay overlay;
[SetUp]
public void SetUp() => Schedule(() =>
{
Children = new[]
{
new Container
{
Size = new Vector2(300),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new[]
{
new Box
{
Colour = Color4.SlateGray,
RelativeSizeAxes = Axes.Both,
},
dimContent = new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Direction = FillDirection.Vertical,
Spacing = new Vector2(10),
RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.9f),
Children = new Drawable[]
{
new OsuSpriteText { Text = "Sample content" },
new TriangleButton { Text = "can't puush me", Width = 200, },
new TriangleButton { Text = "puush me", Width = 200, Action = () => { } },
}
},
overlay = new ProcessingOverlay(dimContent),
}
},
};
});
[Test]
public void ShowHide()
{
AddAssert("not visible", () => !overlay.IsPresent);
AddStep("show", () => overlay.Show());
AddUntilStep("wait for content dim", () => dimContent.Colour != Color4.White);
AddStep("hide", () => overlay.Hide());
AddUntilStep("wait for content restore", () => dimContent.Colour == Color4.White);
}
[Test]
public void ContentRestoreOnDispose()
{
AddAssert("not visible", () => !overlay.IsPresent);
AddStep("show", () => overlay.Show());
AddUntilStep("wait for content dim", () => dimContent.Colour != Color4.White);
AddStep("hide", () => overlay.Expire());
AddUntilStep("wait for content restore", () => dimContent.Colour == Color4.White);
}
}
}

View File

@ -51,6 +51,9 @@ namespace osu.Game.Beatmaps
[NotMapped]
public BeatmapOnlineInfo OnlineInfo { get; set; }
[NotMapped]
public int? MaxCombo { get; set; }
/// <summary>
/// The playable length in milliseconds of this beatmap.
/// </summary>

View File

@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
@ -50,7 +49,7 @@ namespace osu.Game.Beatmaps.Drawables
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(OsuColour.Gray(0.2f), OsuColour.Gray(0.1f)),
Colour = OsuColour.Gray(0.2f),
};
}

View File

@ -14,6 +14,9 @@ namespace osu.Game.Graphics.Containers
{
public class OsuScrollContainer : ScrollContainer<Drawable>
{
public const float SCROLL_BAR_HEIGHT = 10;
public const float SCROLL_BAR_PADDING = 3;
/// <summary>
/// Allows controlling the scroll bar from any position in the container using the right mouse button.
/// Uses the value of <see cref="DistanceDecayOnRightMouseScrollbar"/> to smoothly scroll to the dragged location.
@ -96,8 +99,6 @@ namespace osu.Game.Graphics.Containers
protected class OsuScrollbar : ScrollbarContainer
{
private const float dim_size = 10;
private Color4 hoverColour;
private Color4 defaultColour;
private Color4 highlightColour;
@ -135,7 +136,7 @@ namespace osu.Game.Graphics.Containers
public override void ResizeTo(float val, int duration = 0, Easing easing = Easing.None)
{
Vector2 size = new Vector2(dim_size)
Vector2 size = new Vector2(SCROLL_BAR_HEIGHT)
{
[(int)ScrollDirection] = val
};

View File

@ -4,13 +4,16 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites;
using osu.Game.Utils;
using osuTK;
namespace osu.Game.Graphics
{
public class DrawableDate : OsuSpriteText, IHasTooltip
public class DrawableDate : OsuSpriteText, IHasCustomTooltip
{
private DateTimeOffset date;
@ -75,6 +78,72 @@ namespace osu.Game.Graphics
private void updateTime() => Text = Format();
public virtual string TooltipText => string.Format($"{Date:MMMM d, yyyy h:mm tt \"UTC\"z}");
public ITooltip GetCustomTooltip() => new DateTooltip();
public object TooltipContent => Date;
private class DateTooltip : VisibilityContainer, ITooltip
{
private readonly OsuSpriteText dateText, timeText;
private readonly Box background;
public DateTooltip()
{
AutoSizeAxes = Axes.Both;
Masking = true;
CornerRadius = 5;
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both
},
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Padding = new MarginPadding(10),
Children = new Drawable[]
{
dateText = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
},
timeText = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
}
}
},
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
background.Colour = colours.GreySeafoamDarker;
timeText.Colour = colours.BlueLighter;
}
protected override void PopIn() => this.FadeIn(200, Easing.OutQuint);
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
public bool SetContent(object content)
{
if (!(content is DateTimeOffset date))
return false;
dateText.Text = $"{date:d MMMM yyyy} ";
timeText.Text = $"{date:hh:mm:ss \"UTC\"z}";
return true;
}
public void Move(Vector2 pos) => Position = pos;
}
}
}

View File

@ -6,20 +6,27 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// An overlay that will consume all available space and block input when required.
/// An overlay that will show a loading overlay and completely block input to an area.
/// Also optionally dims target elements.
/// Useful for disabling all elements in a form and showing we are waiting on a response, for instance.
/// </summary>
public class ProcessingOverlay : VisibilityContainer
{
private const float transition_duration = 200;
private readonly Drawable dimTarget;
public ProcessingOverlay()
private Container loadingBox;
private const float transition_duration = 600;
public ProcessingOverlay(Drawable dimTarget = null)
{
this.dimTarget = dimTarget;
RelativeSizeAxes = Axes.Both;
}
@ -28,29 +35,54 @@ namespace osu.Game.Graphics.UserInterface
{
InternalChildren = new Drawable[]
{
new Box
loadingBox = new Container
{
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
Alpha = 0.9f,
Size = new Vector2(80),
Scale = new Vector2(0.8f),
Masking = true,
CornerRadius = 15,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new Drawable[]
{
new Box
{
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
},
new LoadingAnimation { State = { Value = Visibility.Visible } }
}
},
new LoadingAnimation { State = { Value = Visibility.Visible } }
};
}
protected override bool Handle(UIEvent e)
{
return true;
}
protected override bool Handle(UIEvent e) => true;
protected override void PopIn()
{
this.FadeIn(transition_duration * 2, Easing.OutQuint);
this.FadeIn(transition_duration, Easing.OutQuint);
loadingBox.ScaleTo(1, transition_duration, Easing.OutElastic);
dimTarget?.FadeColour(OsuColour.Gray(0.5f), transition_duration, Easing.OutQuint);
}
protected override void PopOut()
{
this.FadeOut(transition_duration, Easing.OutQuint);
loadingBox.ScaleTo(0.8f, transition_duration / 2, Easing.In);
dimTarget?.FadeColour(Color4.White, transition_duration, Easing.OutQuint);
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (State.Value == Visibility.Visible)
{
// ensure we don't leave the target in a bad state.
dimTarget?.FadeColour(Color4.White, transition_duration, Easing.OutQuint);
}
}
}
}

View File

@ -61,6 +61,9 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"failtimes")]
private BeatmapMetrics metrics { get; set; }
[JsonProperty(@"max_combo")]
private int? maxCombo { get; set; }
public BeatmapInfo ToBeatmap(RulesetStore rulesets)
{
var set = BeatmapSet?.ToBeatmapSet(rulesets);
@ -76,6 +79,7 @@ namespace osu.Game.Online.API.Requests.Responses
Status = Status,
BeatmapSet = set,
Metrics = metrics,
MaxCombo = maxCombo,
BaseDifficulty = new BeatmapDifficulty
{
DrainRate = drainRate,

View File

@ -18,7 +18,7 @@ namespace osu.Game.Online.API.Requests.Responses
public class APILegacyUserTopScoreInfo
{
[JsonProperty(@"position")]
public int Position;
public int? Position;
[JsonProperty(@"score")]
public APILegacyScoreInfo Score;

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System.ComponentModel;
using osu.Framework.IO.Network;
using osu.Game.Overlays;
using osu.Game.Overlays.Direct;
using osu.Game.Rulesets;
@ -26,8 +27,21 @@ namespace osu.Game.Online.API.Requests
this.direction = direction;
}
// ReSharper disable once ImpureMethodCallOnReadonlyValueField
protected override string Target => $@"beatmapsets/search?q={query}&m={ruleset.ID ?? 0}&s={searchCategory.ToString().ToLowerInvariant()}&sort={sortCriteria.ToString().ToLowerInvariant()}_{directionString}";
protected override WebRequest CreateWebRequest()
{
var req = base.CreateWebRequest();
req.AddParameter("q", query);
if (ruleset.ID.HasValue)
req.AddParameter("m", ruleset.ID.Value.ToString());
req.AddParameter("s", searchCategory.ToString().ToLowerInvariant());
req.AddParameter("sort", $"{sortCriteria.ToString().ToLowerInvariant()}_{directionString}");
return req;
}
protected override string Target => @"beatmapsets/search";
}
public enum BeatmapSearchCategory

View File

@ -2,12 +2,17 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using Newtonsoft.Json;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
public class SearchBeatmapSetsResponse : ResponseWithCursor
{
[JsonProperty("beatmapsets")]
public IEnumerable<APIBeatmapSet> BeatmapSets;
[JsonProperty("total")]
public int Total;
}
}

View File

@ -41,7 +41,7 @@ namespace osu.Game.Online.Leaderboards
protected Container RankContainer { get; private set; }
private readonly ScoreInfo score;
private readonly int rank;
private readonly int? rank;
private readonly bool allowHighlight;
private Box background;
@ -58,7 +58,7 @@ namespace osu.Game.Online.Leaderboards
[Resolved(CanBeNull = true)]
private DialogOverlay dialogOverlay { get; set; }
public LeaderboardScore(ScoreInfo score, int rank, bool allowHighlight = true)
public LeaderboardScore(ScoreInfo score, int? rank, bool allowHighlight = true)
{
this.score = score;
this.rank = rank;
@ -90,7 +90,7 @@ namespace osu.Game.Online.Leaderboards
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 20, italics: true),
Text = rank.ToMetric(decimals: rank < 100000 ? 1 : 0),
Text = rank == null ? "-" : rank.Value.ToMetric(decimals: rank < 100000 ? 1 : 0),
},
},
},

View File

@ -48,9 +48,11 @@ namespace osu.Game.Overlays.AccountCreation
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
FillFlowContainer mainContent;
InternalChildren = new Drawable[]
{
new FillFlowContainer
mainContent = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
@ -122,7 +124,7 @@ namespace osu.Game.Overlays.AccountCreation
},
},
},
processingOverlay = new ProcessingOverlay { Alpha = 0 }
processingOverlay = new ProcessingOverlay(mainContent)
};
textboxes = new[] { usernameTextBox, emailTextBox, passwordTextBox };

View File

@ -0,0 +1,24 @@
// 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 osu.Framework.Graphics;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.BeatmapListing
{
public class BeatmapListingHeader : OverlayHeader
{
protected override ScreenTitle CreateTitle() => new BeatmapListingTitle();
private class BeatmapListingTitle : ScreenTitle
{
public BeatmapListingTitle()
{
Title = @"beatmap";
Section = @"listing";
}
protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/changelog");
}
}
}

View File

@ -104,6 +104,8 @@ namespace osu.Game.Overlays.BeatmapListing
}
}
});
Category.Value = BeatmapSearchCategory.Leaderboard;
}
[BackgroundDependencyLoader]

View File

@ -8,16 +8,17 @@ using osu.Framework.Graphics;
using osuTK.Graphics;
using osuTK;
using osu.Framework.Input.Events;
using osu.Game.Overlays.Direct;
namespace osu.Game.Overlays.BeatmapListing
{
public class BeatmapListingSortTabControl : OverlaySortTabControl<BeatmapSortCriteria>
public class BeatmapListingSortTabControl : OverlaySortTabControl<DirectSortCriteria>
{
public readonly Bindable<SortDirection> SortDirection = new Bindable<SortDirection>(Overlays.SortDirection.Descending);
public BeatmapListingSortTabControl()
{
Current.Value = BeatmapSortCriteria.Ranked;
Current.Value = DirectSortCriteria.Ranked;
}
protected override SortTabControl CreateControl() => new BeatmapSortTabControl
@ -29,7 +30,7 @@ namespace osu.Game.Overlays.BeatmapListing
{
public readonly Bindable<SortDirection> SortDirection = new Bindable<SortDirection>();
protected override TabItem<BeatmapSortCriteria> CreateTabItem(BeatmapSortCriteria value) => new BeatmapSortTabItem(value)
protected override TabItem<DirectSortCriteria> CreateTabItem(DirectSortCriteria value) => new BeatmapSortTabItem(value)
{
SortDirection = { BindTarget = SortDirection }
};
@ -39,12 +40,12 @@ namespace osu.Game.Overlays.BeatmapListing
{
public readonly Bindable<SortDirection> SortDirection = new Bindable<SortDirection>();
public BeatmapSortTabItem(BeatmapSortCriteria value)
public BeatmapSortTabItem(DirectSortCriteria value)
: base(value)
{
}
protected override TabButton CreateTabButton(BeatmapSortCriteria value) => new BeatmapTabButton(value)
protected override TabButton CreateTabButton(DirectSortCriteria value) => new BeatmapTabButton(value)
{
Active = { BindTarget = Active },
SortDirection = { BindTarget = SortDirection }
@ -66,7 +67,7 @@ namespace osu.Game.Overlays.BeatmapListing
private readonly SpriteIcon icon;
public BeatmapTabButton(BeatmapSortCriteria value)
public BeatmapTabButton(DirectSortCriteria value)
: base(value)
{
Add(icon = new SpriteIcon
@ -104,15 +105,4 @@ namespace osu.Game.Overlays.BeatmapListing
}
}
}
public enum BeatmapSortCriteria
{
Title,
Artist,
Difficulty,
Ranked,
Rating,
Plays,
Favourites,
}
}

View File

@ -0,0 +1,299 @@
// 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.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Threading;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.BeatmapListing;
using osu.Game.Overlays.Direct;
using osu.Game.Rulesets;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays
{
public class BeatmapListingOverlay : FullscreenOverlay
{
[Resolved]
private PreviewTrackManager previewTrackManager { get; set; }
[Resolved]
private RulesetStore rulesets { get; set; }
private SearchBeatmapSetsRequest getSetsRequest;
private Container panelsPlaceholder;
private Drawable currentContent;
private BeatmapListingSearchSection searchSection;
private BeatmapListingSortTabControl sortControl;
public BeatmapListingOverlay()
: base(OverlayColourScheme.Blue)
{
}
[BackgroundDependencyLoader]
private void load()
{
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourProvider.Background6
},
new BasicScrollContainer
{
RelativeSizeAxes = Axes.Both,
ScrollbarVisible = false,
Child = new ReverseChildIDFillFlowContainer<Drawable>
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 10),
Children = new Drawable[]
{
new FillFlowContainer
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Direction = FillDirection.Vertical,
Masking = true,
EdgeEffect = new EdgeEffectParameters
{
Colour = Color4.Black.Opacity(0.25f),
Type = EdgeEffectType.Shadow,
Radius = 3,
Offset = new Vector2(0f, 1f),
},
Children = new Drawable[]
{
new BeatmapListingHeader(),
searchSection = new BeatmapListingSearchSection(),
}
},
new Container
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourProvider.Background4,
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.X,
Height = 40,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourProvider.Background5
},
sortControl = new BeatmapListingSortTabControl
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Margin = new MarginPadding { Left = 20 }
}
}
},
panelsPlaceholder = new Container
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Padding = new MarginPadding { Horizontal = 20 },
}
}
}
}
}
}
}
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
var sortCriteria = sortControl.Current;
var sortDirection = sortControl.SortDirection;
searchSection.Query.BindValueChanged(query =>
{
sortCriteria.Value = string.IsNullOrEmpty(query.NewValue) ? DirectSortCriteria.Ranked : DirectSortCriteria.Relevance;
sortDirection.Value = SortDirection.Descending;
queueUpdateSearch(true);
});
searchSection.Ruleset.BindValueChanged(_ => queueUpdateSearch());
searchSection.Category.BindValueChanged(_ => queueUpdateSearch());
sortCriteria.BindValueChanged(_ => queueUpdateSearch());
sortDirection.BindValueChanged(_ => queueUpdateSearch());
}
private ScheduledDelegate queryChangedDebounce;
private void queueUpdateSearch(bool queryTextChanged = false)
{
getSetsRequest?.Cancel();
queryChangedDebounce?.Cancel();
queryChangedDebounce = Scheduler.AddDelayed(updateSearch, queryTextChanged ? 500 : 100);
}
private void updateSearch()
{
if (!IsLoaded)
return;
if (State.Value == Visibility.Hidden)
return;
if (API == null)
return;
previewTrackManager.StopAnyPlaying(this);
currentContent?.FadeColour(Color4.DimGray, 400, Easing.OutQuint);
getSetsRequest = new SearchBeatmapSetsRequest(
searchSection.Query.Value,
searchSection.Ruleset.Value,
searchSection.Category.Value,
sortControl.Current.Value,
sortControl.SortDirection.Value);
getSetsRequest.Success += response => Schedule(() => recreatePanels(response));
API.Queue(getSetsRequest);
}
private void recreatePanels(SearchBeatmapSetsResponse response)
{
if (response.Total == 0)
{
searchSection.BeatmapSet = null;
LoadComponentAsync(new NotFoundDrawable(), addContentToPlaceholder);
return;
}
var beatmaps = response.BeatmapSets.Select(r => r.ToBeatmapSet(rulesets)).ToList();
var newPanels = new FillFlowContainer<DirectPanel>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(10),
Alpha = 0,
Margin = new MarginPadding { Vertical = 15 },
ChildrenEnumerable = beatmaps.Select<BeatmapSetInfo, DirectPanel>(b => new DirectGridPanel(b)
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
})
};
LoadComponentAsync(newPanels, loaded =>
{
addContentToPlaceholder(loaded);
searchSection.BeatmapSet = beatmaps.First();
});
}
private void addContentToPlaceholder(Drawable content)
{
Drawable lastContent = currentContent;
if (lastContent != null)
{
lastContent.FadeOut(100, Easing.OutQuint).Expire();
// Consider the case when the new content is smaller than the last content.
// If the auto-size computation is delayed until fade out completes, the background remain high for too long making the resulting transition to the smaller height look weird.
// At the same time, if the last content's height is bypassed immediately, there is a period where the new content is at Alpha = 0 when the auto-sized height will be 0.
// To resolve both of these issues, the bypass is delayed until a point when the content transitions (fade-in and fade-out) overlap and it looks good to do so.
lastContent.Delay(25).Schedule(() => lastContent.BypassAutoSizeAxes = Axes.Y);
}
panelsPlaceholder.Add(currentContent = content);
currentContent.FadeIn(200, Easing.OutQuint);
}
protected override void Dispose(bool isDisposing)
{
getSetsRequest?.Cancel();
queryChangedDebounce?.Cancel();
base.Dispose(isDisposing);
}
private class NotFoundDrawable : CompositeDrawable
{
public NotFoundDrawable()
{
RelativeSizeAxes = Axes.X;
Height = 250;
Alpha = 0;
Margin = new MarginPadding { Top = 15 };
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
AddInternal(new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
AutoSizeAxes = Axes.X,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(10, 0),
Children = new Drawable[]
{
new Sprite
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit,
Texture = textures.Get(@"Online/not-found")
},
new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = @"... nope, nothing found.",
}
}
});
}
}
}
}

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;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -50,7 +51,7 @@ namespace osu.Game.Overlays.BeatmapSet
fields.Children = new Drawable[]
{
new Field("mapped by", BeatmapSet.Metadata.Author.Username, OsuFont.GetFont(weight: FontWeight.Regular, italics: true)),
new Field("submitted on", online.Submitted.ToString(@"MMMM d, yyyy"), OsuFont.GetFont(weight: FontWeight.Bold))
new Field("submitted", online.Submitted, OsuFont.GetFont(weight: FontWeight.Bold))
{
Margin = new MarginPadding { Top = 5 },
},
@ -58,11 +59,11 @@ namespace osu.Game.Overlays.BeatmapSet
if (online.Ranked.HasValue)
{
fields.Add(new Field("ranked on", online.Ranked.Value.ToString(@"MMMM d, yyyy"), OsuFont.GetFont(weight: FontWeight.Bold)));
fields.Add(new Field("ranked", online.Ranked.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
}
else if (online.LastUpdated.HasValue)
{
fields.Add(new Field("last updated on", online.LastUpdated.Value.ToString(@"MMMM d, yyyy"), OsuFont.GetFont(weight: FontWeight.Bold)));
fields.Add(new Field("last updated", online.LastUpdated.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
}
}
@ -76,7 +77,7 @@ namespace osu.Game.Overlays.BeatmapSet
new Container
{
AutoSizeAxes = Axes.Both,
CornerRadius = 3,
CornerRadius = 4,
Masking = true,
Child = avatar = new UpdateableAvatar
{
@ -87,7 +88,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
Colour = Color4.Black.Opacity(0.25f),
Type = EdgeEffectType.Shadow,
Radius = 3,
Radius = 4,
Offset = new Vector2(0f, 1f),
},
},
@ -117,15 +118,34 @@ namespace osu.Game.Overlays.BeatmapSet
new OsuSpriteText
{
Text = $"{first} ",
Font = OsuFont.GetFont(size: 13)
Font = OsuFont.GetFont(size: 11)
},
new OsuSpriteText
{
Text = second,
Font = secondFont.With(size: 13)
Font = secondFont.With(size: 11)
},
};
}
public Field(string first, DateTimeOffset second, FontUsage secondFont)
{
AutoSizeAxes = Axes.Both;
Direction = FillDirection.Horizontal;
Children = new[]
{
new OsuSpriteText
{
Text = $"{first} ",
Font = OsuFont.GetFont(size: 13)
},
new DrawableDate(second)
{
Font = secondFont.With(size: 13)
}
};
}
}
}
}

View File

@ -105,7 +105,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
TooltipText = name;
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Height = 24f;
Children = new Drawable[]
{
@ -113,7 +113,8 @@ namespace osu.Game.Overlays.BeatmapSet
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
AutoSizeAxes = Axes.X,
RelativeSizeAxes = Axes.Y,
Children = new Drawable[]
{
new SpriteIcon
@ -121,7 +122,7 @@ namespace osu.Game.Overlays.BeatmapSet
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
Icon = FontAwesome.Solid.Square,
Size = new Vector2(13),
Size = new Vector2(12),
Rotation = 45,
Colour = OsuColour.FromHex(@"441288"),
},
@ -130,7 +131,7 @@ namespace osu.Game.Overlays.BeatmapSet
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
Icon = icon,
Size = new Vector2(13),
Size = new Vector2(12),
Colour = OsuColour.FromHex(@"f7dd55"),
Scale = new Vector2(0.8f),
},
@ -139,7 +140,7 @@ namespace osu.Game.Overlays.BeatmapSet
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Margin = new MarginPadding { Left = 10 },
Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold),
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
},
},
},

View File

@ -6,7 +6,6 @@ using System.Linq;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@ -19,7 +18,6 @@ using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.BeatmapSet
{
@ -34,7 +32,6 @@ namespace osu.Game.Overlays.BeatmapSet
public readonly DifficultiesContainer Difficulties;
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
private BeatmapSetInfo beatmapSet;
public BeatmapSetInfo BeatmapSet
@ -67,7 +64,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding { Left = -(tile_icon_padding + tile_spacing / 2) },
Margin = new MarginPadding { Left = -(tile_icon_padding + tile_spacing / 2), Bottom = 10 },
OnLostHover = () =>
{
showBeatmap(Beatmap.Value);
@ -77,7 +74,6 @@ namespace osu.Game.Overlays.BeatmapSet
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Top = 10 },
Spacing = new Vector2(5f),
Children = new[]
{
@ -85,13 +81,13 @@ namespace osu.Game.Overlays.BeatmapSet
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold)
Font = OsuFont.GetFont(size: 17, weight: FontWeight.Bold)
},
starRating = new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold),
Font = OsuFont.GetFont(size: 11, weight: FontWeight.Bold),
Text = "Star Difficulty",
Alpha = 0,
Margin = new MarginPadding { Bottom = 1 },
@ -192,9 +188,11 @@ namespace osu.Game.Overlays.BeatmapSet
public class DifficultySelectorButton : OsuClickableContainer, IStateful<DifficultySelectorState>
{
private const float transition_duration = 100;
private const float size = 52;
private const float size = 54;
private const float background_size = size - 2;
private readonly Container bg;
private readonly Container background;
private readonly Box backgroundBox;
private readonly DifficultyIcon icon;
public readonly BeatmapInfo Beatmap;
@ -230,16 +228,16 @@ namespace osu.Game.Overlays.BeatmapSet
Children = new Drawable[]
{
bg = new Container
background = new Container
{
RelativeSizeAxes = Axes.Both,
Size = new Vector2(background_size),
Masking = true,
CornerRadius = 4,
Child = new Box
Child = backgroundBox = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black.Opacity(0.5f),
},
Alpha = 0.5f
}
},
icon = new DifficultyIcon(beatmap, shouldShowTooltip: false)
{
@ -273,15 +271,21 @@ namespace osu.Game.Overlays.BeatmapSet
private void fadeIn()
{
bg.FadeIn(transition_duration);
background.FadeIn(transition_duration);
icon.FadeIn(transition_duration);
}
private void fadeOut()
{
bg.FadeOut();
background.FadeOut();
icon.FadeTo(0.7f, transition_duration);
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
backgroundBox.Colour = colourProvider.Background6;
}
}
private class Statistic : FillFlowContainer
@ -314,13 +318,13 @@ namespace osu.Game.Overlays.BeatmapSet
Origin = Anchor.CentreLeft,
Icon = icon,
Shadow = true,
Size = new Vector2(13),
Size = new Vector2(12),
},
text = new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold, italics: true)
Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold, italics: true),
},
};
}

View File

@ -22,6 +22,8 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
{
public class HeaderDownloadButton : BeatmapDownloadTrackingComposite, IHasTooltip
{
private const int text_size = 12;
private readonly bool noVideo;
public string TooltipText => button.Enabled.Value ? "download this beatmap" : "login to download";
@ -80,8 +82,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Icon = FontAwesome.Solid.Download,
Size = new Vector2(16),
Margin = new MarginPadding { Right = 5 },
Size = new Vector2(18),
},
}
},
@ -120,7 +121,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
new OsuSpriteText
{
Text = "Downloading...",
Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold)
Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold)
},
};
break;
@ -131,7 +132,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
new OsuSpriteText
{
Text = "Importing...",
Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold)
Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold)
},
};
break;
@ -146,12 +147,12 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
new OsuSpriteText
{
Text = "Download",
Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold)
Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold)
},
new OsuSpriteText
{
Text = getVideoSuffixText(),
Font = OsuFont.GetFont(size: 11, weight: FontWeight.Bold)
Font = OsuFont.GetFont(size: text_size - 2, weight: FontWeight.Bold)
},
};
this.FadeIn(200);

View File

@ -74,7 +74,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding { Vertical = 10 },
Padding = new MarginPadding { Vertical = 10 }
},
},
new DetailBox

View File

@ -144,12 +144,15 @@ namespace osu.Game.Overlays.BeatmapSet
},
}
},
artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true) },
artist = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true),
Margin = new MarginPadding { Bottom = 20 }
},
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding { Top = 20 },
Child = author = new AuthorInfo(),
},
beatmapAvailability = new BeatmapAvailability(),

View File

@ -20,8 +20,9 @@ namespace osu.Game.Overlays.BeatmapSet
public class Info : Container
{
private const float transition_duration = 250;
private const float metadata_width = 225;
private const float metadata_width = 175;
private const float spacing = 20;
private const float base_height = 220;
private readonly Box successRateBackground;
private readonly Box background;
@ -41,7 +42,7 @@ namespace osu.Game.Overlays.BeatmapSet
OsuSpriteText unrankedPlaceholder;
RelativeSizeAxes = Axes.X;
Height = 220;
Height = base_height;
Masking = true;
EdgeEffect = new EdgeEffectParameters
{
@ -135,6 +136,7 @@ namespace osu.Game.Overlays.BeatmapSet
var setHasLeaderboard = b.NewValue?.OnlineInfo?.Status > 0;
successRate.Alpha = setHasLeaderboard ? 1 : 0;
unrankedPlaceholder.Alpha = setHasLeaderboard ? 0 : 1;
Height = setHasLeaderboard ? 270 : base_height;
};
}
@ -176,8 +178,8 @@ namespace osu.Game.Overlays.BeatmapSet
new OsuSpriteText
{
Text = title,
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Black),
Margin = new MarginPadding { Top = 20 },
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold),
Margin = new MarginPadding { Top = 15 },
},
textFlow = new OsuTextFlowContainer
{

View File

@ -3,7 +3,6 @@
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Framework.Allocation;
using osuTK.Graphics;
using osu.Framework.Graphics.UserInterface;
@ -37,7 +36,6 @@ namespace osu.Game.Overlays.BeatmapSet
public ScopeSelectorTabItem(BeatmapLeaderboardScope value)
: base(value)
{
Text.Font = OsuFont.GetFont(size: 16);
}
protected override bool OnHover(HoverEvent e)

View File

@ -17,13 +17,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
private readonly Box background;
public DrawableTopScore(ScoreInfo score, int position = 1)
public DrawableTopScore(ScoreInfo score, int? position = 1)
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Masking = true;
CornerRadius = 5;
CornerRadius = 4;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
@ -46,7 +46,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
Vertical = 10,
Left = 10,
Right = 25,
Right = 30,
},
Children = new Drawable[]
{

View File

@ -21,7 +21,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 10),
Spacing = new Vector2(0, 20),
Children = new Drawable[]
{
new OsuSpriteText
@ -29,9 +29,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = @"You need to be an osu!supporter to access the friend and country rankings!",
Font = OsuFont.GetFont(weight: FontWeight.Bold),
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold),
},
text = new LinkFlowContainer(t => t.Font = t.Font.With(size: 12))
text = new LinkFlowContainer(t => t.Font = t.Font.With(size: 11))
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,

View File

@ -22,7 +22,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
public class ScoreTable : TableContainer
{
private const float horizontal_inset = 20;
private const float row_height = 25;
private const float row_height = 22;
private const int text_size = 12;
private readonly FillFlowContainer backgroundFlow;
@ -63,7 +63,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
return;
for (int i = 0; i < value.Count; i++)
backgroundFlow.Add(new ScoreTableRowBackground(i, value[i]));
backgroundFlow.Add(new ScoreTableRowBackground(i, value[i], row_height));
Columns = createHeaders(value[0]);
Content = value.Select((s, i) => createContent(i, s)).ToArray().ToRectangular();
@ -77,17 +77,20 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
new TableColumn("rank", Anchor.CentreRight, new Dimension(GridSizeMode.AutoSize)),
new TableColumn("", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 70)), // grade
new TableColumn("score", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)),
new TableColumn("accuracy", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 60, maxSize: 70)),
new TableColumn("player", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 150)),
new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 110))
new TableColumn("accuracy", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, minSize: 60, maxSize: 70)),
new TableColumn("", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 25)), // flag
new TableColumn("player", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 125)),
new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 120))
};
foreach (var statistic in score.SortedStatistics)
columns.Add(new TableColumn(statistic.Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 50, maxSize: 70)));
foreach (var statistic in score.SortedStatistics.Take(score.SortedStatistics.Count() - 1))
columns.Add(new TableColumn(statistic.Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 35, maxSize: 60)));
columns.Add(new TableColumn(score.SortedStatistics.LastOrDefault().Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 45, maxSize: 95)));
columns.AddRange(new[]
{
new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 40, maxSize: 70)),
new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30)),
new TableColumn("mods", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)),
});
@ -96,6 +99,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private Drawable[] createContent(int index, ScoreInfo score)
{
var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: text_size)) { AutoSizeAxes = Axes.Both };
username.AddUserLink(score.User);
var content = new List<Drawable>
{
new OsuSpriteText
@ -105,7 +111,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
},
new UpdateableRank(score.Rank)
{
Size = new Vector2(30, 20)
Size = new Vector2(28, 14)
},
new OsuSpriteText
{
@ -120,35 +126,19 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Font = OsuFont.GetFont(size: text_size),
Colour = score.Accuracy == 1 ? highAccuracyColour : Color4.White
},
};
var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: text_size)) { AutoSizeAxes = Axes.Both };
username.AddUserLink(score.User);
content.AddRange(new Drawable[]
{
new FillFlowContainer
new UpdateableFlag(score.User.Country)
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Margin = new MarginPadding { Right = horizontal_inset },
Spacing = new Vector2(5, 0),
Children = new Drawable[]
{
new UpdateableFlag(score.User.Country)
{
Size = new Vector2(20, 13),
ShowPlaceholderOnNull = false,
},
username
}
Size = new Vector2(19, 13),
ShowPlaceholderOnNull = false,
},
username,
new OsuSpriteText
{
Text = $@"{score.MaxCombo:N0}x",
Font = OsuFont.GetFont(size: text_size)
Font = OsuFont.GetFont(size: text_size),
Colour = score.MaxCombo == score.Beatmap?.MaxCombo ? highAccuracyColour : Color4.White
}
});
};
foreach (var kvp in score.SortedStatistics)
{

View File

@ -22,13 +22,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private readonly int index;
private readonly ScoreInfo score;
public ScoreTableRowBackground(int index, ScoreInfo score)
public ScoreTableRowBackground(int index, ScoreInfo score, float height)
{
this.index = index;
this.score = score;
RelativeSizeAxes = Axes.X;
Height = 25;
Height = height;
CornerRadius = 5;
Masking = true;

View File

@ -90,9 +90,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Width = 0.95f,
Direction = FillDirection.Vertical,
Margin = new MarginPadding { Vertical = spacing },
Padding = new MarginPadding { Horizontal = 50 },
Margin = new MarginPadding { Vertical = 20 },
Children = new Drawable[]
{
new FillFlowContainer
@ -121,7 +121,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Margin = new MarginPadding { Vertical = spacing },
Margin = new MarginPadding { Top = spacing },
Children = new Drawable[]
{
noScoresPlaceholder = new NoScoresPlaceholder

View File

@ -27,7 +27,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private const float bottom_columns_min_width = 45;
private readonly FontUsage smallFont = OsuFont.GetFont(size: 16);
private readonly FontUsage largeFont = OsuFont.GetFont(size: 22);
private readonly FontUsage largeFont = OsuFont.GetFont(size: 22, weight: FontWeight.Light);
private readonly TextColumn totalScoreColumn;
private readonly TextColumn accuracyColumn;
@ -47,7 +47,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(10, 8),
Children = new Drawable[]
{
new FillFlowContainer
@ -117,6 +116,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
public InfoColumn(string title, Drawable content, float? minWidth = null)
{
AutoSizeAxes = Axes.Both;
Margin = new MarginPadding { Vertical = 5 };
InternalChild = new GridContainer
{
@ -128,7 +128,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize),
new Dimension(GridSizeMode.Absolute, 4),
new Dimension(GridSizeMode.Absolute, 2),
new Dimension(GridSizeMode.AutoSize)
},
Content = new[]
@ -138,21 +138,24 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
text = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold),
Text = title.ToUpper()
Text = title.ToUpper(),
// 2px padding bottom + 1px vertical to compensate for the additional spacing because of 1.25 line-height in osu-web
Padding = new MarginPadding { Top = 1, Bottom = 3 }
}
},
new Drawable[]
{
separator = new Box
{
Anchor = Anchor.CentreLeft,
Anchor = Anchor.TopLeft,
RelativeSizeAxes = Axes.X,
Height = 2
}
Height = 2,
},
},
new[]
{
content
// osu-web has 4px margin here but also uses 0.9 line-height, reducing margin to 2px seems like a good alternative to that
content.With(c => c.Margin = new MarginPadding { Top = 2 })
}
}
};
@ -194,9 +197,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
public ModsInfoColumn()
: this(new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
AutoSizeAxes = Axes.X,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(1),
Height = 18f
})
{
}

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;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -12,7 +13,6 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Online.Leaderboards;
using osu.Game.Scoring;
using osu.Game.Users.Drawables;
using osu.Game.Utils;
using osuTK;
using osuTK.Graphics;
@ -24,7 +24,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private readonly UpdateableRank rank;
private readonly UpdateableAvatar avatar;
private readonly LinkFlowContainer usernameText;
private readonly SpriteText date;
private readonly DrawableDate achievedOn;
private readonly UpdateableFlag flag;
public TopScoreUserSection()
@ -67,7 +67,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Origin = Anchor.Centre,
Size = new Vector2(70),
Masking = true,
CornerRadius = 5,
CornerRadius = 4,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
@ -92,11 +92,24 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
},
date = new OsuSpriteText
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Font = OsuFont.GetFont(size: 10)
Children = new[]
{
new OsuSpriteText
{
Text = "achieved ",
Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold)
},
achievedOn = new DrawableDate(DateTimeOffset.MinValue)
{
Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold)
},
}
},
flag = new UpdateableFlag
{
@ -112,9 +125,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
};
}
public int ScorePosition
public int? ScorePosition
{
set => rankText.Text = $"#{value}";
set => rankText.Text = value == null ? "-" : $"#{value}";
}
/// <summary>
@ -126,7 +139,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
avatar.User = value.User;
flag.Country = value.User.Country;
date.Text = $@"achieved {HumanizerUtils.Humanize(value.Date)}";
achievedOn.Date = value.Date;
usernameText.Clear();
usernameText.AddUserLink(value.User);

View File

@ -65,7 +65,7 @@ namespace osu.Game.Overlays.BeatmapSet
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = "Success Rate",
Font = OsuFont.GetFont(size: 13)
Font = OsuFont.GetFont(size: 12)
},
successRate = new Bar
{
@ -82,7 +82,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopCentre,
Font = OsuFont.GetFont(size: 13),
Font = OsuFont.GetFont(size: 12),
},
},
new OsuSpriteText
@ -90,7 +90,7 @@ namespace osu.Game.Overlays.BeatmapSet
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = "Points of Failure",
Font = OsuFont.GetFont(size: 13),
Font = OsuFont.GetFont(size: 12),
Margin = new MarginPadding { Vertical = 20 },
},
},

View File

@ -34,14 +34,13 @@ namespace osu.Game.Overlays.Direct
public enum DirectSortCriteria
{
Relevance,
Title,
Artist,
Creator,
Difficulty,
Ranked,
Rating,
Plays,
Favourites,
Relevance,
}
}

View File

@ -75,8 +75,6 @@ namespace osu.Game.Overlays.Music
},
};
list.Items.BindTo(beatmapSets);
filter.Search.OnCommit = (sender, newText) =>
{
BeatmapInfo toSelect = list.FirstVisibleSet?.Beatmaps?.FirstOrDefault();
@ -87,7 +85,13 @@ namespace osu.Game.Overlays.Music
beatmap.Value.Track.Restart();
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
list.Items.BindTo(beatmapSets);
beatmap.BindValueChanged(working => list.SelectedSet.Value = working.NewValue.BeatmapSetInfo, true);
}

View File

@ -25,7 +25,16 @@ namespace osu.Game.Overlays
[Resolved]
private BeatmapManager beatmaps { get; set; }
public IBindableList<BeatmapSetInfo> BeatmapSets => beatmapSets;
public IBindableList<BeatmapSetInfo> BeatmapSets
{
get
{
if (LoadState < LoadState.Ready)
throw new InvalidOperationException($"{nameof(BeatmapSets)} should not be accessed before the music controller is loaded.");
return beatmapSets;
}
}
/// <summary>
/// Point in time after which the current track will be restarted on triggering a "previous track" action.
@ -54,16 +63,18 @@ namespace osu.Game.Overlays
[BackgroundDependencyLoader]
private void load()
{
beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets().OrderBy(_ => RNG.Next()));
beatmaps.ItemAdded += handleBeatmapAdded;
beatmaps.ItemRemoved += handleBeatmapRemoved;
beatmapSets.AddRange(beatmaps.GetAllUsableBeatmapSets().OrderBy(_ => RNG.Next()));
}
protected override void LoadComplete()
{
base.LoadComplete();
beatmap.BindValueChanged(beatmapChanged, true);
mods.BindValueChanged(_ => ResetTrackAdjustments(), true);
base.LoadComplete();
}
/// <summary>
@ -82,11 +93,16 @@ namespace osu.Game.Overlays
/// </summary>
public bool IsPlaying => current?.Track.IsRunning ?? false;
private void handleBeatmapAdded(BeatmapSetInfo set) =>
Schedule(() => beatmapSets.Add(set));
private void handleBeatmapAdded(BeatmapSetInfo set) => Schedule(() =>
{
if (!beatmapSets.Contains(set))
beatmapSets.Add(set);
});
private void handleBeatmapRemoved(BeatmapSetInfo set) =>
Schedule(() => beatmapSets.RemoveAll(s => s.ID == set.ID));
private void handleBeatmapRemoved(BeatmapSetInfo set) => Schedule(() =>
{
beatmapSets.RemoveAll(s => s.ID == set.ID);
});
private ScheduledDelegate seekDelegate;

View File

@ -58,6 +58,9 @@ namespace osu.Game.Overlays
[Resolved]
private Bindable<WorkingBeatmap> beatmap { get; set; }
[Resolved]
private OsuColour colours { get; set; }
public NowPlayingOverlay()
{
Width = 400;
@ -65,7 +68,7 @@ namespace osu.Game.Overlays
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load()
{
Children = new Drawable[]
{
@ -182,15 +185,15 @@ namespace osu.Game.Overlays
}
}
};
playlist.BeatmapSets.BindTo(musicController.BeatmapSets);
playlist.State.ValueChanged += s => playlistButton.FadeColour(s.NewValue == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint);
}
protected override void LoadComplete()
{
base.LoadComplete();
playlist.BeatmapSets.BindTo(musicController.BeatmapSets);
playlist.State.BindValueChanged(s => playlistButton.FadeColour(s.NewValue == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint), true);
beatmap.BindDisabledChanged(beatmapDisabledChanged, true);
musicController.TrackChanged += trackChanged;

View File

@ -9,6 +9,7 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Graphics;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Rankings.Tables
{
@ -61,18 +62,35 @@ namespace osu.Game.Overlays.Rankings.Tables
}
};
private class CountryName : OsuSpriteText
private class CountryName : OsuHoverContainer
{
protected override IEnumerable<Drawable> EffectTargets => new[] { text };
[Resolved(canBeNull: true)]
private RankingsOverlay rankings { get; set; }
private readonly OsuSpriteText text;
private readonly Country country;
public CountryName(Country country)
{
Font = OsuFont.GetFont(size: 12);
Text = country.FullName ?? string.Empty;
this.country = country;
AutoSizeAxes = Axes.Both;
Add(text = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 12),
Text = country.FullName ?? string.Empty,
});
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
Colour = colourProvider.Light2;
IdleColour = colourProvider.Light2;
HoverColour = colourProvider.Content2;
Action = () => rankings?.ShowCountry(country);
}
}
}

View File

@ -346,20 +346,27 @@ namespace osu.Game.Rulesets.Objects.Drawables
private void updateComboColour()
{
if (HitObject is IHasComboInformation combo)
{
var comboColours = CurrentSkin.GetConfig<GlobalSkinColours, IReadOnlyList<Color4>>(GlobalSkinColours.ComboColours)?.Value;
UpdateComboColour(comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White, comboColours);
}
if (!(HitObject is IHasComboInformation)) return;
var comboColours = CurrentSkin.GetConfig<GlobalSkinColours, IReadOnlyList<Color4>>(GlobalSkinColours.ComboColours)?.Value;
AccentColour.Value = GetComboColour(comboColours);
}
/// <summary>
/// Called when a combo colour change is proposed.
/// Called to retrieve the combo colour. Automatically assigned to <see cref="AccentColour"/>.
/// Defaults to using <see cref="IHasComboInformation.ComboIndex"/> to decide on a colour.
/// </summary>
/// <param name="proposedColour">The proposed combo colour, based off the combo index.</param>
/// <remarks>
/// This will only be called if the <see cref="HitObject"/> implements <see cref="IHasComboInformation"/>.
/// </remarks>
/// <param name="comboColours">A list of combo colours provided by the beatmap or skin. Can be null if not available.</param>
protected virtual void UpdateComboColour(Color4 proposedColour, IReadOnlyList<Color4> comboColours)
protected virtual Color4 GetComboColour(IReadOnlyList<Color4> comboColours)
{
if (!(HitObject is IHasComboInformation combo))
throw new InvalidOperationException($"{nameof(HitObject)} must implement {nameof(IHasComboInformation)}");
return comboColours?.Count > 0 ? comboColours[combo.ComboIndex % comboColours.Count] : Color4.White;
}
/// <summary>

View File

@ -53,7 +53,7 @@ namespace osu.Game.Screens.Multi.Components
{
new TriangleButton
{
Text = "create new item",
Text = "Add new playlist entry",
RelativeSizeAxes = Axes.Both,
Size = Vector2.One,
Action = () => CreateNewItem?.Invoke()

View File

@ -9,12 +9,32 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osuTK;
namespace osu.Game.Screens.Multi.Match.Components
namespace osu.Game.Screens.Multi.Components
{
public abstract class OverlinedDisplay : MultiplayerComposite
{
protected readonly Container Content;
public override Axes RelativeSizeAxes
{
get => base.RelativeSizeAxes;
set
{
base.RelativeSizeAxes = value;
updateDimensions();
}
}
public override Axes AutoSizeAxes
{
get => base.AutoSizeAxes;
protected set
{
base.AutoSizeAxes = value;
updateDimensions();
}
}
protected string Details
{
set => details.Text = value;
@ -22,14 +42,12 @@ namespace osu.Game.Screens.Multi.Match.Components
private readonly Circle line;
private readonly OsuSpriteText details;
private readonly GridContainer grid;
protected OverlinedDisplay(string title)
{
RelativeSizeAxes = Axes.Both;
InternalChild = new GridContainer
InternalChild = grid = new GridContainer
{
RelativeSizeAxes = Axes.Both,
Content = new[]
{
new Drawable[]
@ -62,19 +80,12 @@ namespace osu.Game.Screens.Multi.Match.Components
},
new Drawable[]
{
Content = new Container
{
Margin = new MarginPadding { Top = 5 },
RelativeSizeAxes = Axes.Both
}
Content = new Container { Margin = new MarginPadding { Top = 5 } }
}
},
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize),
new Dimension(GridSizeMode.AutoSize),
}
};
updateDimensions();
}
[BackgroundDependencyLoader]
@ -83,5 +94,23 @@ namespace osu.Game.Screens.Multi.Match.Components
line.Colour = colours.Yellow;
details.Colour = colours.Yellow;
}
private void updateDimensions()
{
grid.RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize),
new Dimension(GridSizeMode.AutoSize),
new Dimension(AutoSizeAxes.HasFlag(Axes.Y) ? GridSizeMode.AutoSize : GridSizeMode.Distributed),
};
// Assigning to none is done so that setting auto and relative size modes doesn't cause exceptions to be thrown
grid.AutoSizeAxes = Content.AutoSizeAxes = Axes.None;
grid.RelativeSizeAxes = Content.RelativeSizeAxes = Axes.None;
// Auto-size when required, otherwise eagerly relative-size
grid.AutoSizeAxes = Content.AutoSizeAxes = AutoSizeAxes;
grid.RelativeSizeAxes = Content.RelativeSizeAxes = ~AutoSizeAxes;
}
}
}

View File

@ -0,0 +1,56 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics.Containers;
namespace osu.Game.Screens.Multi.Components
{
public class OverlinedParticipants : OverlinedDisplay
{
public new Axes AutoSizeAxes
{
get => base.AutoSizeAxes;
set => base.AutoSizeAxes = value;
}
public OverlinedParticipants(Direction direction)
: base("Participants")
{
OsuScrollContainer scroll;
ParticipantsList list;
Content.Add(scroll = new OsuScrollContainer(direction)
{
Child = list = new ParticipantsList()
});
switch (direction)
{
case Direction.Horizontal:
scroll.RelativeSizeAxes = Axes.X;
scroll.Height = ParticipantsList.TILE_SIZE + OsuScrollContainer.SCROLL_BAR_HEIGHT + OsuScrollContainer.SCROLL_BAR_PADDING * 2;
list.AutoSizeAxes = Axes.Both;
break;
case Direction.Vertical:
scroll.RelativeSizeAxes = Axes.Both;
list.RelativeSizeAxes = Axes.X;
list.AutoSizeAxes = Axes.Y;
break;
}
}
[BackgroundDependencyLoader]
private void load()
{
ParticipantCount.BindValueChanged(_ => setParticipantCount());
MaxParticipants.BindValueChanged(_ => setParticipantCount());
setParticipantCount();
}
private void setParticipantCount() => Details = MaxParticipants.Value != null ? $"{ParticipantCount.Value}/{MaxParticipants.Value}" : ParticipantCount.Value.ToString();
}
}

View File

@ -6,7 +6,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Online.Multiplayer;
namespace osu.Game.Screens.Multi.Match.Components
namespace osu.Game.Screens.Multi.Components
{
public class OverlinedPlaylist : OverlinedDisplay
{

View File

@ -8,7 +8,6 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Users;
@ -19,21 +18,39 @@ namespace osu.Game.Screens.Multi.Components
{
public class ParticipantsList : MultiplayerComposite
{
public const float TILE_SIZE = 35;
public override Axes RelativeSizeAxes
{
get => base.RelativeSizeAxes;
set
{
base.RelativeSizeAxes = value;
fill.RelativeSizeAxes = value;
}
}
public new Axes AutoSizeAxes
{
get => base.AutoSizeAxes;
set
{
base.AutoSizeAxes = value;
fill.AutoSizeAxes = value;
}
}
public FillDirection Direction
{
get => fill.Direction;
set => fill.Direction = value;
}
private readonly FillFlowContainer fill;
public ParticipantsList()
{
InternalChild = new OsuScrollContainer
{
RelativeSizeAxes = Axes.Both,
Child = fill = new FillFlowContainer
{
Spacing = new Vector2(10),
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Full,
}
};
InternalChild = fill = new FillFlowContainer { Spacing = new Vector2(10) };
}
[BackgroundDependencyLoader]
@ -96,7 +113,7 @@ namespace osu.Game.Screens.Multi.Components
public UserTile(User user)
{
this.user = user;
Size = new Vector2(70f);
Size = new Vector2(TILE_SIZE);
CornerRadius = 5f;
Masking = true;

View File

@ -52,7 +52,7 @@ namespace osu.Game.Screens.Multi
private readonly bool allowEdit;
private readonly bool allowSelection;
protected override bool ShouldBeConsideredForInput(Drawable child) => allowEdit || SelectedItem.Value == Model;
protected override bool ShouldBeConsideredForInput(Drawable child) => allowEdit || !allowSelection || SelectedItem.Value == Model;
public DrawableRoomPlaylistItem(PlaylistItem item, bool allowEdit, bool allowSelection)
: base(item)

View File

@ -4,8 +4,8 @@
using System.ComponentModel;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Threading;
using osu.Game.Graphics;
using osu.Game.Overlays.SearchableList;
using osu.Game.Rulesets;
using osuTK.Graphics;
@ -14,7 +14,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components
{
public class FilterControl : SearchableListFilterControl<PrimaryFilter, SecondaryFilter>
{
protected override Color4 BackgroundColour => OsuColour.FromHex(@"362e42");
protected override Color4 BackgroundColour => Color4.Black.Opacity(0.5f);
protected override PrimaryFilter DefaultTab => PrimaryFilter.Open;
protected override SecondaryFilter DefaultCategory => SecondaryFilter.Public;

View File

@ -0,0 +1,89 @@
// 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.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Screens.Multi.Components;
using osuTK;
namespace osu.Game.Screens.Multi.Lounge.Components
{
public class RoomInfo : MultiplayerComposite
{
private readonly List<Drawable> statusElements = new List<Drawable>();
private readonly SpriteText roomName;
public RoomInfo()
{
AutoSizeAxes = Axes.Y;
RoomStatusInfo statusInfo;
ModeTypeInfo typeInfo;
ParticipantInfo participantInfo;
InternalChild = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 4),
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
new FillFlowContainer
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
roomName = new OsuSpriteText { Font = OsuFont.GetFont(size: 30) },
statusInfo = new RoomStatusInfo(),
}
},
typeInfo = new ModeTypeInfo
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight
}
}
},
participantInfo = new ParticipantInfo(),
}
};
statusElements.AddRange(new Drawable[] { statusInfo, typeInfo, participantInfo });
}
protected override void LoadComplete()
{
base.LoadComplete();
if (RoomID.Value == null)
statusElements.ForEach(e => e.FadeOut());
RoomID.BindValueChanged(id =>
{
if (id.NewValue == null)
statusElements.ForEach(e => e.FadeOut(100));
else
statusElements.ForEach(e => e.FadeIn(100));
}, true);
RoomName.BindValueChanged(name =>
{
roomName.Text = name.NewValue ?? "No room selected";
}, true);
}
}
}

View File

@ -2,18 +2,12 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Components;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.Multi.Lounge.Components
@ -24,16 +18,9 @@ namespace osu.Game.Screens.Multi.Lounge.Components
private readonly MarginPadding contentPadding = new MarginPadding { Horizontal = 20, Vertical = 10 };
private ParticipantCountDisplay participantCount;
private OsuSpriteText name;
private BeatmapTypeInfo beatmapTypeInfo;
private ParticipantInfo participantInfo;
[Resolved]
private BeatmapManager beatmaps { get; set; }
private readonly Bindable<RoomStatus> status = new Bindable<RoomStatus>(new RoomStatusNoneSelected());
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
@ -42,177 +29,52 @@ namespace osu.Game.Screens.Multi.Lounge.Components
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"343138"),
Colour = Color4.Black,
Alpha = 0.25f
},
new GridContainer
new Container
{
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
Padding = new MarginPadding { Horizontal = 30 },
Child = new GridContainer
{
new Dimension(GridSizeMode.AutoSize),
new Dimension(GridSizeMode.Distributed),
},
Content = new[]
{
new Drawable[]
RelativeSizeAxes = Axes.Both,
Content = new[]
{
new FillFlowContainer
new Drawable[]
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children = new Drawable[]
new FillFlowContainer
{
new Container
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
RelativeSizeAxes = Axes.X,
Height = 200,
Masking = true,
Children = new Drawable[]
new RoomInfo
{
new MultiplayerBackgroundSprite { RelativeSizeAxes = Axes.Both },
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.5f), Color4.Black.Opacity(0)),
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(20),
Children = new Drawable[]
{
participantCount = new ParticipantCountDisplay
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
},
name = new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Font = OsuFont.GetFont(size: 30),
Current = RoomName
},
},
},
RelativeSizeAxes = Axes.X,
Margin = new MarginPadding { Vertical = 60 },
},
},
new StatusColouredContainer(transition_duration)
{
RelativeSizeAxes = Axes.X,
Height = 5,
Child = new Box { RelativeSizeAxes = Axes.Both }
},
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
new OverlinedParticipants(Direction.Horizontal)
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"28242d"),
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
LayoutDuration = transition_duration,
Padding = contentPadding,
Spacing = new Vector2(0f, 5f),
Children = new Drawable[]
{
new StatusColouredContainer(transition_duration)
{
AutoSizeAxes = Axes.Both,
Child = new StatusText
{
Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14),
}
},
beatmapTypeInfo = new BeatmapTypeInfo(),
},
},
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y
},
},
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = contentPadding,
Children = new Drawable[]
{
participantInfo = new ParticipantInfo(),
},
},
},
}
}
},
new Drawable[]
{
new OverlinedPlaylist(false) { RelativeSizeAxes = Axes.Both },
},
},
new Drawable[]
RowDimensions = new[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Horizontal = 10 },
Child = new ParticipantsList { RelativeSizeAxes = Axes.Both }
}
new Dimension(GridSizeMode.AutoSize),
}
}
}
};
Status.BindValueChanged(_ => updateStatus(), true);
RoomID.BindValueChanged(_ => updateStatus(), true);
}
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs(status, new CacheInfo(nameof(Room.Status), typeof(Room)));
return dependencies;
}
private void updateStatus()
{
if (RoomID.Value == null)
{
status.Value = new RoomStatusNoneSelected();
participantCount.FadeOut(transition_duration);
beatmapTypeInfo.FadeOut(transition_duration);
name.FadeOut(transition_duration);
participantInfo.FadeOut(transition_duration);
}
else
{
status.Value = Status.Value;
participantCount.FadeIn(transition_duration);
beatmapTypeInfo.FadeIn(transition_duration);
name.FadeIn(transition_duration);
participantInfo.FadeIn(transition_duration);
}
}
private class RoomStatusNoneSelected : RoomStatus
{
public override string Message => @"No Room Selected";
public override Color4 GetAppropriateColour(OsuColour colours) => colours.Gray8;
}
private class StatusText : OsuSpriteText
{
[Resolved(typeof(Room), nameof(Room.Status))]
private Bindable<RoomStatus> status { get; set; }
[BackgroundDependencyLoader]
private void load()
{
status.BindValueChanged(s => Text = s.NewValue.Message, true);
}
}
}
}

View File

@ -30,6 +30,8 @@ namespace osu.Game.Screens.Multi.Lounge
public LoungeSubScreen()
{
SearchContainer searchContainer;
InternalChildren = new Drawable[]
{
Filter = new FilterControl { Depth = -1 },
@ -49,14 +51,14 @@ namespace osu.Game.Screens.Multi.Lounge
RelativeSizeAxes = Axes.Both,
ScrollbarOverlapsContent = false,
Padding = new MarginPadding(10),
Child = new SearchContainer
Child = searchContainer = new SearchContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = new RoomsContainer { JoinRequested = joinRequested }
},
},
processingOverlay = new ProcessingOverlay { Alpha = 0 }
processingOverlay = new ProcessingOverlay(searchContainer),
}
},
new RoomInspector

View File

@ -8,7 +8,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
using osuTK;
@ -22,7 +21,6 @@ namespace osu.Game.Screens.Multi.Match.Components
public readonly Bindable<PlaylistItem> SelectedItem = new Bindable<PlaylistItem>();
private readonly Drawable background;
private readonly OsuButton startButton;
public Footer()
{
@ -32,7 +30,7 @@ namespace osu.Game.Screens.Multi.Match.Components
InternalChildren = new[]
{
background = new Box { RelativeSizeAxes = Axes.Both },
startButton = new ReadyButton
new ReadyButton
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@ -47,7 +45,6 @@ namespace osu.Game.Screens.Multi.Match.Components
private void load(OsuColour colours)
{
background.Colour = OsuColour.FromHex(@"28242d");
startButton.BackgroundColour = colours.Green;
}
}
}

View File

@ -79,226 +79,235 @@ namespace osu.Game.Screens.Multi.Match.Components
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Container dimContent;
InternalChildren = new Drawable[]
{
new Box
dimContent = new Container
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"28242d"),
},
new GridContainer
{
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
Children = new Drawable[]
{
new Dimension(GridSizeMode.Distributed),
new Dimension(GridSizeMode.AutoSize),
},
Content = new[]
{
new Drawable[]
new Box
{
new OsuScrollContainer
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"28242d"),
},
new GridContainer
{
RelativeSizeAxes = Axes.Both,
RowDimensions = new[]
{
Padding = new MarginPadding
new Dimension(GridSizeMode.Distributed),
new Dimension(GridSizeMode.AutoSize),
},
Content = new[]
{
new Drawable[]
{
Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
Vertical = 10
},
RelativeSizeAxes = Axes.Both,
Children = new[]
{
new Container
new OsuScrollContainer
{
Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING },
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
Padding = new MarginPadding
{
new SectionContainer
Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING,
Vertical = 10
},
RelativeSizeAxes = Axes.Both,
Children = new[]
{
new Container
{
Padding = new MarginPadding { Right = field_padding / 2 },
Children = new[]
Padding = new MarginPadding { Horizontal = SearchableListOverlay.WIDTH_PADDING },
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
new Section("Room name")
new SectionContainer
{
Child = NameField = new SettingsTextBox
Padding = new MarginPadding { Right = field_padding / 2 },
Children = new[]
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
OnCommit = (sender, text) => apply(),
},
},
new Section("Duration")
{
Child = DurationField = new DurationDropdown
{
RelativeSizeAxes = Axes.X,
Items = new[]
new Section("Room name")
{
TimeSpan.FromMinutes(30),
TimeSpan.FromHours(1),
TimeSpan.FromHours(2),
TimeSpan.FromHours(4),
TimeSpan.FromHours(8),
TimeSpan.FromHours(12),
//TimeSpan.FromHours(16),
TimeSpan.FromHours(24),
TimeSpan.FromDays(3),
TimeSpan.FromDays(7)
}
}
},
new Section("Room visibility")
{
Alpha = disabled_alpha,
Child = AvailabilityPicker = new RoomAvailabilityPicker
{
Enabled = { Value = false }
},
},
new Section("Game type")
{
Alpha = disabled_alpha,
Child = new FillFlowContainer
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Direction = FillDirection.Vertical,
Spacing = new Vector2(7),
Children = new Drawable[]
{
TypePicker = new GameTypePicker
Child = NameField = new SettingsTextBox
{
RelativeSizeAxes = Axes.X,
Enabled = { Value = false }
},
typeLabel = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 14),
Colour = colours.Yellow
TabbableContentContainer = this,
OnCommit = (sender, text) => apply(),
},
},
},
},
new Section("Max participants")
{
Alpha = disabled_alpha,
Child = MaxParticipantsField = new SettingsNumberTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
ReadOnly = true,
OnCommit = (sender, text) => apply()
},
},
new Section("Password (optional)")
{
Alpha = disabled_alpha,
Child = new SettingsPasswordTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
ReadOnly = true,
OnCommit = (sender, text) => apply()
},
},
},
},
new SectionContainer
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Padding = new MarginPadding { Left = field_padding / 2 },
Children = new[]
{
new Section("Playlist")
{
Child = new GridContainer
{
RelativeSizeAxes = Axes.X,
Height = 300,
Content = new[]
new Section("Duration")
{
new Drawable[]
Child = DurationField = new DurationDropdown
{
playlist = new DrawableRoomPlaylist(true, true) { RelativeSizeAxes = Axes.Both }
},
new Drawable[]
{
new OsuButton
RelativeSizeAxes = Axes.X,
Items = new[]
{
RelativeSizeAxes = Axes.X,
Height = 40,
Text = "Edit playlist",
Action = () => EditPlaylist?.Invoke()
TimeSpan.FromMinutes(30),
TimeSpan.FromHours(1),
TimeSpan.FromHours(2),
TimeSpan.FromHours(4),
TimeSpan.FromHours(8),
TimeSpan.FromHours(12),
//TimeSpan.FromHours(16),
TimeSpan.FromHours(24),
TimeSpan.FromDays(3),
TimeSpan.FromDays(7)
}
}
},
RowDimensions = new[]
new Section("Room visibility")
{
new Dimension(),
new Dimension(GridSizeMode.AutoSize),
}
}
Alpha = disabled_alpha,
Child = AvailabilityPicker = new RoomAvailabilityPicker
{
Enabled = { Value = false }
},
},
new Section("Game type")
{
Alpha = disabled_alpha,
Child = new FillFlowContainer
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Direction = FillDirection.Vertical,
Spacing = new Vector2(7),
Children = new Drawable[]
{
TypePicker = new GameTypePicker
{
RelativeSizeAxes = Axes.X,
Enabled = { Value = false }
},
typeLabel = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 14),
Colour = colours.Yellow
},
},
},
},
new Section("Max participants")
{
Alpha = disabled_alpha,
Child = MaxParticipantsField = new SettingsNumberTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
ReadOnly = true,
OnCommit = (sender, text) => apply()
},
},
new Section("Password (optional)")
{
Alpha = disabled_alpha,
Child = new SettingsPasswordTextBox
{
RelativeSizeAxes = Axes.X,
TabbableContentContainer = this,
ReadOnly = true,
OnCommit = (sender, text) => apply()
},
},
},
},
new SectionContainer
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Padding = new MarginPadding { Left = field_padding / 2 },
Children = new[]
{
new Section("Playlist")
{
Child = new GridContainer
{
RelativeSizeAxes = Axes.X,
Height = 300,
Content = new[]
{
new Drawable[]
{
playlist = new DrawableRoomPlaylist(true, true) { RelativeSizeAxes = Axes.Both }
},
new Drawable[]
{
new PurpleTriangleButton
{
RelativeSizeAxes = Axes.X,
Height = 40,
Text = "Edit playlist",
Action = () => EditPlaylist?.Invoke()
}
}
},
RowDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.AutoSize),
}
}
},
},
},
},
},
}
},
}
},
},
},
new Drawable[]
{
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Y = 2,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"28242d").Darken(0.5f).Opacity(1f),
},
new FillFlowContainer
},
new Drawable[]
{
new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Y = 2,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 20),
Margin = new MarginPadding { Vertical = 20 },
Padding = new MarginPadding { Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING },
Children = new Drawable[]
{
ApplyButton = new CreateRoomButton
new Box
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Size = new Vector2(230, 55),
Enabled = { Value = false },
Action = apply,
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"28242d").Darken(0.5f).Opacity(1f),
},
ErrorText = new OsuSpriteText
new FillFlowContainer
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Alpha = 0,
Depth = 1,
Colour = colours.RedDark
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 20),
Margin = new MarginPadding { Vertical = 20 },
Padding = new MarginPadding { Horizontal = OsuScreen.HORIZONTAL_OVERFLOW_PADDING },
Children = new Drawable[]
{
ApplyButton = new CreateRoomButton
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Size = new Vector2(230, 55),
Enabled = { Value = false },
Action = apply,
},
ErrorText = new OsuSpriteText
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Alpha = 0,
Depth = 1,
Colour = colours.RedDark
}
}
}
}
}
}
}
}
},
}
},
processingOverlay = new ProcessingOverlay { Alpha = 0 }
processingOverlay = new ProcessingOverlay(dimContent)
};
TypePicker.Current.BindValueChanged(type => typeLabel.Text = type.NewValue?.Name ?? string.Empty, true);
@ -447,10 +456,7 @@ namespace osu.Game.Screens.Multi.Match.Components
Menu.MaxHeight = 100;
}
protected override string GenerateItemText(TimeSpan item)
{
return item.Humanize();
}
protected override string GenerateItemText(TimeSpan item) => item.Humanize();
}
}
}

View File

@ -1,29 +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 osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Screens.Multi.Components;
namespace osu.Game.Screens.Multi.Match.Components
{
public class OverlinedParticipants : OverlinedDisplay
{
public OverlinedParticipants()
: base("Participants")
{
Content.Add(new ParticipantsList { RelativeSizeAxes = Axes.Both });
}
[BackgroundDependencyLoader]
private void load()
{
ParticipantCount.BindValueChanged(_ => setParticipantCount());
MaxParticipants.BindValueChanged(_ => setParticipantCount());
setParticipantCount();
}
private void setParticipantCount() => Details = MaxParticipants.Value != null ? $"{ParticipantCount.Value}/{MaxParticipants.Value}" : ParticipantCount.Value.ToString();
}
}

View File

@ -0,0 +1,20 @@
// 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 osu.Framework.Allocation;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Screens.Multi.Match.Components
{
public class PurpleTriangleButton : TriangleButton
{
[BackgroundDependencyLoader]
private void load()
{
BackgroundColour = OsuColour.FromHex(@"593790");
Triangles.ColourLight = OsuColour.FromHex(@"7247b6");
Triangles.ColourDark = OsuColour.FromHex(@"593790");
}
}
}

View File

@ -6,12 +6,13 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Multiplayer;
namespace osu.Game.Screens.Multi.Match.Components
{
public class ReadyButton : OsuButton
public class ReadyButton : TriangleButton
{
public readonly Bindable<PlaylistItem> SelectedItem = new Bindable<PlaylistItem>();
@ -32,12 +33,16 @@ namespace osu.Game.Screens.Multi.Match.Components
}
[BackgroundDependencyLoader]
private void load()
private void load(OsuColour colours)
{
beatmaps.ItemAdded += beatmapAdded;
beatmaps.ItemRemoved += beatmapRemoved;
SelectedItem.BindValueChanged(item => updateSelectedItem(item.NewValue), true);
BackgroundColour = colours.Green;
Triangles.ColourDark = colours.Green;
Triangles.ColourLight = colours.GreenLight;
}
private void updateSelectedItem(PlaylistItem item)

View File

@ -5,14 +5,11 @@ using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Screens;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.GameTypes;
using osu.Game.Rulesets.Mods;
@ -20,7 +17,6 @@ using osu.Game.Screens.Multi.Components;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Screens.Multi.Play;
using osu.Game.Screens.Select;
using osuTK.Graphics;
using Footer = osu.Game.Screens.Multi.Match.Components.Footer;
namespace osu.Game.Screens.Multi.Match
@ -64,12 +60,6 @@ namespace osu.Game.Screens.Multi.Match
{
InternalChildren = new Drawable[]
{
new HeaderBackgroundSprite
{
RelativeSizeAxes = Axes.X,
Height = 200,
Colour = ColourInfo.GradientVertical(Color4.White.Opacity(0.4f), Color4.White.Opacity(0))
},
new GridContainer
{
RelativeSizeAxes = Axes.Both,
@ -114,7 +104,7 @@ namespace osu.Game.Screens.Multi.Match
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Right = 5 },
Child = new OverlinedParticipants()
Child = new OverlinedParticipants(Direction.Vertical) { RelativeSizeAxes = Axes.Both }
},
new Container
{
@ -122,6 +112,7 @@ namespace osu.Game.Screens.Multi.Match
Padding = new MarginPadding { Horizontal = 5 },
Child = new OverlinedPlaylist(true) // Temporarily always allow selection
{
RelativeSizeAxes = Axes.Both,
SelectedItem = { BindTarget = SelectedItem }
}
},
@ -252,15 +243,5 @@ namespace osu.Game.Screens.Multi.Match
if (beatmapManager != null)
beatmapManager.ItemAdded -= beatmapAdded;
}
private class HeaderBackgroundSprite : MultiplayerBackgroundSprite
{
protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BackgroundSprite { RelativeSizeAxes = Axes.Both };
private class BackgroundSprite : UpdateableBeatmapBackgroundSprite
{
protected override double TransformDuration => 200;
}
}
}
}

View File

@ -4,24 +4,27 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Logging;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Input;
using osu.Game.Online.API;
using osu.Game.Online.Multiplayer;
using osu.Game.Overlays.BeatmapSet.Buttons;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Multi.Components;
using osu.Game.Screens.Multi.Lounge;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Screens.Multi.Match;
using osu.Game.Screens.Multi.Match.Components;
using osu.Game.Screens.Play;
using osuTK;
@ -62,6 +65,9 @@ namespace osu.Game.Screens.Multi
[Resolved(CanBeNull = true)]
private OsuLogo logo { get; set; }
private readonly Drawable header;
private readonly Drawable headerBackground;
public Multiplayer()
{
Anchor = Anchor.Centre;
@ -69,54 +75,65 @@ namespace osu.Game.Screens.Multi
RelativeSizeAxes = Axes.Both;
Padding = new MarginPadding { Horizontal = -HORIZONTAL_OVERFLOW_PADDING };
var backgroundColour = OsuColour.FromHex(@"3e3a44");
InternalChild = waves = new MultiplayerWaveContainer
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Container
new Box
{
RelativeSizeAxes = Axes.Both,
Masking = true,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"3e3a44"),
},
new Triangles
{
RelativeSizeAxes = Axes.Both,
ColourLight = OsuColour.FromHex(@"3c3842"),
ColourDark = OsuColour.FromHex(@"393540"),
TriangleScale = 5,
},
},
Colour = backgroundColour,
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = Header.HEIGHT },
Child = screenStack = new MultiplayerSubScreenStack { RelativeSizeAxes = Axes.Both }
Children = new[]
{
header = new Container
{
RelativeSizeAxes = Axes.X,
Height = 400,
Children = new[]
{
headerBackground = new Container
{
RelativeSizeAxes = Axes.Both,
Width = 1.25f,
Masking = true,
Children = new Drawable[]
{
new HeaderBackgroundSprite
{
RelativeSizeAxes = Axes.X,
Height = 400 // Keep a static height so the header doesn't change as it's resized between subscreens
},
}
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Bottom = -1 }, // 1px padding to avoid a 1px gap due to masking
Child = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(backgroundColour.Opacity(0.7f), backgroundColour)
},
}
}
},
screenStack = new MultiplayerSubScreenStack { RelativeSizeAxes = Axes.Both }
}
},
new Header(screenStack),
createButton = new HeaderButton
createButton = new CreateRoomButton
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
RelativeSizeAxes = Axes.None,
Size = new Vector2(150, Header.HEIGHT - 20),
Margin = new MarginPadding
{
Top = 10,
Right = 10 + HORIZONTAL_OVERFLOW_PADDING,
},
Text = "Create room",
Action = () => loungeSubScreen.Open(new Room
{
Name = { Value = $"{api.LocalUser}'s awesome room" }
}),
Action = createRoom
},
roomManager = new RoomManager()
}
@ -248,6 +265,11 @@ namespace osu.Game.Screens.Multi
logo.Delay(WaveContainer.DISAPPEAR_DURATION / 2).FadeOut();
}
private void createRoom()
{
loungeSubScreen.Open(new Room { Name = { Value = $"{api.LocalUser}'s awesome room" } });
}
private void beginHandlingTrack()
{
Beatmap.BindValueChanged(updateTrack, true);
@ -259,7 +281,10 @@ namespace osu.Game.Screens.Multi
Beatmap.ValueChanged -= updateTrack;
}
private void screenPushed(IScreen lastScreen, IScreen newScreen) => subScreenChanged(newScreen);
private void screenPushed(IScreen lastScreen, IScreen newScreen)
{
subScreenChanged(newScreen);
}
private void screenExited(IScreen lastScreen, IScreen newScreen)
{
@ -271,6 +296,19 @@ namespace osu.Game.Screens.Multi
private void subScreenChanged(IScreen newScreen)
{
switch (newScreen)
{
case LoungeSubScreen _:
header.Delay(MultiplayerSubScreen.RESUME_TRANSITION_DELAY).ResizeHeightTo(400, MultiplayerSubScreen.APPEAR_DURATION, Easing.OutQuint);
headerBackground.MoveToX(0, MultiplayerSubScreen.X_MOVE_DURATION, Easing.OutQuint);
break;
case MatchSubScreen _:
header.ResizeHeightTo(135, MultiplayerSubScreen.APPEAR_DURATION, Easing.OutQuint);
headerBackground.MoveToX(-MultiplayerSubScreen.X_SHIFT, MultiplayerSubScreen.X_MOVE_DURATION, Easing.OutQuint);
break;
}
updatePollingRate(isIdle.Value);
createButton.FadeTo(newScreen is LoungeSubScreen ? 1 : 0, 200);
@ -327,5 +365,36 @@ namespace osu.Game.Screens.Multi
FourthWaveColour = OsuColour.FromHex(@"392850");
}
}
private class HeaderBackgroundSprite : MultiplayerBackgroundSprite
{
protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BackgroundSprite { RelativeSizeAxes = Axes.Both };
private class BackgroundSprite : UpdateableBeatmapBackgroundSprite
{
protected override double TransformDuration => 200;
}
}
public class CreateRoomButton : PurpleTriangleButton
{
public CreateRoomButton()
{
Size = new Vector2(150, Header.HEIGHT - 20);
Margin = new MarginPadding
{
Top = 10,
Right = 10 + HORIZONTAL_OVERFLOW_PADDING,
};
}
[BackgroundDependencyLoader]
private void load()
{
Triangles.TriangleScale = 1.5f;
Text = "Create room";
}
}
}
}

View File

@ -4,7 +4,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Screens;
using osu.Game.Graphics.Containers;
namespace osu.Game.Screens.Multi
{
@ -24,31 +23,41 @@ namespace osu.Game.Screens.Multi
RelativeSizeAxes = Axes.Both;
}
public const float X_SHIFT = 200;
public const double X_MOVE_DURATION = 800;
public const double RESUME_TRANSITION_DELAY = DISAPPEAR_DURATION / 2;
public const double APPEAR_DURATION = 800;
public const double DISAPPEAR_DURATION = 500;
public override void OnEntering(IScreen last)
{
this.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
this.FadeInFromZero(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
this.MoveToX(200).MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
this.FadeInFromZero(APPEAR_DURATION, Easing.OutQuint);
this.FadeInFromZero(APPEAR_DURATION, Easing.OutQuint);
this.MoveToX(X_SHIFT).MoveToX(0, X_MOVE_DURATION, Easing.OutQuint);
}
public override bool OnExiting(IScreen next)
{
this.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint);
this.MoveToX(200, WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint);
this.FadeOut(DISAPPEAR_DURATION, Easing.OutQuint);
this.MoveToX(X_SHIFT, X_MOVE_DURATION, Easing.OutQuint);
return false;
}
public override void OnResuming(IScreen last)
{
this.FadeIn(WaveContainer.APPEAR_DURATION, Easing.OutQuint);
this.MoveToX(0, WaveContainer.APPEAR_DURATION, Easing.OutQuint);
this.Delay(RESUME_TRANSITION_DELAY).FadeIn(APPEAR_DURATION, Easing.OutQuint);
this.MoveToX(0, X_MOVE_DURATION, Easing.OutQuint);
}
public override void OnSuspending(IScreen next)
{
this.FadeOut(WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint);
this.MoveToX(-200, WaveContainer.DISAPPEAR_DURATION, Easing.OutQuint);
this.FadeOut(DISAPPEAR_DURATION, Easing.OutQuint);
this.MoveToX(-X_SHIFT, X_MOVE_DURATION, Easing.OutQuint);
}
public override string ToString() => Title;

View File

@ -12,6 +12,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
@ -211,12 +212,24 @@ namespace osu.Game.Screens.Select.Carousel
{
private readonly BindableBool filtered = new BindableBool();
private readonly CarouselBeatmap item;
public FilterableDifficultyIcon(CarouselBeatmap item)
: base(item.Beatmap)
{
filtered.BindTo(item.Filtered);
filtered.ValueChanged += isFiltered => Schedule(() => this.FadeTo(isFiltered.NewValue ? 0.1f : 1, 100));
filtered.TriggerChange();
this.item = item;
}
protected override bool OnClick(ClickEvent e)
{
if (!filtered.Value)
item.State.Value = CarouselItemState.Selected;
return true;
}
}

View File

@ -1,7 +1,6 @@
// 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 osuTK;
using osuTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
@ -51,7 +50,6 @@ namespace osu.Game.Screens.Select.Details
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(4f),
Children = new[]
{
FirstValue = new StatisticRow(), //circle size/key amount
@ -199,6 +197,7 @@ namespace osu.Game.Screens.Select.Details
this.forceDecimalPlaces = forceDecimalPlaces;
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Padding = new MarginPadding { Vertical = 2.5f };
Children = new Drawable[]
{
@ -206,9 +205,11 @@ namespace osu.Game.Screens.Select.Details
{
Width = name_width,
AutoSizeAxes = Axes.Y,
// osu-web uses 1.25 line-height, which at 12px font size makes the element 14px tall - this compentates that difference
Padding = new MarginPadding { Vertical = 1 },
Child = name = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 13)
Font = OsuFont.GetFont(size: 12)
},
},
bar = new Bar
@ -239,7 +240,7 @@ namespace osu.Game.Screens.Select.Details
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 13)
Font = OsuFont.GetFont(size: 12)
},
},
};

View File

@ -71,31 +71,32 @@ namespace osu.Game.Screens.Select.Details
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = "User Rating",
Font = OsuFont.GetFont(size: 13)
Font = OsuFont.GetFont(size: 12),
Margin = new MarginPadding { Bottom = 5 },
},
ratingsBar = new Bar
{
RelativeSizeAxes = Axes.X,
Height = 5,
Margin = new MarginPadding { Top = 5 },
},
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding { Bottom = 10 },
Children = new[]
{
negativeRatings = new OsuSpriteText
{
Text = "0",
Font = OsuFont.GetFont(size: 13)
Font = OsuFont.GetFont(size: 12)
},
positiveRatings = new OsuSpriteText
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Text = @"0",
Font = OsuFont.GetFont(size: 13)
Font = OsuFont.GetFont(size: 12)
},
},
},
@ -104,8 +105,8 @@ namespace osu.Game.Screens.Select.Details
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = "Rating Spread",
Font = OsuFont.GetFont(size: 13),
Margin = new MarginPadding { Top = 10, Bottom = 5 },
Font = OsuFont.GetFont(size: 12),
Margin = new MarginPadding { Bottom = 5 },
},
},
},

View File

@ -22,7 +22,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.219.0" />
<PackageReference Include="ppy.osu.Framework" Version="2020.218.0" />
<PackageReference Include="Sentry" Version="2.0.3" />
<PackageReference Include="SharpCompress" Version="0.24.0" />

View File

@ -73,7 +73,7 @@
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.219.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.218.0" />
</ItemGroup>
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->