1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-27 17:53:15 +08:00

Create a new collection via a placeholder item

This commit is contained in:
smoogipoo 2020-09-08 16:43:07 +09:00
parent 1260e30cde
commit 0bf6bfe5ee
3 changed files with 163 additions and 47 deletions

View File

@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
@ -10,19 +12,94 @@ namespace osu.Game.Collections
{ {
public class DrawableCollectionList : OsuRearrangeableListContainer<BeatmapCollection> public class DrawableCollectionList : OsuRearrangeableListContainer<BeatmapCollection>
{ {
protected override ScrollContainer<Drawable> CreateScrollContainer() => base.CreateScrollContainer().With(d => private Scroll scroll;
{
d.ScrollbarVisible = false;
d.Padding = new MarginPadding(10);
});
protected override FillFlowContainer<RearrangeableListItem<BeatmapCollection>> CreateListFillFlowContainer() => new FillFlowContainer<RearrangeableListItem<BeatmapCollection>> protected override ScrollContainer<Drawable> CreateScrollContainer() => scroll = new Scroll();
protected override FillFlowContainer<RearrangeableListItem<BeatmapCollection>> CreateListFillFlowContainer() => new Flow
{ {
LayoutDuration = 200, DragActive = { BindTarget = DragActive }
LayoutEasing = Easing.OutQuint,
Spacing = new Vector2(0, 5)
}; };
protected override OsuRearrangeableListItem<BeatmapCollection> CreateOsuDrawable(BeatmapCollection item) => new DrawableCollectionListItem(item); protected override OsuRearrangeableListItem<BeatmapCollection> CreateOsuDrawable(BeatmapCollection item)
{
if (item == scroll.PlaceholderItem.Model)
return scroll.ReplacePlaceholder();
return new DrawableCollectionListItem(item, true);
}
private class Scroll : OsuScrollContainer
{
public DrawableCollectionListItem PlaceholderItem { get; private set; }
protected override Container<Drawable> Content => content;
private readonly Container content;
private readonly Container<DrawableCollectionListItem> placeholderContainer;
public Scroll()
{
ScrollbarVisible = false;
Padding = new MarginPadding(10);
base.Content.Add(new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
LayoutDuration = 200,
LayoutEasing = Easing.OutQuint,
Children = new Drawable[]
{
content = new Container { RelativeSizeAxes = Axes.X },
placeholderContainer = new Container<DrawableCollectionListItem>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y
}
}
});
ReplacePlaceholder();
}
protected override void Update()
{
base.Update();
// AutoSizeAxes cannot be used as the height should represent the post-layout-transform height at all times, so that the placeholder doesn't bounce around.
content.Height = ((Flow)Child).Children.Sum(c => c.DrawHeight + 5);
}
/// <summary>
/// Replaces the current <see cref="PlaceholderItem"/> with a new one, and returns the previous.
/// </summary>
public DrawableCollectionListItem ReplacePlaceholder()
{
var previous = PlaceholderItem;
placeholderContainer.Clear(false);
placeholderContainer.Add(PlaceholderItem = new DrawableCollectionListItem(new BeatmapCollection(), false));
return previous;
}
}
private class Flow : FillFlowContainer<RearrangeableListItem<BeatmapCollection>>
{
public readonly IBindable<bool> DragActive = new Bindable<bool>();
public Flow()
{
Spacing = new Vector2(0, 5);
LayoutEasing = Easing.OutQuint;
}
protected override void LoadComplete()
{
base.LoadComplete();
DragActive.BindValueChanged(active => LayoutDuration = active.NewValue ? 200 : 0);
}
}
} }
} }

View File

@ -3,6 +3,7 @@
using System; using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -21,20 +22,33 @@ namespace osu.Game.Collections
public class DrawableCollectionListItem : OsuRearrangeableListItem<BeatmapCollection> public class DrawableCollectionListItem : OsuRearrangeableListItem<BeatmapCollection>
{ {
private const float item_height = 35; private const float item_height = 35;
private const float button_width = item_height * 0.75f; private const float button_width = item_height * 0.75f;
public DrawableCollectionListItem(BeatmapCollection item) private readonly Bindable<bool> isCreated = new Bindable<bool>();
public DrawableCollectionListItem(BeatmapCollection item, bool isCreated)
: base(item) : base(item)
{ {
this.isCreated.Value = isCreated;
ShowDragHandle.BindTo(this.isCreated);
} }
protected override Drawable CreateContent() => new ItemContent(Model); protected override Drawable CreateContent() => new ItemContent(Model)
{
IsCreated = { BindTarget = isCreated }
};
private class ItemContent : CircularContainer private class ItemContent : CircularContainer
{ {
public readonly Bindable<bool> IsCreated = new Bindable<bool>();
private readonly IBindable<string> collectionName;
private readonly BeatmapCollection collection; private readonly BeatmapCollection collection;
[Resolved]
private BeatmapCollectionManager collectionManager { get; set; }
private ItemTextBox textBox; private ItemTextBox textBox;
public ItemContent(BeatmapCollection collection) public ItemContent(BeatmapCollection collection)
@ -44,6 +58,8 @@ namespace osu.Game.Collections
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = item_height; Height = item_height;
Masking = true; Masking = true;
collectionName = collection.Name.GetBoundCopy();
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -55,6 +71,7 @@ namespace osu.Game.Collections
{ {
Anchor = Anchor.CentreRight, Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight, Origin = Anchor.CentreRight,
IsCreated = { BindTarget = IsCreated },
IsTextBoxHovered = v => textBox.ReceivePositionalInputAt(v) IsTextBoxHovered = v => textBox.ReceivePositionalInputAt(v)
}, },
new Container new Container
@ -68,12 +85,37 @@ namespace osu.Game.Collections
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Size = Vector2.One, Size = Vector2.One,
CornerRadius = item_height / 2, CornerRadius = item_height / 2,
Current = collection.Name Current = collection.Name,
PlaceholderText = IsCreated.Value ? string.Empty : "Create a new collection"
}, },
} }
}, },
}; };
} }
protected override void LoadComplete()
{
base.LoadComplete();
collectionName.BindValueChanged(_ => createNewCollection(), true);
}
private void createNewCollection()
{
if (IsCreated.Value)
return;
if (string.IsNullOrEmpty(collectionName.Value))
return;
// Add the new collection and disable our placeholder. If all text is removed, the placeholder should not show back again.
collectionManager.Collections.Add(collection);
textBox.PlaceholderText = string.Empty;
// When this item changes from placeholder to non-placeholder (via changing containers), its textbox will lose focus, so it needs to be re-focused.
Schedule(() => GetContainingInputManager().ChangeFocus(textBox));
IsCreated.Value = true;
}
} }
private class ItemTextBox : OsuTextBox private class ItemTextBox : OsuTextBox
@ -90,6 +132,8 @@ namespace osu.Game.Collections
public class DeleteButton : CompositeDrawable public class DeleteButton : CompositeDrawable
{ {
public readonly IBindable<bool> IsCreated = new Bindable<bool>();
public Func<Vector2, bool> IsTextBoxHovered; public Func<Vector2, bool> IsTextBoxHovered;
[Resolved(CanBeNull = true)] [Resolved(CanBeNull = true)]
@ -100,6 +144,7 @@ namespace osu.Game.Collections
private readonly BeatmapCollection collection; private readonly BeatmapCollection collection;
private Drawable fadeContainer;
private Drawable background; private Drawable background;
public DeleteButton(BeatmapCollection collection) public DeleteButton(BeatmapCollection collection)
@ -108,42 +153,51 @@ namespace osu.Game.Collections
RelativeSizeAxes = Axes.Y; RelativeSizeAxes = Axes.Y;
Width = button_width + item_height / 2; // add corner radius to cover with fill Width = button_width + item_height / 2; // add corner radius to cover with fill
Alpha = 0.1f;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
InternalChildren = new[] InternalChild = fadeContainer = new Container
{ {
background = new Box RelativeSizeAxes = Axes.Both,
Alpha = 0.1f,
Children = new[]
{ {
RelativeSizeAxes = Axes.Both, background = new Box
Colour = colours.Red {
}, RelativeSizeAxes = Axes.Both,
new SpriteIcon Colour = colours.Red
{ },
Anchor = Anchor.CentreRight, new SpriteIcon
Origin = Anchor.Centre, {
X = -button_width * 0.6f, Anchor = Anchor.CentreRight,
Size = new Vector2(10), Origin = Anchor.Centre,
Icon = FontAwesome.Solid.Trash X = -button_width * 0.6f,
Size = new Vector2(10),
Icon = FontAwesome.Solid.Trash
}
} }
}; };
} }
protected override void LoadComplete()
{
base.LoadComplete();
IsCreated.BindValueChanged(created => Alpha = created.NewValue ? 1 : 0, true);
}
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) && !IsTextBoxHovered(screenSpacePos); public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) && !IsTextBoxHovered(screenSpacePos);
protected override bool OnHover(HoverEvent e) protected override bool OnHover(HoverEvent e)
{ {
this.FadeTo(1f, 100, Easing.Out); fadeContainer.FadeTo(1f, 100, Easing.Out);
return false; return false;
} }
protected override void OnHoverLost(HoverLostEvent e) protected override void OnHoverLost(HoverLostEvent e)
{ {
this.FadeTo(0.1f, 100); fadeContainer.FadeTo(0.1f, 100);
} }
protected override bool OnClick(ClickEvent e) protected override bool OnClick(ClickEvent e)

View File

@ -8,7 +8,6 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osuTK; using osuTK;
namespace osu.Game.Collections namespace osu.Game.Collections
@ -51,9 +50,7 @@ namespace osu.Game.Collections
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
RowDimensions = new[] RowDimensions = new[]
{ {
new Dimension(GridSizeMode.Absolute, 50), new Dimension(GridSizeMode.AutoSize),
new Dimension(),
new Dimension(GridSizeMode.Absolute, 50),
}, },
Content = new[] Content = new[]
{ {
@ -65,6 +62,7 @@ namespace osu.Game.Collections
Origin = Anchor.Centre, Origin = Anchor.Centre,
Text = "Manage collections", Text = "Manage collections",
Font = OsuFont.GetFont(size: 30), Font = OsuFont.GetFont(size: 30),
Padding = new MarginPadding { Vertical = 10 },
} }
}, },
new Drawable[] new Drawable[]
@ -87,19 +85,6 @@ namespace osu.Game.Collections
} }
} }
}, },
new Drawable[]
{
new OsuButton
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Size = Vector2.One,
Padding = new MarginPadding(10),
Text = "Create new collection",
Action = () => collectionManager.Collections.Add(new BeatmapCollection { Name = { Value = "My new collection" } })
},
},
} }
} }
} }