Merge remote-tracking branch 'origin/master' into rearrangeable-playlist

This commit is contained in:
smoogipoo
2020-02-04 16:55:55 +09:00
181 changed files with 3643 additions and 1690 deletions

View File

@ -2,17 +2,14 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osuTK;
using System.Linq;
namespace osu.Game.Overlays.BeatmapSet
{
public class BeatmapRulesetSelector : RulesetSelector
public class BeatmapRulesetSelector : OverlayRulesetSelector
{
private readonly Bindable<BeatmapSetInfo> beatmapSet = new Bindable<BeatmapSetInfo>();
@ -28,21 +25,9 @@ namespace osu.Game.Overlays.BeatmapSet
}
}
public BeatmapRulesetSelector()
{
AutoSizeAxes = Axes.Both;
}
protected override TabItem<RulesetInfo> CreateTabItem(RulesetInfo value) => new BeatmapRulesetTabItem(value)
{
BeatmapSet = { BindTarget = beatmapSet }
};
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(10, 0),
};
}
}

View File

@ -3,143 +3,74 @@
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;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets;
using osuTK;
using osuTK.Graphics;
using System.Linq;
namespace osu.Game.Overlays.BeatmapSet
{
public class BeatmapRulesetTabItem : TabItem<RulesetInfo>
public class BeatmapRulesetTabItem : OverlayRulesetTabItem
{
private readonly OsuSpriteText name, count;
private readonly Box bar;
public readonly Bindable<BeatmapSetInfo> BeatmapSet = new Bindable<BeatmapSetInfo>();
public override bool PropagatePositionalInputSubTree => Enabled.Value && !Active.Value && base.PropagatePositionalInputSubTree;
[Resolved]
private OverlayColourProvider colourProvider { get; set; }
private OsuSpriteText count;
private Container countContainer;
public BeatmapRulesetTabItem(RulesetInfo value)
: base(value)
{
AutoSizeAxes = Axes.Both;
}
FillFlowContainer nameContainer;
Children = new Drawable[]
[BackgroundDependencyLoader]
private void load()
{
Add(countContainer = new Container
{
nameContainer = new FillFlowContainer
AutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Masking = true,
CornerRadius = 4f,
Children = new Drawable[]
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Margin = new MarginPadding { Bottom = 7.5f },
Spacing = new Vector2(2.5f),
Children = new Drawable[]
new Box
{
name = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = value.Name,
Font = OsuFont.Default.With(size: 18),
},
new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 4f,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black.Opacity(0.5f),
},
count = new OsuSpriteText
{
Alpha = 0,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Margin = new MarginPadding { Horizontal = 5f },
Font = OsuFont.Default.With(weight: FontWeight.SemiBold),
}
}
}
RelativeSizeAxes = Axes.Both,
Colour = colourProvider.Background6
},
count = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Margin = new MarginPadding { Horizontal = 5f },
Font = OsuFont.Default.With(weight: FontWeight.SemiBold),
Colour = colourProvider.Foreground1,
}
},
bar = new Box
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.X,
},
new HoverClickSounds(),
};
}
});
}
protected override void LoadComplete()
{
base.LoadComplete();
BeatmapSet.BindValueChanged(setInfo =>
{
var beatmapsCount = setInfo.NewValue?.Beatmaps.Count(b => b.Ruleset.Equals(Value)) ?? 0;
count.Text = beatmapsCount.ToString();
count.Alpha = beatmapsCount > 0 ? 1f : 0f;
countContainer.FadeTo(beatmapsCount > 0 ? 1 : 0);
Enabled.Value = beatmapsCount > 0;
}, true);
Enabled.BindValueChanged(v => nameContainer.Alpha = v.NewValue ? 1f : 0.5f, true);
}
[Resolved]
private OsuColour colour { get; set; }
protected override void LoadComplete()
{
base.LoadComplete();
count.Colour = colour.Gray9;
bar.Colour = colour.Blue;
updateState();
}
private void updateState()
{
var isHoveredOrActive = IsHovered || Active.Value;
bar.ResizeHeightTo(isHoveredOrActive ? 4 : 0, 200, Easing.OutQuint);
name.Colour = isHoveredOrActive ? colour.GrayE : colour.GrayC;
name.Font = name.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Regular);
}
#region Hovering and activation logic
protected override void OnActivated() => updateState();
protected override void OnDeactivated() => updateState();
protected override bool OnHover(HoverEvent e)
{
updateState();
return false;
}
protected override void OnHoverLost(HoverLostEvent e) => updateState();
#endregion
}
}

View File

@ -0,0 +1,35 @@
// 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.Bindables;
using osu.Framework.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets;
namespace osu.Game.Overlays.BeatmapSet
{
public class BeatmapSetHeader : OverlayHeader
{
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
public BeatmapRulesetSelector RulesetSelector { get; private set; }
protected override ScreenTitle CreateTitle() => new BeatmapHeaderTitle();
protected override Drawable CreateTitleContent() => RulesetSelector = new BeatmapRulesetSelector
{
Current = Ruleset
};
private class BeatmapHeaderTitle : ScreenTitle
{
public BeatmapHeaderTitle()
{
Title = @"beatmap";
Section = @"info";
}
protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/changelog");
}
}
}

View File

@ -26,11 +26,9 @@ namespace osu.Game.Overlays.BeatmapSet
public class Header : BeatmapDownloadTrackingComposite
{
private const float transition_duration = 200;
private const float tabs_height = 50;
private const float buttons_height = 45;
private const float buttons_spacing = 5;
private readonly Box tabsBg;
private readonly UpdateableBeatmapSetCover cover;
private readonly OsuSpriteText title, artist;
private readonly AuthorInfo author;
@ -41,14 +39,13 @@ namespace osu.Game.Overlays.BeatmapSet
public bool DownloadButtonsVisible => downloadButtonsContainer.Any();
public readonly BeatmapRulesetSelector RulesetSelector;
public BeatmapRulesetSelector RulesetSelector => beatmapSetHeader.RulesetSelector;
public readonly BeatmapPicker Picker;
private readonly FavouriteButton favouriteButton;
private readonly FillFlowContainer fadeContent;
private readonly LoadingAnimation loading;
private readonly BeatmapSetHeader beatmapSetHeader;
[Cached(typeof(IBindable<RulesetInfo>))]
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
@ -69,154 +66,145 @@ namespace osu.Game.Overlays.BeatmapSet
Offset = new Vector2(0f, 1f),
};
InternalChildren = new Drawable[]
InternalChild = new FillFlowContainer
{
new Container
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
RelativeSizeAxes = Axes.X,
Height = tabs_height,
Children = new Drawable[]
beatmapSetHeader = new BeatmapSetHeader
{
tabsBg = new Box
{
RelativeSizeAxes = Axes.Both,
},
RulesetSelector = new BeatmapRulesetSelector
{
Current = ruleset,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
}
Ruleset = { BindTarget = ruleset },
},
},
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Top = tabs_height },
Children = new Drawable[]
new Container
{
new Container
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
new Container
{
cover = new UpdateableBeatmapSetCover
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Masking = true,
},
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.3f), Color4.Black.Opacity(0.8f)),
},
},
},
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding
{
Top = 20,
Bottom = 30,
Left = BeatmapSetOverlay.X_PADDING,
Right = BeatmapSetOverlay.X_PADDING + BeatmapSetOverlay.RIGHT_WIDTH,
},
Children = new Drawable[]
{
fadeContent = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children = new Drawable[]
cover = new UpdateableBeatmapSetCover
{
new Container
RelativeSizeAxes = Axes.Both,
Masking = true,
},
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.3f), Color4.Black.Opacity(0.8f)),
},
},
},
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding
{
Top = 20,
Bottom = 30,
Left = BeatmapSetOverlay.X_PADDING,
Right = BeatmapSetOverlay.X_PADDING + BeatmapSetOverlay.RIGHT_WIDTH,
},
Children = new Drawable[]
{
fadeContent = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = Picker = new BeatmapPicker(),
},
new FillFlowContainer
{
Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
new Container
{
title = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 37, weight: FontWeight.Bold, italics: true)
},
externalLink = new ExternalLinkButton
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Margin = new MarginPadding { Left = 3, Bottom = 4 }, //To better lineup with the font
},
}
},
artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 25, weight: FontWeight.SemiBold, italics: true) },
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding { Top = 20 },
Child = author = new AuthorInfo(),
},
beatmapAvailability = new BeatmapAvailability(),
new Container
{
RelativeSizeAxes = Axes.X,
Height = buttons_height,
Margin = new MarginPadding { Top = 10 },
Children = new Drawable[]
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = Picker = new BeatmapPicker(),
},
new FillFlowContainer
{
favouriteButton = new FavouriteButton
Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
BeatmapSet = { BindTarget = BeatmapSet }
},
downloadButtonsContainer = new FillFlowContainer
title = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 37, weight: FontWeight.Bold, italics: true)
},
externalLink = new ExternalLinkButton
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Margin = new MarginPadding { Left = 3, Bottom = 4 }, //To better lineup with the font
},
}
},
artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 25, weight: FontWeight.SemiBold, italics: true) },
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding { Top = 20 },
Child = author = new AuthorInfo(),
},
beatmapAvailability = new BeatmapAvailability(),
new Container
{
RelativeSizeAxes = Axes.X,
Height = buttons_height,
Margin = new MarginPadding { Top = 10 },
Children = new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = buttons_height + buttons_spacing },
Spacing = new Vector2(buttons_spacing),
favouriteButton = new FavouriteButton
{
BeatmapSet = { BindTarget = BeatmapSet }
},
downloadButtonsContainer = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = buttons_height + buttons_spacing },
Spacing = new Vector2(buttons_spacing),
},
},
},
},
},
},
}
},
loading = new LoadingAnimation
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Scale = new Vector2(1.5f),
},
new FillFlowContainer
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Top = BeatmapSetOverlay.TOP_PADDING, Right = BeatmapSetOverlay.X_PADDING },
Direction = FillDirection.Vertical,
Spacing = new Vector2(10),
Children = new Drawable[]
}
},
loading = new LoadingAnimation
{
onlineStatusPill = new BeatmapSetOnlineStatusPill
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Scale = new Vector2(1.5f),
},
new FillFlowContainer
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Top = BeatmapSetOverlay.TOP_PADDING, Right = BeatmapSetOverlay.X_PADDING },
Direction = FillDirection.Vertical,
Spacing = new Vector2(10),
Children = new Drawable[]
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
TextSize = 14,
TextPadding = new MarginPadding { Horizontal = 25, Vertical = 8 }
onlineStatusPill = new BeatmapSetOnlineStatusPill
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
TextSize = 14,
TextPadding = new MarginPadding { Horizontal = 25, Vertical = 8 }
},
Details = new Details(),
},
Details = new Details(),
},
},
},
},
}
};
Picker.Beatmap.ValueChanged += b =>
@ -229,8 +217,6 @@ namespace osu.Game.Overlays.BeatmapSet
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
tabsBg.Colour = colours.Gray3;
State.BindValueChanged(_ => updateDownloadButtons());
BeatmapSet.BindValueChanged(setInfo =>

View File

@ -116,7 +116,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
new OsuSpriteText
{
Margin = new MarginPadding { Right = horizontal_inset },
Text = $@"{score.Accuracy:P2}",
Text = score.DisplayAccuracy,
Font = OsuFont.GetFont(size: text_size),
Colour = score.Accuracy == 1 ? highAccuracyColour : Color4.White
},

View File

@ -92,7 +92,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
set
{
totalScoreColumn.Text = $@"{value.TotalScore:N0}";
accuracyColumn.Text = $@"{value.Accuracy:P2}";
accuracyColumn.Text = value.DisplayAccuracy;
maxComboColumn.Text = $@"{value.MaxCombo:N0}x";
ppColumn.Text = $@"{value.PP:N0}";

View File

@ -42,7 +42,7 @@ namespace osu.Game.Overlays.BeatmapSet
int playCount = beatmap?.OnlineInfo?.PlayCount ?? 0;
var rate = playCount != 0 ? (float)passCount / playCount : 0;
successPercent.Text = rate.ToString("P0");
successPercent.Text = rate.ToString("0%");
successRate.Length = rate;
percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic);

View File

@ -14,7 +14,7 @@ namespace osu.Game.Overlays.Changelog
{
public class ChangelogHeader : BreadcrumbControlOverlayHeader
{
public readonly Bindable<APIChangelogBuild> Current = new Bindable<APIChangelogBuild>();
public readonly Bindable<APIChangelogBuild> Build = new Bindable<APIChangelogBuild>();
public Action ListingSelected;
@ -25,18 +25,18 @@ namespace osu.Game.Overlays.Changelog
public ChangelogHeader()
{
TabControl.AddItem(listing_string);
TabControl.Current.ValueChanged += e =>
Current.ValueChanged += e =>
{
if (e.NewValue == listing_string)
ListingSelected?.Invoke();
};
Current.ValueChanged += showBuild;
Build.ValueChanged += showBuild;
Streams.Current.ValueChanged += e =>
{
if (e.NewValue?.LatestBuild != null && !e.NewValue.Equals(Current.Value?.UpdateStream))
Current.Value = e.NewValue.LatestBuild;
if (e.NewValue?.LatestBuild != null && !e.NewValue.Equals(Build.Value?.UpdateStream))
Build.Value = e.NewValue.LatestBuild;
};
}
@ -50,7 +50,7 @@ namespace osu.Game.Overlays.Changelog
if (e.NewValue != null)
{
TabControl.AddItem(e.NewValue.ToString());
TabControl.Current.Value = e.NewValue.ToString();
Current.Value = e.NewValue.ToString();
updateCurrentStream();
@ -58,7 +58,7 @@ namespace osu.Game.Overlays.Changelog
}
else
{
TabControl.Current.Value = listing_string;
Current.Value = listing_string;
Streams.Current.Value = null;
title.Version = null;
}
@ -86,10 +86,10 @@ namespace osu.Game.Overlays.Changelog
private void updateCurrentStream()
{
if (Current.Value == null)
if (Build.Value == null)
return;
Streams.Current.Value = Streams.Items.FirstOrDefault(s => s.Name == Current.Value.UpdateStream.Name);
Streams.Current.Value = Streams.Items.FirstOrDefault(s => s.Name == Build.Value.UpdateStream.Name);
}
private class ChangelogHeaderTitle : ScreenTitle

View File

@ -78,7 +78,7 @@ namespace osu.Game.Overlays
sampleBack = audio.Samples.Get(@"UI/generic-select-soft");
Header.Current.BindTo(Current);
Header.Build.BindTo(Current);
Current.BindValueChanged(e =>
{

View File

@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Chat.Selection
private const float text_size = 15;
private const float transition_duration = 100;
private readonly Channel channel;
public readonly Channel Channel;
private readonly Bindable<bool> joinedBind = new Bindable<bool>();
private readonly OsuSpriteText name;
@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Chat.Selection
private Color4 topicColour;
private Color4 hoverColour;
public IEnumerable<string> FilterTerms => new[] { channel.Name, channel.Topic };
public IEnumerable<string> FilterTerms => new[] { Channel.Name, Channel.Topic ?? string.Empty };
public bool MatchingFilter
{
@ -50,7 +50,7 @@ namespace osu.Game.Overlays.Chat.Selection
public ChannelListItem(Channel channel)
{
this.channel = channel;
Channel = channel;
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
@ -148,7 +148,7 @@ namespace osu.Game.Overlays.Chat.Selection
hoverColour = colours.Yellow;
joinedBind.ValueChanged += joined => updateColour(joined.NewValue);
joinedBind.BindTo(channel.Joined);
joinedBind.BindTo(Channel.Joined);
joinedBind.TriggerChange();
FinishTransforms(true);
@ -156,7 +156,7 @@ namespace osu.Game.Overlays.Chat.Selection
protected override bool OnHover(HoverEvent e)
{
if (!channel.Joined.Value)
if (!Channel.Joined.Value)
name.FadeColour(hoverColour, 50, Easing.OutQuint);
return base.OnHover(e);
@ -164,7 +164,7 @@ namespace osu.Game.Overlays.Chat.Selection
protected override void OnHoverLost(HoverLostEvent e)
{
if (!channel.Joined.Value)
if (!Channel.Joined.Value)
name.FadeColour(Color4.White, transition_duration);
}

View File

@ -321,8 +321,10 @@ namespace osu.Game.Overlays
private void selectTab(int index)
{
var channel = ChannelTabControl.Items.Skip(index).FirstOrDefault();
if (channel != null && !(channel is ChannelSelectorTabItem.ChannelSelectorTabChannel))
var channel = ChannelTabControl.Items
.Where(tab => !(tab is ChannelSelectorTabItem.ChannelSelectorTabChannel))
.ElementAtOrDefault(index);
if (channel != null)
ChannelTabControl.Current.Value = channel;
}

View File

@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Comments
private int currentPage;
private FillFlowContainer content;
private DeletedChildrenPlaceholder deletedChildrenPlaceholder;
private DeletedCommentsCounter deletedCommentsCounter;
private CommentsShowMoreButton moreButton;
private TotalCommentsCounter commentCounter;
@ -68,6 +68,7 @@ namespace osu.Game.Overlays.Comments
},
new Container
{
Name = @"Footer",
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
@ -84,7 +85,7 @@ namespace osu.Game.Overlays.Comments
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
deletedChildrenPlaceholder = new DeletedChildrenPlaceholder
deletedCommentsCounter = new DeletedCommentsCounter
{
ShowDeleted = { BindTarget = ShowDeleted }
},
@ -153,7 +154,8 @@ namespace osu.Game.Overlays.Comments
private void clearComments()
{
currentPage = 1;
deletedChildrenPlaceholder.DeletedCount.Value = 0;
deletedCommentsCounter.Count.Value = 0;
moreButton.Show();
moreButton.IsLoading = true;
content.Clear();
}
@ -162,29 +164,14 @@ namespace osu.Game.Overlays.Comments
{
loadCancellation = new CancellationTokenSource();
var page = new FillFlowContainer
LoadComponentAsync(new CommentsPage(response)
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
};
foreach (var c in response.Comments)
{
if (c.IsTopLevel)
{
page.Add(new DrawableComment(c)
{
ShowDeleted = { BindTarget = ShowDeleted }
});
}
}
LoadComponentAsync(page, loaded =>
ShowDeleted = { BindTarget = ShowDeleted }
}, loaded =>
{
content.Add(loaded);
deletedChildrenPlaceholder.DeletedCount.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel);
deletedCommentsCounter.Count.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel);
if (response.HasMore)
{
@ -194,10 +181,12 @@ namespace osu.Game.Overlays.Comments
moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments;
moreButton.IsLoading = false;
}
else
{
moreButton.Hide();
}
commentCounter.Current.Value = response.Total;
moreButton.FadeTo(response.HasMore ? 1 : 0);
}, loadCancellation.Token);
}

View File

@ -0,0 +1,92 @@
// 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.Containers;
using osu.Framework.Graphics;
using osu.Framework.Bindables;
using osu.Game.Online.API.Requests.Responses;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites;
using System.Linq;
namespace osu.Game.Overlays.Comments
{
public class CommentsPage : CompositeDrawable
{
public readonly BindableBool ShowDeleted = new BindableBool();
private readonly CommentBundle commentBundle;
public CommentsPage(CommentBundle commentBundle)
{
this.commentBundle = commentBundle;
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
FillFlowContainer flow;
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
AddRangeInternal(new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colourProvider.Background5
},
flow = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
}
});
if (!commentBundle.Comments.Any())
{
flow.Add(new NoCommentsPlaceholder());
return;
}
foreach (var c in commentBundle.Comments)
{
if (c.IsTopLevel)
{
flow.Add(new DrawableComment(c)
{
ShowDeleted = { BindTarget = ShowDeleted }
});
}
}
}
private class NoCommentsPlaceholder : CompositeDrawable
{
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
Height = 80;
RelativeSizeAxes = Axes.X;
AddRangeInternal(new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colourProvider.Background4
},
new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Margin = new MarginPadding { Left = 50 },
Text = @"No comments yet."
}
});
}
}
}
}

View File

@ -14,6 +14,8 @@ namespace osu.Game.Overlays.Comments
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
Height = 20;
IdleColour = colourProvider.Background2;
HoverColour = colourProvider.Background1;
ChevronIconColour = colourProvider.Foreground1;

View File

@ -12,51 +12,56 @@ using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Comments
{
public class DeletedChildrenPlaceholder : FillFlowContainer
public class DeletedCommentsCounter : CompositeDrawable
{
public readonly BindableBool ShowDeleted = new BindableBool();
public readonly BindableInt DeletedCount = new BindableInt();
public readonly BindableInt Count = new BindableInt();
private readonly SpriteText countText;
public DeletedChildrenPlaceholder()
public DeletedCommentsCounter()
{
AutoSizeAxes = Axes.Both;
Direction = FillDirection.Horizontal;
Spacing = new Vector2(3, 0);
Margin = new MarginPadding { Vertical = 10, Left = 80 };
Children = new Drawable[]
InternalChild = new FillFlowContainer
{
new SpriteIcon
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(3, 0),
Children = new Drawable[]
{
Icon = FontAwesome.Solid.Trash,
Size = new Vector2(14),
},
countText = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
new SpriteIcon
{
Icon = FontAwesome.Solid.Trash,
Size = new Vector2(14),
},
countText = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
}
}
};
}
protected override void LoadComplete()
{
DeletedCount.BindValueChanged(_ => updateDisplay(), true);
ShowDeleted.BindValueChanged(_ => updateDisplay(), true);
base.LoadComplete();
Count.BindValueChanged(_ => updateDisplay(), true);
ShowDeleted.BindValueChanged(_ => updateDisplay(), true);
}
private void updateDisplay()
{
if (DeletedCount.Value != 0)
if (!ShowDeleted.Value && Count.Value != 0)
{
countText.Text = @"deleted comment".ToQuantity(DeletedCount.Value);
this.FadeTo(ShowDeleted.Value ? 0 : 1);
countText.Text = @"deleted comment".ToQuantity(Count.Value);
Show();
}
else
{
Hide();
}
}
}
}

View File

@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Comments
{
LinkFlowContainer username;
FillFlowContainer childCommentsContainer;
DeletedChildrenPlaceholder deletedChildrenPlaceholder;
DeletedCommentsCounter deletedCommentsCounter;
FillFlowContainer info;
LinkFlowContainer message;
GridContainer content;
@ -184,7 +184,7 @@ namespace osu.Game.Overlays.Comments
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical
},
deletedChildrenPlaceholder = new DeletedChildrenPlaceholder
deletedCommentsCounter = new DeletedCommentsCounter
{
ShowDeleted = { BindTarget = ShowDeleted }
}
@ -193,7 +193,7 @@ namespace osu.Game.Overlays.Comments
}
};
deletedChildrenPlaceholder.DeletedCount.Value = comment.DeletedChildrenCount;
deletedCommentsCounter.Count.Value = comment.DeletedChildrenCount;
if (comment.UserId.HasValue)
username.AddUserLink(comment.User);
@ -213,7 +213,7 @@ namespace osu.Game.Overlays.Comments
if (comment.HasMessage)
{
var formattedSource = MessageFormatter.FormatText(comment.GetMessage);
var formattedSource = MessageFormatter.FormatText(comment.Message);
message.AddLinks(formattedSource.Text, formattedSource.Links);
}
@ -343,7 +343,7 @@ namespace osu.Game.Overlays.Comments
if (parentComment == null)
return string.Empty;
return parentComment.HasMessage ? parentComment.GetMessage : parentComment.IsDeleted ? @"deleted" : string.Empty;
return parentComment.HasMessage ? parentComment.Message : parentComment.IsDeleted ? @"deleted" : string.Empty;
}
}
}

View File

@ -18,11 +18,11 @@ namespace osu.Game.Overlays
protected IAPIProvider API { get; private set; }
[Cached]
private readonly OverlayColourProvider colourProvider;
protected readonly OverlayColourProvider ColourProvider;
protected FullscreenOverlay(OverlayColourScheme colourScheme)
{
colourProvider = new OverlayColourProvider(colourScheme);
ColourProvider = new OverlayColourProvider(colourScheme);
RelativeSizeAxes = Axes.Both;
RelativePositionAxes = Axes.Both;
@ -43,10 +43,10 @@ namespace osu.Game.Overlays
[BackgroundDependencyLoader]
private void load()
{
Waves.FirstWaveColour = colourProvider.Light4;
Waves.SecondWaveColour = colourProvider.Light3;
Waves.ThirdWaveColour = colourProvider.Dark4;
Waves.FourthWaveColour = colourProvider.Dark3;
Waves.FirstWaveColour = ColourProvider.Light4;
Waves.SecondWaveColour = ColourProvider.Light3;
Waves.ThirdWaveColour = ColourProvider.Dark4;
Waves.FourthWaveColour = ColourProvider.Dark3;
}
public override void Show()

View File

@ -30,6 +30,8 @@ namespace osu.Game.Overlays.Mods
{
public class ModSelectOverlay : WaveOverlayContainer
{
public const float HEIGHT = 510;
protected readonly TriangleButton DeselectAllButton;
protected readonly TriangleButton CustomiseButton;
protected readonly TriangleButton CloseButton;
@ -47,7 +49,7 @@ namespace osu.Game.Overlays.Mods
protected readonly Container ModSettingsContainer;
protected readonly Bindable<IReadOnlyList<Mod>> SelectedMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
public readonly Bindable<IReadOnlyList<Mod>> SelectedMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
private Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods;
@ -66,7 +68,8 @@ namespace osu.Game.Overlays.Mods
Waves.ThirdWaveColour = OsuColour.FromHex(@"005774");
Waves.FourthWaveColour = OsuColour.FromHex(@"003a4e");
Height = 510;
RelativeSizeAxes = Axes.Both;
Padding = new MarginPadding { Horizontal = -OsuScreen.HORIZONTAL_OVERFLOW_PADDING };
Children = new Drawable[]
@ -85,8 +88,7 @@ namespace osu.Game.Overlays.Mods
new Triangles
{
TriangleScale = 5,
RelativeSizeAxes = Axes.X,
Height = Height, //set the height from the start to ensure correct triangle density.
RelativeSizeAxes = Axes.Both,
ColourLight = new Color4(53, 66, 82, 255),
ColourDark = new Color4(41, 54, 70, 255),
},
@ -321,14 +323,13 @@ namespace osu.Game.Overlays.Mods
}
[BackgroundDependencyLoader(true)]
private void load(OsuColour colours, AudioManager audio, Bindable<IReadOnlyList<Mod>> selectedMods, OsuGameBase osu)
private void load(OsuColour colours, AudioManager audio, OsuGameBase osu)
{
LowMultiplierColour = colours.Red;
HighMultiplierColour = colours.Green;
UnrankedLabel.Colour = colours.Blue;
availableMods = osu.AvailableMods.GetBoundCopy();
SelectedMods.BindTo(selectedMods);
sampleOn = audio.Samples.Get(@"UI/check-on");
sampleOff = audio.Samples.Get(@"UI/check-off");

View File

@ -196,7 +196,7 @@ namespace osu.Game.Overlays
if (!instant)
queuedDirection = TrackChangeDirection.Next;
var playable = BeatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).Skip(1).FirstOrDefault() ?? BeatmapSets.FirstOrDefault();
var playable = BeatmapSets.SkipWhile(i => i.ID != current.BeatmapSetInfo.ID).ElementAtOrDefault(1) ?? BeatmapSets.FirstOrDefault();
if (playable != null)
{

View File

@ -14,7 +14,7 @@ namespace osu.Game.Overlays.News
private NewsHeaderTitle title;
public readonly Bindable<string> Current = new Bindable<string>(null);
public readonly Bindable<string> Post = new Bindable<string>(null);
public Action ShowFrontPage;
@ -22,13 +22,13 @@ namespace osu.Game.Overlays.News
{
TabControl.AddItem(front_page_string);
TabControl.Current.ValueChanged += e =>
Current.ValueChanged += e =>
{
if (e.NewValue == front_page_string)
ShowFrontPage?.Invoke();
};
Current.ValueChanged += showPost;
Post.ValueChanged += showPost;
}
private void showPost(ValueChangedEvent<string> e)
@ -39,13 +39,13 @@ namespace osu.Game.Overlays.News
if (e.NewValue != null)
{
TabControl.AddItem(e.NewValue);
TabControl.Current.Value = e.NewValue;
Current.Value = e.NewValue;
title.IsReadingPost = true;
}
else
{
TabControl.Current.Value = front_page_string;
Current.Value = front_page_string;
title.IsReadingPost = false;
}
}

View File

@ -60,7 +60,7 @@ namespace osu.Game.Overlays
},
};
header.Current.BindTo(Current);
header.Post.BindTo(Current);
Current.TriggerChange();
}

View File

@ -50,14 +50,29 @@ namespace osu.Game.Overlays
RelativeSizeAxes = Axes.Both,
Colour = Color4.Gray,
},
title = CreateTitle().With(title =>
new Container
{
title.Margin = new MarginPadding
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding
{
Horizontal = UserProfileOverlay.CONTENT_X_MARGIN,
Vertical = 10,
Left = UserProfileOverlay.CONTENT_X_MARGIN
};
})
},
Children = new[]
{
title = CreateTitle().With(title =>
{
title.Anchor = Anchor.CentreLeft;
title.Origin = Anchor.CentreLeft;
}),
CreateTitleContent().With(content =>
{
content.Anchor = Anchor.CentreRight;
content.Origin = Anchor.CentreRight;
})
}
}
}
},
}
@ -75,10 +90,16 @@ namespace osu.Game.Overlays
}
[NotNull]
protected virtual Drawable CreateContent() => Drawable.Empty();
protected virtual Drawable CreateContent() => Empty();
[NotNull]
protected virtual Drawable CreateBackground() => Drawable.Empty();
protected virtual Drawable CreateBackground() => Empty();
/// <summary>
/// Creates a <see cref="Drawable"/> on the opposite side of the <see cref="ScreenTitle"/>. Used mostly to create <see cref="OverlayRulesetSelector"/>.
/// </summary>
[NotNull]
protected virtual Drawable CreateTitleContent() => Empty();
protected abstract ScreenTitle CreateTitle();
}

View File

@ -0,0 +1,28 @@
// 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.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Rulesets;
using osuTK;
namespace osu.Game.Overlays
{
public class OverlayRulesetSelector : RulesetSelector
{
public OverlayRulesetSelector()
{
AutoSizeAxes = Axes.Both;
}
protected override TabItem<RulesetInfo> CreateTabItem(RulesetInfo value) => new OverlayRulesetTabItem(value);
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(25, 0),
};
}
}

View File

@ -0,0 +1,97 @@
// 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.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets;
using osuTK.Graphics;
using osuTK;
using osu.Framework.Allocation;
namespace osu.Game.Overlays
{
public class OverlayRulesetTabItem : TabItem<RulesetInfo>
{
private Color4 accentColour;
protected virtual Color4 AccentColour
{
get => accentColour;
set
{
accentColour = value;
text.FadeColour(value, 120, Easing.OutQuint);
}
}
protected override Container<Drawable> Content { get; }
[Resolved]
private OverlayColourProvider colourProvider { get; set; }
private readonly OsuSpriteText text;
public OverlayRulesetTabItem(RulesetInfo value)
: base(value)
{
AutoSizeAxes = Axes.Both;
AddRangeInternal(new Drawable[]
{
Content = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(3, 0),
Child = text = new OsuSpriteText
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Text = value.Name,
}
},
new HoverClickSounds()
});
Enabled.Value = true;
}
protected override void LoadComplete()
{
base.LoadComplete();
Enabled.BindValueChanged(_ => updateState(), true);
}
public override bool PropagatePositionalInputSubTree => Enabled.Value && !Active.Value && base.PropagatePositionalInputSubTree;
protected override bool OnHover(HoverEvent e)
{
base.OnHover(e);
updateState();
return true;
}
protected override void OnHoverLost(HoverLostEvent e)
{
base.OnHoverLost(e);
updateState();
}
protected override void OnActivated() => updateState();
protected override void OnDeactivated() => updateState();
private void updateState()
{
text.Font = text.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Medium);
AccentColour = Enabled.Value ? getActiveColour() : colourProvider.Foreground1;
}
private Color4 getActiveColour() => IsHovered || Active.Value ? Color4.White : colourProvider.Highlight1;
}
}

View File

@ -1,4 +1,4 @@
// 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.
using System;
@ -33,16 +33,16 @@ namespace osu.Game.Overlays.Profile.Header
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OverlayColourProvider colourProvider)
{
iconColour = colours.GreySeafoamLighter;
iconColour = colourProvider.Foreground1;
InternalChildren = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.GreySeafoamDark,
Colour = colourProvider.Background4
},
new FillFlowContainer
{
@ -82,7 +82,7 @@ namespace osu.Game.Overlays.Profile.Header
else
{
topLinkContainer.AddText("Joined ");
topLinkContainer.AddText(new DrawableDate(user.JoinDate), embolden);
topLinkContainer.AddText(new DrawableDate(user.JoinDate, italic: false), embolden);
}
addSpacer(topLinkContainer);
@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Profile.Header
else if (user.LastVisit.HasValue)
{
topLinkContainer.AddText("Last seen ");
topLinkContainer.AddText(new DrawableDate(user.LastVisit.Value), embolden);
topLinkContainer.AddText(new DrawableDate(user.LastVisit.Value, italic: false), embolden);
addSpacer(topLinkContainer);
}
@ -111,34 +111,42 @@ namespace osu.Game.Overlays.Profile.Header
topLinkContainer.AddText("Contributed ");
topLinkContainer.AddLink($@"{user.PostCount:#,##0} forum posts", $"https://osu.ppy.sh/users/{user.Id}/posts", creationParameters: embolden);
string websiteWithoutProtcol = user.Website;
string websiteWithoutProtocol = user.Website;
if (!string.IsNullOrEmpty(websiteWithoutProtcol))
if (!string.IsNullOrEmpty(websiteWithoutProtocol))
{
if (Uri.TryCreate(websiteWithoutProtcol, UriKind.Absolute, out var uri))
if (Uri.TryCreate(websiteWithoutProtocol, UriKind.Absolute, out var uri))
{
websiteWithoutProtcol = uri.Host + uri.PathAndQuery + uri.Fragment;
websiteWithoutProtcol = websiteWithoutProtcol.TrimEnd('/');
websiteWithoutProtocol = uri.Host + uri.PathAndQuery + uri.Fragment;
websiteWithoutProtocol = websiteWithoutProtocol.TrimEnd('/');
}
}
tryAddInfo(FontAwesome.Solid.MapMarker, user.Location);
tryAddInfo(OsuIcon.Heart, user.Interests);
tryAddInfo(FontAwesome.Solid.Suitcase, user.Occupation);
bottomLinkContainer.NewLine();
bool anyInfoAdded = false;
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.MapMarker, user.Location);
anyInfoAdded |= tryAddInfo(OsuIcon.Heart, user.Interests);
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.Suitcase, user.Occupation);
if (anyInfoAdded)
bottomLinkContainer.NewLine();
if (!string.IsNullOrEmpty(user.Twitter))
tryAddInfo(FontAwesome.Brands.Twitter, "@" + user.Twitter, $@"https://twitter.com/{user.Twitter}");
tryAddInfo(FontAwesome.Brands.Discord, user.Discord);
tryAddInfo(FontAwesome.Brands.Skype, user.Skype, @"skype:" + user.Skype + @"?chat");
tryAddInfo(FontAwesome.Brands.Lastfm, user.Lastfm, $@"https://last.fm/users/{user.Lastfm}");
tryAddInfo(FontAwesome.Solid.Link, websiteWithoutProtcol, user.Website);
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Twitter, "@" + user.Twitter, $@"https://twitter.com/{user.Twitter}");
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Discord, user.Discord);
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Skype, user.Skype, @"skype:" + user.Skype + @"?chat");
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Lastfm, user.Lastfm, $@"https://last.fm/users/{user.Lastfm}");
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.Link, websiteWithoutProtocol, user.Website);
// If no information was added to the bottomLinkContainer, hide it to avoid unwanted padding
bottomLinkContainer.Alpha = anyInfoAdded ? 1 : 0;
}
private void addSpacer(OsuTextFlowContainer textFlow) => textFlow.AddArbitraryDrawable(new Container { Width = 15 });
private void tryAddInfo(IconUsage icon, string content, string link = null)
private bool tryAddInfo(IconUsage icon, string content, string link = null)
{
if (string.IsNullOrEmpty(content)) return;
if (string.IsNullOrEmpty(content)) return false;
// newlines could be contained in API returned user content.
content = content.Replace("\n", " ");
@ -155,6 +163,7 @@ namespace osu.Game.Overlays.Profile.Header
bottomLinkContainer.AddText(" " + content, embolden);
addSpacer(bottomLinkContainer);
return true;
}
private void embolden(SpriteText text) => text.Font = text.Font.With(weight: FontWeight.Bold);

View File

@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using osu.Game.Overlays.Profile.Header.Components;
using osu.Game.Users;
using osuTK;
@ -28,7 +27,7 @@ namespace osu.Game.Overlays.Profile.Header
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, TextureStore textures)
private void load(OverlayColourProvider colourProvider, TextureStore textures)
{
Container<Drawable> hiddenDetailContainer;
Container<Drawable> expandedDetailContainer;
@ -38,7 +37,7 @@ namespace osu.Game.Overlays.Profile.Header
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.GreySeafoam
Colour = colourProvider.Background4
},
new FillFlowContainer
{
@ -119,12 +118,12 @@ namespace osu.Game.Overlays.Profile.Header
hiddenDetailGlobal = new OverlinedInfoContainer
{
Title = "Global Ranking",
LineColour = colours.Yellow
LineColour = colourProvider.Highlight1
},
hiddenDetailCountry = new OverlinedInfoContainer
{
Title = "Country Ranking",
LineColour = colours.Yellow
LineColour = colourProvider.Highlight1
},
}
}

View File

@ -6,7 +6,6 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osuTK;
namespace osu.Game.Overlays.Profile.Header.Components
@ -25,10 +24,10 @@ namespace osu.Game.Overlays.Profile.Header.Components
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OverlayColourProvider colourProvider)
{
IdleColour = colours.GreySeafoamLight;
HoverColour = colours.GreySeafoamLight.Darken(0.2f);
IdleColour = colourProvider.Background2;
HoverColour = colourProvider.Background2.Lighten(0.2f);
Child = icon = new SpriteIcon
{

View File

@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Profile.Header.Components
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OverlayColourProvider colourProvider)
{
InternalChildren = new Drawable[]
{
@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Profile.Header.Components
RelativeSizeAxes = Axes.Both,
BackgroundColour = Color4.Black,
Direction = BarDirection.LeftToRight,
AccentColour = colours.Yellow
AccentColour = colourProvider.Highlight1
}
},
levelProgressText = new OsuSpriteText

View File

@ -43,7 +43,8 @@ namespace osu.Game.Overlays.Profile.Header.Components
line = new Circle
{
RelativeSizeAxes = Axes.X,
Height = 4,
Height = 2,
Margin = new MarginPadding { Bottom = 2 }
},
title = new OsuSpriteText
{

View File

@ -6,7 +6,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Game.Graphics;
using osu.Game.Users;
namespace osu.Game.Overlays.Profile.Header.Components
@ -27,12 +26,12 @@ namespace osu.Game.Overlays.Profile.Header.Components
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OverlayColourProvider colourProvider)
{
InternalChild = info = new OverlinedInfoContainer
{
Title = "Total Play Time",
LineColour = colours.Yellow,
LineColour = colourProvider.Highlight1,
};
User.BindValueChanged(updateTime, true);

View File

@ -2,12 +2,11 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osuTK.Graphics;
namespace osu.Game.Overlays.Profile.Header.Components
{
@ -24,9 +23,6 @@ namespace osu.Game.Overlays.Profile.Header.Components
{
AutoSizeAxes = Axes.X;
IdleColour = Color4.Black;
HoverColour = OsuColour.Gray(0.1f);
base.Content.Add(new CircularContainer
{
Masking = true,
@ -47,5 +43,12 @@ namespace osu.Game.Overlays.Profile.Header.Components
}
});
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
IdleColour = colourProvider.Background6;
HoverColour = colourProvider.Background5;
}
}
}

View File

@ -1,63 +1,29 @@
// 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.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Rulesets;
using osu.Game.Users;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.Profile.Header.Components
{
public class ProfileRulesetSelector : RulesetSelector
public class ProfileRulesetSelector : OverlayRulesetSelector
{
private Color4 accentColour = Color4.White;
public readonly Bindable<User> User = new Bindable<User>();
public ProfileRulesetSelector()
{
TabContainer.Masking = false;
TabContainer.Spacing = new Vector2(10, 0);
AutoSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
accentColour = colours.Seafoam;
foreach (TabItem<RulesetInfo> tabItem in TabContainer)
((ProfileRulesetTabItem)tabItem).AccentColour = accentColour;
}
protected override void LoadComplete()
{
base.LoadComplete();
User.BindValueChanged(u => SetDefaultRuleset(Rulesets.GetRuleset(u.NewValue?.PlayMode ?? "osu")), true);
}
public void SetDefaultRuleset(RulesetInfo ruleset)
{
foreach (TabItem<RulesetInfo> tabItem in TabContainer)
foreach (var tabItem in TabContainer)
((ProfileRulesetTabItem)tabItem).IsDefault = ((ProfileRulesetTabItem)tabItem).Value.ID == ruleset.ID;
}
protected override TabItem<RulesetInfo> CreateTabItem(RulesetInfo value) => new ProfileRulesetTabItem(value)
{
AccentColour = accentColour
};
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
{
Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
};
protected override TabItem<RulesetInfo> CreateTabItem(RulesetInfo value) => new ProfileRulesetTabItem(value);
}
}

View File

@ -2,40 +2,15 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.Profile.Header.Components
{
public class ProfileRulesetTabItem : TabItem<RulesetInfo>, IHasAccentColour
public class ProfileRulesetTabItem : OverlayRulesetTabItem
{
private readonly OsuSpriteText text;
private readonly SpriteIcon icon;
private Color4 accentColour;
public Color4 AccentColour
{
get => accentColour;
set
{
if (accentColour == value)
return;
accentColour = value;
updateState();
}
}
private bool isDefault;
public bool IsDefault
@ -52,74 +27,30 @@ namespace osu.Game.Overlays.Profile.Header.Components
}
}
protected override Color4 AccentColour
{
get => base.AccentColour;
set
{
base.AccentColour = value;
icon.FadeColour(value, 120, Easing.OutQuint);
}
}
private readonly SpriteIcon icon;
public ProfileRulesetTabItem(RulesetInfo value)
: base(value)
{
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
Add(icon = new SpriteIcon
{
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(3, 0),
Children = new Drawable[]
{
text = new OsuSpriteText
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Text = value.Name,
},
icon = new SpriteIcon
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Alpha = 0,
AlwaysPresent = true,
Icon = FontAwesome.Solid.Star,
Size = new Vector2(12),
},
}
},
new HoverClickSounds()
};
}
protected override bool OnHover(HoverEvent e)
{
base.OnHover(e);
updateState();
return true;
}
protected override void OnHoverLost(HoverLostEvent e)
{
base.OnHoverLost(e);
updateState();
}
protected override void OnActivated() => updateState();
protected override void OnDeactivated() => updateState();
private void updateState()
{
text.Font = text.Font.With(weight: Active.Value ? FontWeight.Bold : FontWeight.Medium);
if (IsHovered || Active.Value)
{
text.FadeColour(Color4.White, 120, Easing.InQuad);
icon.FadeColour(Color4.White, 120, Easing.InQuad);
}
else
{
text.FadeColour(AccentColour, 120, Easing.InQuad);
icon.FadeColour(AccentColour, 120, Easing.InQuad);
}
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Alpha = 0,
AlwaysPresent = true,
Icon = FontAwesome.Solid.Star,
Size = new Vector2(12),
});
}
}
}

View File

@ -167,9 +167,9 @@ namespace osu.Game.Overlays.Profile.Header.Components
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OverlayColourProvider colourProvider, OsuColour colours)
{
ballBg.Colour = colours.GreySeafoamDarker;
ballBg.Colour = colourProvider.Background5;
movingBall.BorderColour = line.Colour = colours.Yellow;
}
@ -270,7 +270,9 @@ namespace osu.Game.Overlays.Profile.Header.Components
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
background.Colour = colours.GreySeafoamDark;
// Temporary colour since it's currently impossible to change it without bugs (see https://github.com/ppy/osu-framework/issues/3231)
// If above is fixed, this should use OverlayColourProvider
background.Colour = colours.Gray1;
}
public bool SetContent(object content)

View File

@ -54,7 +54,7 @@ namespace osu.Game.Overlays.Profile.Header
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OverlayColourProvider colourProvider, OsuColour colours)
{
AutoSizeAxes = Axes.Y;
@ -65,7 +65,7 @@ namespace osu.Game.Overlays.Profile.Header
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.GreySeafoamDarker,
Colour = colourProvider.Background5,
},
fillFlow = new FillFlowContainer
{
@ -152,12 +152,12 @@ namespace osu.Game.Overlays.Profile.Header
detailGlobalRank = new OverlinedInfoContainer(true, 110)
{
Title = "Global Ranking",
LineColour = colours.Yellow,
LineColour = colourProvider.Highlight1,
},
detailCountryRank = new OverlinedInfoContainer(false, 110)
{
Title = "Country Ranking",
LineColour = colours.Yellow,
LineColour = colourProvider.Highlight1,
},
}
}

View File

@ -8,7 +8,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Overlays.Profile.Header.Components;
using osu.Game.Users;
using osuTK;
@ -23,7 +22,7 @@ namespace osu.Game.Overlays.Profile.Header
public readonly Bindable<User> User = new Bindable<User>();
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OverlayColourProvider colourProvider)
{
Alpha = 0;
AutoSizeAxes = Axes.Y;
@ -34,7 +33,7 @@ namespace osu.Game.Overlays.Profile.Header
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.GreySeafoamDarker,
Colour = colourProvider.Background5,
},
new Container //artificial shadow
{

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 System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -33,7 +32,7 @@ namespace osu.Game.Overlays.Profile.Header
private FillFlowContainer userStats;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OverlayColourProvider colourProvider)
{
Height = 150;
@ -42,7 +41,7 @@ namespace osu.Game.Overlays.Profile.Header
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.GreySeafoamDark,
Colour = colourProvider.Background5,
},
new FillFlowContainer
{
@ -117,7 +116,7 @@ namespace osu.Game.Overlays.Profile.Header
RelativeSizeAxes = Axes.X,
Height = 1.5f,
Margin = new MarginPadding { Top = 10 },
Colour = colours.GreySeafoamLighter,
Colour = colourProvider.Light1,
},
new FillFlowContainer
{
@ -137,7 +136,7 @@ namespace osu.Game.Overlays.Profile.Header
Margin = new MarginPadding { Left = 10 },
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
Colour = colours.GreySeafoamLighter,
Colour = colourProvider.Light1,
}
}
},
@ -178,7 +177,7 @@ namespace osu.Game.Overlays.Profile.Header
if (user?.Statistics != null)
{
userStats.Add(new UserStatsLine("Ranked Score", user.Statistics.RankedScore.ToString("#,##0")));
userStats.Add(new UserStatsLine("Hit Accuracy", Math.Round(user.Statistics.Accuracy, 2).ToString("#0.00'%'")));
userStats.Add(new UserStatsLine("Hit Accuracy", user.Statistics.DisplayAccuracy));
userStats.Add(new UserStatsLine("Play Count", user.Statistics.PlayCount.ToString("#,##0")));
userStats.Add(new UserStatsLine("Total Score", user.Statistics.TotalScore.ToString("#,##0")));
userStats.Add(new UserStatsLine("Total Hits", user.Statistics.TotalHits.ToString("#,##0")));

View File

@ -95,10 +95,10 @@ namespace osu.Game.Overlays.Profile
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OverlayColourProvider colourProvider)
{
background.Colour = colours.GreySeafoamDarker;
underscore.Colour = colours.Seafoam;
background.Colour = colourProvider.Background5;
underscore.Colour = colourProvider.Highlight1;
}
private class SectionTriangles : Container
@ -128,11 +128,11 @@ namespace osu.Game.Overlays.Profile
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OverlayColourProvider colourProvider)
{
triangles.ColourLight = colours.GreySeafoamDark;
triangles.ColourDark = colours.GreySeafoamDarker.Darken(0.2f);
foreground.Colour = ColourInfo.GradientVertical(colours.GreySeafoamDarker, colours.GreySeafoamDarker.Opacity(0));
triangles.ColourLight = colourProvider.Background4;
triangles.ColourDark = colourProvider.Background5.Darken(0.2f);
foreground.Colour = ColourInfo.GradientVertical(colourProvider.Background5, colourProvider.Background5.Opacity(0));
}
}
}

View File

@ -10,7 +10,7 @@ using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Profile.Sections
{
/// <summary>
/// Display artist/title/mapper information, commonly used as the left portion of a profile or score display row (see <see cref="DrawableProfileRow"/>).
/// Display artist/title/mapper information, commonly used as the left portion of a profile or score display row.
/// </summary>
public abstract class BeatmapMetadataContainer : OsuHoverContainer
{

View File

@ -1,124 +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.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.Profile.Sections
{
public abstract class DrawableProfileRow : Container
{
private const int fade_duration = 200;
private Box underscoreLine;
private Box coloredBackground;
private Container background;
/// <summary>
/// A visual element displayed to the left of <see cref="LeftFlowContainer"/> content.
/// </summary>
protected abstract Drawable CreateLeftVisual();
protected FillFlowContainer LeftFlowContainer { get; private set; }
protected FillFlowContainer RightFlowContainer { get; private set; }
protected override Container<Drawable> Content { get; }
protected DrawableProfileRow()
{
RelativeSizeAxes = Axes.X;
Height = 60;
Content = new Container
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 0.97f,
};
}
[BackgroundDependencyLoader(true)]
private void load(OsuColour colour)
{
InternalChildren = new Drawable[]
{
background = new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 3,
Alpha = 0,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Offset = new Vector2(0f, 1f),
Radius = 1f,
Colour = Color4.Black.Opacity(0.2f),
},
Child = coloredBackground = new Box { RelativeSizeAxes = Axes.Both }
},
Content,
underscoreLine = new Box
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
RelativeSizeAxes = Axes.X,
Height = 1,
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Children = new[]
{
CreateLeftVisual(),
LeftFlowContainer = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Margin = new MarginPadding { Left = 10 },
Direction = FillDirection.Vertical,
},
}
},
RightFlowContainer = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Direction = FillDirection.Vertical,
},
};
coloredBackground.Colour = underscoreLine.Colour = colour.Gray4;
}
protected override bool OnClick(ClickEvent e) => true;
protected override bool OnHover(HoverEvent e)
{
background.FadeIn(fade_duration, Easing.OutQuint);
underscoreLine.FadeOut(fade_duration, Easing.OutQuint);
return true;
}
protected override void OnHoverLost(HoverLostEvent e)
{
background.FadeOut(fade_duration, Easing.OutQuint);
underscoreLine.FadeIn(fade_duration, Easing.OutQuint);
base.OnHoverLost(e);
}
}
}

View File

@ -4,7 +4,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
@ -13,32 +12,25 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osuTK;
using System.Collections.Generic;
using osu.Framework.Graphics.Cursor;
namespace osu.Game.Overlays.Profile.Sections.Historical
{
public class DrawableMostPlayedBeatmap : OsuHoverContainer
public class DrawableMostPlayedBeatmap : CompositeDrawable
{
private const int cover_width = 100;
private const int corner_radius = 6;
private const int height = 50;
private readonly BeatmapInfo beatmap;
private readonly int playCount;
private Box background;
protected override IEnumerable<Drawable> EffectTargets => new[] { background };
public DrawableMostPlayedBeatmap(BeatmapInfo beatmap, int playCount)
{
this.beatmap = beatmap;
this.playCount = playCount;
Enabled.Value = true; //manually enabled, because we have no action
RelativeSizeAxes = Axes.X;
Height = height;
Height = 50;
Masking = true;
CornerRadius = corner_radius;
@ -47,10 +39,7 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
IdleColour = colours.GreySeafoam;
HoverColour = colours.GreySeafoamLight;
Children = new Drawable[]
AddRangeInternal(new Drawable[]
{
new UpdateableBeatmapSetCover
{
@ -72,46 +61,48 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
CornerRadius = corner_radius,
Children = new Drawable[]
{
background = new Box { RelativeSizeAxes = Axes.Both },
new Container
new ProfileItemContainer
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(10),
Children = new Drawable[]
Child = new Container
{
new FillFlowContainer
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(10),
Children = new Drawable[]
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Children = new Drawable[]
new FillFlowContainer
{
new MostPlayedBeatmapMetadataContainer(beatmap),
new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular))
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Colour = colours.GreySeafoamLighter
}.With(d =>
{
d.AddText("mapped by ");
d.AddUserLink(beatmap.Metadata.Author);
}),
}
},
new PlayCountText(playCount)
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight
},
}
},
new MostPlayedBeatmapMetadataContainer(beatmap),
new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular))
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Colour = colours.GreySeafoamLighter
}.With(d =>
{
d.AddText("mapped by ");
d.AddUserLink(beatmap.Metadata.Author);
}),
}
},
new PlayCountText(playCount)
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight
},
}
},
}
}
}
}
}
};
});
}
private class MostPlayedBeatmapMetadataContainer : BeatmapMetadataContainer

View File

@ -101,7 +101,7 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu
{
Masking = true,
RelativeSizeAxes = Axes.X,
Height = 5,
Height = 2,
Child = lineBackground = new Box
{
RelativeSizeAxes = Axes.Both,
@ -128,10 +128,10 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OverlayColourProvider colourProvider)
{
lineBackground.Colour = colours.Yellow;
DescriptionText.Colour = colours.GreySeafoamLighter;
lineBackground.Colour = colourProvider.Highlight1;
DescriptionText.Colour = colourProvider.Foreground1;
}
}
}

View File

@ -0,0 +1,63 @@
// 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.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osuTK.Graphics;
namespace osu.Game.Overlays.Profile.Sections
{
public class ProfileItemContainer : Container
{
private const int hover_duration = 200;
protected override Container<Drawable> Content => content;
private Color4 idleColour;
private Color4 hoverColour;
private readonly Box background;
private readonly Container content;
public ProfileItemContainer()
{
RelativeSizeAxes = Axes.Both;
Masking = true;
CornerRadius = 6;
AddRangeInternal(new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
},
content = new Container
{
RelativeSizeAxes = Axes.Both,
}
});
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
background.Colour = idleColour = colourProvider.Background3;
hoverColour = colourProvider.Background2;
}
protected override bool OnHover(HoverEvent e)
{
background.FadeColour(hoverColour, hover_duration, Easing.OutQuint);
return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e)
{
base.OnHoverLost(e);
background.FadeColour(idleColour, hover_duration, Easing.OutQuint);
}
}
}

View File

@ -2,7 +2,6 @@
// 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.Overlays.Profile.Sections
@ -10,11 +9,11 @@ namespace osu.Game.Overlays.Profile.Sections
public class ProfileShowMoreButton : ShowMoreButton
{
[BackgroundDependencyLoader]
private void load(OsuColour colors)
private void load(OverlayColourProvider colourProvider)
{
IdleColour = colors.GreySeafoamDark;
HoverColour = colors.GreySeafoam;
ChevronIconColour = colors.Yellow;
IdleColour = colourProvider.Background2;
HoverColour = colourProvider.Background1;
ChevronIconColour = colourProvider.Foreground1;
}
}
}

View File

@ -1,47 +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.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Scoring;
namespace osu.Game.Overlays.Profile.Sections.Ranks
{
public class DrawablePerformanceScore : DrawableProfileScore
{
private readonly double? weight;
public DrawablePerformanceScore(ScoreInfo score, double? weight = null)
: base(score)
{
this.weight = weight;
}
[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
double pp = Score.PP ?? 0;
RightFlowContainer.Add(new OsuSpriteText
{
Text = $"{pp:0}pp",
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold, italics: true)
});
if (weight.HasValue)
{
RightFlowContainer.Add(new OsuSpriteText
{
Text = $"weighted: {pp * weight:0}pp ({weight:P0})",
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Colour = colour.GrayA,
Font = OsuFont.GetFont(size: 11, weight: FontWeight.Regular, italics: true)
});
}
}
}
}

View File

@ -1,76 +1,233 @@
// 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 System;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Leaderboards;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
using osu.Game.Beatmaps;
using osu.Framework.Localisation;
using osu.Framework.Graphics.Containers;
using osuTK;
namespace osu.Game.Overlays.Profile.Sections.Ranks
{
public abstract class DrawableProfileScore : DrawableProfileRow
public class DrawableProfileScore : CompositeDrawable
{
private readonly FillFlowContainer modsContainer;
private const int height = 40;
private const int performance_width = 80;
private const float performance_background_shear = 0.45f;
private static readonly float performance_background_width = performance_width + (height / 4f * MathF.Tan(performance_background_shear));
protected readonly ScoreInfo Score;
protected DrawableProfileScore(ScoreInfo score)
[Resolved]
private OsuColour colours { get; set; }
[Resolved]
private OverlayColourProvider colourProvider { get; set; }
public DrawableProfileScore(ScoreInfo score)
{
Score = score;
RelativeSizeAxes = Axes.X;
Height = 60;
Children = new Drawable[]
Height = height;
}
[BackgroundDependencyLoader]
private void load()
{
AddInternal(new ProfileItemContainer
{
modsContainer = new FillFlowContainer
Children = new Drawable[]
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Spacing = new Vector2(1),
Margin = new MarginPadding { Right = 160 }
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = 10, Right = performance_width + 30 },
Children = new Drawable[]
{
new FillFlowContainer
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(8, 0),
Children = new Drawable[]
{
new UpdateableRank(Score.Rank)
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Size = new Vector2(50, 20),
},
new FillFlowContainer
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 2),
Children = new Drawable[]
{
new ScoreBeatmapMetadataContainer(Score.Beatmap),
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(5, 0),
Children = new Drawable[]
{
new OsuSpriteText
{
Text = $"{Score.Beatmap.Version}",
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular),
Colour = colours.Yellow
},
new DrawableDate(Score.Date, 12)
{
Colour = colourProvider.Foreground1
}
}
}
}
}
}
},
new FillFlowContainer
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(15),
Children = new[]
{
CreateRightContent().With(c =>
{
c.Anchor = Anchor.CentreRight;
c.Origin = Anchor.CentreRight;
}),
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(2),
Children = Score.Mods.Select(mod => new ModIcon(mod)
{
Scale = new Vector2(0.35f)
}).ToList(),
}
}
}
}
},
new Container
{
RelativeSizeAxes = Axes.Y,
Width = performance_width,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Children = new[]
{
new Box
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
RelativeSizeAxes = Axes.Y,
Width = performance_background_width,
Height = 0.5f,
Colour = colourProvider.Background4,
Shear = new Vector2(-performance_background_shear, 0),
EdgeSmoothness = new Vector2(2, 0),
},
new Box
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
RelativeSizeAxes = Axes.Y,
RelativePositionAxes = Axes.Y,
Width = performance_background_width,
Height = -0.5f,
Position = new Vector2(0, 1),
Colour = colourProvider.Background4,
Shear = new Vector2(performance_background_shear, 0),
EdgeSmoothness = new Vector2(2, 0),
},
createDrawablePerformance().With(d =>
{
d.Anchor = Anchor.Centre;
d.Origin = Anchor.Centre;
})
}
}
}
};
});
}
[BackgroundDependencyLoader(true)]
private void load(OsuColour colour)
[NotNull]
protected virtual Drawable CreateRightContent() => CreateDrawableAccuracy();
protected OsuSpriteText CreateDrawableAccuracy() => new OsuSpriteText
{
var text = new OsuSpriteText
{
Text = $"accuracy: {Score.Accuracy:P2}",
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Colour = colour.GrayA,
Font = OsuFont.GetFont(size: 11, weight: FontWeight.Regular, italics: true)
};
RightFlowContainer.Insert(1, text);
LeftFlowContainer.Add(new ProfileScoreBeatmapMetadataContainer(Score.Beatmap));
LeftFlowContainer.Add(new DrawableDate(Score.Date));
foreach (Mod mod in Score.Mods)
modsContainer.Add(new ModIcon(mod) { Scale = new Vector2(0.5f) });
}
protected override Drawable CreateLeftVisual() => new UpdateableRank(Score.Rank)
{
RelativeSizeAxes = Axes.Y,
Width = 60,
FillMode = FillMode.Fit,
Text = Score.DisplayAccuracy,
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
Colour = colours.Yellow,
};
private class ProfileScoreBeatmapMetadataContainer : BeatmapMetadataContainer
private Drawable createDrawablePerformance()
{
public ProfileScoreBeatmapMetadataContainer(BeatmapInfo beatmap)
if (Score.PP.HasValue)
{
return new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Children = new[]
{
new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Font = OsuFont.GetFont(weight: FontWeight.Bold),
Text = $"{Score.PP:0}",
Colour = colourProvider.Highlight1
},
new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
Text = "pp",
Colour = colourProvider.Light3
}
}
};
}
return new OsuSpriteText
{
Font = OsuFont.GetFont(weight: FontWeight.Bold),
Text = "-",
Colour = colourProvider.Highlight1
};
}
private class ScoreBeatmapMetadataContainer : BeatmapMetadataContainer
{
public ScoreBeatmapMetadataContainer(BeatmapInfo beatmap)
: base(beatmap)
{
}
@ -79,16 +236,19 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
{
new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Text = new LocalisedString((
$"{beatmap.Metadata.TitleUnicode ?? beatmap.Metadata.Title} [{beatmap.Version}] ",
$"{beatmap.Metadata.Title ?? beatmap.Metadata.TitleUnicode} [{beatmap.Version}] ")),
Font = OsuFont.GetFont(size: 15, weight: FontWeight.SemiBold, italics: true)
$"{beatmap.Metadata.TitleUnicode ?? beatmap.Metadata.Title} ",
$"{beatmap.Metadata.Title ?? beatmap.Metadata.TitleUnicode} ")),
Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold, italics: true)
},
new OsuSpriteText
{
Text = new LocalisedString((beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist)),
Padding = new MarginPadding { Top = 3 },
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Regular, italics: true)
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Text = "by " + new LocalisedString((beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist)),
Font = OsuFont.GetFont(size: 12, italics: true)
},
};
}

View File

@ -0,0 +1,55 @@
// 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.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Scoring;
namespace osu.Game.Overlays.Profile.Sections.Ranks
{
public class DrawableProfileWeightedScore : DrawableProfileScore
{
private readonly double weight;
public DrawableProfileWeightedScore(ScoreInfo score, double weight)
: base(score)
{
this.weight = weight;
}
protected override Drawable CreateRightContent() => new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
new Container
{
AutoSizeAxes = Axes.Y,
Width = 60,
Child = CreateDrawableAccuracy()
},
new OsuSpriteText
{
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
Text = $"{Score.PP * weight:0}pp",
},
}
},
new OsuSpriteText
{
Font = OsuFont.GetFont(size: 12),
Text = $@"weighted {weight:0%}"
}
}
};
}
}

View File

@ -1,31 +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.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Scoring;
namespace osu.Game.Overlays.Profile.Sections.Ranks
{
public class DrawableTotalScore : DrawableProfileScore
{
public DrawableTotalScore(ScoreInfo score)
: base(score)
{
}
[BackgroundDependencyLoader]
private void load()
{
RightFlowContainer.Add(new OsuSpriteText
{
Text = Score.TotalScore.ToString("#,###"),
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Font = OsuFont.GetFont(size: 18, weight: FontWeight.Bold, italics: true)
});
}
}
}

View File

@ -15,14 +15,12 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
{
public class PaginatedScoreContainer : PaginatedContainer<APILegacyScoreInfo>
{
private readonly bool includeWeight;
private readonly ScoreType type;
public PaginatedScoreContainer(ScoreType type, Bindable<User> user, string header, string missing, bool includeWeight = false)
public PaginatedScoreContainer(ScoreType type, Bindable<User> user, string header, string missing)
: base(user, header, missing)
{
this.type = type;
this.includeWeight = includeWeight;
ItemsPerPage = 5;
@ -43,10 +41,10 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
switch (type)
{
default:
return new DrawablePerformanceScore(model.CreateScoreInfo(Rulesets), includeWeight ? Math.Pow(0.95, ItemsContainer.Count) : (double?)null);
return new DrawableProfileScore(model.CreateScoreInfo(Rulesets));
case ScoreType.Recent:
return new DrawableTotalScore(model.CreateScoreInfo(Rulesets));
case ScoreType.Best:
return new DrawableProfileWeightedScore(model.CreateScoreInfo(Rulesets), Math.Pow(0.95, ItemsContainer.Count));
}
}
}

View File

@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Profile.Sections
{
Children = new[]
{
new PaginatedScoreContainer(ScoreType.Best, User, "Best Performance", "No performance records. :(", true),
new PaginatedScoreContainer(ScoreType.Best, User, "Best Performance", "No performance records. :("),
new PaginatedScoreContainer(ScoreType.Firsts, User, "First Place Ranks", "No awesome performance records yet. :("),
};
}

View File

@ -1,9 +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.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
@ -11,12 +13,19 @@ using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat;
using osu.Game.Online.Leaderboards;
using osu.Game.Rulesets;
namespace osu.Game.Overlays.Profile.Sections.Recent
{
public class DrawableRecentActivity : DrawableProfileRow
public class DrawableRecentActivity : CompositeDrawable
{
private IAPIProvider api;
private const int font_size = 14;
[Resolved]
private IAPIProvider api { get; set; }
[Resolved]
private RulesetStore rulesets { get; set; }
private readonly APIRecentActivity activity;
@ -28,139 +37,191 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
}
[BackgroundDependencyLoader]
private void load(IAPIProvider api)
private void load(OverlayColourProvider colourProvider)
{
this.api = api;
LeftFlowContainer.Padding = new MarginPadding { Left = 10, Right = 160 };
LeftFlowContainer.Add(content = new LinkFlowContainer
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
AddInternal(new GridContainer
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
ColumnDimensions = new[]
{
new Dimension(GridSizeMode.Absolute, size: 28),
new Dimension(),
new Dimension(GridSizeMode.AutoSize)
},
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize)
},
Content = new[]
{
new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = createIcon().With(icon =>
{
icon.Anchor = Anchor.Centre;
icon.Origin = Anchor.Centre;
})
},
content = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: font_size))
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
},
new DrawableDate(activity.CreatedAt)
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Colour = colourProvider.Foreground1,
Font = OsuFont.GetFont(size: font_size),
}
}
}
});
RightFlowContainer.Add(new DrawableDate(activity.CreatedAt)
{
Font = OsuFont.GetFont(size: 13),
Colour = OsuColour.Gray(0xAA),
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
});
var formatted = createMessage();
content.AddLinks(formatted.Text, formatted.Links);
createMessage();
}
protected override Drawable CreateLeftVisual()
private Drawable createIcon()
{
switch (activity.Type)
{
case RecentActivityType.Rank:
return new UpdateableRank(activity.ScoreRank)
{
RelativeSizeAxes = Axes.Y,
Width = 60,
RelativeSizeAxes = Axes.X,
Height = 11,
FillMode = FillMode.Fit,
Margin = new MarginPadding { Top = 2 }
};
case RecentActivityType.Achievement:
return new DelayedLoadWrapper(new MedalIcon(activity.Achievement.Slug)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit,
})
{
RelativeSizeAxes = Axes.Y,
Width = 60,
RelativeSizeAxes = Axes.X,
Width = 0.5f,
Height = 18
};
default:
return new Container
{
RelativeSizeAxes = Axes.Y,
Width = 60,
FillMode = FillMode.Fit,
};
return Empty();
}
}
private string toAbsoluteUrl(string url) => $"{api.Endpoint}{url}";
private MessageFormatter.MessageFormatterResult createMessage()
private void createMessage()
{
string userLinkTemplate() => $"[{toAbsoluteUrl(activity.User?.Url)} {activity.User?.Username}]";
string beatmapLinkTemplate() => $"[{toAbsoluteUrl(activity.Beatmap?.Url)} {activity.Beatmap?.Title}]";
string beatmapsetLinkTemplate() => $"[{toAbsoluteUrl(activity.Beatmapset?.Url)} {activity.Beatmapset?.Title}]";
string message;
switch (activity.Type)
{
case RecentActivityType.Achievement:
message = $"{userLinkTemplate()} unlocked the {activity.Achievement.Name} medal!";
addUserLink();
addText($" unlocked the \"{activity.Achievement.Name}\" medal!");
break;
case RecentActivityType.BeatmapPlaycount:
message = $"{beatmapLinkTemplate()} has been played {activity.Count} times!";
addBeatmapLink();
addText($" has been played {activity.Count} times!");
break;
case RecentActivityType.BeatmapsetApprove:
message = $"{beatmapsetLinkTemplate()} has been {activity.Approval.ToString().ToLowerInvariant()}!";
addBeatmapsetLink();
addText($" has been {activity.Approval.ToString().ToLowerInvariant()}!");
break;
case RecentActivityType.BeatmapsetDelete:
message = $"{beatmapsetLinkTemplate()} has been deleted.";
addBeatmapsetLink();
addText(" has been deleted.");
break;
case RecentActivityType.BeatmapsetRevive:
message = $"{beatmapsetLinkTemplate()} has been revived from eternal slumber by {userLinkTemplate()}.";
addBeatmapsetLink();
addText(" has been revived from eternal slumber by ");
addUserLink();
break;
case RecentActivityType.BeatmapsetUpdate:
message = $"{userLinkTemplate()} has updated the beatmap {beatmapsetLinkTemplate()}!";
addUserLink();
addText(" has updated the beatmap ");
addBeatmapsetLink();
break;
case RecentActivityType.BeatmapsetUpload:
message = $"{userLinkTemplate()} has submitted a new beatmap {beatmapsetLinkTemplate()}!";
addUserLink();
addText(" has submitted a new beatmap ");
addBeatmapsetLink();
break;
case RecentActivityType.Medal:
// apparently this shouldn't exist look at achievement instead (https://github.com/ppy/osu-web/blob/master/resources/assets/coffee/react/profile-page/recent-activity.coffee#L111)
message = string.Empty;
break;
case RecentActivityType.Rank:
message = $"{userLinkTemplate()} achieved rank #{activity.Rank} on {beatmapLinkTemplate()} ({activity.Mode}!)";
addUserLink();
addText($" achieved rank #{activity.Rank} on ");
addBeatmapLink();
addText($" ({getRulesetName()})");
break;
case RecentActivityType.RankLost:
message = $"{userLinkTemplate()} has lost first place on {beatmapLinkTemplate()} ({activity.Mode}!)";
addUserLink();
addText(" has lost first place on ");
addBeatmapLink();
addText($" ({getRulesetName()})");
break;
case RecentActivityType.UserSupportAgain:
message = $"{userLinkTemplate()} has once again chosen to support osu! - thanks for your generosity!";
addUserLink();
addText(" has once again chosen to support osu! - thanks for your generosity!");
break;
case RecentActivityType.UserSupportFirst:
message = $"{userLinkTemplate()} has become an osu!supporter - thanks for your generosity!";
addUserLink();
addText(" has become an osu!supporter - thanks for your generosity!");
break;
case RecentActivityType.UserSupportGift:
message = $"{userLinkTemplate()} has received the gift of osu!supporter!";
addUserLink();
addText(" has received the gift of osu!supporter!");
break;
case RecentActivityType.UsernameChange:
message = $"{activity.User?.PreviousUsername} has changed their username to {userLinkTemplate()}!";
break;
default:
message = string.Empty;
addText($"{activity.User?.PreviousUsername} has changed their username to ");
addUserLink();
break;
}
return MessageFormatter.FormatText(message);
}
private string getRulesetName() =>
rulesets.AvailableRulesets.FirstOrDefault(r => r.ShortName == activity.Mode)?.Name ?? activity.Mode;
private void addUserLink()
=> content.AddLink(activity.User?.Username, LinkAction.OpenUserProfile, getLinkArgument(activity.User?.Url), creationParameters: t => t.Font = getLinkFont(FontWeight.Bold));
private void addBeatmapLink()
=> content.AddLink(activity.Beatmap?.Title, LinkAction.OpenBeatmap, getLinkArgument(activity.Beatmap?.Url), creationParameters: t => t.Font = getLinkFont());
private void addBeatmapsetLink()
=> content.AddLink(activity.Beatmapset?.Title, LinkAction.OpenBeatmapSet, getLinkArgument(activity.Beatmapset?.Url), creationParameters: t => t.Font = getLinkFont());
private string getLinkArgument(string url) => MessageFormatter.GetLinkDetails($"{api.Endpoint}{url}").Argument;
private FontUsage getLinkFont(FontWeight fontWeight = FontWeight.Regular)
=> OsuFont.GetFont(size: font_size, weight: fontWeight, italics: true);
private void addText(string text)
=> content.AddText(text, t => t.Font = OsuFont.GetFont(size: font_size, weight: FontWeight.SemiBold));
}
}

View File

@ -23,8 +23,7 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
Child = sprite = new Sprite
{
Height = 40,
Width = 40,
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
};

View File

@ -8,6 +8,7 @@ using osu.Framework.Bindables;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.API;
using System.Collections.Generic;
using osuTK;
namespace osu.Game.Overlays.Profile.Sections.Recent
{
@ -16,7 +17,8 @@ namespace osu.Game.Overlays.Profile.Sections.Recent
public PaginatedRecentActivityContainer(Bindable<User> user, string header, string missing)
: base(user, header, missing)
{
ItemsPerPage = 5;
ItemsPerPage = 10;
ItemsContainer.Spacing = new Vector2(0, 8);
}
protected override APIRequest<List<APIRecentActivity>> CreateRequest() =>

View File

@ -0,0 +1,161 @@
// 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.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests.Responses;
using osuTK;
using System;
using System.Collections.Generic;
using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Overlays.Rankings
{
public class SpotlightSelector : CompositeDrawable, IHasCurrentValue<APISpotlight>
{
private readonly Box background;
private readonly SpotlightsDropdown dropdown;
private readonly BindableWithCurrent<APISpotlight> current = new BindableWithCurrent<APISpotlight>();
public Bindable<APISpotlight> Current
{
get => current.Current;
set => current.Current = value;
}
public IEnumerable<APISpotlight> Spotlights
{
get => dropdown.Items;
set => dropdown.Items = value;
}
private readonly InfoColumn startDateColumn;
private readonly InfoColumn endDateColumn;
public SpotlightSelector()
{
RelativeSizeAxes = Axes.X;
Height = 100;
InternalChildren = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 },
Children = new Drawable[]
{
dropdown = new SpotlightsDropdown
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
Current = Current,
Depth = -float.MaxValue
},
new FillFlowContainer
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(15, 0),
Children = new Drawable[]
{
startDateColumn = new InfoColumn(@"Start Date"),
endDateColumn = new InfoColumn(@"End Date"),
}
}
}
},
};
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
background.Colour = colourProvider.Dark3;
}
protected override void LoadComplete()
{
base.LoadComplete();
Current.BindValueChanged(onCurrentChanged);
}
private void onCurrentChanged(ValueChangedEvent<APISpotlight> spotlight)
{
startDateColumn.Value = dateToString(spotlight.NewValue.StartDate);
endDateColumn.Value = dateToString(spotlight.NewValue.EndDate);
}
private string dateToString(DateTimeOffset date) => date.ToString("yyyy-MM-dd");
private class InfoColumn : FillFlowContainer
{
public string Value
{
set => valueText.Text = value;
}
private readonly OsuSpriteText valueText;
public InfoColumn(string name)
{
AutoSizeAxes = Axes.Both;
Direction = FillDirection.Vertical;
Children = new Drawable[]
{
new OsuSpriteText
{
Text = name,
Font = OsuFont.GetFont(size: 10),
},
new Container
{
AutoSizeAxes = Axes.X,
Height = 20,
Child = valueText = new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Font = OsuFont.GetFont(size: 18, weight: FontWeight.Light),
}
}
};
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
valueText.Colour = colourProvider.Content2;
}
}
private class SpotlightsDropdown : OsuDropdown<APISpotlight>
{
private DropdownMenu menu;
protected override DropdownMenu CreateMenu() => menu = base.CreateMenu().With(m => m.MaxHeight = 400);
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
menu.BackgroundColour = colourProvider.Background5;
AccentColour = colourProvider.Background6;
}
}
}
}

View File

@ -40,7 +40,7 @@ namespace osu.Game.Overlays.Rankings.Tables
protected sealed override Drawable[] CreateAdditionalContent(UserStatistics item) => new[]
{
new ColoredRowText { Text = $@"{item.Accuracy:F2}%", },
new ColoredRowText { Text = item.DisplayAccuracy, },
new ColoredRowText { Text = $@"{item.PlayCount:N0}", },
}.Concat(CreateUniqueContent(item)).Concat(new[]
{

View File

@ -17,10 +17,34 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
{
Children = new Drawable[]
{
new SettingsSlider<double> { LabelText = "Master", Bindable = audio.Volume, KeyboardStep = 0.01f },
new SettingsSlider<double> { LabelText = "Master (window inactive)", Bindable = config.GetBindable<double>(OsuSetting.VolumeInactive), KeyboardStep = 0.01f },
new SettingsSlider<double> { LabelText = "Effect", Bindable = audio.VolumeSample, KeyboardStep = 0.01f },
new SettingsSlider<double> { LabelText = "Music", Bindable = audio.VolumeTrack, KeyboardStep = 0.01f },
new SettingsSlider<double>
{
LabelText = "Master",
Bindable = audio.Volume,
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
new SettingsSlider<double>
{
LabelText = "Master (window inactive)",
Bindable = config.GetBindable<double>(OsuSetting.VolumeInactive),
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
new SettingsSlider<double>
{
LabelText = "Effect",
Bindable = audio.VolumeSample,
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
new SettingsSlider<double>
{
LabelText = "Music",
Bindable = audio.VolumeTrack,
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
};
}
}

View File

@ -21,13 +21,15 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
{
LabelText = "Background dim",
Bindable = config.GetBindable<double>(OsuSetting.DimLevel),
KeyboardStep = 0.01f
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
new SettingsSlider<double>
{
LabelText = "Background blur",
Bindable = config.GetBindable<double>(OsuSetting.BlurLevel),
KeyboardStep = 0.01f
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
new SettingsCheckbox
{

View File

@ -98,25 +98,29 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
{
LabelText = "Horizontal position",
Bindable = scalingPositionX,
KeyboardStep = 0.01f
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
new SettingsSlider<float>
{
LabelText = "Vertical position",
Bindable = scalingPositionY,
KeyboardStep = 0.01f
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
new SettingsSlider<float>
{
LabelText = "Horizontal scale",
Bindable = scalingSizeX,
KeyboardStep = 0.01f
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
new SettingsSlider<float>
{
LabelText = "Vertical scale",
Bindable = scalingSizeY,
KeyboardStep = 0.01f
KeyboardStep = 0.01f,
DisplayAsPercentage = true
},
}
},

View File

@ -3,6 +3,7 @@
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.Settings
@ -22,16 +23,32 @@ namespace osu.Game.Overlays.Settings
RelativeSizeAxes = Axes.X
};
/// <summary>
/// When set, value changes based on user input are only transferred to any bound control's Current on commit.
/// This is useful if the UI interaction could be adversely affected by the value changing, such as the position of the <see cref="SliderBar{T}"/> on the screen.
/// </summary>
public bool TransferValueOnCommit
{
get => ((TSlider)Control).TransferValueOnCommit;
set => ((TSlider)Control).TransferValueOnCommit = value;
}
/// <summary>
/// A custom step value for each key press which actuates a change on this control.
/// </summary>
public float KeyboardStep
{
get => ((TSlider)Control).KeyboardStep;
set => ((TSlider)Control).KeyboardStep = value;
}
/// <summary>
/// Whether to format the tooltip as a percentage or the actual value.
/// </summary>
public bool DisplayAsPercentage
{
get => ((TSlider)Control).DisplayAsPercentage;
set => ((TSlider)Control).DisplayAsPercentage = value;
}
}
}

View File

@ -3,6 +3,7 @@
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@ -17,10 +18,18 @@ namespace osu.Game.Overlays
/// An overlay header which contains a <see cref="OsuTabControl{T}"/>.
/// </summary>
/// <typeparam name="T">The type of item to be represented by tabs.</typeparam>
public abstract class TabControlOverlayHeader<T> : OverlayHeader
public abstract class TabControlOverlayHeader<T> : OverlayHeader, IHasCurrentValue<T>
{
protected OsuTabControl<T> TabControl;
private readonly BindableWithCurrent<T> current = new BindableWithCurrent<T>();
public Bindable<T> Current
{
get => current.Current;
set => current.Current = value;
}
private readonly Box controlBackground;
protected TabControlOverlayHeader()
@ -35,7 +44,11 @@ namespace osu.Game.Overlays
{
RelativeSizeAxes = Axes.Both,
},
TabControl = CreateTabControl().With(control => control.Margin = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN })
TabControl = CreateTabControl().With(control =>
{
control.Margin = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN };
control.Current = current;
})
}
});
}

View File

@ -99,7 +99,7 @@ namespace osu.Game.Overlays.Toolbar
{
int requested = e.Key - Key.Number1;
RulesetInfo found = Rulesets.AvailableRulesets.Skip(requested).FirstOrDefault();
RulesetInfo found = Rulesets.AvailableRulesets.ElementAtOrDefault(requested);
if (found != null)
Current.Value = found;
return true;

View File

@ -8,7 +8,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Profile;
@ -30,7 +29,7 @@ namespace osu.Game.Overlays
public const float CONTENT_X_MARGIN = 70;
public UserProfileOverlay()
: base(OverlayColourScheme.Green)
: base(OverlayColourScheme.Pink)
{
}
@ -68,13 +67,13 @@ namespace osu.Game.Overlays
RelativeSizeAxes = Axes.X,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Height = 30
Height = 34
};
Add(new Box
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(0.1f)
Colour = ColourProvider.Background6
});
Add(sectionsContainer = new ProfileSectionsContainer
@ -83,7 +82,8 @@ namespace osu.Game.Overlays
FixedHeader = tabs,
HeaderBackground = new Box
{
Colour = OsuColour.Gray(34),
// this is only visible as the ProfileTabControl background
Colour = ColourProvider.Background5,
RelativeSizeAxes = Axes.Both
},
});
@ -165,9 +165,9 @@ namespace osu.Game.Overlays
};
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OverlayColourProvider colourProvider)
{
AccentColour = colours.Seafoam;
AccentColour = colourProvider.Highlight1;
}
private class ProfileTabItem : OverlayTabItem