2019-01-24 16:43:03 +08:00
|
|
|
// 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.
|
2018-04-13 17:19:50 +08:00
|
|
|
|
2019-12-19 01:02:57 +08:00
|
|
|
using System;
|
2018-04-13 17:19:50 +08:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
2019-02-21 18:04:31 +08:00
|
|
|
using osu.Framework.Bindables;
|
2018-11-20 15:51:59 +08:00
|
|
|
using osuTK;
|
|
|
|
using osuTK.Graphics;
|
2018-04-13 17:19:50 +08:00
|
|
|
using osu.Framework.Graphics;
|
|
|
|
using osu.Framework.Graphics.Containers;
|
|
|
|
using osu.Game.Graphics;
|
|
|
|
using osu.Game.Graphics.UserInterface;
|
|
|
|
using osu.Game.Online.API;
|
|
|
|
using osu.Game.Online.API.Requests;
|
|
|
|
using osu.Game.Overlays.SearchableList;
|
|
|
|
using osu.Game.Overlays.Social;
|
|
|
|
using osu.Game.Users;
|
2019-08-28 06:14:35 +08:00
|
|
|
using System.Threading;
|
2019-12-19 01:21:33 +08:00
|
|
|
using osu.Framework.Allocation;
|
2019-09-07 03:56:46 +08:00
|
|
|
using osu.Framework.Threading;
|
2018-04-13 17:19:50 +08:00
|
|
|
|
|
|
|
namespace osu.Game.Overlays
|
|
|
|
{
|
2019-05-14 13:18:06 +08:00
|
|
|
public class SocialOverlay : SearchableListOverlay<SocialTab, SocialSortCriteria, SortDirection>
|
2018-04-13 17:19:50 +08:00
|
|
|
{
|
|
|
|
private readonly LoadingAnimation loading;
|
|
|
|
private FillFlowContainer<SocialPanel> panels;
|
|
|
|
|
|
|
|
protected override Color4 BackgroundColour => OsuColour.FromHex(@"60284b");
|
|
|
|
protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"672b51");
|
|
|
|
protected override Color4 TrianglesColourDark => OsuColour.FromHex(@"5c2648");
|
|
|
|
|
|
|
|
protected override SearchableListHeader<SocialTab> CreateHeader() => new Header();
|
|
|
|
protected override SearchableListFilterControl<SocialSortCriteria, SortDirection> CreateFilterControl() => new FilterControl();
|
|
|
|
|
2019-12-19 01:02:57 +08:00
|
|
|
private User[] users = Array.Empty<User>();
|
2019-02-28 12:31:40 +08:00
|
|
|
|
2019-12-19 01:02:57 +08:00
|
|
|
public User[] Users
|
2018-04-13 17:19:50 +08:00
|
|
|
{
|
2019-02-28 12:58:19 +08:00
|
|
|
get => users;
|
2018-04-13 17:19:50 +08:00
|
|
|
set
|
|
|
|
{
|
2019-12-19 01:02:57 +08:00
|
|
|
if (users == value)
|
2018-04-13 17:19:50 +08:00
|
|
|
return;
|
|
|
|
|
2019-12-19 01:02:57 +08:00
|
|
|
users = value ?? Array.Empty<User>();
|
2019-12-19 01:21:33 +08:00
|
|
|
|
|
|
|
if (LoadState >= LoadState.Ready)
|
|
|
|
recreatePanels();
|
2018-04-13 17:19:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public SocialOverlay()
|
2020-01-24 17:24:35 +08:00
|
|
|
: base(OverlayColourScheme.Pink)
|
2018-04-13 17:19:50 +08:00
|
|
|
{
|
|
|
|
Add(loading = new LoadingAnimation());
|
|
|
|
|
2019-02-22 16:51:39 +08:00
|
|
|
Filter.Search.Current.ValueChanged += text =>
|
2018-04-13 17:19:50 +08:00
|
|
|
{
|
2019-02-22 16:51:39 +08:00
|
|
|
if (!string.IsNullOrEmpty(text.NewValue))
|
2018-04-13 17:19:50 +08:00
|
|
|
{
|
|
|
|
// force searching in players until searching for friends is supported
|
|
|
|
Header.Tabs.Current.Value = SocialTab.AllPlayers;
|
|
|
|
|
|
|
|
if (Filter.Tabs.Current.Value != SocialSortCriteria.Rank)
|
|
|
|
Filter.Tabs.Current.Value = SocialSortCriteria.Rank;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-07-02 14:17:15 +08:00
|
|
|
Header.Tabs.Current.ValueChanged += _ => queueUpdate();
|
2019-09-19 08:35:56 +08:00
|
|
|
Filter.Tabs.Current.ValueChanged += _ => onFilterUpdate();
|
2018-04-13 17:19:50 +08:00
|
|
|
|
2019-12-19 01:02:57 +08:00
|
|
|
Filter.DisplayStyleControl.DisplayStyle.ValueChanged += _ => recreatePanels();
|
|
|
|
Filter.DisplayStyleControl.Dropdown.Current.ValueChanged += _ => recreatePanels();
|
2018-04-13 17:19:50 +08:00
|
|
|
|
2019-07-02 14:17:15 +08:00
|
|
|
currentQuery.BindTo(Filter.Search.Current);
|
2019-02-22 16:51:39 +08:00
|
|
|
currentQuery.ValueChanged += query =>
|
2018-04-13 17:19:50 +08:00
|
|
|
{
|
2019-09-07 03:56:46 +08:00
|
|
|
queryChangedDebounce?.Cancel();
|
2018-04-13 17:19:50 +08:00
|
|
|
|
2019-02-22 16:51:39 +08:00
|
|
|
if (string.IsNullOrEmpty(query.NewValue))
|
2019-07-02 14:17:15 +08:00
|
|
|
queueUpdate();
|
2018-04-13 17:19:50 +08:00
|
|
|
else
|
2019-09-07 03:56:46 +08:00
|
|
|
queryChangedDebounce = Scheduler.AddDelayed(updateSearch, 500);
|
2018-04-13 17:19:50 +08:00
|
|
|
};
|
2019-07-02 14:17:15 +08:00
|
|
|
}
|
2018-04-13 17:19:50 +08:00
|
|
|
|
2019-12-19 01:21:33 +08:00
|
|
|
[BackgroundDependencyLoader]
|
|
|
|
private void load()
|
|
|
|
{
|
|
|
|
recreatePanels();
|
|
|
|
}
|
|
|
|
|
2019-07-02 14:17:15 +08:00
|
|
|
private APIRequest getUsersRequest;
|
|
|
|
|
|
|
|
private readonly Bindable<string> currentQuery = new Bindable<string>();
|
|
|
|
|
2019-09-07 03:56:46 +08:00
|
|
|
private ScheduledDelegate queryChangedDebounce;
|
|
|
|
|
2019-07-02 14:17:15 +08:00
|
|
|
private void queueUpdate() => Scheduler.AddOnce(updateSearch);
|
|
|
|
|
2019-08-28 06:14:35 +08:00
|
|
|
private CancellationTokenSource loadCancellation;
|
|
|
|
|
2019-07-02 14:17:15 +08:00
|
|
|
private void updateSearch()
|
|
|
|
{
|
2019-09-07 03:56:46 +08:00
|
|
|
queryChangedDebounce?.Cancel();
|
2019-07-02 14:17:15 +08:00
|
|
|
|
|
|
|
if (!IsLoaded)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Users = null;
|
|
|
|
clearPanels();
|
|
|
|
getUsersRequest?.Cancel();
|
|
|
|
|
|
|
|
if (API?.IsLoggedIn != true)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (Header.Tabs.Current.Value)
|
|
|
|
{
|
|
|
|
case SocialTab.Friends:
|
|
|
|
var friendRequest = new GetFriendsRequest(); // TODO filter arguments?
|
2019-12-19 01:02:57 +08:00
|
|
|
friendRequest.Success += users => Users = users.ToArray();
|
2019-07-02 14:17:15 +08:00
|
|
|
API.Queue(getUsersRequest = friendRequest);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
var userRequest = new GetUsersRequest(); // TODO filter arguments!
|
2019-12-19 01:02:57 +08:00
|
|
|
userRequest.Success += res => Users = res.Users.Select(r => r.User).ToArray();
|
2019-07-02 14:17:15 +08:00
|
|
|
API.Queue(getUsersRequest = userRequest);
|
|
|
|
break;
|
|
|
|
}
|
2018-04-13 17:19:50 +08:00
|
|
|
}
|
|
|
|
|
2019-12-19 01:02:57 +08:00
|
|
|
private void recreatePanels()
|
2018-04-13 17:19:50 +08:00
|
|
|
{
|
|
|
|
clearPanels();
|
|
|
|
|
|
|
|
if (Users == null)
|
2019-08-27 08:53:16 +08:00
|
|
|
{
|
|
|
|
loading.Hide();
|
2018-04-13 17:19:50 +08:00
|
|
|
return;
|
2019-08-27 08:53:16 +08:00
|
|
|
}
|
2018-04-13 17:19:50 +08:00
|
|
|
|
2019-12-19 01:02:57 +08:00
|
|
|
IEnumerable<User> sortedUsers = Users;
|
|
|
|
|
|
|
|
switch (Filter.Tabs.Current.Value)
|
|
|
|
{
|
|
|
|
case SocialSortCriteria.Location:
|
|
|
|
sortedUsers = sortedUsers.OrderBy(u => u.Country.FullName);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SocialSortCriteria.Name:
|
|
|
|
sortedUsers = sortedUsers.OrderBy(u => u.Username);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Filter.DisplayStyleControl.Dropdown.Current.Value == SortDirection.Descending)
|
|
|
|
sortedUsers = sortedUsers.Reverse();
|
|
|
|
|
2018-04-13 17:19:50 +08:00
|
|
|
var newPanels = new FillFlowContainer<SocialPanel>
|
|
|
|
{
|
|
|
|
RelativeSizeAxes = Axes.X,
|
|
|
|
AutoSizeAxes = Axes.Y,
|
|
|
|
Spacing = new Vector2(10f),
|
|
|
|
Margin = new MarginPadding { Top = 10 },
|
2019-12-19 01:02:57 +08:00
|
|
|
ChildrenEnumerable = sortedUsers.Select(u =>
|
2018-04-13 17:19:50 +08:00
|
|
|
{
|
|
|
|
SocialPanel panel;
|
2019-04-01 11:16:05 +08:00
|
|
|
|
2019-12-19 01:02:57 +08:00
|
|
|
switch (Filter.DisplayStyleControl.DisplayStyle.Value)
|
2018-04-13 17:19:50 +08:00
|
|
|
{
|
|
|
|
case PanelDisplayStyle.Grid:
|
|
|
|
panel = new SocialGridPanel(u)
|
|
|
|
{
|
|
|
|
Anchor = Anchor.TopCentre,
|
|
|
|
Origin = Anchor.TopCentre
|
|
|
|
};
|
|
|
|
break;
|
2019-04-01 11:16:05 +08:00
|
|
|
|
2018-04-13 17:19:50 +08:00
|
|
|
default:
|
|
|
|
panel = new SocialListPanel(u);
|
|
|
|
break;
|
|
|
|
}
|
2019-02-28 12:31:40 +08:00
|
|
|
|
2018-04-13 17:19:50 +08:00
|
|
|
panel.Status.BindTo(u.Status);
|
2019-05-06 02:51:55 +08:00
|
|
|
panel.Activity.BindTo(u.Activity);
|
2018-04-13 17:19:50 +08:00
|
|
|
return panel;
|
|
|
|
})
|
|
|
|
};
|
|
|
|
|
|
|
|
LoadComponentAsync(newPanels, f =>
|
|
|
|
{
|
2019-09-07 03:56:46 +08:00
|
|
|
if (panels != null)
|
|
|
|
ScrollFlow.Remove(panels);
|
|
|
|
|
2019-08-27 08:53:16 +08:00
|
|
|
loading.Hide();
|
2018-04-13 17:19:50 +08:00
|
|
|
ScrollFlow.Add(panels = newPanels);
|
2019-12-19 10:26:22 +08:00
|
|
|
}, (loadCancellation = new CancellationTokenSource()).Token);
|
2018-04-13 17:19:50 +08:00
|
|
|
}
|
|
|
|
|
2019-09-19 08:35:56 +08:00
|
|
|
private void onFilterUpdate()
|
|
|
|
{
|
2019-09-19 09:09:14 +08:00
|
|
|
if (Filter.Tabs.Current.Value == SocialSortCriteria.Rank)
|
2019-09-19 08:35:56 +08:00
|
|
|
{
|
|
|
|
queueUpdate();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-19 01:02:57 +08:00
|
|
|
recreatePanels();
|
2018-04-13 17:19:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private void clearPanels()
|
|
|
|
{
|
2019-08-28 06:02:26 +08:00
|
|
|
loading.Show();
|
|
|
|
|
2019-08-28 06:14:35 +08:00
|
|
|
loadCancellation?.Cancel();
|
|
|
|
|
2018-04-13 17:19:50 +08:00
|
|
|
if (panels != null)
|
|
|
|
{
|
|
|
|
panels.Expire();
|
|
|
|
panels = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-14 13:18:06 +08:00
|
|
|
public override void APIStateChanged(IAPIProvider api, APIState state)
|
2018-04-13 17:19:50 +08:00
|
|
|
{
|
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case APIState.Online:
|
2019-07-02 14:17:15 +08:00
|
|
|
queueUpdate();
|
2018-04-13 17:19:50 +08:00
|
|
|
break;
|
2019-04-01 11:16:05 +08:00
|
|
|
|
2018-04-13 17:19:50 +08:00
|
|
|
default:
|
|
|
|
Users = null;
|
|
|
|
clearPanels();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public enum SortDirection
|
|
|
|
{
|
|
|
|
Ascending,
|
|
|
|
Descending
|
|
|
|
}
|
|
|
|
}
|