diff --git a/osu.Game/Overlays/News/Displays/ArticleListing.cs b/osu.Game/Overlays/News/Displays/ArticleListing.cs index b49326a1f1..dc3b17b323 100644 --- a/osu.Game/Overlays/News/Displays/ArticleListing.cs +++ b/osu.Game/Overlays/News/Displays/ArticleListing.cs @@ -2,14 +2,13 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osuTK; @@ -20,26 +19,16 @@ namespace osu.Game.Overlays.News.Displays /// public class ArticleListing : CompositeDrawable { - public Action SidebarMetadataUpdated; - - [Resolved] - private IAPIProvider api { get; set; } + private readonly Action fetchMorePosts; private FillFlowContainer content; private ShowMoreButton showMore; - private GetNewsRequest request; - private Cursor lastCursor; + private CancellationTokenSource cancellationToken; - private readonly int? year; - - /// - /// Instantiate a listing for the specified year. - /// - /// The year to load articles from. If null, will show the most recent articles. - public ArticleListing(int? year = null) + public ArticleListing(Action fetchMorePosts) { - this.year = year; + this.fetchMorePosts = fetchMorePosts; } [BackgroundDependencyLoader] @@ -47,6 +36,7 @@ namespace osu.Game.Overlays.News.Displays { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + Padding = new MarginPadding { Vertical = 20, @@ -75,53 +65,25 @@ namespace osu.Game.Overlays.News.Displays { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Margin = new MarginPadding - { - Top = 15 - }, - Action = performFetch, + Margin = new MarginPadding { Top = 15 }, + Action = fetchMorePosts, Alpha = 0 } } }; - - performFetch(); } - private void performFetch() - { - request?.Cancel(); - - request = new GetNewsRequest(year, lastCursor); - request.Success += response => Schedule(() => onSuccess(response)); - api.PerformAsync(request); - } - - private CancellationTokenSource cancellationToken; - - private void onSuccess(GetNewsResponse response) - { - cancellationToken?.Cancel(); - - // only needs to be updated on the initial load, as the content won't change during pagination. - if (lastCursor == null) - SidebarMetadataUpdated?.Invoke(response.SidebarMetadata); - - // store cursor for next pagination request. - lastCursor = response.Cursor; - - LoadComponentsAsync(response.NewsPosts.Select(p => new NewsCard(p)).ToList(), loaded => + public void AddPosts(IEnumerable posts, bool morePostsAvailable) => Schedule(() => + LoadComponentsAsync(posts.Select(p => new NewsCard(p)).ToList(), loaded => { content.AddRange(loaded); - showMore.IsLoading = false; - showMore.Alpha = response.Cursor != null ? 1 : 0; - }, (cancellationToken = new CancellationTokenSource()).Token); - } + showMore.Alpha = morePostsAvailable ? 1 : 0; + }, (cancellationToken = new CancellationTokenSource()).Token) + ); protected override void Dispose(bool isDisposing) { - request?.Cancel(); cancellationToken?.Cancel(); base.Dispose(isDisposing); } diff --git a/osu.Game/Overlays/NewsOverlay.cs b/osu.Game/Overlays/NewsOverlay.cs index dd6de40ecb..12e3f81ca1 100644 --- a/osu.Game/Overlays/NewsOverlay.cs +++ b/osu.Game/Overlays/NewsOverlay.cs @@ -6,6 +6,7 @@ using System.Threading; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Online.API.Requests; using osu.Game.Overlays.News; using osu.Game.Overlays.News.Displays; using osu.Game.Overlays.News.Sidebar; @@ -14,13 +15,21 @@ namespace osu.Game.Overlays { public class NewsOverlay : OnlineOverlay { - private readonly Bindable article = new Bindable(null); + private readonly Bindable article = new Bindable(); private readonly Container sidebarContainer; private readonly NewsSidebar sidebar; - private readonly Container content; + private GetNewsRequest request; + + private Cursor lastCursor; + + /// + /// The year currently being displayed. If null, the main listing is being displayed. + /// + private int? displayedYear; + private CancellationTokenSource cancellationToken; private bool displayUpdateRequired = true; @@ -65,7 +74,13 @@ namespace osu.Game.Overlays base.LoadComplete(); // should not be run until first pop-in to avoid requesting data before user views. - article.BindValueChanged(onArticleChanged); + article.BindValueChanged(a => + { + if (a.NewValue == null) + loadListing(); + else + loadArticle(a.NewValue); + }); } protected override NewsHeader CreateHeader() => new NewsHeader { ShowFrontPage = ShowFrontPage }; @@ -95,7 +110,7 @@ namespace osu.Game.Overlays public void ShowYear(int year) { - loadFrontPage(year); + loadListing(year); Show(); } @@ -108,7 +123,11 @@ namespace osu.Game.Overlays protected void LoadDisplay(Drawable display) { ScrollFlow.ScrollToStart(); - LoadComponentAsync(display, loaded => content.Child = loaded, (cancellationToken = new CancellationTokenSource()).Token); + LoadComponentAsync(display, loaded => + { + content.Child = loaded; + Loading.Hide(); + }, (cancellationToken = new CancellationTokenSource()).Token); } protected override void UpdateAfterChildren() @@ -118,48 +137,65 @@ namespace osu.Game.Overlays sidebarContainer.Y = Math.Clamp(ScrollFlow.Current - Header.DrawHeight, 0, Math.Max(ScrollFlow.ScrollContent.DrawHeight - DrawHeight - Header.DrawHeight, 0)); } - private void onArticleChanged(ValueChangedEvent article) + private void loadListing(int? year = null) { - if (article.NewValue == null) - loadFrontPage(); - else - loadArticle(article.NewValue); - } - - private void loadFrontPage(int? year = null) - { - beginLoading(); - Header.SetFrontPage(); - var page = new ArticleListing(year); - page.SidebarMetadataUpdated += metadata => Schedule(() => + displayedYear = year; + lastCursor = null; + + beginLoading(true); + + request = new GetNewsRequest(displayedYear); + request.Success += response => Schedule(() => { - sidebar.Metadata.Value = metadata; - Loading.Hide(); + lastCursor = response.Cursor; + sidebar.Metadata.Value = response.SidebarMetadata; + + var listing = new ArticleListing(getMorePosts); + listing.AddPosts(response.NewsPosts, response.Cursor != null); + LoadDisplay(listing); }); - LoadDisplay(page); + + API.PerformAsync(request); + } + + private void getMorePosts() + { + beginLoading(false); + + request = new GetNewsRequest(displayedYear, lastCursor); + request.Success += response => Schedule(() => + { + lastCursor = response.Cursor; + if (content.Child is ArticleListing listing) + listing.AddPosts(response.NewsPosts, response.Cursor != null); + }); + + API.PerformAsync(request); } private void loadArticle(string article) { - beginLoading(); + // This is not yet implemented nor called from anywhere. + beginLoading(true); Header.SetArticle(article); - - // Temporary, should be handled by ArticleDisplay later LoadDisplay(Empty()); - Loading.Hide(); } - private void beginLoading() + private void beginLoading(bool showLoadingOverlay) { + request?.Cancel(); cancellationToken?.Cancel(); - Loading.Show(); + + if (showLoadingOverlay) + Loading.Show(); } protected override void Dispose(bool isDisposing) { + request?.Cancel(); cancellationToken?.Cancel(); base.Dispose(isDisposing); }