Skip to content

Commit baab447

Browse files
authored
Merge pull request #33683 from bdach/blocking-not-terrible
Add block / unblock options to chat and user profile overlay
2 parents 70db766 + 32285f4 commit baab447

File tree

6 files changed

+293
-50
lines changed

6 files changed

+293
-50
lines changed

osu.Game/Overlays/Chat/DrawableChatUsername.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
using osu.Game.Resources.Localisation.Web;
2929
using osu.Game.Screens;
3030
using osu.Game.Screens.Play;
31+
using osu.Game.Users;
3132
using osuTK;
3233
using osuTK.Graphics;
3334
using ChatStrings = osu.Game.Localisation.ChatStrings;
@@ -92,6 +93,9 @@ public override float Width
9293
[Resolved]
9394
private Bindable<Channel?>? currentChannel { get; set; }
9495

96+
[Resolved]
97+
private IDialogOverlay? dialogOverlay { get; set; }
98+
9599
private readonly APIUser user;
96100
private readonly OsuSpriteText drawableText;
97101

@@ -208,6 +212,9 @@ public MenuItem[] ContextMenuItems
208212

209213
items.Add(new OsuMenuItemSpacer());
210214
items.Add(new OsuMenuItem(UsersStrings.ReportButtonText, MenuItemType.Destructive, ReportRequested));
215+
items.Add(api.Blocks.Any(b => b.TargetID == user.OnlineID)
216+
? new OsuMenuItem(UsersStrings.BlocksButtonUnblock, MenuItemType.Standard, () => dialogOverlay?.Push(ConfirmBlockActionDialog.Unblock(user)))
217+
: new OsuMenuItem(UsersStrings.BlocksButtonBlock, MenuItemType.Destructive, () => dialogOverlay?.Push(ConfirmBlockActionDialog.Block(user))));
211218

212219
return items.ToArray();
213220
}

osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ private void load(OverlayColourProvider colourProvider)
5555
{
5656
User = { BindTarget = User }
5757
},
58+
new UserActionsButton
59+
{
60+
User = { BindTarget = User }
61+
}
5862
}
5963
},
6064
new Container
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
2+
// See the LICENCE file in the repository root for full licence text.
3+
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using osu.Framework.Allocation;
7+
using osu.Framework.Bindables;
8+
using osu.Framework.Extensions;
9+
using osu.Framework.Graphics;
10+
using osu.Framework.Graphics.Containers;
11+
using osu.Framework.Graphics.Cursor;
12+
using osu.Framework.Graphics.Shapes;
13+
using osu.Framework.Graphics.Sprites;
14+
using osu.Framework.Graphics.UserInterface;
15+
using osu.Framework.Input.Events;
16+
using osu.Framework.Localisation;
17+
using osu.Game.Graphics;
18+
using osu.Game.Graphics.Containers;
19+
using osu.Game.Graphics.Sprites;
20+
using osu.Game.Graphics.UserInterfaceV2;
21+
using osu.Game.Online.API;
22+
using osu.Game.Online.API.Requests.Responses;
23+
using osu.Game.Resources.Localisation.Web;
24+
using osu.Game.Users;
25+
using osuTK;
26+
27+
namespace osu.Game.Overlays.Profile.Header.Components
28+
{
29+
public partial class UserActionsButton : OsuHoverContainer, IHasPopover
30+
{
31+
public readonly Bindable<UserProfileData?> User = new Bindable<UserProfileData?>();
32+
33+
private Box background = null!;
34+
35+
protected override IEnumerable<Drawable> EffectTargets => [background];
36+
37+
[Resolved]
38+
private OverlayColourProvider colourProvider { get; set; } = null!;
39+
40+
[Resolved]
41+
private IAPIProvider api { get; set; } = null!;
42+
43+
[BackgroundDependencyLoader]
44+
private void load()
45+
{
46+
IdleColour = colourProvider.Background2;
47+
HoverColour = colourProvider.Background1;
48+
49+
Size = new Vector2(40);
50+
Masking = true;
51+
CornerRadius = 20;
52+
53+
Child = new CircularContainer
54+
{
55+
Masking = true,
56+
RelativeSizeAxes = Axes.Both,
57+
Children = new Drawable[]
58+
{
59+
background = new Box
60+
{
61+
RelativeSizeAxes = Axes.Both,
62+
},
63+
new SpriteIcon
64+
{
65+
Size = new Vector2(12),
66+
Anchor = Anchor.Centre,
67+
Origin = Anchor.Centre,
68+
Icon = FontAwesome.Solid.EllipsisV,
69+
},
70+
}
71+
};
72+
73+
Action = this.ShowPopover;
74+
}
75+
76+
protected override void LoadComplete()
77+
{
78+
base.LoadComplete();
79+
80+
User.BindValueChanged(_ => Alpha = User.Value?.User.OnlineID == api.LocalUser.Value.OnlineID ? 0 : 1, true);
81+
}
82+
83+
public Popover GetPopover() => new UserActionPopover(User.Value!.User);
84+
85+
private partial class UserActionPopover : OsuPopover
86+
{
87+
private readonly APIUser user;
88+
89+
public UserActionPopover(APIUser user)
90+
: base(false)
91+
{
92+
this.user = user;
93+
}
94+
95+
[BackgroundDependencyLoader]
96+
private void load(OverlayColourProvider colourProvider, IAPIProvider api, IDialogOverlay? dialogOverlay)
97+
{
98+
Background.Colour = colourProvider.Background6;
99+
100+
bool userBlocked = api.Blocks.Any(b => b.TargetID == user.Id);
101+
102+
AllowableAnchors = [Anchor.BottomCentre, Anchor.TopCentre];
103+
104+
Child = new FillFlowContainer
105+
{
106+
Width = 160,
107+
AutoSizeAxes = Axes.Y,
108+
Padding = new MarginPadding { Horizontal = 5, Vertical = 10 },
109+
Children = new Drawable[]
110+
{
111+
new UserAction(FontAwesome.Solid.Ban, userBlocked ? UsersStrings.BlocksButtonUnblock : UsersStrings.BlocksButtonBlock)
112+
{
113+
Action = () =>
114+
{
115+
dialogOverlay?.Push(userBlocked ? ConfirmBlockActionDialog.Unblock(user) : ConfirmBlockActionDialog.Block(user));
116+
this.HidePopover();
117+
}
118+
}
119+
}
120+
};
121+
}
122+
}
123+
124+
private partial class UserAction : OsuClickableContainer
125+
{
126+
private readonly IconUsage icon;
127+
private readonly LocalisableString caption;
128+
129+
private Box background = null!;
130+
private CircularContainer indicator = null!;
131+
132+
public UserAction(IconUsage icon, LocalisableString caption)
133+
{
134+
this.icon = icon;
135+
this.caption = caption;
136+
}
137+
138+
[BackgroundDependencyLoader]
139+
private void load(OverlayColourProvider colourProvider)
140+
{
141+
RelativeSizeAxes = Content.RelativeSizeAxes = Axes.X;
142+
AutoSizeAxes = Content.AutoSizeAxes = Axes.Y;
143+
144+
Masking = true;
145+
CornerRadius = 4;
146+
Children = new Drawable[]
147+
{
148+
background = new Box
149+
{
150+
RelativeSizeAxes = Axes.Both,
151+
Colour = colourProvider.Background5,
152+
Alpha = 0,
153+
},
154+
indicator = new Circle
155+
{
156+
Width = 4,
157+
Height = 14,
158+
X = 10,
159+
Colour = colourProvider.Highlight1,
160+
Anchor = Anchor.CentreLeft,
161+
Origin = Anchor.Centre,
162+
Alpha = 0,
163+
},
164+
new FillFlowContainer
165+
{
166+
AutoSizeAxes = Axes.Y,
167+
RelativeSizeAxes = Axes.X,
168+
Padding = new MarginPadding { Horizontal = 25, Vertical = 5 },
169+
Direction = FillDirection.Horizontal,
170+
Spacing = new Vector2(5, 0),
171+
Children = new Drawable[]
172+
{
173+
new SpriteIcon
174+
{
175+
Icon = icon,
176+
Size = new Vector2(11),
177+
Anchor = Anchor.CentreLeft,
178+
Origin = Anchor.CentreLeft,
179+
},
180+
new OsuSpriteText
181+
{
182+
Text = caption,
183+
Font = OsuFont.Style.Body,
184+
Anchor = Anchor.CentreLeft,
185+
Origin = Anchor.CentreLeft,
186+
UseFullGlyphHeight = false,
187+
}
188+
}
189+
}
190+
};
191+
}
192+
193+
protected override bool OnHover(HoverEvent e)
194+
{
195+
updateState();
196+
return true;
197+
}
198+
199+
protected override void OnHoverLost(HoverLostEvent e)
200+
{
201+
updateState();
202+
base.OnHoverLost(e);
203+
}
204+
205+
private void updateState()
206+
{
207+
background.Alpha = indicator.Alpha = IsHovered ? 1 : 0;
208+
}
209+
}
210+
}
211+
}

osu.Game/Overlays/UserProfileOverlay.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using osu.Framework.Extensions.ObjectExtensions;
1010
using osu.Framework.Graphics;
1111
using osu.Framework.Graphics.Containers;
12+
using osu.Framework.Graphics.Cursor;
1213
using osu.Framework.Graphics.Shapes;
1314
using osu.Framework.Graphics.UserInterface;
1415
using osu.Framework.Input.Events;
@@ -55,13 +56,17 @@ public partial class UserProfileOverlay : FullscreenOverlay<ProfileHeader>
5556
public UserProfileOverlay()
5657
: base(OverlayColourScheme.Pink)
5758
{
58-
base.Content.AddRange(new Drawable[]
59+
base.Content.Add(new PopoverContainer
5960
{
60-
onlineViewContainer = new OnlineViewContainer($"Sign in to view the {Header.Title.Title}")
61+
RelativeSizeAxes = Axes.Both,
62+
Children = new Drawable[]
6163
{
62-
RelativeSizeAxes = Axes.Both
63-
},
64-
loadingLayer = new LoadingLayer(true)
64+
onlineViewContainer = new OnlineViewContainer($"Sign in to view the {Header.Title.Title}")
65+
{
66+
RelativeSizeAxes = Axes.Both
67+
},
68+
loadingLayer = new LoadingLayer(true)
69+
}
6570
});
6671
}
6772

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
2+
// See the LICENCE file in the repository root for full licence text.
3+
4+
using System;
5+
using osu.Framework.Allocation;
6+
using osu.Framework.Graphics.Sprites;
7+
using osu.Framework.Localisation;
8+
using osu.Game.Localisation;
9+
using osu.Game.Online.API;
10+
using osu.Game.Online.API.Requests;
11+
using osu.Game.Online.API.Requests.Responses;
12+
using osu.Game.Overlays;
13+
using osu.Game.Overlays.Dialog;
14+
using osu.Game.Overlays.Notifications;
15+
16+
namespace osu.Game.Users
17+
{
18+
public partial class ConfirmBlockActionDialog : DangerousActionDialog
19+
{
20+
private readonly APIUser user;
21+
22+
[Resolved]
23+
private IAPIProvider api { get; set; } = null!;
24+
25+
[Resolved]
26+
private NotificationOverlay? notifications { get; set; }
27+
28+
private ConfirmBlockActionDialog(APIUser user, LocalisableString text, Action<ConfirmBlockActionDialog> action)
29+
{
30+
this.user = user;
31+
BodyText = text;
32+
DangerousAction = () => action(this);
33+
}
34+
35+
public static ConfirmBlockActionDialog Block(APIUser user) => new ConfirmBlockActionDialog(user, ContextMenuStrings.ConfirmBlockUser(user.Username), d => d.toggleBlock(true));
36+
public static ConfirmBlockActionDialog Unblock(APIUser user) => new ConfirmBlockActionDialog(user, ContextMenuStrings.ConfirmUnblockUser(user.Username), d => d.toggleBlock(false));
37+
38+
private void toggleBlock(bool block)
39+
{
40+
APIRequest req = block ? new BlockUserRequest(user.OnlineID) : new UnblockUserRequest(user.OnlineID);
41+
42+
req.Success += () =>
43+
{
44+
api.UpdateLocalBlocks();
45+
};
46+
47+
req.Failure += e =>
48+
{
49+
notifications?.Post(new SimpleNotification
50+
{
51+
Text = e.Message,
52+
Icon = FontAwesome.Solid.Times,
53+
});
54+
};
55+
56+
api.Queue(req);
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)