From 64f62bd2bfbccd702bb39039bc77166eb16a1b0b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 10 Oct 2019 12:06:25 +0300 Subject: [PATCH] Implement CommentsHeader component --- .../Visual/Online/TestSceneCommentsHeader.cs | 39 +++++ osu.Game/Overlays/Comments/CommentsHeader.cs | 137 ++++++++++++++++++ osu.Game/Overlays/Comments/HeaderButton.cs | 72 +++++++++ osu.Game/Overlays/Comments/SortSelector.cs | 106 ++++++++++++++ osu.Game/osu.Game.csproj | 3 + 5 files changed, 357 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs create mode 100644 osu.Game/Overlays/Comments/CommentsHeader.cs create mode 100644 osu.Game/Overlays/Comments/HeaderButton.cs create mode 100644 osu.Game/Overlays/Comments/SortSelector.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs new file mode 100644 index 0000000000..52318605d9 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs @@ -0,0 +1,39 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.Bindables; +using osu.Game.Overlays.Comments; + +namespace osu.Game.Tests.Visual.Online +{ + [TestFixture] + public class TestSceneCommentsHeader : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(CommentsHeader), + typeof(HeaderButton), + typeof(SortSelector), + }; + + private readonly Bindable sort = new Bindable(); + private readonly BindableBool showDeleted = new BindableBool(); + + public TestSceneCommentsHeader() + { + Add(new CommentsHeader + { + Sort = { BindTarget = sort }, + ShowDeleted = { BindTarget = showDeleted } + }); + + AddStep("Trigger ShowDeleted", () => showDeleted.Value = !showDeleted.Value); + AddStep("Select old", () => sort.Value = SortCommentsBy.Old); + AddStep("Select new", () => sort.Value = SortCommentsBy.New); + AddStep("Select top", () => sort.Value = SortCommentsBy.Top); + } + } +} diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs new file mode 100644 index 0000000000..c21ec90048 --- /dev/null +++ b/osu.Game/Overlays/Comments/CommentsHeader.cs @@ -0,0 +1,137 @@ +// Copyright (c) ppy Pty Ltd . 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.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Framework.Graphics.Sprites; +using osuTK; +using osu.Framework.Input.Events; + +namespace osu.Game.Overlays.Comments +{ + public class CommentsHeader : CompositeDrawable + { + private const int height = 40; + private const int spacing = 10; + private const int padding = 50; + private const int text_size = 14; + + public readonly Bindable Sort = new Bindable(); + public readonly BindableBool ShowDeleted = new BindableBool(); + + private readonly Box background; + + public CommentsHeader() + { + RelativeSizeAxes = Axes.X; + Height = height; + AddRangeInternal(new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = padding }, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(spacing, 0), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Children = new Drawable[] + { + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: text_size), + Text = @"Sort by" + }, + new SortSelector + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Current = Sort + } + } + }, + new ShowDeletedButton + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Checked = { BindTarget = ShowDeleted } + } + } + } + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray3; + } + + private class ShowDeletedButton : HeaderButton + { + private const int spacing = 5; + + public readonly BindableBool Checked = new BindableBool(); + + private readonly SpriteIcon checkboxIcon; + + public ShowDeletedButton() + { + Add(new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(spacing, 0), + Children = new Drawable[] + { + checkboxIcon = new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(10), + }, + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: text_size), + Text = @"Show deleted" + } + }, + }); + } + + protected override void LoadComplete() + { + Checked.BindValueChanged(onCheckedChanged, true); + base.LoadComplete(); + } + + private void onCheckedChanged(ValueChangedEvent isChecked) + { + checkboxIcon.Icon = isChecked.NewValue ? FontAwesome.Solid.CheckSquare : FontAwesome.Regular.Square; + } + + protected override bool OnClick(ClickEvent e) + { + Checked.Value = !Checked.Value; + return base.OnClick(e); + } + } + } +} diff --git a/osu.Game/Overlays/Comments/HeaderButton.cs b/osu.Game/Overlays/Comments/HeaderButton.cs new file mode 100644 index 0000000000..231a364759 --- /dev/null +++ b/osu.Game/Overlays/Comments/HeaderButton.cs @@ -0,0 +1,72 @@ +// Copyright (c) ppy Pty Ltd . 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.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Framework.Input.Events; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.Comments +{ + public class HeaderButton : Container + { + private const int height = 20; + private const int corner_radius = 3; + private const int margin = 10; + private const int duration = 200; + + protected override Container Content => content; + + private readonly Box background; + private readonly Container content; + + public HeaderButton() + { + AutoSizeAxes = Axes.X; + Height = height; + Masking = true; + CornerRadius = corner_radius; + AddRangeInternal(new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + }, + content = new Container + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Horizontal = margin } + }, + new HoverClickSounds(), + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray4; + } + + protected override bool OnHover(HoverEvent e) + { + FadeInBackground(); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + base.OnHoverLost(e); + FadeOutBackground(); + } + + protected void FadeInBackground() => background.FadeIn(duration, Easing.OutQuint); + + protected void FadeOutBackground() => background.FadeOut(duration, Easing.OutQuint); + } +} diff --git a/osu.Game/Overlays/Comments/SortSelector.cs b/osu.Game/Overlays/Comments/SortSelector.cs new file mode 100644 index 0000000000..b4e29477d7 --- /dev/null +++ b/osu.Game/Overlays/Comments/SortSelector.cs @@ -0,0 +1,106 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osuTK; +using osu.Game.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Framework.Bindables; +using osu.Framework.Allocation; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Comments +{ + public class SortSelector : OsuTabControl + { + private const int spacing = 5; + + protected override Dropdown CreateDropdown() => null; + + protected override TabItem CreateTabItem(SortCommentsBy value) => new SortTabItem(value); + + protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(spacing, 0), + }; + + public SortSelector() + { + AutoSizeAxes = Axes.Both; + } + + private class SortTabItem : TabItem + { + private readonly TabContent content; + + public SortTabItem(SortCommentsBy value) + : base(value) + { + AutoSizeAxes = Axes.Both; + Child = content = new TabContent(value) + { + Active = { BindTarget = Active } + }; + } + + protected override void OnActivated() => content.Activate(); + + protected override void OnDeactivated() => content.Deactivate(); + + private class TabContent : HeaderButton + { + private const int text_size = 14; + + public readonly BindableBool Active = new BindableBool(); + + [Resolved] + private OsuColour colours { get; set; } + + private readonly SpriteText text; + + public TabContent(SortCommentsBy value) + { + Add(text = new SpriteText + { + Font = OsuFont.GetFont(size: text_size), + Text = value.ToString() + }); + } + + public void Activate() + { + FadeInBackground(); + text.Font = text.Font.With(weight: FontWeight.Bold); + text.Colour = colours.BlueLighter; + } + + public void Deactivate() + { + if (!IsHovered) + FadeOutBackground(); + + text.Font = text.Font.With(weight: FontWeight.Medium); + text.Colour = Color4.White; + } + + protected override void OnHoverLost(HoverLostEvent e) + { + if (!Active.Value) base.OnHoverLost(e); + } + } + } + } + + public enum SortCommentsBy + { + New, + Old, + Top + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8cbc8b0af3..28d5dd796c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -32,4 +32,7 @@ + + +