1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 08:07:24 +08:00

Tables implementation

This commit is contained in:
Andrei Zavatski 2019-09-27 19:33:52 +03:00
parent 2a395956aa
commit bbaf21a69d
6 changed files with 630 additions and 0 deletions

View File

@ -0,0 +1,148 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using osu.Framework.Graphics.Containers;
using osu.Game.Overlays.Rankings.Tables;
using osu.Framework.Graphics;
using osu.Game.Online.API.Requests;
using osu.Game.Rulesets;
using osu.Game.Graphics.UserInterface;
using System.Threading;
using osu.Game.Online.API;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Taiko;
using osu.Game.Rulesets.Catch;
using osu.Framework.Allocation;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneRankingsTables : OsuTestScene
{
protected override bool UseOnlineAPI => true;
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(PerformanceTable),
typeof(ScoresTable),
typeof(CountriesTable),
typeof(TableRowBackground),
};
[Resolved]
private IAPIProvider api { get; set; }
private readonly BasicScrollContainer scrollFlow;
private readonly DimmedLoadingLayer loading;
private CancellationTokenSource cancellationToken;
private APIRequest request;
public TestSceneRankingsTables()
{
Children = new Drawable[]
{
scrollFlow = new BasicScrollContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Width = 0.8f,
},
loading = new DimmedLoadingLayer(),
};
}
protected override void LoadComplete()
{
base.LoadComplete();
AddStep("Osu performance", () => createPerformanceTable(new OsuRuleset().RulesetInfo, null));
AddStep("Mania scores", () => createScoreTable(new ManiaRuleset().RulesetInfo));
AddStep("Taiko country scores", () => createCountryTable(new TaikoRuleset().RulesetInfo));
AddStep("Catch US performance page 10", () => createPerformanceTable(new CatchRuleset().RulesetInfo, "US", 10));
}
private void createCountryTable(RulesetInfo ruleset, int page = 1)
{
loading.Show();
request?.Cancel();
cancellationToken?.Cancel();
cancellationToken = new CancellationTokenSource();
request = new GetCountryRankingsRequest(ruleset, page);
((GetCountryRankingsRequest)request).Success += rankings => Schedule(() =>
{
var table = new CountriesTable(page)
{
Rankings = rankings,
};
LoadComponentAsync(table, t =>
{
scrollFlow.Clear();
scrollFlow.Add(t);
loading.Hide();
}, cancellationToken.Token);
});
api.Queue(request);
}
private void createPerformanceTable(RulesetInfo ruleset, string country, int page = 1)
{
loading.Show();
request?.Cancel();
cancellationToken?.Cancel();
cancellationToken = new CancellationTokenSource();
request = new GetUserRankingsRequest(ruleset, country: country, page: page);
((GetUserRankingsRequest)request).Success += rankings => Schedule(() =>
{
var table = new PerformanceTable(page)
{
Rankings = rankings,
};
LoadComponentAsync(table, t =>
{
scrollFlow.Clear();
scrollFlow.Add(t);
loading.Hide();
}, cancellationToken.Token);
});
api.Queue(request);
}
private void createScoreTable(RulesetInfo ruleset, int page = 1)
{
loading.Show();
request?.Cancel();
cancellationToken?.Cancel();
cancellationToken = new CancellationTokenSource();
request = new GetUserRankingsRequest(ruleset, UserRankingsType.Score, page);
((GetUserRankingsRequest)request).Success += rankings => Schedule(() =>
{
var table = new ScoresTable(page)
{
Rankings = rankings,
};
LoadComponentAsync(table, t =>
{
scrollFlow.Clear();
scrollFlow.Add(t);
loading.Hide();
}, cancellationToken.Token);
});
api.Queue(request);
}
}
}

View File

@ -0,0 +1,88 @@
// 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.Users.Drawables;
using osuTK;
using osu.Game.Online.API.Requests.Responses;
using System;
namespace osu.Game.Overlays.Rankings.Tables
{
public class CountriesTable : RankingsTable<APICountryRankings>
{
public CountriesTable(int page = 1)
: base(page)
{
}
protected override TableColumn[] CreateHeaders() => new[]
{
new TableColumn("", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 50)), // place
new TableColumn("", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed)), // flag and country name
new TableColumn("Active Users", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 100)),
new TableColumn("Play Count", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 100)),
new TableColumn("Ranked Score", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 100)),
new TableColumn("Avg. Score", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 100)),
new TableColumn("Performance", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 80)),
new TableColumn("Avg. Perf.", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 50)),
};
protected override Drawable[] CreateContent(int index, APICountryRankings item) => new Drawable[]
{
new OsuSpriteText
{
Text = $"#{index + 1}",
Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.Bold)
},
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(7, 0),
Children = new Drawable[]
{
new UpdateableFlag(item.Country)
{
Size = new Vector2(20, 13),
ShowPlaceholderOnNull = false,
},
new OsuSpriteText
{
Text = $@"{item.Country.FullName}",
Font = OsuFont.GetFont(size: TEXT_SIZE),
}
}
},
new ColoredText
{
Text = $@"{item.ActiveUsers:N0}",
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new ColoredMetricNumber(item.PlayCount)
{
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new ColoredMetricNumber(item.RankedScore)
{
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new ColoredMetricNumber(item.RankedScore / Math.Max(item.ActiveUsers, 1))
{
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new MetricNumber(item.Performance)
{
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new ColoredText
{
Text = $@"{item.Performance / Math.Max(item.ActiveUsers, 1):N0}",
Font = OsuFont.GetFont(size: TEXT_SIZE),
}
};
}
}

View File

@ -0,0 +1,102 @@
// 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 System.Collections.Generic;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Users.Drawables;
using osuTK;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Overlays.Rankings.Tables
{
public class PerformanceTable : RankingsTable<APIUserRankings>
{
public PerformanceTable(int page = 1)
: base(page)
{
}
protected override TableColumn[] CreateHeaders() => new[]
{
new TableColumn("", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 50)), // place
new TableColumn("", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed)), // flag and username
new TableColumn("Accuracy", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 80)),
new TableColumn("Play Count", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 80)),
new TableColumn("Performance", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 80)),
new TableColumn("SS", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 50)),
new TableColumn("S", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 50)),
new TableColumn("A", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 50)),
};
protected override Drawable[] CreateContent(int index, APIUserRankings item)
{
var content = new List<Drawable>
{
new OsuSpriteText
{
Text = $"#{index + 1}",
Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.Bold)
},
};
var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: TEXT_SIZE)) { AutoSizeAxes = Axes.Both };
username.AddUserLink(item.User);
content.Add(new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(7, 0),
Children = new Drawable[]
{
new UpdateableFlag(item.User.Country)
{
Size = new Vector2(20, 13),
ShowPlaceholderOnNull = false,
},
username
}
});
content.AddRange(new Drawable[]
{
new ColoredText
{
Text = $@"{item.Accuracy:F2}%",
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new ColoredText
{
Text = $@"{item.PlayCount:N0}",
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new OsuSpriteText
{
Text = $@"{item.PP:N0}",
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new ColoredText
{
Text = $@"{item.GradesCount.SS + item.GradesCount.SSPlus:N0}",
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new ColoredText
{
Text = $@"{item.GradesCount.S + item.GradesCount.SPlus:N0}",
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new ColoredText
{
Text = $@"{item.GradesCount.A:N0}",
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
});
return content.ToArray();
}
}
}

View File

@ -0,0 +1,128 @@
// 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 System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Cursor;
using osu.Game.Utils;
namespace osu.Game.Overlays.Rankings.Tables
{
public abstract class RankingsTable<TModel> : TableContainer
{
protected const int TEXT_SIZE = 14;
private const float horizontal_inset = 20;
private const float row_height = 25;
private const int items_per_page = 50;
private readonly int page;
private readonly FillFlowContainer backgroundFlow;
public IReadOnlyList<TModel> Rankings
{
set
{
Content = null;
backgroundFlow.Clear();
if (value?.Any() != true)
return;
value.ForEach(_ => backgroundFlow.Add(new TableRowBackground()));
Columns = CreateHeaders();
Content = value.Select((s, i) => CreateContent(page * items_per_page - (items_per_page - i), s)).ToArray().ToRectangular();
}
}
protected RankingsTable(int page)
{
this.page = page;
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Padding = new MarginPadding { Horizontal = horizontal_inset };
RowSize = new Dimension(GridSizeMode.Absolute, row_height);
AddInternal(backgroundFlow = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Depth = 1f,
Margin = new MarginPadding { Top = row_height }
});
}
protected abstract TableColumn[] CreateHeaders();
protected abstract Drawable[] CreateContent(int index, TModel item);
protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? string.Empty, HighlightedColumn());
protected virtual string HighlightedColumn() => @"Performance";
private class HeaderText : OsuSpriteText
{
private readonly string highlighted;
public HeaderText(string text, string highlighted)
{
this.highlighted = highlighted;
Text = text;
Font = OsuFont.GetFont(size: 12);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (Text != highlighted)
Colour = colours.GreySeafoamLighter;
}
}
protected class MetricNumber : OsuSpriteText, IHasTooltip
{
public string TooltipText => $"{value:N0}";
private readonly long value;
public MetricNumber(long value)
{
this.value = value;
Text = HumanizerUtils.ToMetric(value);
}
}
protected class ColoredMetricNumber : MetricNumber
{
public ColoredMetricNumber(long value)
: base(value)
{
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Colour = colours.GreySeafoamLighter;
}
}
protected class ColoredText : OsuSpriteText
{
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Colour = colours.GreySeafoamLighter;
}
}
}
}

View File

@ -0,0 +1,108 @@
// 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.Users.Drawables;
using osuTK;
using osu.Game.Online.API.Requests.Responses;
using System.Collections.Generic;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Rankings.Tables
{
public class ScoresTable : RankingsTable<APIUserRankings>
{
public ScoresTable(int page = 1)
: base(page)
{
}
protected override TableColumn[] CreateHeaders() => new[]
{
new TableColumn("", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 50)), // place
new TableColumn("", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed)), // flag and username
new TableColumn("Accuracy", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 80)),
new TableColumn("Play Count", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 80)),
new TableColumn("Total Score", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 100)),
new TableColumn("Ranked Score", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 100)),
new TableColumn("SS", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 70)),
new TableColumn("S", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 70)),
new TableColumn("A", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 70)),
};
protected override Drawable[] CreateContent(int index, APIUserRankings item)
{
var content = new List<Drawable>
{
new OsuSpriteText
{
Text = $"#{index + 1}",
Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.Bold)
},
};
var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: TEXT_SIZE)) { AutoSizeAxes = Axes.Both };
username.AddUserLink(item.User);
content.Add(new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(7, 0),
Children = new Drawable[]
{
new UpdateableFlag(item.User.Country)
{
Size = new Vector2(20, 13),
ShowPlaceholderOnNull = false,
},
username
}
});
content.AddRange(new Drawable[]
{
new ColoredText
{
Text = $@"{item.Accuracy:F2}%",
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new ColoredText
{
Text = $@"{item.PlayCount:N0}",
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new ColoredMetricNumber(item.TotalScore)
{
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new MetricNumber(item.RankedScore)
{
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new ColoredText
{
Text = $@"{item.GradesCount.SS + item.GradesCount.SSPlus:N0}",
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new ColoredText
{
Text = $@"{item.GradesCount.S + item.GradesCount.SPlus:N0}",
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
new ColoredText
{
Text = $@"{item.GradesCount.A:N0}",
Font = OsuFont.GetFont(size: TEXT_SIZE),
},
});
return content.ToArray();
}
protected override string HighlightedColumn() => @"Ranked Score";
}
}

View File

@ -0,0 +1,56 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osuTK.Graphics;
namespace osu.Game.Overlays.Rankings.Tables
{
public class TableRowBackground : CompositeDrawable
{
private const int fade_duration = 100;
private readonly Box background;
private Color4 idleColour;
private Color4 hoverColour;
public TableRowBackground()
{
RelativeSizeAxes = Axes.X;
Height = 25;
CornerRadius = 3;
Masking = true;
InternalChild = background = new Box
{
RelativeSizeAxes = Axes.Both,
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
background.Colour = idleColour = colours.GreySeafoam;
hoverColour = colours.GreySeafoamLight;
}
protected override bool OnHover(HoverEvent e)
{
background.FadeColour(hoverColour, fade_duration, Easing.OutQuint);
return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e)
{
background.FadeColour(idleColour, fade_duration, Easing.OutQuint);
base.OnHoverLost(e);
}
}
}