1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-19 07:43:01 +08:00

Merge pull request #11190 from frenzibyte/api-friends-list

Add global friends list to API providers
This commit is contained in:
Dean Herbert 2020-12-18 16:44:29 +09:00 committed by GitHub
commit 9618f512d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 97 additions and 50 deletions

View File

@ -26,7 +26,7 @@ namespace osu.Desktop
[Resolved] [Resolved]
private IBindable<RulesetInfo> ruleset { get; set; } private IBindable<RulesetInfo> ruleset { get; set; }
private Bindable<User> user; private IBindable<User> user;
private readonly IBindable<UserStatus> status = new Bindable<UserStatus>(); private readonly IBindable<UserStatus> status = new Bindable<UserStatus>();
private readonly IBindable<UserActivity> activity = new Bindable<UserActivity>(); private readonly IBindable<UserActivity> activity = new Bindable<UserActivity>();

View File

@ -2,6 +2,7 @@
// 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 osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Online.API;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using osu.Game.Users; using osu.Game.Users;
@ -16,7 +17,7 @@ namespace osu.Game.Tests.Visual.Menus
AddStep("toggle support", () => AddStep("toggle support", () =>
{ {
API.LocalUser.Value = new User ((DummyAPIAccess)API).LocalUser.Value = new User
{ {
Username = API.LocalUser.Value.Username, Username = API.LocalUser.Value.Username,
Id = API.LocalUser.Value.Id + 1, Id = API.LocalUser.Value.Id + 1,

View File

@ -14,7 +14,7 @@ namespace osu.Game.Tests.Visual.Online
{ {
private readonly Container userPanelArea; private readonly Container userPanelArea;
private Bindable<User> localUser; private IBindable<User> localUser;
public TestSceneAccountCreationOverlay() public TestSceneAccountCreationOverlay()
{ {

View File

@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Online
[Cached] [Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
private TestFriendDisplay display; private FriendDisplay display;
[SetUp] [SetUp]
public void Setup() => Schedule(() => public void Setup() => Schedule(() =>
@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual.Online
Child = new BasicScrollContainer Child = new BasicScrollContainer
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Child = display = new TestFriendDisplay() Child = display = new FriendDisplay()
}; };
}); });
@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.Online
[Test] [Test]
public void TestOnline() public void TestOnline()
{ {
AddStep("Fetch online", () => display?.Fetch()); // No need to do anything, fetch is performed automatically.
} }
private List<User> getUsers() => new List<User> private List<User> getUsers() => new List<User>
@ -76,10 +76,5 @@ namespace osu.Game.Tests.Visual.Online
LastVisit = DateTimeOffset.Now LastVisit = DateTimeOffset.Now
} }
}; };
private class TestFriendDisplay : FriendDisplay
{
public void Fetch() => PerformFetch();
}
} }
} }

View File

@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.Chat; using osu.Game.Online.Chat;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Users; using osu.Game.Users;
@ -18,6 +19,8 @@ namespace osu.Game.Tests.Visual.Online
[Cached(typeof(IChannelPostTarget))] [Cached(typeof(IChannelPostTarget))]
private PostTarget postTarget { get; set; } private PostTarget postTarget { get; set; }
private DummyAPIAccess api => (DummyAPIAccess)API;
public TestSceneNowPlayingCommand() public TestSceneNowPlayingCommand()
{ {
Add(postTarget = new PostTarget()); Add(postTarget = new PostTarget());
@ -26,7 +29,7 @@ namespace osu.Game.Tests.Visual.Online
[Test] [Test]
public void TestGenericActivity() public void TestGenericActivity()
{ {
AddStep("Set activity", () => API.Activity.Value = new UserActivity.InLobby(null)); AddStep("Set activity", () => api.Activity.Value = new UserActivity.InLobby(null));
AddStep("Run command", () => Add(new NowPlayingCommand())); AddStep("Run command", () => Add(new NowPlayingCommand()));
@ -36,7 +39,7 @@ namespace osu.Game.Tests.Visual.Online
[Test] [Test]
public void TestEditActivity() public void TestEditActivity()
{ {
AddStep("Set activity", () => API.Activity.Value = new UserActivity.Editing(new BeatmapInfo())); AddStep("Set activity", () => api.Activity.Value = new UserActivity.Editing(new BeatmapInfo()));
AddStep("Run command", () => Add(new NowPlayingCommand())); AddStep("Run command", () => Add(new NowPlayingCommand()));
@ -46,7 +49,7 @@ namespace osu.Game.Tests.Visual.Online
[Test] [Test]
public void TestPlayActivity() public void TestPlayActivity()
{ {
AddStep("Set activity", () => API.Activity.Value = new UserActivity.SoloGame(new BeatmapInfo(), new RulesetInfo())); AddStep("Set activity", () => api.Activity.Value = new UserActivity.SoloGame(new BeatmapInfo(), new RulesetInfo()));
AddStep("Run command", () => Add(new NowPlayingCommand())); AddStep("Run command", () => Add(new NowPlayingCommand()));
@ -57,7 +60,7 @@ namespace osu.Game.Tests.Visual.Online
[TestCase(false)] [TestCase(false)]
public void TestLinkPresence(bool hasOnlineId) public void TestLinkPresence(bool hasOnlineId)
{ {
AddStep("Set activity", () => API.Activity.Value = new UserActivity.InLobby(null)); AddStep("Set activity", () => api.Activity.Value = new UserActivity.InLobby(null));
AddStep("Set beatmap", () => Beatmap.Value = new DummyWorkingBeatmap(Audio, null) AddStep("Set beatmap", () => Beatmap.Value = new DummyWorkingBeatmap(Audio, null)
{ {

View File

@ -39,9 +39,15 @@ namespace osu.Game.Online.API
private string password; private string password;
public Bindable<User> LocalUser { get; } = new Bindable<User>(createGuestUser()); public IBindable<User> LocalUser => localUser;
public IBindableList<User> Friends => friends;
public IBindable<UserActivity> Activity => activity;
public Bindable<UserActivity> Activity { get; } = new Bindable<UserActivity>(); private Bindable<User> localUser { get; } = new Bindable<User>(createGuestUser());
private BindableList<User> friends { get; } = new BindableList<User>();
private Bindable<UserActivity> activity { get; } = new Bindable<UserActivity>();
protected bool HasLogin => authentication.Token.Value != null || (!string.IsNullOrEmpty(ProvidedUsername) && !string.IsNullOrEmpty(password)); protected bool HasLogin => authentication.Token.Value != null || (!string.IsNullOrEmpty(ProvidedUsername) && !string.IsNullOrEmpty(password));
@ -61,10 +67,10 @@ namespace osu.Game.Online.API
authentication.TokenString = config.Get<string>(OsuSetting.Token); authentication.TokenString = config.Get<string>(OsuSetting.Token);
authentication.Token.ValueChanged += onTokenChanged; authentication.Token.ValueChanged += onTokenChanged;
LocalUser.BindValueChanged(u => localUser.BindValueChanged(u =>
{ {
u.OldValue?.Activity.UnbindFrom(Activity); u.OldValue?.Activity.UnbindFrom(activity);
u.NewValue.Activity.BindTo(Activity); u.NewValue.Activity.BindTo(activity);
}, true); }, true);
var thread = new Thread(run) var thread = new Thread(run)
@ -134,23 +140,37 @@ namespace osu.Game.Online.API
} }
var userReq = new GetUserRequest(); var userReq = new GetUserRequest();
userReq.Success += u => userReq.Success += u =>
{ {
LocalUser.Value = u; localUser.Value = u;
// todo: save/pull from settings // todo: save/pull from settings
LocalUser.Value.Status.Value = new UserStatusOnline(); localUser.Value.Status.Value = new UserStatusOnline();
failureCount = 0; failureCount = 0;
};
if (!handleRequest(userReq))
{
failConnectionProcess();
continue;
}
// getting user's friends is considered part of the connection process.
var friendsReq = new GetFriendsRequest();
friendsReq.Success += res =>
{
friends.AddRange(res);
//we're connected! //we're connected!
state.Value = APIState.Online; state.Value = APIState.Online;
}; };
if (!handleRequest(userReq)) if (!handleRequest(friendsReq))
{ {
if (State.Value == APIState.Connecting) failConnectionProcess();
state.Value = APIState.Failing;
continue; continue;
} }
@ -186,6 +206,13 @@ namespace osu.Game.Online.API
Thread.Sleep(50); Thread.Sleep(50);
} }
void failConnectionProcess()
{
// if something went wrong during the connection process, we want to reset the state (but only if still connecting).
if (State.Value == APIState.Connecting)
state.Value = APIState.Failing;
}
} }
public void Perform(APIRequest request) public void Perform(APIRequest request)
@ -322,7 +349,7 @@ namespace osu.Game.Online.API
return true; return true;
} }
public bool IsLoggedIn => LocalUser.Value.Id > 1; public bool IsLoggedIn => localUser.Value.Id > 1;
public void Queue(APIRequest request) public void Queue(APIRequest request)
{ {
@ -352,8 +379,12 @@ namespace osu.Game.Online.API
password = null; password = null;
authentication.Clear(); authentication.Clear();
// Scheduled prior to state change such that the state changed event is invoked with the correct user present // Scheduled prior to state change such that the state changed event is invoked with the correct user and their friends present
Schedule(() => LocalUser.Value = createGuestUser()); Schedule(() =>
{
localUser.Value = createGuestUser();
friends.Clear();
});
state.Value = APIState.Offline; state.Value = APIState.Offline;
} }

View File

@ -18,6 +18,8 @@ namespace osu.Game.Online.API
Id = 1001, Id = 1001,
}); });
public BindableList<User> Friends { get; } = new BindableList<User>();
public Bindable<UserActivity> Activity { get; } = new Bindable<UserActivity>(); public Bindable<UserActivity> Activity { get; } = new Bindable<UserActivity>();
public string AccessToken => "token"; public string AccessToken => "token";
@ -86,5 +88,9 @@ namespace osu.Game.Online.API
} }
public void SetState(APIState newState) => state.Value = newState; public void SetState(APIState newState) => state.Value = newState;
IBindable<User> IAPIProvider.LocalUser => LocalUser;
IBindableList<User> IAPIProvider.Friends => Friends;
IBindable<UserActivity> IAPIProvider.Activity => Activity;
} }
} }

View File

@ -13,13 +13,19 @@ namespace osu.Game.Online.API
/// The local user. /// The local user.
/// This is not thread-safe and should be scheduled locally if consumed from a drawable component. /// This is not thread-safe and should be scheduled locally if consumed from a drawable component.
/// </summary> /// </summary>
Bindable<User> LocalUser { get; } IBindable<User> LocalUser { get; }
/// <summary>
/// The user's friends.
/// This is not thread-safe and should be scheduled locally if consumed from a drawable component.
/// </summary>
IBindableList<User> Friends { get; }
/// <summary> /// <summary>
/// The current user's activity. /// The current user's activity.
/// This is not thread-safe and should be scheduled locally if consumed from a drawable component. /// This is not thread-safe and should be scheduled locally if consumed from a drawable component.
/// </summary> /// </summary>
Bindable<UserActivity> Activity { get; } IBindable<UserActivity> Activity { get; }
/// <summary> /// <summary>
/// Retrieve the OAuth access token. /// Retrieve the OAuth access token.

View File

@ -51,7 +51,6 @@ using osu.Game.Screens.Select;
using osu.Game.Updater; using osu.Game.Updater;
using osu.Game.Utils; using osu.Game.Utils;
using LogLevel = osu.Framework.Logging.LogLevel; using LogLevel = osu.Framework.Logging.LogLevel;
using osu.Game.Users;
using System.IO; using System.IO;
namespace osu.Game namespace osu.Game
@ -976,7 +975,7 @@ namespace osu.Game
if (newScreen is IOsuScreen newOsuScreen) if (newScreen is IOsuScreen newOsuScreen)
{ {
OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode); OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode);
((IBindable<UserActivity>)API.Activity).BindTo(newOsuScreen.Activity); API.Activity.BindTo(newOsuScreen.Activity);
MusicController.AllowRateAdjustments = newOsuScreen.AllowRateAdjustments; MusicController.AllowRateAdjustments = newOsuScreen.AllowRateAdjustments;

View File

@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
private PostBeatmapFavouriteRequest request; private PostBeatmapFavouriteRequest request;
private LoadingLayer loading; private LoadingLayer loading;
private readonly Bindable<User> localUser = new Bindable<User>(); private readonly IBindable<User> localUser = new Bindable<User>();
public string TooltipText public string TooltipText
{ {

View File

@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>(); public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>(); private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private readonly Bindable<BeatmapLeaderboardScope> scope = new Bindable<BeatmapLeaderboardScope>(BeatmapLeaderboardScope.Global); private readonly Bindable<BeatmapLeaderboardScope> scope = new Bindable<BeatmapLeaderboardScope>(BeatmapLeaderboardScope.Global);
private readonly Bindable<User> user = new Bindable<User>(); private readonly IBindable<User> user = new Bindable<User>();
private readonly Box background; private readonly Box background;
private readonly ScoreTable scoreTable; private readonly ScoreTable scoreTable;

View File

@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Comments
public readonly Bindable<CommentsSortCriteria> Sort = new Bindable<CommentsSortCriteria>(); public readonly Bindable<CommentsSortCriteria> Sort = new Bindable<CommentsSortCriteria>();
public readonly BindableBool ShowDeleted = new BindableBool(); public readonly BindableBool ShowDeleted = new BindableBool();
protected readonly Bindable<User> User = new Bindable<User>(); protected readonly IBindable<User> User = new Bindable<User>();
[Resolved] [Resolved]
private IAPIProvider api { get; set; } private IAPIProvider api { get; set; }

View File

@ -5,18 +5,18 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Users; using osu.Game.Users;
using osuTK; using osuTK;
namespace osu.Game.Overlays.Dashboard.Friends namespace osu.Game.Overlays.Dashboard.Friends
{ {
public class FriendDisplay : OverlayView<List<User>> public class FriendDisplay : CompositeDrawable
{ {
private List<User> users = new List<User>(); private List<User> users = new List<User>();
@ -41,8 +41,16 @@ namespace osu.Game.Overlays.Dashboard.Friends
private Container itemsPlaceholder; private Container itemsPlaceholder;
private LoadingLayer loading; private LoadingLayer loading;
[BackgroundDependencyLoader] private readonly IBindableList<User> apiFriends = new BindableList<User>();
private void load(OverlayColourProvider colourProvider)
public FriendDisplay()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
}
[BackgroundDependencyLoader(true)]
private void load(OverlayColourProvider colourProvider, IAPIProvider api)
{ {
InternalChild = new FillFlowContainer InternalChild = new FillFlowContainer
{ {
@ -132,6 +140,9 @@ namespace osu.Game.Overlays.Dashboard.Friends
background.Colour = colourProvider.Background4; background.Colour = colourProvider.Background4;
controlBackground.Colour = colourProvider.Background5; controlBackground.Colour = colourProvider.Background5;
apiFriends.BindTo(api.Friends);
apiFriends.BindCollectionChanged((_, __) => Schedule(() => Users = apiFriends.ToList()), true);
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -143,13 +154,6 @@ namespace osu.Game.Overlays.Dashboard.Friends
userListToolbar.SortCriteria.BindValueChanged(_ => recreatePanels()); userListToolbar.SortCriteria.BindValueChanged(_ => recreatePanels());
} }
protected override APIRequest<List<User>> CreateRequest() => new GetFriendsRequest();
protected override void OnSuccess(List<User> response)
{
Users = response;
}
private void recreatePanels() private void recreatePanels()
{ {
if (!users.Any()) if (!users.Any())

View File

@ -50,6 +50,8 @@ namespace osu.Game.Overlays.Profile.Header.Components
} }
}; };
// todo: when friending/unfriending is implemented, the APIAccess.Friends list should be updated accordingly.
User.BindValueChanged(user => updateFollowers(user.NewValue), true); User.BindValueChanged(user => updateFollowers(user.NewValue), true);
} }

View File

@ -22,7 +22,7 @@ namespace osu.Game.Screens.Backgrounds
private int currentDisplay; private int currentDisplay;
private const int background_count = 7; private const int background_count = 7;
private Bindable<User> user; private IBindable<User> user;
private Bindable<Skin> skin; private Bindable<Skin> skin;
private Bindable<BackgroundSource> mode; private Bindable<BackgroundSource> mode;
private Bindable<IntroSequence> introSequence; private Bindable<IntroSequence> introSequence;

View File

@ -147,7 +147,7 @@ namespace osu.Game.Screens.Menu
if (nextScreen != null) if (nextScreen != null)
LoadComponentAsync(nextScreen); LoadComponentAsync(nextScreen);
currentUser.BindTo(api.LocalUser); ((IBindable<User>)currentUser).BindTo(api.LocalUser);
} }
public override void OnEntering(IScreen last) public override void OnEntering(IScreen last)

View File

@ -12,7 +12,7 @@ namespace osu.Game.Screens.Menu
{ {
internal class MenuLogoVisualisation : LogoVisualisation internal class MenuLogoVisualisation : LogoVisualisation
{ {
private Bindable<User> user; private IBindable<User> user;
private Bindable<Skin> skin; private Bindable<Skin> skin;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -35,7 +35,7 @@ namespace osu.Game.Screens.Menu
private const double box_fade_in_time = 65; private const double box_fade_in_time = 65;
private const int box_width = 200; private const int box_width = 200;
private Bindable<User> user; private IBindable<User> user;
private Bindable<Skin> skin; private Bindable<Skin> skin;
[Resolved] [Resolved]