From 78ce6f1cd21e81858f7f923dab907e52dde020e9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 17 Dec 2020 13:30:55 +0300 Subject: [PATCH 01/13] Add friends list to API providers --- osu.Game/Online/API/APIAccess.cs | 14 ++++++++++++-- osu.Game/Online/API/DummyAPIAccess.cs | 7 +++++++ osu.Game/Online/API/IAPIProvider.cs | 6 ++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index b916339a53..f084f6f2c7 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -41,6 +41,8 @@ namespace osu.Game.Online.API public Bindable LocalUser { get; } = new Bindable(createGuestUser()); + public BindableList Friends { get; } = new BindableList(); + public Bindable Activity { get; } = new Bindable(); protected bool HasLogin => authentication.Token.Value != null || (!string.IsNullOrEmpty(ProvidedUsername) && !string.IsNullOrEmpty(password)); @@ -143,6 +145,10 @@ namespace osu.Game.Online.API failureCount = 0; + var friendsReq = new GetFriendsRequest(); + friendsReq.Success += f => Friends.AddRange(f); + handleRequest(friendsReq); + //we're connected! state.Value = APIState.Online; }; @@ -352,8 +358,12 @@ namespace osu.Game.Online.API password = null; authentication.Clear(); - // Scheduled prior to state change such that the state changed event is invoked with the correct user present - Schedule(() => LocalUser.Value = createGuestUser()); + // 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(); + Friends.Clear(); + }); state.Value = APIState.Offline; } diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index e275676cea..7e5a6378ec 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -5,6 +5,7 @@ using System; using System.Threading; using System.Threading.Tasks; using osu.Framework.Bindables; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Game.Users; @@ -18,6 +19,12 @@ namespace osu.Game.Online.API Id = 1001, }); + public BindableList Friends { get; } = new BindableList(new User + { + Username = @"Dummy's friend", + Id = 2002, + }.Yield()); + public Bindable Activity { get; } = new Bindable(); public string AccessToken => "token"; diff --git a/osu.Game/Online/API/IAPIProvider.cs b/osu.Game/Online/API/IAPIProvider.cs index cadc806f4f..3f62b37a48 100644 --- a/osu.Game/Online/API/IAPIProvider.cs +++ b/osu.Game/Online/API/IAPIProvider.cs @@ -15,6 +15,12 @@ namespace osu.Game.Online.API /// Bindable LocalUser { get; } + /// + /// The user's friends. + /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. + /// + BindableList Friends { get; } + /// /// The current user's activity. /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. From 449b9a21aefe912280728fd621fe11c782fbdb28 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 17 Dec 2020 13:31:57 +0300 Subject: [PATCH 02/13] Allow OverlayView fetching with no API requests required --- osu.Game/Overlays/OverlayView.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/OverlayView.cs b/osu.Game/Overlays/OverlayView.cs index c254cdf290..f5ef183bd5 100644 --- a/osu.Game/Overlays/OverlayView.cs +++ b/osu.Game/Overlays/OverlayView.cs @@ -42,25 +42,29 @@ namespace osu.Game.Overlays /// /// Create the API request for fetching data. /// - protected abstract APIRequest CreateRequest(); + protected virtual APIRequest CreateRequest() => null; /// /// Fired when results arrive from the main API request. /// /// - protected abstract void OnSuccess(T response); + protected virtual void OnSuccess(T response) + { + } /// /// Force a re-request for data from the API. /// - protected void PerformFetch() + protected virtual void PerformFetch() { request?.Cancel(); - request = CreateRequest(); - request.Success += response => Schedule(() => OnSuccess(response)); - API.Queue(request); + if (request != null) + { + request.Success += response => Schedule(() => OnSuccess(response)); + API.Queue(request); + } } private void onlineStateChanged(ValueChangedEvent state) => Schedule(() => From 94175d053289d944765c24d3e486f402929692e0 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 17 Dec 2020 13:33:17 +0300 Subject: [PATCH 03/13] Use global friends list instead of always fetching --- osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs index 41b25ee1a5..8a8ac36e14 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs @@ -9,8 +9,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; using osu.Game.Users; using osuTK; @@ -143,11 +141,11 @@ namespace osu.Game.Overlays.Dashboard.Friends userListToolbar.SortCriteria.BindValueChanged(_ => recreatePanels()); } - protected override APIRequest> CreateRequest() => new GetFriendsRequest(); - - protected override void OnSuccess(List response) + protected override void PerformFetch() { - Users = response; + base.PerformFetch(); + + Users = API.Friends.ToList(); } private void recreatePanels() From 904a4daa985b8f5e37573520a9147ad9adb80167 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 17 Dec 2020 13:33:49 +0300 Subject: [PATCH 04/13] Add todo comment reminding of updating friends list along --- osu.Game/Overlays/Profile/Header/Components/AddFriendButton.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Profile/Header/Components/AddFriendButton.cs b/osu.Game/Overlays/Profile/Header/Components/AddFriendButton.cs index 6e1b6e2c7d..6c2b2dc16a 100644 --- a/osu.Game/Overlays/Profile/Header/Components/AddFriendButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/AddFriendButton.cs @@ -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); } From 5d180753fa3cbc40971c867e5d1b36cdf1484306 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 17 Dec 2020 13:44:30 +0300 Subject: [PATCH 05/13] Complete connection once friends list is succesfully fetched --- osu.Game/Online/API/APIAccess.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index f084f6f2c7..806a42a38b 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -146,11 +146,15 @@ namespace osu.Game.Online.API failureCount = 0; var friendsReq = new GetFriendsRequest(); - friendsReq.Success += f => Friends.AddRange(f); - handleRequest(friendsReq); + friendsReq.Success += f => + { + Friends.AddRange(f); - //we're connected! - state.Value = APIState.Online; + //we're connected! + state.Value = APIState.Online; + }; + + handleRequest(friendsReq); }; if (!handleRequest(userReq)) From 5e4f667cffac3ce6f4bfb108b29697e8fea9ba40 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Dec 2020 01:27:58 +0300 Subject: [PATCH 06/13] Revert "Allow OverlayView fetching with no API requests required" This reverts commit 449b9a21aefe912280728fd621fe11c782fbdb28. --- osu.Game/Overlays/OverlayView.cs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/OverlayView.cs b/osu.Game/Overlays/OverlayView.cs index f5ef183bd5..c254cdf290 100644 --- a/osu.Game/Overlays/OverlayView.cs +++ b/osu.Game/Overlays/OverlayView.cs @@ -42,29 +42,25 @@ namespace osu.Game.Overlays /// /// Create the API request for fetching data. /// - protected virtual APIRequest CreateRequest() => null; + protected abstract APIRequest CreateRequest(); /// /// Fired when results arrive from the main API request. /// /// - protected virtual void OnSuccess(T response) - { - } + protected abstract void OnSuccess(T response); /// /// Force a re-request for data from the API. /// - protected virtual void PerformFetch() + protected void PerformFetch() { request?.Cancel(); - request = CreateRequest(); - if (request != null) - { - request.Success += response => Schedule(() => OnSuccess(response)); - API.Queue(request); - } + request = CreateRequest(); + request.Success += response => Schedule(() => OnSuccess(response)); + + API.Queue(request); } private void onlineStateChanged(ValueChangedEvent state) => Schedule(() => From 9c22753f3fb23f94a19b3870d7cc1e46638e616e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Dec 2020 02:51:19 +0300 Subject: [PATCH 07/13] Remove unnecessary inheritance to OverlayView --- .../Visual/Online/TestSceneFriendDisplay.cs | 11 +++----- .../Dashboard/Friends/FriendDisplay.cs | 26 ++++++++++++------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs index 0cc6e9f358..9bece39ca0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs @@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); - private TestFriendDisplay display; + private FriendDisplay display; [SetUp] public void Setup() => Schedule(() => @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual.Online Child = new BasicScrollContainer { RelativeSizeAxes = Axes.Both, - Child = display = new TestFriendDisplay() + Child = display = new FriendDisplay() }; }); @@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestOnline() { - AddStep("Fetch online", () => display?.Fetch()); + // No need to do anything, fetch is performed automatically. } private List getUsers() => new List @@ -76,10 +76,5 @@ namespace osu.Game.Tests.Visual.Online LastVisit = DateTimeOffset.Now } }; - - private class TestFriendDisplay : FriendDisplay - { - public void Fetch() => PerformFetch(); - } } } diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs index 8a8ac36e14..cc26a11da1 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs @@ -5,16 +5,18 @@ 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.Game.Graphics.UserInterface; +using osu.Game.Online.API; using osu.Game.Users; using osuTK; namespace osu.Game.Overlays.Dashboard.Friends { - public class FriendDisplay : OverlayView> + public class FriendDisplay : CompositeDrawable { private List users = new List(); @@ -39,8 +41,16 @@ namespace osu.Game.Overlays.Dashboard.Friends private Container itemsPlaceholder; private LoadingLayer loading; - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private readonly IBindableList apiFriends = new BindableList(); + + public FriendDisplay() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader(true)] + private void load(OverlayColourProvider colourProvider, IAPIProvider api) { InternalChild = new FillFlowContainer { @@ -130,6 +140,9 @@ namespace osu.Game.Overlays.Dashboard.Friends background.Colour = colourProvider.Background4; controlBackground.Colour = colourProvider.Background5; + + apiFriends.BindTo(api.Friends); + apiFriends.BindCollectionChanged((_, __) => Schedule(() => Users = apiFriends.ToList()), true); } protected override void LoadComplete() @@ -141,13 +154,6 @@ namespace osu.Game.Overlays.Dashboard.Friends userListToolbar.SortCriteria.BindValueChanged(_ => recreatePanels()); } - protected override void PerformFetch() - { - base.PerformFetch(); - - Users = API.Friends.ToList(); - } - private void recreatePanels() { if (!users.Any()) From 8a01e567a146d71405b8feeb7bfd7d532569b000 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 18 Dec 2020 03:06:28 +0300 Subject: [PATCH 08/13] Fix API potentially getting stuck in connecting state --- osu.Game/Online/API/APIAccess.cs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 806a42a38b..b42c78e9cd 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -145,16 +145,14 @@ namespace osu.Game.Online.API failureCount = 0; - var friendsReq = new GetFriendsRequest(); - friendsReq.Success += f => + fetchFriends(() => { - Friends.AddRange(f); - //we're connected! state.Value = APIState.Online; - }; - - handleRequest(friendsReq); + }, () => + { + state.Value = APIState.Failing; + }); }; if (!handleRequest(userReq)) @@ -255,6 +253,19 @@ namespace osu.Game.Online.API return null; } + private void fetchFriends(Action onSuccess, Action onFail) + { + var friendsReq = new GetFriendsRequest(); + friendsReq.Success += res => + { + Friends.AddRange(res); + onSuccess?.Invoke(); + }; + + if (!handleRequest(friendsReq)) + onFail?.Invoke(); + } + /// /// Handle a single API request. /// Ensures all exceptions are caught and dealt with correctly. From 206bf3713ed2af58b97b55489783848728934dde Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 15:16:36 +0900 Subject: [PATCH 09/13] Make IAPIProvider read-only bindables into IBindables --- osu.Desktop/DiscordRichPresence.cs | 2 +- .../Visual/Menus/TestSceneDisclaimer.cs | 3 ++- .../Online/TestSceneAccountCreationOverlay.cs | 2 +- .../Online/TestSceneNowPlayingCommand.cs | 11 +++++--- osu.Game/Online/API/APIAccess.cs | 26 +++++++++++-------- osu.Game/Online/API/DummyAPIAccess.cs | 4 +++ osu.Game/Online/API/IAPIProvider.cs | 6 ++--- osu.Game/OsuGame.cs | 3 +-- .../BeatmapSet/Buttons/FavouriteButton.cs | 2 +- .../BeatmapSet/Scores/ScoresContainer.cs | 2 +- .../Overlays/Comments/CommentsContainer.cs | 2 +- .../Backgrounds/BackgroundScreenDefault.cs | 2 +- osu.Game/Screens/Menu/Disclaimer.cs | 2 +- .../Screens/Menu/MenuLogoVisualisation.cs | 2 +- osu.Game/Screens/Menu/MenuSideFlashes.cs | 2 +- 15 files changed, 41 insertions(+), 30 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 26d7402a5b..f1878d967d 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -26,7 +26,7 @@ namespace osu.Desktop [Resolved] private IBindable ruleset { get; set; } - private Bindable user; + private IBindable user; private readonly IBindable status = new Bindable(); private readonly IBindable activity = new Bindable(); diff --git a/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs b/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs index 49fab08ded..9cbdee3632 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Game.Online.API; using osu.Game.Screens.Menu; using osu.Game.Users; @@ -16,7 +17,7 @@ namespace osu.Game.Tests.Visual.Menus AddStep("toggle support", () => { - API.LocalUser.Value = new User + ((DummyAPIAccess)API).LocalUser.Value = new User { Username = API.LocalUser.Value.Username, Id = API.LocalUser.Value.Id + 1, diff --git a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs index 6c8ec917ba..dcfe0432a8 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs @@ -14,7 +14,7 @@ namespace osu.Game.Tests.Visual.Online { private readonly Container userPanelArea; - private Bindable localUser; + private IBindable localUser; public TestSceneAccountCreationOverlay() { diff --git a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs index 8e151a987a..0324da6cf5 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Online.API; using osu.Game.Online.Chat; using osu.Game.Rulesets; using osu.Game.Users; @@ -18,6 +19,8 @@ namespace osu.Game.Tests.Visual.Online [Cached(typeof(IChannelPostTarget))] private PostTarget postTarget { get; set; } + private DummyAPIAccess api => (DummyAPIAccess)API; + public TestSceneNowPlayingCommand() { Add(postTarget = new PostTarget()); @@ -26,7 +29,7 @@ namespace osu.Game.Tests.Visual.Online [Test] 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())); @@ -36,7 +39,7 @@ namespace osu.Game.Tests.Visual.Online [Test] 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())); @@ -46,7 +49,7 @@ namespace osu.Game.Tests.Visual.Online [Test] 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())); @@ -57,7 +60,7 @@ namespace osu.Game.Tests.Visual.Online [TestCase(false)] 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) { diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index b42c78e9cd..b96475d5bf 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -39,11 +39,15 @@ namespace osu.Game.Online.API private string password; - public Bindable LocalUser { get; } = new Bindable(createGuestUser()); + public IBindable LocalUser => localUser; + public IBindableList Friends => friends; + public IBindable Activity => activity; - public BindableList Friends { get; } = new BindableList(); + private Bindable localUser { get; } = new Bindable(createGuestUser()); - public Bindable Activity { get; } = new Bindable(); + private BindableList friends { get; } = new BindableList(); + + private Bindable activity { get; } = new Bindable(); protected bool HasLogin => authentication.Token.Value != null || (!string.IsNullOrEmpty(ProvidedUsername) && !string.IsNullOrEmpty(password)); @@ -63,10 +67,10 @@ namespace osu.Game.Online.API authentication.TokenString = config.Get(OsuSetting.Token); authentication.Token.ValueChanged += onTokenChanged; - LocalUser.BindValueChanged(u => + localUser.BindValueChanged(u => { - u.OldValue?.Activity.UnbindFrom(Activity); - u.NewValue.Activity.BindTo(Activity); + u.OldValue?.Activity.UnbindFrom(activity); + u.NewValue.Activity.BindTo(activity); }, true); var thread = new Thread(run) @@ -138,10 +142,10 @@ namespace osu.Game.Online.API var userReq = new GetUserRequest(); userReq.Success += u => { - LocalUser.Value = u; + localUser.Value = u; // todo: save/pull from settings - LocalUser.Value.Status.Value = new UserStatusOnline(); + localUser.Value.Status.Value = new UserStatusOnline(); failureCount = 0; @@ -343,7 +347,7 @@ namespace osu.Game.Online.API return true; } - public bool IsLoggedIn => LocalUser.Value.Id > 1; + public bool IsLoggedIn => localUser.Value.Id > 1; public void Queue(APIRequest request) { @@ -376,8 +380,8 @@ namespace osu.Game.Online.API // 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(); - Friends.Clear(); + localUser.Value = createGuestUser(); + friends.Clear(); }); state.Value = APIState.Offline; diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index 7e5a6378ec..a0bc8dd9d6 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -93,5 +93,9 @@ namespace osu.Game.Online.API } public void SetState(APIState newState) => state.Value = newState; + + IBindable IAPIProvider.LocalUser => LocalUser; + IBindableList IAPIProvider.Friends => Friends; + IBindable IAPIProvider.Activity => Activity; } } diff --git a/osu.Game/Online/API/IAPIProvider.cs b/osu.Game/Online/API/IAPIProvider.cs index 3f62b37a48..3a444460f2 100644 --- a/osu.Game/Online/API/IAPIProvider.cs +++ b/osu.Game/Online/API/IAPIProvider.cs @@ -13,19 +13,19 @@ namespace osu.Game.Online.API /// The local user. /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. /// - Bindable LocalUser { get; } + IBindable LocalUser { get; } /// /// The user's friends. /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. /// - BindableList Friends { get; } + IBindableList Friends { get; } /// /// The current user's activity. /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. /// - Bindable Activity { get; } + IBindable Activity { get; } /// /// Retrieve the OAuth access token. diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index d67d790ce2..1e342fa464 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -51,7 +51,6 @@ using osu.Game.Screens.Select; using osu.Game.Updater; using osu.Game.Utils; using LogLevel = osu.Framework.Logging.LogLevel; -using osu.Game.Users; using System.IO; namespace osu.Game @@ -976,7 +975,7 @@ namespace osu.Game if (newScreen is IOsuScreen newOsuScreen) { OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode); - ((IBindable)API.Activity).BindTo(newOsuScreen.Activity); + API.Activity.BindTo(newOsuScreen.Activity); MusicController.AllowRateAdjustments = newOsuScreen.AllowRateAdjustments; diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs index 742b1055b2..c983b337b5 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private PostBeatmapFavouriteRequest request; private LoadingLayer loading; - private readonly Bindable localUser = new Bindable(); + private readonly IBindable localUser = new Bindable(); public string TooltipText { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index a58d662de7..9a2dcd014a 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores public readonly Bindable Beatmap = new Bindable(); private readonly Bindable ruleset = new Bindable(); private readonly Bindable scope = new Bindable(BeatmapLeaderboardScope.Global); - private readonly Bindable user = new Bindable(); + private readonly IBindable user = new Bindable(); private readonly Box background; private readonly ScoreTable scoreTable; diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 2a78748be6..513fabf52a 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Comments public readonly Bindable Sort = new Bindable(); public readonly BindableBool ShowDeleted = new BindableBool(); - protected readonly Bindable User = new Bindable(); + protected readonly IBindable User = new Bindable(); [Resolved] private IAPIProvider api { get; set; } diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index 8beb955824..bd4577fd57 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Backgrounds private int currentDisplay; private const int background_count = 7; - private Bindable user; + private IBindable user; private Bindable skin; private Bindable mode; private Bindable introSequence; diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 8368047d5a..ceec12c967 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -147,7 +147,7 @@ namespace osu.Game.Screens.Menu if (nextScreen != null) LoadComponentAsync(nextScreen); - currentUser.BindTo(api.LocalUser); + ((IBindable)currentUser).BindTo(api.LocalUser); } public override void OnEntering(IScreen last) diff --git a/osu.Game/Screens/Menu/MenuLogoVisualisation.cs b/osu.Game/Screens/Menu/MenuLogoVisualisation.cs index 92add458f9..c44beeffa5 100644 --- a/osu.Game/Screens/Menu/MenuLogoVisualisation.cs +++ b/osu.Game/Screens/Menu/MenuLogoVisualisation.cs @@ -12,7 +12,7 @@ namespace osu.Game.Screens.Menu { internal class MenuLogoVisualisation : LogoVisualisation { - private Bindable user; + private IBindable user; private Bindable skin; [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/Menu/MenuSideFlashes.cs b/osu.Game/Screens/Menu/MenuSideFlashes.cs index 2ff8132d47..a1ae4555ed 100644 --- a/osu.Game/Screens/Menu/MenuSideFlashes.cs +++ b/osu.Game/Screens/Menu/MenuSideFlashes.cs @@ -35,7 +35,7 @@ namespace osu.Game.Screens.Menu private const double box_fade_in_time = 65; private const int box_width = 200; - private Bindable user; + private IBindable user; private Bindable skin; [Resolved] From d36169f697ce53809bbec26b44411b28c66f6b0a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 15:16:48 +0900 Subject: [PATCH 10/13] Move friend request to a more understandable place in connection flow --- osu.Game/Online/API/APIAccess.cs | 36 +++++++++++++------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index b96475d5bf..93d913dfad 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -140,6 +140,7 @@ namespace osu.Game.Online.API } var userReq = new GetUserRequest(); + userReq.Success += u => { localUser.Value = u; @@ -148,15 +149,6 @@ namespace osu.Game.Online.API localUser.Value.Status.Value = new UserStatusOnline(); failureCount = 0; - - fetchFriends(() => - { - //we're connected! - state.Value = APIState.Online; - }, () => - { - state.Value = APIState.Failing; - }); }; if (!handleRequest(userReq)) @@ -166,6 +158,19 @@ namespace osu.Game.Online.API 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! + state.Value = APIState.Online; + }; + + if (!handleRequest(friendsReq)) + state.Value = APIState.Failing; // The Success callback event is fired on the main thread, so we should wait for that to run before proceeding. // Without this, we will end up circulating this Connecting loop multiple times and queueing up many web requests // before actually going online. @@ -257,19 +262,6 @@ namespace osu.Game.Online.API return null; } - private void fetchFriends(Action onSuccess, Action onFail) - { - var friendsReq = new GetFriendsRequest(); - friendsReq.Success += res => - { - Friends.AddRange(res); - onSuccess?.Invoke(); - }; - - if (!handleRequest(friendsReq)) - onFail?.Invoke(); - } - /// /// Handle a single API request. /// Ensures all exceptions are caught and dealt with correctly. From 57c5d45c022844e729e11c4236d7fa0b8cc93ed9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 15:19:38 +0900 Subject: [PATCH 11/13] Standardise and extract common connection failure handling logic --- osu.Game/Online/API/APIAccess.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 93d913dfad..fe500b9548 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -153,8 +153,7 @@ namespace osu.Game.Online.API if (!handleRequest(userReq)) { - if (State.Value == APIState.Connecting) - state.Value = APIState.Failing; + failConnectionProcess(); continue; } @@ -170,7 +169,11 @@ namespace osu.Game.Online.API }; if (!handleRequest(friendsReq)) - state.Value = APIState.Failing; + { + failConnectionProcess(); + continue; + } + // The Success callback event is fired on the main thread, so we should wait for that to run before proceeding. // Without this, we will end up circulating this Connecting loop multiple times and queueing up many web requests // before actually going online. @@ -203,6 +206,13 @@ namespace osu.Game.Online.API 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) From 99b670627a847e42ca245923b6e89f70f3a1ea04 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 15:25:12 +0900 Subject: [PATCH 12/13] Remove unused placeholder friend in DummyAPI implementation --- osu.Game/Online/API/DummyAPIAccess.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index a0bc8dd9d6..4e1bc21df3 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -19,11 +19,7 @@ namespace osu.Game.Online.API Id = 1001, }); - public BindableList Friends { get; } = new BindableList(new User - { - Username = @"Dummy's friend", - Id = 2002, - }.Yield()); + public BindableList Friends { get; } = new BindableList(); public Bindable Activity { get; } = new Bindable(); From a749dca20b14a247cb8828cc0171b99be5e6f141 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Dec 2020 15:43:15 +0900 Subject: [PATCH 13/13] Remove left over using statement --- osu.Game/Online/API/DummyAPIAccess.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index 4e1bc21df3..265298270c 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -5,7 +5,6 @@ using System; using System.Threading; using System.Threading.Tasks; using osu.Framework.Bindables; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Game.Users;