diff --git a/osu.Game/Screens/Ranking/UserTagControl.cs b/osu.Game/Screens/Ranking/UserTagControl.cs index da9dfd66d3..e323107783 100644 --- a/osu.Game/Screens/Ranking/UserTagControl.cs +++ b/osu.Game/Screens/Ranking/UserTagControl.cs @@ -5,36 +5,22 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; -using System.Threading; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Caching; using osu.Framework.Extensions; -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Effects; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; -using osu.Framework.Localisation; -using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Extensions; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Graphics.UserInterfaceV2; -using osu.Game.Input.Bindings; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; -using osu.Game.Screens.Ranking.Statistics; using osuTK; namespace osu.Game.Screens.Ranking @@ -286,180 +272,6 @@ namespace osu.Game.Screens.Ranking protected override bool OnClick(ClickEvent e) => true; - private partial class DrawableUserTag : OsuAnimatedButton - { - public readonly UserTag UserTag; - - public Action? OnSelected { get; set; } - - private readonly Bindable voteCount = new Bindable(); - private readonly BindableBool voted = new BindableBool(); - private readonly Bindable confirmed = new BindableBool(); - private readonly BindableBool updating = new BindableBool(); - - protected Box MainBackground { get; private set; } = null!; - private Box voteBackground = null!; - - protected OsuSpriteText TagCategoryText { get; private set; } = null!; - protected OsuSpriteText TagNameText { get; private set; } = null!; - protected VoteCountText VoteCountText { get; private set; } = null!; - - private readonly bool showVoteCount; - - private LoadingLayer loadingLayer = null!; - - [Resolved] - private OsuColour colours { get; set; } = null!; - - public DrawableUserTag(UserTag userTag, bool showVoteCount = true) - { - UserTag = userTag; - this.showVoteCount = showVoteCount; - voteCount.BindTo(userTag.VoteCount); - updating.BindTo(userTag.Updating); - voted.BindTo(userTag.Voted); - - AutoSizeAxes = Axes.Both; - - ScaleOnMouseDown = 0.95f; - } - - [BackgroundDependencyLoader] - private void load() - { - CornerRadius = 5; - Masking = true; - EdgeEffect = new EdgeEffectParameters - { - Colour = colours.Lime1, - Radius = 6, - Type = EdgeEffectType.Glow, - }; - Content.AddRange(new Drawable[] - { - MainBackground = new Box - { - RelativeSizeAxes = Axes.Both, - Depth = float.MaxValue, - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new[] - { - TagCategoryText = new OsuSpriteText - { - Alpha = UserTag.GroupName != null ? 0.6f : 0, - Text = UserTag.GroupName ?? default(LocalisableString), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Margin = new MarginPadding { Horizontal = 6 } - }, - new Container - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0.1f, - Blending = BlendingParameters.Additive, - }, - TagNameText = new OsuSpriteText - { - Text = UserTag.DisplayName, - Font = OsuFont.Default.With(weight: FontWeight.SemiBold), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Margin = new MarginPadding { Horizontal = 6, Vertical = 3, }, - }, - } - }, - showVoteCount - ? new Container - { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Children = new Drawable[] - { - voteBackground = new Box - { - RelativeSizeAxes = Axes.Both, - }, - VoteCountText = new VoteCountText(voteCount) - { - Margin = new MarginPadding { Horizontal = 6 }, - }, - } - } - : Empty(), - } - }, - loadingLayer = new LoadingLayer(dimBackground: true), - }); - - TooltipText = UserTag.Description; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - const double transition_duration = 300; - - updating.BindValueChanged(u => loadingLayer.State.Value = u.NewValue ? Visibility.Visible : Visibility.Hidden); - - if (showVoteCount) - { - voteCount.BindValueChanged(_ => - { - confirmed.Value = voteCount.Value >= 10; - }, true); - voted.BindValueChanged(v => - { - if (v.NewValue) - { - voteBackground.FadeColour(colours.Lime2, transition_duration, Easing.OutQuint); - VoteCountText.FadeColour(Colour4.Black, transition_duration, Easing.OutQuint); - } - else - { - voteBackground.FadeColour(colours.Gray2, transition_duration, Easing.OutQuint); - VoteCountText.FadeColour(Colour4.White, transition_duration, Easing.OutQuint); - } - }, true); - - confirmed.BindValueChanged(c => - { - if (c.NewValue) - { - MainBackground.FadeColour(colours.Lime2, transition_duration, Easing.OutQuint); - TagCategoryText.FadeColour(Colour4.Black, transition_duration, Easing.OutQuint); - TagNameText.FadeColour(Colour4.Black, transition_duration, Easing.OutQuint); - FadeEdgeEffectTo(0.3f, transition_duration, Easing.OutQuint); - } - else - { - MainBackground.FadeColour(colours.Gray6, transition_duration, Easing.OutQuint); - TagCategoryText.FadeColour(Colour4.White, transition_duration, Easing.OutQuint); - TagNameText.FadeColour(Colour4.White, transition_duration, Easing.OutQuint); - FadeEdgeEffectTo(0f, transition_duration, Easing.OutQuint); - } - }, true); - } - - FinishTransforms(true); - - Action = () => OnSelected?.Invoke(UserTag); - } - } - private partial class AddNewTagUserTag : DrawableUserTag, IHasPopover { public BindableDictionary AvailableTags { get; } = new BindableDictionary(); @@ -493,292 +305,5 @@ namespace osu.Game.Screens.Ranking OnSelected = OnTagSelected, }; } - - private partial class AddTagsPopover : OsuPopover - { - private SearchTextBox searchBox = null!; - private SearchContainer searchContainer = null!; - - public BindableDictionary AvailableTags { get; } = new BindableDictionary(); - - public Action? OnSelected { get; set; } - - private CancellationTokenSource? loadCancellationTokenSource; - - [BackgroundDependencyLoader] - private void load() - { - AllowableAnchors = new[] - { - Anchor.TopCentre, - Anchor.BottomCentre, - }; - - Children = new Drawable[] - { - new Container - { - Size = new Vector2(400, 300), - Children = new Drawable[] - { - searchBox = new SearchTextBox - { - HoldFocus = true, - RelativeSizeAxes = Axes.X, - Depth = float.MinValue, - }, - new OsuScrollContainer - { - RelativeSizeAxes = Axes.X, - Y = 40, - Height = 260, - ScrollbarOverlapsContent = false, - Child = searchContainer = new SearchContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Right = 5, Bottom = 10 }, - Direction = FillDirection.Vertical, - Spacing = new Vector2(10), - } - } - }, - }, - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - AvailableTags.BindCollectionChanged((_, _) => - { - loadCancellationTokenSource?.Cancel(); - loadCancellationTokenSource = new CancellationTokenSource(); - - LoadComponentsAsync(createItems(AvailableTags.Values), loaded => - { - searchContainer.Clear(); - searchContainer.AddRange(loaded); - }, loadCancellationTokenSource.Token); - }, true); - searchBox.Current.BindValueChanged(_ => searchContainer.SearchTerm = searchBox.Current.Value, true); - } - - private IEnumerable createItems(IEnumerable tags) - { - var grouped = tags.GroupBy(tag => tag.GroupName).OrderBy(group => group.Key); - - foreach (var group in grouped) - { - var drawableGroup = new GroupFlow(group.Key); - - foreach (var tag in group.OrderBy(t => t.FullName)) - drawableGroup.Add(new DrawableAddableTag(tag) { Action = () => OnSelected?.Invoke(tag) }); - - yield return drawableGroup; - } - } - - public override bool OnPressed(KeyBindingPressEvent e) - { - if (e.Action == GlobalAction.Select && !e.Repeat) - { - attemptSelect(); - return true; - } - - return false; - } - - private void attemptSelect() - { - var visibleItems = searchContainer.ChildrenOfType().Where(d => d.IsPresent).ToArray(); - - if (visibleItems.Length == 1) - OnSelected?.Invoke(visibleItems.Single().Tag); - } - - private partial class GroupFlow : FillFlowContainer, IFilterable - { - public IEnumerable FilterTerms { get; } - - public bool MatchingFilter - { - set => Alpha = value ? 1 : 0; - } - - public bool FilteringActive { set { } } - - public GroupFlow(string? name) - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Direction = FillDirection.Vertical; - Spacing = new Vector2(5); - - Add(new StatisticItemHeader { Text = name ?? "uncategorised" }); - - FilterTerms = name == null ? [] : [name]; - } - } - - private partial class DrawableAddableTag : OsuAnimatedButton, IFilterable - { - public readonly UserTag Tag; - - private Box votedBackground = null!; - private SpriteIcon votedIcon = null!; - - private readonly Bindable voted = new Bindable(); - private readonly BindableBool updating = new BindableBool(); - - private LoadingLayer loadingLayer = null!; - - public DrawableAddableTag(UserTag tag) - { - Tag = tag; - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - - ScaleOnMouseDown = 0.95f; - - voted.BindTo(Tag.Voted); - updating.BindTo(Tag.Updating); - } - - [Resolved] - private OsuColour colours { get; set; } = null!; - - [BackgroundDependencyLoader] - private void load() - { - Content.AddRange(new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Gray7, - Depth = float.MaxValue, - }, - new Container - { - RelativeSizeAxes = Axes.Y, - Width = 30, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Depth = float.MaxValue, - Children = new Drawable[] - { - votedBackground = new Box - { - RelativeSizeAxes = Axes.Both, - }, - votedIcon = new SpriteIcon - { - Size = new Vector2(16), - Icon = FontAwesome.Solid.ThumbsUp, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - } - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(2), - Padding = new MarginPadding(5) { Right = 35 }, - Children = new Drawable[] - { - new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(weight: FontWeight.SemiBold)) - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Text = Tag.DisplayName, - }, - new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(size: 14)) - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Text = Tag.Description, - } - } - }, - loadingLayer = new LoadingLayer(dimBackground: true), - }); - } - - public IEnumerable FilterTerms => [Tag.FullName, Tag.Description]; - - public bool MatchingFilter { set => Alpha = value ? 1 : 0; } - public bool FilteringActive { set { } } - - protected override void LoadComplete() - { - base.LoadComplete(); - - voted.BindValueChanged(_ => - { - votedBackground.FadeColour(voted.Value ? colours.Lime2 : colours.Gray2, 250, Easing.OutQuint); - votedIcon.FadeColour(voted.Value ? Colour4.Black : Colour4.White, 250, Easing.OutQuint); - }, true); - FinishTransforms(true); - - updating.BindValueChanged(u => loadingLayer.State.Value = u.NewValue ? Visibility.Visible : Visibility.Hidden); - } - } - } - - private partial class VoteCountText : CompositeDrawable - { - private OsuSpriteText? text; - - private readonly Bindable voteCount; - - public VoteCountText(Bindable voteCount) - { - RelativeSizeAxes = Axes.Y; - AutoSizeAxes = Axes.X; - - this.voteCount = voteCount.GetBoundCopy(); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - voteCount.BindValueChanged(count => - { - OsuSpriteText? previousText = text; - - AddInternal(text = new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(weight: FontWeight.SemiBold), - Text = voteCount.Value.ToLocalisableString(), - }); - - if (previousText != null) - { - const double transition_duration = 500; - - bool isIncrease = count.NewValue > count.OldValue; - - text.MoveToY(isIncrease ? 20 : -20) - .MoveToY(0, transition_duration, Easing.OutExpo); - - previousText.BypassAutoSizeAxes = Axes.Both; - previousText.MoveToY(isIncrease ? -20 : 20, transition_duration, Easing.OutExpo).Expire(); - - AutoSizeDuration = 300; - AutoSizeEasing = Easing.OutQuint; - } - }, true); - } - } } } diff --git a/osu.Game/Screens/Ranking/UserTagControl_AddTagsPopover.cs b/osu.Game/Screens/Ranking/UserTagControl_AddTagsPopover.cs new file mode 100644 index 0000000000..90fd8c19c2 --- /dev/null +++ b/osu.Game/Screens/Ranking/UserTagControl_AddTagsPopover.cs @@ -0,0 +1,267 @@ +// 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 System.Linq; +using System.Threading; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Framework.Testing; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Input.Bindings; +using osu.Game.Screens.Ranking.Statistics; +using osuTK; + +namespace osu.Game.Screens.Ranking +{ + public partial class UserTagControl + { + private partial class AddTagsPopover : OsuPopover + { + private SearchTextBox searchBox = null!; + private SearchContainer searchContainer = null!; + + public BindableDictionary AvailableTags { get; } = new BindableDictionary(); + + public Action? OnSelected { get; set; } + + private CancellationTokenSource? loadCancellationTokenSource; + + [BackgroundDependencyLoader] + private void load() + { + AllowableAnchors = new[] + { + Anchor.TopCentre, + Anchor.BottomCentre, + }; + + Children = new Drawable[] + { + new Container + { + Size = new Vector2(400, 300), + Children = new Drawable[] + { + searchBox = new SearchTextBox + { + HoldFocus = true, + RelativeSizeAxes = Axes.X, + Depth = float.MinValue, + }, + new OsuScrollContainer + { + RelativeSizeAxes = Axes.X, + Y = 40, + Height = 260, + ScrollbarOverlapsContent = false, + Child = searchContainer = new SearchContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Right = 5, Bottom = 10 }, + Direction = FillDirection.Vertical, + Spacing = new Vector2(10), + } + } + }, + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + AvailableTags.BindCollectionChanged((_, _) => + { + loadCancellationTokenSource?.Cancel(); + loadCancellationTokenSource = new CancellationTokenSource(); + + LoadComponentsAsync(createItems(AvailableTags.Values), loaded => + { + searchContainer.Clear(); + searchContainer.AddRange(loaded); + }, loadCancellationTokenSource.Token); + }, true); + searchBox.Current.BindValueChanged(_ => searchContainer.SearchTerm = searchBox.Current.Value, true); + } + + private IEnumerable createItems(IEnumerable tags) + { + var grouped = tags.GroupBy(tag => tag.GroupName).OrderBy(group => group.Key); + + foreach (var group in grouped) + { + var drawableGroup = new GroupFlow(group.Key); + + foreach (var tag in group.OrderBy(t => t.FullName)) + drawableGroup.Add(new DrawableAddableTag(tag) { Action = () => OnSelected?.Invoke(tag) }); + + yield return drawableGroup; + } + } + + public override bool OnPressed(KeyBindingPressEvent e) + { + if (e.Action == GlobalAction.Select && !e.Repeat) + { + attemptSelect(); + return true; + } + + return false; + } + + private void attemptSelect() + { + var visibleItems = searchContainer.ChildrenOfType().Where(d => d.IsPresent).ToArray(); + + if (visibleItems.Length == 1) + OnSelected?.Invoke(visibleItems.Single().Tag); + } + + private partial class GroupFlow : FillFlowContainer, IFilterable + { + public IEnumerable FilterTerms { get; } + + public bool MatchingFilter + { + set => Alpha = value ? 1 : 0; + } + + public bool FilteringActive { set { } } + + public GroupFlow(string? name) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Direction = FillDirection.Vertical; + Spacing = new Vector2(5); + + Add(new StatisticItemHeader { Text = name ?? "uncategorised" }); + + FilterTerms = name == null ? [] : [name]; + } + } + + private partial class DrawableAddableTag : OsuAnimatedButton, IFilterable + { + public readonly UserTag Tag; + + private Box votedBackground = null!; + private SpriteIcon votedIcon = null!; + + private readonly Bindable voted = new Bindable(); + private readonly BindableBool updating = new BindableBool(); + + private LoadingLayer loadingLayer = null!; + + public DrawableAddableTag(UserTag tag) + { + Tag = tag; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + ScaleOnMouseDown = 0.95f; + + voted.BindTo(Tag.Voted); + updating.BindTo(Tag.Updating); + } + + [Resolved] + private OsuColour colours { get; set; } = null!; + + [BackgroundDependencyLoader] + private void load() + { + Content.AddRange(new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Gray7, + Depth = float.MaxValue, + }, + new Container + { + RelativeSizeAxes = Axes.Y, + Width = 30, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Depth = float.MaxValue, + Children = new Drawable[] + { + votedBackground = new Box + { + RelativeSizeAxes = Axes.Both, + }, + votedIcon = new SpriteIcon + { + Size = new Vector2(16), + Icon = FontAwesome.Solid.ThumbsUp, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + } + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(2), + Padding = new MarginPadding(5) { Right = 35 }, + Children = new Drawable[] + { + new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(weight: FontWeight.SemiBold)) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = Tag.DisplayName, + }, + new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(size: 14)) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = Tag.Description, + } + } + }, + loadingLayer = new LoadingLayer(dimBackground: true), + }); + } + + public IEnumerable FilterTerms => [Tag.FullName, Tag.Description]; + + public bool MatchingFilter { set => Alpha = value ? 1 : 0; } + public bool FilteringActive { set { } } + + protected override void LoadComplete() + { + base.LoadComplete(); + + voted.BindValueChanged(_ => + { + votedBackground.FadeColour(voted.Value ? colours.Lime2 : colours.Gray2, 250, Easing.OutQuint); + votedIcon.FadeColour(voted.Value ? Colour4.Black : Colour4.White, 250, Easing.OutQuint); + }, true); + FinishTransforms(true); + + updating.BindValueChanged(u => loadingLayer.State.Value = u.NewValue ? Visibility.Visible : Visibility.Hidden); + } + } + } + } +} diff --git a/osu.Game/Screens/Ranking/UserTagControl_DrawableUserTag.cs b/osu.Game/Screens/Ranking/UserTagControl_DrawableUserTag.cs new file mode 100644 index 0000000000..e54d88bca2 --- /dev/null +++ b/osu.Game/Screens/Ranking/UserTagControl_DrawableUserTag.cs @@ -0,0 +1,256 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.Ranking +{ + public partial class UserTagControl + { + private partial class DrawableUserTag : OsuAnimatedButton + { + public readonly UserTag UserTag; + + public Action? OnSelected { get; set; } + + private readonly Bindable voteCount = new Bindable(); + private readonly BindableBool voted = new BindableBool(); + private readonly Bindable confirmed = new BindableBool(); + private readonly BindableBool updating = new BindableBool(); + + protected Box MainBackground { get; private set; } = null!; + private Box voteBackground = null!; + + protected OsuSpriteText TagCategoryText { get; private set; } = null!; + protected OsuSpriteText TagNameText { get; private set; } = null!; + + private VoteCountText voteCountText = null!; + + private readonly bool showVoteCount; + + private LoadingLayer loadingLayer = null!; + + private FillFlowContainer contentFlow = null!; + + [Resolved] + private OsuColour colours { get; set; } = null!; + + public DrawableUserTag(UserTag userTag, bool showVoteCount = true) + { + UserTag = userTag; + this.showVoteCount = showVoteCount; + voteCount.BindTo(userTag.VoteCount); + updating.BindTo(userTag.Updating); + voted.BindTo(userTag.Voted); + + ScaleOnMouseDown = 0.95f; + } + + [BackgroundDependencyLoader] + private void load() + { + CornerRadius = 5; + Masking = true; + + EdgeEffect = new EdgeEffectParameters + { + Colour = colours.Lime1, + Radius = 6, + Type = EdgeEffectType.Glow, + }; + + Content.AddRange(new Drawable[] + { + MainBackground = new Box + { + RelativeSizeAxes = Axes.Both, + Depth = float.MaxValue, + }, + contentFlow = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new[] + { + TagCategoryText = new OsuSpriteText + { + Alpha = UserTag.GroupName != null ? 0.6f : 0, + Text = UserTag.GroupName ?? default(LocalisableString), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Horizontal = 6 } + }, + new Container + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0.1f, + Blending = BlendingParameters.Additive, + }, + TagNameText = new OsuSpriteText + { + Text = UserTag.DisplayName, + Font = OsuFont.Default.With(weight: FontWeight.SemiBold), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Horizontal = 6, Vertical = 3, }, + }, + } + }, + showVoteCount + ? new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Children = new Drawable[] + { + voteBackground = new Box + { + RelativeSizeAxes = Axes.Both, + }, + voteCountText = new VoteCountText(voteCount) + { + Margin = new MarginPadding { Horizontal = 6 }, + }, + } + } + : Empty(), + } + }, + loadingLayer = new LoadingLayer(dimBackground: true), + }); + + TooltipText = UserTag.Description; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + const double transition_duration = 300; + + updating.BindValueChanged(u => loadingLayer.State.Value = u.NewValue ? Visibility.Visible : Visibility.Hidden); + + if (showVoteCount) + { + voteCount.BindValueChanged(_ => + { + confirmed.Value = voteCount.Value >= 10; + }, true); + voted.BindValueChanged(v => + { + if (v.NewValue) + { + voteBackground.FadeColour(colours.Lime2, transition_duration, Easing.OutQuint); + voteCountText.FadeColour(Colour4.Black, transition_duration, Easing.OutQuint); + } + else + { + voteBackground.FadeColour(colours.Gray2, transition_duration, Easing.OutQuint); + voteCountText.FadeColour(Colour4.White, transition_duration, Easing.OutQuint); + } + }, true); + + confirmed.BindValueChanged(c => + { + if (c.NewValue) + { + MainBackground.FadeColour(colours.Lime2, transition_duration, Easing.OutQuint); + TagCategoryText.FadeColour(Colour4.Black, transition_duration, Easing.OutQuint); + TagNameText.FadeColour(Colour4.Black, transition_duration, Easing.OutQuint); + FadeEdgeEffectTo(0.3f, transition_duration, Easing.OutQuint); + } + else + { + MainBackground.FadeColour(colours.Gray6, transition_duration, Easing.OutQuint); + TagCategoryText.FadeColour(Colour4.White, transition_duration, Easing.OutQuint); + TagNameText.FadeColour(Colour4.White, transition_duration, Easing.OutQuint); + FadeEdgeEffectTo(0f, transition_duration, Easing.OutQuint); + } + }, true); + } + + FinishTransforms(true); + + Action = () => OnSelected?.Invoke(UserTag); + } + + protected override void Update() + { + base.Update(); + + // Grab size from the actual flow. If we were to use AutoSize, the mouse down animation would cause + // our size to change, resulting in weird fill flow interactions. + Size = contentFlow.Size; + } + + private partial class VoteCountText : CompositeDrawable + { + private OsuSpriteText? text; + + private readonly Bindable voteCount; + + public VoteCountText(Bindable voteCount) + { + RelativeSizeAxes = Axes.Y; + AutoSizeAxes = Axes.X; + + this.voteCount = voteCount.GetBoundCopy(); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + voteCount.BindValueChanged(count => + { + OsuSpriteText? previousText = text; + + AddInternal(text = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(weight: FontWeight.SemiBold), + Text = voteCount.Value.ToLocalisableString(), + }); + + if (previousText != null) + { + const double transition_duration = 500; + + bool isIncrease = count.NewValue > count.OldValue; + + text.MoveToY(isIncrease ? 20 : -20) + .MoveToY(0, transition_duration, Easing.OutExpo); + + previousText.BypassAutoSizeAxes = Axes.Both; + previousText.MoveToY(isIncrease ? -20 : 20, transition_duration, Easing.OutExpo).Expire(); + + AutoSizeDuration = 300; + AutoSizeEasing = Easing.OutQuint; + } + }, true); + } + } + } + } +}