1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-13 14:52:57 +08:00

Merge branch 'master' into fix-custom-directory-tests

This commit is contained in:
Bartłomiej Dach 2021-12-21 13:08:27 +01:00 committed by GitHub
commit e35a8cab65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 401 additions and 397 deletions

View File

@ -1,9 +1,10 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System;
using NUnit.Framework; using NUnit.Framework;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Input; using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Tests.NonVisual namespace osu.Game.Tests.NonVisual
{ {
@ -11,37 +12,32 @@ namespace osu.Game.Tests.NonVisual
public class SessionStaticsTest public class SessionStaticsTest
{ {
private SessionStatics sessionStatics; private SessionStatics sessionStatics;
private IdleTracker sessionIdleTracker;
[SetUp] [Test]
public void SetUp() public void TestSessionStaticsReset()
{ {
sessionStatics = new SessionStatics(); sessionStatics = new SessionStatics();
sessionIdleTracker = new GameIdleTracker(1000);
sessionStatics.SetValue(Static.LoginOverlayDisplayed, true); sessionStatics.SetValue(Static.LoginOverlayDisplayed, true);
sessionStatics.SetValue(Static.MutedAudioNotificationShownOnce, true); sessionStatics.SetValue(Static.MutedAudioNotificationShownOnce, true);
sessionStatics.SetValue(Static.LowBatteryNotificationShownOnce, true); sessionStatics.SetValue(Static.LowBatteryNotificationShownOnce, true);
sessionStatics.SetValue(Static.LastHoverSoundPlaybackTime, (double?)1d); sessionStatics.SetValue(Static.LastHoverSoundPlaybackTime, (double?)1d);
sessionStatics.SetValue(Static.SeasonalBackgrounds, new APISeasonalBackgrounds { EndDate = new DateTimeOffset(2022, 1, 1, 0, 0, 0, TimeSpan.Zero) });
sessionIdleTracker.IsIdle.BindValueChanged(e => Assert.IsFalse(sessionStatics.GetBindable<bool>(Static.LoginOverlayDisplayed).IsDefault);
{ Assert.IsFalse(sessionStatics.GetBindable<bool>(Static.MutedAudioNotificationShownOnce).IsDefault);
if (e.NewValue) Assert.IsFalse(sessionStatics.GetBindable<bool>(Static.LowBatteryNotificationShownOnce).IsDefault);
sessionStatics.ResetValues(); Assert.IsFalse(sessionStatics.GetBindable<double?>(Static.LastHoverSoundPlaybackTime).IsDefault);
}); Assert.IsFalse(sessionStatics.GetBindable<APISeasonalBackgrounds>(Static.SeasonalBackgrounds).IsDefault);
}
sessionStatics.ResetAfterInactivity();
[Test]
[Timeout(2000)]
public void TestSessionStaticsReset()
{
sessionIdleTracker.IsIdle.BindValueChanged(e =>
{
Assert.IsTrue(sessionStatics.GetBindable<bool>(Static.LoginOverlayDisplayed).IsDefault); Assert.IsTrue(sessionStatics.GetBindable<bool>(Static.LoginOverlayDisplayed).IsDefault);
Assert.IsTrue(sessionStatics.GetBindable<bool>(Static.MutedAudioNotificationShownOnce).IsDefault); Assert.IsTrue(sessionStatics.GetBindable<bool>(Static.MutedAudioNotificationShownOnce).IsDefault);
Assert.IsTrue(sessionStatics.GetBindable<bool>(Static.LowBatteryNotificationShownOnce).IsDefault); Assert.IsTrue(sessionStatics.GetBindable<bool>(Static.LowBatteryNotificationShownOnce).IsDefault);
Assert.IsTrue(sessionStatics.GetBindable<double?>(Static.LastHoverSoundPlaybackTime).IsDefault); // some statics should not reset despite inactivity.
}); Assert.IsFalse(sessionStatics.GetBindable<double?>(Static.LastHoverSoundPlaybackTime).IsDefault);
Assert.IsFalse(sessionStatics.GetBindable<APISeasonalBackgrounds>(Static.SeasonalBackgrounds).IsDefault);
} }
} }
} }

View File

@ -252,7 +252,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
[Test] [Test]
public void TestNormal() public void TestNormal()
{ {
createTestCase(beatmapSetInfo => new BeatmapCard(beatmapSetInfo)); createTestCase(beatmapSetInfo => new BeatmapCardNormal(beatmapSetInfo));
} }
[Test] [Test]
@ -264,7 +264,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
[Test] [Test]
public void TestHoverState() public void TestHoverState()
{ {
AddStep("create cards", () => Child = createContent(OverlayColourScheme.Blue, s => new BeatmapCard(s))); AddStep("create cards", () => Child = createContent(OverlayColourScheme.Blue, s => new BeatmapCardNormal(s)));
AddStep("Hover card", () => InputManager.MoveMouseTo(firstCard())); AddStep("Hover card", () => InputManager.MoveMouseTo(firstCard()));
AddWaitStep("wait for potential state change", 5); AddWaitStep("wait for potential state change", 5);
@ -281,10 +281,10 @@ namespace osu.Game.Tests.Visual.Beatmaps
AddWaitStep("wait for potential state change", 5); AddWaitStep("wait for potential state change", 5);
AddAssert("card is still expanded", () => firstCard().Expanded.Value); AddAssert("card is still expanded", () => firstCard().Expanded.Value);
AddStep("Hover away", () => InputManager.MoveMouseTo(this.ChildrenOfType<BeatmapCard>().Last())); AddStep("Hover away", () => InputManager.MoveMouseTo(this.ChildrenOfType<BeatmapCardNormal>().Last()));
AddUntilStep("card is not expanded", () => !firstCard().Expanded.Value); AddUntilStep("card is not expanded", () => !firstCard().Expanded.Value);
BeatmapCard firstCard() => this.ChildrenOfType<BeatmapCard>().First(); BeatmapCardNormal firstCard() => this.ChildrenOfType<BeatmapCardNormal>().First();
} }
} }
} }

View File

@ -3,284 +3,78 @@
#nullable enable #nullable enable
using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Beatmaps.Drawables.Cards.Statistics;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface;
using osu.Game.Online;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapSet;
using osuTK;
using osu.Game.Resources.Localisation.Web;
namespace osu.Game.Beatmaps.Drawables.Cards namespace osu.Game.Beatmaps.Drawables.Cards
{ {
public class BeatmapCard : BeatmapCardBase public abstract class BeatmapCard : OsuClickableContainer
{ {
protected override Drawable IdleContent => idleBottomContent; public const float TRANSITION_DURATION = 400;
protected override Drawable DownloadInProgressContent => downloadProgressBar; public const float CORNER_RADIUS = 10;
private const float width = 408; public IBindable<bool> Expanded { get; }
private const float height = 100;
[Cached] protected readonly APIBeatmapSet BeatmapSet;
private readonly BeatmapCardContent content; protected readonly Bindable<BeatmapSetFavouriteState> FavouriteState;
private BeatmapCardThumbnail thumbnail = null!; protected abstract Drawable IdleContent { get; }
private CollapsibleButtonContainer buttonContainer = null!; protected abstract Drawable DownloadInProgressContent { get; }
private FillFlowContainer<BeatmapCardStatistic> statisticsContainer = null!; protected readonly BeatmapDownloadTracker DownloadTracker;
private FillFlowContainer idleBottomContent = null!; protected BeatmapCard(APIBeatmapSet beatmapSet, bool allowExpansion = true)
private BeatmapCardDownloadProgressBar downloadProgressBar = null!; : base(HoverSampleSet.Submit)
[Resolved]
private OverlayColourProvider colourProvider { get; set; } = null!;
public BeatmapCard(APIBeatmapSet beatmapSet, bool allowExpansion = true)
: base(beatmapSet, allowExpansion)
{ {
content = new BeatmapCardContent(height); Expanded = new BindableBool { Disabled = !allowExpansion };
BeatmapSet = beatmapSet;
FavouriteState = new Bindable<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount));
DownloadTracker = new BeatmapDownloadTracker(beatmapSet);
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader(true)]
private void load() private void load(BeatmapSetOverlay? beatmapSetOverlay)
{ {
Width = width; Action = () => beatmapSetOverlay?.FetchAndShowBeatmapSet(BeatmapSet.OnlineID);
Height = height;
FillFlowContainer leftIconArea = null!; AddInternal(DownloadTracker);
GridContainer titleContainer = null!; }
GridContainer artistContainer = null!;
Child = content.With(c => protected override void LoadComplete()
{ {
c.MainContent = new Container base.LoadComplete();
{
RelativeSizeAxes = Axes.Both, DownloadTracker.State.BindValueChanged(_ => UpdateState());
Children = new Drawable[] Expanded.BindValueChanged(_ => UpdateState(), true);
{ FinishTransforms(true);
thumbnail = new BeatmapCardThumbnail(BeatmapSet)
{
Name = @"Left (icon) area",
Size = new Vector2(height),
Padding = new MarginPadding { Right = CORNER_RADIUS },
Child = leftIconArea = new FillFlowContainer
{
Margin = new MarginPadding(5),
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(1)
} }
},
buttonContainer = new CollapsibleButtonContainer(BeatmapSet) protected override bool OnHover(HoverEvent e)
{ {
X = height - CORNER_RADIUS, UpdateState();
Width = width - height + CORNER_RADIUS, return base.OnHover(e);
FavouriteState = { BindTarget = FavouriteState },
ButtonsCollapsedWidth = CORNER_RADIUS,
ButtonsExpandedWidth = 30,
ButtonsPadding = new MarginPadding { Vertical = 17.5f },
Children = new Drawable[]
{
new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
titleContainer = new GridContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
ColumnDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.AutoSize)
},
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize)
},
Content = new[]
{
new[]
{
new OsuSpriteText
{
Text = new RomanisableString(BeatmapSet.TitleUnicode, BeatmapSet.Title),
Font = OsuFont.Default.With(size: 22.5f, weight: FontWeight.SemiBold),
RelativeSizeAxes = Axes.X,
Truncate = true
},
Empty()
} }
protected override void OnHoverLost(HoverLostEvent e)
{
UpdateState();
base.OnHoverLost(e);
} }
},
artistContainer = new GridContainer protected virtual void UpdateState()
{ {
RelativeSizeAxes = Axes.X, bool showProgress = DownloadTracker.State.Value == DownloadState.Downloading || DownloadTracker.State.Value == DownloadState.Importing;
AutoSizeAxes = Axes.Y,
ColumnDimensions = new[] IdleContent.FadeTo(showProgress ? 0 : 1, TRANSITION_DURATION, Easing.OutQuint);
{ DownloadInProgressContent.FadeTo(showProgress ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
new Dimension(),
new Dimension(GridSizeMode.AutoSize)
},
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize)
},
Content = new[]
{
new[]
{
new OsuSpriteText
{
Text = createArtistText(),
Font = OsuFont.Default.With(size: 17.5f, weight: FontWeight.SemiBold),
RelativeSizeAxes = Axes.X,
Truncate = true
},
Empty()
},
}
},
new LinkFlowContainer(s =>
{
s.Shadow = false;
s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold);
}).With(d =>
{
d.AutoSizeAxes = Axes.Both;
d.Margin = new MarginPadding { Top = 2 };
d.AddText("mapped by ", t => t.Colour = colourProvider.Content2);
d.AddUserLink(BeatmapSet.Author);
}),
}
},
new Container
{
Name = @"Bottom content",
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Children = new Drawable[]
{
idleBottomContent = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 3),
AlwaysPresent = true,
Children = new Drawable[]
{
statisticsContainer = new FillFlowContainer<BeatmapCardStatistic>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(10, 0),
Alpha = 0,
AlwaysPresent = true,
ChildrenEnumerable = createStatistics()
},
new BeatmapCardExtraInfoRow(BeatmapSet)
}
},
downloadProgressBar = new BeatmapCardDownloadProgressBar
{
RelativeSizeAxes = Axes.X,
Height = 6,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
State = { BindTarget = DownloadTracker.State },
Progress = { BindTarget = DownloadTracker.Progress }
}
}
}
}
}
}
};
c.ExpandedContent = new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Horizontal = 10, Vertical = 13 },
Child = new BeatmapCardDifficultyList(BeatmapSet)
};
c.Expanded.BindTarget = Expanded;
});
if (BeatmapSet.HasVideo)
leftIconArea.Add(new IconPill(FontAwesome.Solid.Film) { IconSize = new Vector2(20) });
if (BeatmapSet.HasStoryboard)
leftIconArea.Add(new IconPill(FontAwesome.Solid.Image) { IconSize = new Vector2(20) });
if (BeatmapSet.HasExplicitContent)
{
titleContainer.Content[0][1] = new ExplicitContentBeatmapPill
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Margin = new MarginPadding { Left = 5 }
};
}
if (BeatmapSet.TrackId != null)
{
artistContainer.Content[0][1] = new FeaturedArtistBeatmapPill
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Margin = new MarginPadding { Left = 5 }
};
}
}
private LocalisableString createArtistText()
{
var romanisableArtist = new RomanisableString(BeatmapSet.ArtistUnicode, BeatmapSet.Artist);
return BeatmapsetsStrings.ShowDetailsByArtist(romanisableArtist);
}
private IEnumerable<BeatmapCardStatistic> createStatistics()
{
var hypesStatistic = HypesStatistic.CreateFor(BeatmapSet);
if (hypesStatistic != null)
yield return hypesStatistic;
var nominationsStatistic = NominationsStatistic.CreateFor(BeatmapSet);
if (nominationsStatistic != null)
yield return nominationsStatistic;
yield return new FavouritesStatistic(BeatmapSet) { Current = FavouriteState };
yield return new PlayCountStatistic(BeatmapSet);
var dateStatistic = BeatmapCardDateStatistic.CreateFor(BeatmapSet);
if (dateStatistic != null)
yield return dateStatistic;
}
protected override void UpdateState()
{
base.UpdateState();
bool showDetails = IsHovered || Expanded.Value;
buttonContainer.ShowDetails.Value = showDetails;
thumbnail.Dimmed.Value = showDetails;
statisticsContainer.FadeTo(showDetails ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
} }
} }
} }

View File

@ -1,80 +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.
#nullable enable
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
namespace osu.Game.Beatmaps.Drawables.Cards
{
public abstract class BeatmapCardBase : OsuClickableContainer
{
public const float TRANSITION_DURATION = 400;
public const float CORNER_RADIUS = 10;
public IBindable<bool> Expanded { get; }
protected readonly APIBeatmapSet BeatmapSet;
protected readonly Bindable<BeatmapSetFavouriteState> FavouriteState;
protected abstract Drawable IdleContent { get; }
protected abstract Drawable DownloadInProgressContent { get; }
protected readonly BeatmapDownloadTracker DownloadTracker;
protected BeatmapCardBase(APIBeatmapSet beatmapSet, bool allowExpansion = true)
: base(HoverSampleSet.Submit)
{
Expanded = new BindableBool { Disabled = !allowExpansion };
BeatmapSet = beatmapSet;
FavouriteState = new Bindable<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount));
DownloadTracker = new BeatmapDownloadTracker(beatmapSet);
}
[BackgroundDependencyLoader(true)]
private void load(BeatmapSetOverlay? beatmapSetOverlay)
{
Action = () => beatmapSetOverlay?.FetchAndShowBeatmapSet(BeatmapSet.OnlineID);
AddInternal(DownloadTracker);
}
protected override void LoadComplete()
{
base.LoadComplete();
DownloadTracker.State.BindValueChanged(_ => UpdateState());
Expanded.BindValueChanged(_ => UpdateState(), true);
FinishTransforms(true);
}
protected override bool OnHover(HoverEvent e)
{
UpdateState();
return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e)
{
UpdateState();
base.OnHoverLost(e);
}
protected virtual void UpdateState()
{
bool showProgress = DownloadTracker.State.Value == DownloadState.Downloading || DownloadTracker.State.Value == DownloadState.Importing;
IdleContent.FadeTo(showProgress ? 0 : 1, TRANSITION_DURATION, Easing.OutQuint);
DownloadInProgressContent.FadeTo(showProgress ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
}
}
}

View File

@ -54,7 +54,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
CornerRadius = BeatmapCardBase.CORNER_RADIUS, CornerRadius = BeatmapCard.CORNER_RADIUS,
Masking = true, Masking = true,
Unhovered = _ => updateFromHoverChange(), Unhovered = _ => updateFromHoverChange(),
Children = new Drawable[] Children = new Drawable[]
@ -67,7 +67,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Height = height, Height = height,
CornerRadius = BeatmapCardBase.CORNER_RADIUS, CornerRadius = BeatmapCard.CORNER_RADIUS,
Masking = true, Masking = true,
}, },
dropdownContent = new HoverHandlingContainer dropdownContent = new HoverHandlingContainer
@ -91,7 +91,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards
borderContainer = new Container borderContainer = new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
CornerRadius = BeatmapCardBase.CORNER_RADIUS, CornerRadius = BeatmapCard.CORNER_RADIUS,
Masking = true, Masking = true,
BorderThickness = 3, BorderThickness = 3,
Child = new Box Child = new Box
@ -143,9 +143,9 @@ namespace osu.Game.Beatmaps.Drawables.Cards
// This avoids depth issues where a hovered (scaled) card to the right of another card would be beneath the card to the left. // This avoids depth issues where a hovered (scaled) card to the right of another card would be beneath the card to the left.
this.ScaleTo(Expanded.Value ? 1.03f : 1, 500, Easing.OutQuint); this.ScaleTo(Expanded.Value ? 1.03f : 1, 500, Easing.OutQuint);
background.FadeTo(Expanded.Value ? 1 : 0, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); background.FadeTo(Expanded.Value ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
dropdownContent.FadeTo(Expanded.Value ? 1 : 0, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); dropdownContent.FadeTo(Expanded.Value ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
borderContainer.FadeTo(Expanded.Value ? 1 : 0, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); borderContainer.FadeTo(Expanded.Value ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
content.TweenEdgeEffectTo(new EdgeEffectParameters content.TweenEdgeEffectTo(new EdgeEffectParameters
{ {
@ -154,7 +154,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards
Radius = 10, Radius = 10,
Colour = Colour4.Black.Opacity(Expanded.Value ? 0.3f : 0f), Colour = Colour4.Black.Opacity(Expanded.Value ? 0.3f : 0f),
Hollow = true, Hollow = true,
}, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); }, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
} }
private class ExpandedContentScrollContainer : OsuScrollContainer private class ExpandedContentScrollContainer : OsuScrollContainer

View File

@ -62,10 +62,10 @@ namespace osu.Game.Beatmaps.Drawables.Cards
private void updateState() => Schedule(() => private void updateState() => Schedule(() =>
{ {
background.FadeColour(Dimmed.Value ? colourProvider.Background4 : colourProvider.Background2, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); background.FadeColour(Dimmed.Value ? colourProvider.Background4 : colourProvider.Background2, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
var gradient = ColourInfo.GradientHorizontal(Colour4.White.Opacity(0), Colour4.White.Opacity(0.2f)); var gradient = ColourInfo.GradientHorizontal(Colour4.White.Opacity(0), Colour4.White.Opacity(0.2f));
cover.FadeColour(gradient, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); cover.FadeColour(gradient, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
}); });
} }
} }

View File

@ -82,14 +82,14 @@ namespace osu.Game.Beatmaps.Drawables.Cards
break; break;
case DownloadState.Importing: case DownloadState.Importing:
foregroundFill.FadeColour(colours.Yellow, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); foregroundFill.FadeColour(colours.Yellow, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
break; break;
} }
} }
private void progressChanged() private void progressChanged()
{ {
foreground.ResizeWidthTo((float)progress.Value, progress.Value > 0 ? BeatmapCardBase.TRANSITION_DURATION : 0, Easing.OutQuint); foreground.ResizeWidthTo((float)progress.Value, progress.Value > 0 ? BeatmapCard.TRANSITION_DURATION : 0, Easing.OutQuint);
} }
} }
} }

View File

@ -20,7 +20,7 @@ using osu.Game.Resources.Localisation.Web;
namespace osu.Game.Beatmaps.Drawables.Cards namespace osu.Game.Beatmaps.Drawables.Cards
{ {
public class BeatmapCardExtra : BeatmapCardBase public class BeatmapCardExtra : BeatmapCard
{ {
protected override Drawable IdleContent => idleBottomContent; protected override Drawable IdleContent => idleBottomContent;
protected override Drawable DownloadInProgressContent => downloadProgressBar; protected override Drawable DownloadInProgressContent => downloadProgressBar;

View File

@ -0,0 +1,286 @@
// 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.
#nullable enable
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Beatmaps.Drawables.Cards.Statistics;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapSet;
using osuTK;
using osu.Game.Resources.Localisation.Web;
namespace osu.Game.Beatmaps.Drawables.Cards
{
public class BeatmapCardNormal : BeatmapCard
{
protected override Drawable IdleContent => idleBottomContent;
protected override Drawable DownloadInProgressContent => downloadProgressBar;
private const float width = 408;
private const float height = 100;
[Cached]
private readonly BeatmapCardContent content;
private BeatmapCardThumbnail thumbnail = null!;
private CollapsibleButtonContainer buttonContainer = null!;
private FillFlowContainer<BeatmapCardStatistic> statisticsContainer = null!;
private FillFlowContainer idleBottomContent = null!;
private BeatmapCardDownloadProgressBar downloadProgressBar = null!;
[Resolved]
private OverlayColourProvider colourProvider { get; set; } = null!;
public BeatmapCardNormal(APIBeatmapSet beatmapSet, bool allowExpansion = true)
: base(beatmapSet, allowExpansion)
{
content = new BeatmapCardContent(height);
}
[BackgroundDependencyLoader]
private void load()
{
Width = width;
Height = height;
FillFlowContainer leftIconArea = null!;
GridContainer titleContainer = null!;
GridContainer artistContainer = null!;
Child = content.With(c =>
{
c.MainContent = new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
thumbnail = new BeatmapCardThumbnail(BeatmapSet)
{
Name = @"Left (icon) area",
Size = new Vector2(height),
Padding = new MarginPadding { Right = CORNER_RADIUS },
Child = leftIconArea = new FillFlowContainer
{
Margin = new MarginPadding(5),
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(1)
}
},
buttonContainer = new CollapsibleButtonContainer(BeatmapSet)
{
X = height - CORNER_RADIUS,
Width = width - height + CORNER_RADIUS,
FavouriteState = { BindTarget = FavouriteState },
ButtonsCollapsedWidth = CORNER_RADIUS,
ButtonsExpandedWidth = 30,
ButtonsPadding = new MarginPadding { Vertical = 17.5f },
Children = new Drawable[]
{
new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
titleContainer = new GridContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
ColumnDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.AutoSize)
},
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize)
},
Content = new[]
{
new[]
{
new OsuSpriteText
{
Text = new RomanisableString(BeatmapSet.TitleUnicode, BeatmapSet.Title),
Font = OsuFont.Default.With(size: 22.5f, weight: FontWeight.SemiBold),
RelativeSizeAxes = Axes.X,
Truncate = true
},
Empty()
}
}
},
artistContainer = new GridContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
ColumnDimensions = new[]
{
new Dimension(),
new Dimension(GridSizeMode.AutoSize)
},
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize)
},
Content = new[]
{
new[]
{
new OsuSpriteText
{
Text = createArtistText(),
Font = OsuFont.Default.With(size: 17.5f, weight: FontWeight.SemiBold),
RelativeSizeAxes = Axes.X,
Truncate = true
},
Empty()
},
}
},
new LinkFlowContainer(s =>
{
s.Shadow = false;
s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold);
}).With(d =>
{
d.AutoSizeAxes = Axes.Both;
d.Margin = new MarginPadding { Top = 2 };
d.AddText("mapped by ", t => t.Colour = colourProvider.Content2);
d.AddUserLink(BeatmapSet.Author);
}),
}
},
new Container
{
Name = @"Bottom content",
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Children = new Drawable[]
{
idleBottomContent = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 3),
AlwaysPresent = true,
Children = new Drawable[]
{
statisticsContainer = new FillFlowContainer<BeatmapCardStatistic>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(10, 0),
Alpha = 0,
AlwaysPresent = true,
ChildrenEnumerable = createStatistics()
},
new BeatmapCardExtraInfoRow(BeatmapSet)
}
},
downloadProgressBar = new BeatmapCardDownloadProgressBar
{
RelativeSizeAxes = Axes.X,
Height = 6,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
State = { BindTarget = DownloadTracker.State },
Progress = { BindTarget = DownloadTracker.Progress }
}
}
}
}
}
}
};
c.ExpandedContent = new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Horizontal = 10, Vertical = 13 },
Child = new BeatmapCardDifficultyList(BeatmapSet)
};
c.Expanded.BindTarget = Expanded;
});
if (BeatmapSet.HasVideo)
leftIconArea.Add(new IconPill(FontAwesome.Solid.Film) { IconSize = new Vector2(20) });
if (BeatmapSet.HasStoryboard)
leftIconArea.Add(new IconPill(FontAwesome.Solid.Image) { IconSize = new Vector2(20) });
if (BeatmapSet.HasExplicitContent)
{
titleContainer.Content[0][1] = new ExplicitContentBeatmapPill
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Margin = new MarginPadding { Left = 5 }
};
}
if (BeatmapSet.TrackId != null)
{
artistContainer.Content[0][1] = new FeaturedArtistBeatmapPill
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Margin = new MarginPadding { Left = 5 }
};
}
}
private LocalisableString createArtistText()
{
var romanisableArtist = new RomanisableString(BeatmapSet.ArtistUnicode, BeatmapSet.Artist);
return BeatmapsetsStrings.ShowDetailsByArtist(romanisableArtist);
}
private IEnumerable<BeatmapCardStatistic> createStatistics()
{
var hypesStatistic = HypesStatistic.CreateFor(BeatmapSet);
if (hypesStatistic != null)
yield return hypesStatistic;
var nominationsStatistic = NominationsStatistic.CreateFor(BeatmapSet);
if (nominationsStatistic != null)
yield return nominationsStatistic;
yield return new FavouritesStatistic(BeatmapSet) { Current = FavouriteState };
yield return new PlayCountStatistic(BeatmapSet);
var dateStatistic = BeatmapCardDateStatistic.CreateFor(BeatmapSet);
if (dateStatistic != null)
yield return dateStatistic;
}
protected override void UpdateState()
{
base.UpdateState();
bool showDetails = IsHovered || Expanded.Value;
buttonContainer.ShowDetails.Value = showDetails;
thumbnail.Dimmed.Value = showDetails;
statisticsContainer.FadeTo(showDetails ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
}
}
}

View File

@ -88,8 +88,8 @@ namespace osu.Game.Beatmaps.Drawables.Cards
{ {
bool shouldDim = Dimmed.Value || playButton.Playing.Value; bool shouldDim = Dimmed.Value || playButton.Playing.Value;
playButton.FadeTo(shouldDim ? 1 : 0, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); playButton.FadeTo(shouldDim ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
cover.FadeColour(shouldDim ? OsuColour.Gray(0.2f) : Color4.White, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); cover.FadeColour(shouldDim ? OsuColour.Gray(0.2f) : Color4.White, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
} }
} }
} }

View File

@ -115,7 +115,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
bool isHovered = IsHovered && Enabled.Value; bool isHovered = IsHovered && Enabled.Value;
content.ScaleTo(isHovered ? 1.2f : 1, 500, Easing.OutQuint); content.ScaleTo(isHovered ? 1.2f : 1, 500, Easing.OutQuint);
content.FadeColour(isHovered ? HoverColour : IdleColour, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); content.FadeColour(isHovered ? HoverColour : IdleColour, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
} }
} }
} }

View File

@ -69,7 +69,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
case DownloadState.LocallyAvailable: case DownloadState.LocallyAvailable:
Action = null; Action = null;
TooltipText = string.Empty; TooltipText = string.Empty;
this.FadeOut(BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); this.FadeOut(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
break; break;
case DownloadState.NotDownloaded: case DownloadState.NotDownloaded:
@ -81,7 +81,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
} }
Action = () => beatmaps.Download(beatmapSet, preferNoVideo.Value); Action = () => beatmaps.Download(beatmapSet, preferNoVideo.Value);
this.FadeIn(BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); this.FadeIn(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
spinner.Hide(); spinner.Hide();
Icon.Show(); Icon.Show();

View File

@ -43,7 +43,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
private void updateState() private void updateState()
{ {
this.FadeTo(state.Value == DownloadState.LocallyAvailable ? 1 : 0, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); this.FadeTo(state.Value == DownloadState.LocallyAvailable ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
} }
} }
} }

View File

@ -141,7 +141,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards.Buttons
private void toggleLoading(bool loading) private void toggleLoading(bool loading)
{ {
Enabled.Value = !loading; Enabled.Value = !loading;
icon.FadeTo(loading ? 0 : 1, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); icon.FadeTo(loading ? 0 : 1, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
loadingSpinner.State.Value = loading ? Visibility.Visible : Visibility.Hidden; loadingSpinner.State.Value = loading ? Visibility.Visible : Visibility.Hidden;
} }
} }

View File

@ -78,7 +78,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards
RelativeSizeAxes = Axes.Y; RelativeSizeAxes = Axes.Y;
Masking = true; Masking = true;
CornerRadius = BeatmapCardBase.CORNER_RADIUS; CornerRadius = BeatmapCard.CORNER_RADIUS;
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
@ -133,7 +133,7 @@ namespace osu.Game.Beatmaps.Drawables.Cards
{ {
Name = @"Main content", Name = @"Main content",
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
CornerRadius = BeatmapCardBase.CORNER_RADIUS, CornerRadius = BeatmapCard.CORNER_RADIUS,
Masking = true, Masking = true,
Children = new Drawable[] Children = new Drawable[]
{ {
@ -169,10 +169,10 @@ namespace osu.Game.Beatmaps.Drawables.Cards
{ {
float targetWidth = Width - (ShowDetails.Value ? ButtonsExpandedWidth : ButtonsCollapsedWidth); float targetWidth = Width - (ShowDetails.Value ? ButtonsExpandedWidth : ButtonsCollapsedWidth);
mainArea.ResizeWidthTo(targetWidth, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); mainArea.ResizeWidthTo(targetWidth, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
background.FadeColour(downloadTracker.State.Value == DownloadState.LocallyAvailable ? colours.Lime0 : colourProvider.Background3, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); background.FadeColour(downloadTracker.State.Value == DownloadState.LocallyAvailable ? colours.Lime0 : colourProvider.Background3, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
buttons.FadeTo(ShowDetails.Value ? 1 : 0, BeatmapCardBase.TRANSITION_DURATION, Easing.OutQuint); buttons.FadeTo(ShowDetails.Value ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
foreach (var button in buttons) foreach (var button in buttons)
{ {

View File

@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Bindables;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays; using osu.Game.Overlays;
@ -13,18 +12,27 @@ namespace osu.Game.Configuration
/// </summary> /// </summary>
public class SessionStatics : InMemoryConfigManager<Static> public class SessionStatics : InMemoryConfigManager<Static>
{ {
protected override void InitialiseDefaults() => ResetValues(); protected override void InitialiseDefaults()
public void ResetValues()
{ {
ensureDefault(SetDefault(Static.LoginOverlayDisplayed, false)); SetDefault(Static.LoginOverlayDisplayed, false);
ensureDefault(SetDefault(Static.MutedAudioNotificationShownOnce, false)); SetDefault(Static.MutedAudioNotificationShownOnce, false);
ensureDefault(SetDefault(Static.LowBatteryNotificationShownOnce, false)); SetDefault(Static.LowBatteryNotificationShownOnce, false);
ensureDefault(SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null)); SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null);
ensureDefault(SetDefault<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null)); SetDefault<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null);
} }
private void ensureDefault<T>(Bindable<T> bindable) => bindable.SetDefault(); /// <summary>
/// Revert statics to their defaults after being idle for appropriate amount of time.
/// </summary>
/// <remarks>
/// This only affects a subset of statics which the user would expect to have reset after a break.
/// </remarks>
public void ResetAfterInactivity()
{
GetBindable<bool>(Static.LoginOverlayDisplayed).SetDefault();
GetBindable<bool>(Static.MutedAudioNotificationShownOnce).SetDefault();
GetBindable<bool>(Static.LowBatteryNotificationShownOnce).SetDefault();
}
} }
public enum Static public enum Static

View File

@ -680,7 +680,7 @@ namespace osu.Game
sessionIdleTracker.IsIdle.BindValueChanged(idle => sessionIdleTracker.IsIdle.BindValueChanged(idle =>
{ {
if (idle.NewValue) if (idle.NewValue)
SessionStatics.ResetValues(); SessionStatics.ResetAfterInactivity();
}); });
Add(sessionIdleTracker); Add(sessionIdleTracker);

View File

@ -33,7 +33,7 @@ namespace osu.Game.Overlays
private Drawable currentContent; private Drawable currentContent;
private Container panelTarget; private Container panelTarget;
private FillFlowContainer<BeatmapCard> foundContent; private FillFlowContainer<BeatmapCardNormal> foundContent;
private NotFoundDrawable notFoundContent; private NotFoundDrawable notFoundContent;
private SupporterRequiredDrawable supporterRequiredContent; private SupporterRequiredDrawable supporterRequiredContent;
private BeatmapListingFilterControl filterControl; private BeatmapListingFilterControl filterControl;
@ -78,7 +78,7 @@ namespace osu.Game.Overlays
Padding = new MarginPadding { Horizontal = 20 }, Padding = new MarginPadding { Horizontal = 20 },
Children = new Drawable[] Children = new Drawable[]
{ {
foundContent = new FillFlowContainer<BeatmapCard>(), foundContent = new FillFlowContainer<BeatmapCardNormal>(),
notFoundContent = new NotFoundDrawable(), notFoundContent = new NotFoundDrawable(),
supporterRequiredContent = new SupporterRequiredDrawable(), supporterRequiredContent = new SupporterRequiredDrawable(),
} }
@ -135,7 +135,7 @@ namespace osu.Game.Overlays
return; return;
} }
var newPanels = searchResult.Results.Select(b => new BeatmapCard(b) var newPanels = searchResult.Results.Select(b => new BeatmapCardNormal(b)
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
@ -152,7 +152,7 @@ namespace osu.Game.Overlays
// spawn new children with the contained so we only clear old content at the last moment. // spawn new children with the contained so we only clear old content at the last moment.
// reverse ID flow is required for correct Z-ordering of the cards' expandable content (last card should be front-most). // reverse ID flow is required for correct Z-ordering of the cards' expandable content (last card should be front-most).
var content = new ReverseChildIDFillFlowContainer<BeatmapCard> var content = new ReverseChildIDFillFlowContainer<BeatmapCardNormal>
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,

View File

@ -61,7 +61,7 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage); new GetUserBeatmapsRequest(User.Value.Id, type, VisiblePages++, ItemsPerPage);
protected override Drawable CreateDrawableItem(APIBeatmapSet model) => model.OnlineID > 0 protected override Drawable CreateDrawableItem(APIBeatmapSet model) => model.OnlineID > 0
? new BeatmapCard(model) ? new BeatmapCardNormal(model)
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,

View File

@ -136,12 +136,12 @@ namespace osu.Game.Overlays.Rankings
{ {
new ScoresTable(1, response.Users), new ScoresTable(1, response.Users),
// reverse ID flow is required for correct Z-ordering of the cards' expandable content (last card should be front-most). // reverse ID flow is required for correct Z-ordering of the cards' expandable content (last card should be front-most).
new ReverseChildIDFillFlowContainer<BeatmapCard> new ReverseChildIDFillFlowContainer<BeatmapCardNormal>
{ {
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Spacing = new Vector2(10), Spacing = new Vector2(10),
Children = response.BeatmapSets.Select(b => new BeatmapCard(b) Children = response.BeatmapSets.Select(b => new BeatmapCardNormal(b)
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,

View File

@ -228,7 +228,7 @@ namespace osu.Game.Screens.Play
onlineBeatmapRequest.Success += beatmapSet => Schedule(() => onlineBeatmapRequest.Success += beatmapSet => Schedule(() =>
{ {
this.beatmapSet = beatmapSet; this.beatmapSet = beatmapSet;
beatmapPanelContainer.Child = new BeatmapCard(this.beatmapSet, allowExpansion: false); beatmapPanelContainer.Child = new BeatmapCardNormal(this.beatmapSet, allowExpansion: false);
checkForAutomaticDownload(); checkForAutomaticDownload();
}); });