/// <summary> /// Fired when the stories come in for a type /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Collector_OnCollectionUpdated(UpdateTypes type, OnCollectionUpdatedArgs <Post> e) { if (e.ChangedItems.Count > 0) { // If we successfully got the post now get the images GetImagesFromPosts(e.ChangedItems, type); } }
private void Collector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs <Post> e) { List <string> newTrendingSubs = new List <string>(); if (e.ChangedItems.Count > 0) { // We got it! Post todaysPost = e.ChangedItems[0]; string selfText = e.ChangedItems[0].Selftext; // Parse out the subreddits. This isn't going to be pretty. // There inst any api to get these right now (that I can find) // so this is the best we have. try { // This is so bad. The only way to really find them is to look for the ## and then ** // I hope they never change this or this will explode so quickly int nextHash = selfText.IndexOf("##"); while (nextHash != -1) { // Find the bold indicator int nextBold = selfText.IndexOf("**", nextHash); if (nextBold == -1) { break; } nextBold += 2; // Find the last bold indicator int endBold = selfText.IndexOf("**", nextBold); if (endBold == -1) { break; } // Get the subreddit string subreddit = selfText.Substring(nextBold, endBold - nextBold); newTrendingSubs.Add(subreddit); // Update the index nextHash = selfText.IndexOf("##", endBold + 2); } } catch (Exception ex) { m_baconMan.MessageMan.DebugDia("failed to parse trending subs post", ex); } } // If we get this far we are going to say this is good enough and set the // time and list. If our parser breaks we don't want to make a ton of requests // constantly. LastTrendingSubs = newTrendingSubs; LastUpdate = DateTime.Now; // Fire the event if we are good or not. If the list is empty that's fine FireReadyEvent(newTrendingSubs); }
private async void Collector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs <Message> e) { await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { // Setup the insert int insertIndex = e.StartingPosition; // Lock the list lock (m_messageList) { // Set up the objects for the UI foreach (Message message in e.ChangedItems) { // Check if we are adding or inserting. bool isReplace = insertIndex < m_messageList.Count; if (isReplace) { if (m_messageList[insertIndex].Id.Equals(message.Id)) { // If the message is the same just update the UI vars m_messageList[insertIndex].Body = message.Body; m_messageList[insertIndex].IsNew = message.IsNew; } else { // Replace the current item m_messageList[insertIndex] = message; } } else { // Add it to the end m_messageList.Add(message); } insertIndex++; } // If it was a fresh update, remove anything past the last story sent. while (e.IsFreshUpdate && m_messageList.Count > e.ChangedItems.Count) { m_messageList.RemoveAt(m_messageList.Count - 1); } } }); }
/// <summary> /// Attempts to prefetch comments. Returns true if it is going, or false it not. /// </summary> /// <returns></returns> public bool PreFetchComments() { // Only attempt to do this once. if (m_attemptedToLoadComments) { return(false); } m_attemptedToLoadComments = true; // Do this in a background thread Task.Run(() => { // Get the comment collector, if we don't want to show a subset don't give it the target comment m_commentCollector = CommentCollector.GetCollector(m_post, App.BaconMan, m_showThreadSubset ? m_targetComment : null); // Sub to collection callbacks for the comments. m_commentCollector.OnCollectionUpdated += CommentCollector_OnCollectionUpdated; m_commentCollector.OnCollectorStateChange += CommentCollector_OnCollectorStateChange; // Request a few comments so we will fill the screen. // If the user scrolls we will get more later. // To fix a bug where reddit doesn't give us the same // comments the first time as the next, we will // #bug #todo because of the "can't ask for more" bug we will // just ask for all of the comments here. if (!m_commentCollector.Update(false, 150)) { // If update returns false it isn't going to update because it has a cache. So just show the // cache. OnCollectionUpdatedArgs <Comment> args = new OnCollectionUpdatedArgs <Comment>() { ChangedItems = m_commentCollector.GetCurrentPosts(), IsFreshUpdate = true, IsInsert = false, StartingPosition = 0 }; CommentCollector_OnCollectionUpdated(null, args); } }); return(true); }
/// <summary> /// Fired when comments are updated /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void CommentCollector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs <Comment> e) { // Jump to the UI thread await global::Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () => { // If this is fresh clear if (e.IsFreshUpdate) { // Remove each individually so we get nice animations while (m_commentList.Count != 0) { m_commentList.RemoveAt(m_commentList.Count - 1); } } // Add the new posts to the end of the list foreach (Comment comment in e.ChangedItems) { m_commentList.Add(comment); } }); }
/// <summary> /// Fired when the comment sort is changed. /// </summary> public void ChangeCommentSort() { // Show loading m_post.FlipViewShowLoadingMoreComments = true; // Do this in a background thread Task.Run(() => { // Kill the current collector if (m_commentCollector != null) { m_commentCollector.OnCollectionUpdated -= CommentCollector_OnCollectionUpdated; m_commentCollector.OnCollectorStateChange -= CommentCollector_OnCollectorStateChange; } m_commentCollector = null; // Get a new collector with the new sort m_commentCollector = new DeferredCollector <Comment>(CommentCollector.GetCollector(m_post, App.BaconMan)); // Sub to collection callbacks for the comments. m_commentCollector.OnCollectionUpdated += CommentCollector_OnCollectionUpdated; m_commentCollector.OnCollectorStateChange += CommentCollector_OnCollectorStateChange; // Force our collector to update. if (!m_commentCollector.LoadAllItems(true, m_post.CurrentCommentShowingCount)) { // If update returns false it isn't going to update because it has a cache. So just show the // cache. OnCollectionUpdatedArgs <Comment> args = new OnCollectionUpdatedArgs <Comment>() { ChangedItems = m_commentCollector.GetCurrentItems(true), IsFreshUpdate = true, IsInsert = false, StartingPosition = 0 }; CommentCollector_OnCollectionUpdated(null, args); } }); }
/// <summary> /// Attempts to prefetch comments. Returns true if it is going, or false it not. /// </summary> /// <returns></returns> public bool PreFetchComments() { // Only attempt to do this once. if (m_attemptedToLoadComments) { return(false); } m_attemptedToLoadComments = true; // Do this in a background thread Task.Run(() => { // Get the comment collector, if we don't want to show a subset don't give it the target comment m_commentCollector = CommentCollector.GetCollector(m_post, App.BaconMan, m_showThreadSubset ? m_targetComment : null); // Sub to collection callbacks for the comments. m_commentCollector.OnCollectionUpdated += CommentCollector_OnCollectionUpdated; m_commentCollector.OnCollectorStateChange += CommentCollector_OnCollectorStateChange; // We have to ask for all the comments here bc we can't extend. if (!m_commentCollector.Update(false, m_post.CurrentCommentShowingCount)) { // If update returns false it isn't going to update because it has a cache. So just show the // cache. OnCollectionUpdatedArgs <Comment> args = new OnCollectionUpdatedArgs <Comment>() { ChangedItems = m_commentCollector.GetCurrentPosts(), IsFreshUpdate = true, IsInsert = false, StartingPosition = 0 }; CommentCollector_OnCollectionUpdated(null, args); } }); return(true); }
/// <summary> /// Fired when the stories come in for a type /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Collector_OnCollectionUpdatedLockScreen(object sender, OnCollectionUpdatedArgs <Post> e) { Collector_OnCollectionUpdated(UpdateTypes.LockScreen, e); }
/// <summary> /// Fired when the comment sort is changed. /// </summary> public void ChangeCommentSort() { // Show loading m_post.FlipViewShowLoadingMoreComments = true; // Do this in a background thread Task.Run(() => { // Delete the collector DeleteCollector(); // Make a new one. DeferredCollector<Comment> collector = EnsureCollector(); // Force our collector to update. if (!collector.LoadAllItems(true, m_post.CurrentCommentShowingCount)) { // If update returns false it isn't going to update because it has a cache. So just show the // cache. OnCollectionUpdatedArgs<Comment> args = new OnCollectionUpdatedArgs<Comment>() { ChangedItems = collector.GetCurrentItems(true), IsFreshUpdate = true, IsInsert = false, StartingPosition = 0 }; CommentCollector_OnCollectionUpdated(null, args); } }); }
/// <summary> /// Fired when we have subreddit results /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void CurrentSubCollector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs <Subreddit> e) { await global::Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { // Subreddits are always at the top of the list int insertIndex = 1; bool showAll = m_currentSearchType.HasValue && m_currentSearchType.Value == SearchResultTypes.Subreddit; // Lock the list lock (m_searchResultsList) { // Insert the header SearchResult header = new SearchResult() { ResultType = SearchResultTypes.Header, HeaderText = "Subreddit Results" }; m_searchResultsList.Insert(0, header); int count = 0; foreach (Subreddit subreddit in e.ChangedItems) { // Make sure it isn't private. Since we can't show these we will skip them for now // #todo fix this if (subreddit.SubredditType != null && subreddit.SubredditType.Equals("private")) { continue; } // Make the result SearchResult subredditResult = new SearchResult() { ResultType = SearchResultTypes.Subreddit, MajorText = subreddit.Title, MarkdownText = subreddit.PublicDescription, MinorAccentText = $"/r/{subreddit.DisplayName}", DataContext = subreddit }; // Add it to the list m_searchResultsList.Insert(insertIndex, subredditResult); // Itter count++; insertIndex++; // If we are showing everything only show the top 3 results. // Otherwise show everything. if (!showAll && count > 2) { break; } } // Insert no results if so if (e.ChangedItems.Count == 0) { // Insert the header SearchResult noResults = new SearchResult() { ResultType = SearchResultTypes.NoResults }; m_searchResultsList.Insert(insertIndex, noResults); insertIndex++; } // Insert show more if we didn't show all if (e.ChangedItems.Count != 0 && !showAll) { // Insert the header SearchResult showMore = new SearchResult() { ResultType = SearchResultTypes.ShowMore, DataContext = c_subredditShowMoreHeader }; m_searchResultsList.Insert(insertIndex, showMore); } } }); }
/// <summary> /// Fired when we have subreddit results /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void CurrentSubCollector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs<Subreddit> e) { await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { // Subreddits are always at the top of the list int insertIndex = 1; bool showAll = m_currentSearchType.HasValue && m_currentSearchType.Value == SearchResultTypes.Subreddit; // Lock the list lock(m_searchResultsList) { // Insert the header SearchResult header = new SearchResult() { ResultType = SearchResultTypes.Header, HeaderText = "Subreddit Results" }; m_searchResultsList.Insert(0, header); int count = 0; foreach(Subreddit subreddit in e.ChangedItems) { // Make sure it isn't private. Since we can't show these we will skip them for now // #todo fix this if(subreddit.SubredditType != null && subreddit.SubredditType.Equals("private")) { continue; } // Make the result SearchResult subredditResult = new SearchResult() { ResultType = SearchResultTypes.Subreddit, MajorText = subreddit.Title, MinorText = subreddit.PublicDescription, MinorAccentText = $"/r/{subreddit.DisplayName}", DataContext = subreddit }; // Hide the minor text if there isn't any if(String.IsNullOrWhiteSpace(subreddit.PublicDescription)) { subredditResult.ShowMinorText = Visibility.Collapsed; } // Add it to the list m_searchResultsList.Insert(insertIndex, subredditResult); // Itter count++; insertIndex++; // If we are showing everything only show the top 3 results. // Otherwise show everything. if(!showAll && count > 2) { break; } } // Insert no results if so if(e.ChangedItems.Count == 0) { // Insert the header SearchResult noResults = new SearchResult() { ResultType = SearchResultTypes.NoResults }; m_searchResultsList.Insert(insertIndex, noResults); insertIndex++; } // Insert show more if we didn't show all if(e.ChangedItems.Count != 0 && !showAll) { // Insert the header SearchResult showMore = new SearchResult() { ResultType = SearchResultTypes.ShowMore, DataContext = c_subredditShowMoreHeader }; m_searchResultsList.Insert(insertIndex, showMore); } } }); }
private async void Collector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs<Message> e) { await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { // Setup the insert int insertIndex = e.StartingPosition; // Lock the list lock (m_messageList) { // Set up the objects for the UI foreach (Message message in e.ChangedItems) { // Check if we are adding or inserting. bool isReplace = insertIndex < m_messageList.Count; if (isReplace) { if (m_messageList[insertIndex].Id.Equals(message.Id)) { // If the message is the same just update the UI vars m_messageList[insertIndex].Body = message.Body; } else { // Replace the current item m_messageList[insertIndex] = message; } } else { // Add it to the end m_messageList.Add(message); } insertIndex++; } // If it was a fresh update, remove anything past the last story sent. while (e.IsFreshUpdate && m_messageList.Count > e.ChangedItems.Count) { m_messageList.RemoveAt(m_messageList.Count - 1); } } }); }
/// <summary> /// Fired when the stories come in for a type /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Collector_OnCollectionUpdated(UpdateTypes type, OnCollectionUpdatedArgs<Post> e) { if(e.ChangedItems.Count > 0) { // If we successfully got the post now get the images GetImagesFromPosts(e.ChangedItems, type); } }
/// <summary> /// Fired when the stories come in for a type /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Collector_OnCollectionUpdatedBand(object sender, OnCollectionUpdatedArgs<Post> e) { Collector_OnCollectionUpdated(UpdateTypes.Band, e); }
/// <summary> /// Fired when the stories come in for a type /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Collector_OnCollectionUpdatedDesktop(object sender, OnCollectionUpdatedArgs<Post> e) { Collector_OnCollectionUpdated(UpdateTypes.Desktop, e); }
/// <summary> /// Fired when the stories come in for a type /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Collector_OnCollectionUpdatedLockScreen(object sender, OnCollectionUpdatedArgs<Post> e) { Collector_OnCollectionUpdated(UpdateTypes.LockScreen, e); }
private void Collector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs<Post> e) { List<string> newTrendingSubs = new List<string>(); if (e.ChangedItems.Count > 0) { // We got it! Post todaysPost = e.ChangedItems[0]; string selfText = e.ChangedItems[0].Selftext; // Parse out the subreddits. This isn't going to be pretty. // There inst any api to get these right now (that I can find) // so this is the best we have. try { // This is so bad. The only way to really find them is to look for the ## and then ** // I hope they never change this or this will explode so quickly int nextHash = selfText.IndexOf("##"); while (nextHash != -1) { // Find the bold indicator int nextBold = selfText.IndexOf("**", nextHash); if(nextBold == -1) { break; } nextBold += 2; // Find the last bold indicator int endBold = selfText.IndexOf("**", nextBold); if (endBold == -1) { break; } // Get the subreddit string subreddit = selfText.Substring(nextBold, endBold - nextBold); newTrendingSubs.Add(subreddit); // Update the index nextHash = selfText.IndexOf("##", endBold + 2); } } catch(Exception ex) { m_baconMan.TelemetryMan.ReportUnExpectedEvent(this, "failedtoParseTrendingPost", ex); m_baconMan.MessageMan.DebugDia("failed to parse trending subs post", ex); } } // If we get this far we are going to say this is good enough and set the // time and list. If our parser breaks we don't want to make a ton of requests // constantly. LastTrendingSubs = newTrendingSubs; LastUpdate = DateTime.Now; // Fire the event if we are good or not. If the list is empty that's fine FireReadyEvent(newTrendingSubs); }
/// <summary> /// Attempts to prefetch comments. Returns true if it is going, or false it not. /// </summary> /// <returns></returns> public bool PreFetchComments() { // Only attempt to do this once. if(m_attemptedToLoadComments) { return false; } m_attemptedToLoadComments = true; // Do this in a background thread Task.Run(() => { // Get the comment collector, if we don't want to show a subset don't give it the target comment m_commentCollector = CommentCollector.GetCollector(m_post, App.BaconMan, m_showThreadSubset ? m_targetComment : null); // Sub to collection callbacks for the comments. m_commentCollector.OnCollectionUpdated += CommentCollector_OnCollectionUpdated; m_commentCollector.OnCollectorStateChange += CommentCollector_OnCollectorStateChange; // We have to ask for all the comments here bc we can't extend. if (!m_commentCollector.Update(false, m_post.CurrentCommentShowingCount)) { // If update returns false it isn't going to update because it has a cache. So just show the // cache. OnCollectionUpdatedArgs<Comment> args = new OnCollectionUpdatedArgs<Comment>() { ChangedItems = m_commentCollector.GetCurrentPosts(), IsFreshUpdate = true, IsInsert = false, StartingPosition = 0 }; CommentCollector_OnCollectionUpdated(null, args); } }); return true; }
/// <summary> /// Fired when the stories come in for a type /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Collector_OnCollectionUpdatedDesktop(object sender, OnCollectionUpdatedArgs <Post> e) { Collector_OnCollectionUpdated(UpdateTypes.Desktop, e); }
/// <summary> /// Fired when the stories come in for a type /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Collector_OnCollectionUpdatedBand(object sender, OnCollectionUpdatedArgs <Post> e) { Collector_OnCollectionUpdated(UpdateTypes.Band, e); }
/// <summary> /// Used by the get subreddit stories to return posts. /// We can't use a lambda because the weak events don't support it. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Collector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs<Post> e) { m_currentSubredditPosts = e.ChangedItems; m_autoReset.Set(); }
/// <summary> /// Fired when the collection list has been updated. /// </summary> /// <param name="startingPos"></param> /// <param name="changedPosts"></param> private void Collector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs <Post> args) { // Update the post or posts SetPosts(args.StartingPosition, args.ChangedItems, args.IsFreshUpdate); }
/// <summary> /// Used by the get subreddit stories to return posts. /// We can't use a lambda because the weak events don't support it. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Collector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs <Post> e) { m_currentSubredditPosts = e.ChangedItems; m_autoReset.Set(); }
/// <summary> /// Fired when we have post results /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void CurrentPostCollector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs<Post> e) { await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { // Posts insert at the bottom of the list. bool showAll = m_currentSearchType.HasValue && m_currentSearchType.Value == SearchResultTypes.Post; // Lock the list lock (m_searchResultsList) { // Insert the header SearchResult header = new SearchResult() { ResultType = SearchResultTypes.Header, HeaderText = "Post Results" }; m_searchResultsList.Add(header); // Insert the items int count = 0; foreach (Post post in e.ChangedItems) { // Make the result SearchResult postResult = new SearchResult() { ResultType = SearchResultTypes.Post, MajorText = post.Title, MinorText = $"{post.SubTextLine1} to {post.Subreddit}", MinorAccentText = $"({post.Score}) score; {post.NumComments} comments", DataContext = post }; // Add it to the list m_searchResultsList.Add(postResult); // Itter count++; // If we are showing everything only show the top 3 results. // Otherwise show everything. if (!showAll && count > 2) { break; } } // Insert no results if so if (e.ChangedItems.Count == 0) { // Insert the header SearchResult noResults = new SearchResult() { ResultType = SearchResultTypes.NoResults }; m_searchResultsList.Add(noResults); } // Insert show more if we didn't show all if (e.ChangedItems.Count != 0 && !showAll) { // Insert the header SearchResult showMore = new SearchResult() { ResultType = SearchResultTypes.ShowMore, DataContext = c_postShowMoreHeader }; m_searchResultsList.Add(showMore); } } }); }
/// <summary> /// Fired when comments are updated /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void CommentCollector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs<Comment> e) { // Jump to the UI thread await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () => { // If this is fresh clear if (e.IsFreshUpdate) { // Remove each individually so we get nice animations while (m_commentList.Count != 0) { m_commentList.RemoveAt(m_commentList.Count - 1); } } // Add the new posts to the end of the list foreach (Comment comment in e.ChangedItems) { m_commentList.Add(comment); } }); }
private async void CommentCollector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs <Comment> e) { // Dispatch to the UI thread await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { // Setup the insert int insertIndex = e.StartingPosition; // Lock the list lock (m_post.Comments) { lock (m_fullCommentList) { if (e.IsFreshUpdate) { // Reset the full list m_fullCommentList.Clear(); // For fresh updates we can just replace everything and expand anything that isn't. for (int i = 0; i < e.ChangedItems.Count; i++) { Comment newComment = e.ChangedItems[i]; Comment currentComment = i >= m_post.Comments.Count ? null : m_post.Comments[i]; if (currentComment == null) { m_post.Comments.Add(newComment); } else { if (newComment.Id.Equals(currentComment.Id)) { // Update the comment m_post.Comments[i].Author = newComment.Author; m_post.Comments[i].Score = newComment.Score; m_post.Comments[i].TimeString = newComment.TimeString; m_post.Comments[i].CollapsedCommentCount = newComment.CollapsedCommentCount; m_post.Comments[i].Body = newComment.Body; m_post.Comments[i].Likes = newComment.Likes; m_post.Comments[i].ShowFullComment = true; } else { // Replace it m_post.Comments[i] = newComment; } } // Always add to the full list m_fullCommentList.Add(newComment); } // Trim off anything that shouldn't be here anymore while (m_post.Comments.Count > e.ChangedItems.Count) { m_post.Comments.RemoveAt(m_post.Comments.Count - 1); } } else { // This is tricky because the comment list in the post is a subset of the main list due to collapse. // Thus items are missing or moved in that list. // How we will do it is the following. We will make all of actions to the main list. If the operation is // "add at the end" we will do it to both lists because it is safe no matter what the state of the comment list. // If we have an insert or replace we will build two lists. Once the main list is updated we will then address updating // the comment list properly. // This list tracks any inserts we need to do. The key is the parent comment id, the value is the comment to // be inserted. List <KeyValuePair <string, Comment> > insertList = new List <KeyValuePair <string, Comment> >(); // This list tracks any replaces we need to do. The key is the parent comment id, the value is the comment to // be inserted. List <KeyValuePair <string, Comment> > replaceList = new List <KeyValuePair <string, Comment> >(); // First update the main list foreach (Comment comment in e.ChangedItems) { if (m_targetComment != null && comment.Id.Equals(m_targetComment)) { comment.IsHighlighted = true; } // Check if this is a add or replace if not an insert bool isReplace = insertIndex < m_fullCommentList.Count; // If we are inserting just insert it where it should be. if (e.IsInsert) { m_fullCommentList.Insert(insertIndex, comment); // Make sure we have a parent, if not use empty string string parentComment = insertIndex > 0 ? m_fullCommentList[insertIndex - 1].Id : string.Empty; insertList.Add(new KeyValuePair <string, Comment>(parentComment, comment)); } else if (isReplace) { // Grab the id that we are replacing and the comment to replace it. replaceList.Add(new KeyValuePair <string, Comment>(m_fullCommentList[insertIndex].Id, comment)); // Replace the current item m_fullCommentList[insertIndex] = comment; } else { // Add it to the end of the main list m_fullCommentList.Add(comment); // If we are adding it to the end of the main list it is safe to add it to the end of the UI list. m_post.Comments.Add(comment); } insertIndex++; } // Now deal with the insert list. foreach (KeyValuePair <string, Comment> insertPair in insertList) { // If the key is empty string we are inserting into the head if (String.IsNullOrWhiteSpace(insertPair.Key)) { m_post.Comments.Insert(0, insertPair.Value); } else { // Try to find the parent comment. for (int i = 0; i < m_post.Comments.Count; i++) { Comment comment = m_post.Comments[i]; if (comment.Id.Equals(insertPair.Key)) { // We found the parent, it is not collapsed we should insert this comment after it. if (comment.ShowFullComment) { m_post.Comments.Insert(i + 1, insertPair.Value); } // We are done, break out of this parent search. break; } } } } // Now deal with the replace list. for (int replaceCount = 0; replaceCount < replaceList.Count; replaceCount++) { KeyValuePair <string, Comment> replacePair = replaceList[replaceCount]; // Try to find the comment we will replace; Note if is very important that we start at the current replace point // because this comment might have been added before this count already due to a perviouse replace. In that case // we don't want to accidentally find that one instead of this one. for (int i = replaceCount; i < m_post.Comments.Count; i++) { Comment comment = m_post.Comments[i]; if (comment.Id.Equals(replacePair.Key)) { // If the id is the same we are updating. If we replace the comment the UI will freak out, // so just update the UI values if (comment.Id.Equals(replacePair.Value.Id)) { m_post.Comments[i].Author = replacePair.Value.Author; m_post.Comments[i].Score = replacePair.Value.Score; m_post.Comments[i].TimeString = replacePair.Value.TimeString; m_post.Comments[i].CollapsedCommentCount = replacePair.Value.CollapsedCommentCount; m_post.Comments[i].Body = replacePair.Value.Body; m_post.Comments[i].Likes = replacePair.Value.Likes; } else { // Replace the comment with this one m_post.Comments[i] = replacePair.Value; } // We are done, break out of the search for the match. break; } } } } } } }); }
/// <summary> /// Fired when the collection list has been updated. /// </summary> /// <param name="startingPos"></param> /// <param name="changedPosts"></param> private void Collector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs <Post> args) { // Update the posts UpdatePosts(args.StartingPosition, args.ChangedItems); }
/// <summary> /// Fired when we have post results /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void CurrentPostCollector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs <Post> e) { await global::Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { // Posts insert at the bottom of the list. bool showAll = m_currentSearchType.HasValue && m_currentSearchType.Value == SearchResultTypes.Post; // Lock the list lock (m_searchResultsList) { // Insert the header SearchResult header = new SearchResult() { ResultType = SearchResultTypes.Header, HeaderText = "Post Results" }; m_searchResultsList.Add(header); // Insert the items int count = 0; foreach (Post post in e.ChangedItems) { // Make the result SearchResult postResult = new SearchResult() { ResultType = SearchResultTypes.Post, MajorText = post.Title, MinorText = $"{post.SubTextLine1} to {post.Subreddit}", MinorAccentText = $"({post.Score}) score; {post.NumComments} comments", DataContext = post }; // Add it to the list m_searchResultsList.Add(postResult); // Itter count++; // If we are showing everything only show the top 3 results. // Otherwise show everything. if (!showAll && count > 2) { break; } } // Insert no results if so if (e.ChangedItems.Count == 0) { // Insert the header SearchResult noResults = new SearchResult() { ResultType = SearchResultTypes.NoResults }; m_searchResultsList.Add(noResults); } // Insert show more if we didn't show all if (e.ChangedItems.Count != 0 && !showAll) { // Insert the header SearchResult showMore = new SearchResult() { ResultType = SearchResultTypes.ShowMore, DataContext = c_postShowMoreHeader }; m_searchResultsList.Add(showMore); } } }); }
/// <summary> /// Attempts to prefetch comments. Returns true if it is going, or false it not. /// </summary> /// <returns></returns> public bool PreFetchComments() { // Only attempt to do this once. if(m_attemptedToLoadComments) { return false; } m_attemptedToLoadComments = true; // Do this in a background thread Task.Run(() => { // Get the comment collector, if we don't want to show a subset don't give it the target comment m_commentCollector = CommentCollector.GetCollector(m_post, App.BaconMan, m_showThreadSubset ? m_targetComment : null); // Sub to collection callbacks for the comments. m_commentCollector.OnCollectionUpdated += CommentCollector_OnCollectionUpdated; m_commentCollector.OnCollectorStateChange += CommentCollector_OnCollectorStateChange; // Request a few comments so we will fill the screen. // If the user scrolls we will get more later. // To fix a bug where reddit doesn't give us the same // comments the first time as the next, we will // #bug #todo because of the "can't ask for more" bug we will // just ask for all of the comments here. if (!m_commentCollector.Update(false, 150)) { // If update returns false it isn't going to update because it has a cache. So just show the // cache. OnCollectionUpdatedArgs<Comment> args = new OnCollectionUpdatedArgs<Comment>() { ChangedItems = m_commentCollector.GetCurrentPosts(), IsFreshUpdate = true, IsInsert = false, StartingPosition = 0 }; CommentCollector_OnCollectionUpdated(null, args); } }); return true; }
/// <summary> /// Fired when the collection list has been updated. /// </summary> /// <param name="startingPos"></param> /// <param name="changedPosts"></param> private void Collector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs<Post> args) { // Update the post or posts SetPosts(args.StartingPosition, args.ChangedItems, args.IsFreshUpdate); }
private async void CommentCollector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs<Comment> e) { // Dispatch to the UI thread await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { // Setup the insert int insertIndex = e.StartingPosition; // Lock the list lock (Comments) { lock(m_fullCommentList) { if (e.IsFreshUpdate) { // Reset the full list m_fullCommentList.Clear(); // For fresh updates we can just replace everything and expand anything that isn't. for (int i = 0; i < e.ChangedItems.Count; i++) { Comment newComment = e.ChangedItems[i]; Comment currentComment = i >= Comments.Count ? null : Comments[i]; // Check for highlight if (!String.IsNullOrWhiteSpace(m_targetComment) && newComment.Id.Equals(m_targetComment)) { newComment.IsHighlighted = true; } if (currentComment == null) { Comments.Add(newComment); } else { if (newComment.Id.Equals(currentComment.Id)) { // Update the comment Comments[i].Author = newComment.Author; Comments[i].Score = newComment.Score; Comments[i].TimeString = newComment.TimeString; Comments[i].CollapsedCommentCount = newComment.CollapsedCommentCount; Comments[i].Body = newComment.Body; Comments[i].Likes = newComment.Likes; Comments[i].ShowFullComment = true; } else { // Replace it Comments[i] = newComment; } } // Always add to the full list m_fullCommentList.Add(newComment); } // Trim off anything that shouldn't be here anymore while (Comments.Count > e.ChangedItems.Count) { Comments.RemoveAt(Comments.Count - 1); } } else { // This is tricky because the comment list in the post is a subset of the main list due to collapse. // Thus items are missing or moved in that list. // How we will do it is the following. We will make all of actions to the main list. If the operation is // "add at the end" we will do it to both lists because it is safe no matter what the state of the comment list. // If we have an insert or replace we will build two lists. Once the main list is updated we will then address updating // the comment list properly. // This list tracks any inserts we need to do. The key is the parent comment id, the value is the comment to // be inserted. List<KeyValuePair<string, Comment>> insertList = new List<KeyValuePair<string, Comment>>(); // This list tracks any replaces we need to do. The key is the parent comment id, the value is the comment to // be inserted. List<KeyValuePair<string, Comment>> replaceList = new List<KeyValuePair<string, Comment>>(); // First update the main list foreach (Comment comment in e.ChangedItems) { if (!String.IsNullOrWhiteSpace(m_targetComment) && comment.Id.Equals(m_targetComment)) { comment.IsHighlighted = true; } // Check if this is a add or replace if not an insert bool isReplace = insertIndex < m_fullCommentList.Count; // If we are inserting just insert it where it should be. if (e.IsInsert) { m_fullCommentList.Insert(insertIndex, comment); // Make sure we have a parent, if not use empty string string parentComment = insertIndex > 0 ? m_fullCommentList[insertIndex - 1].Id : string.Empty; insertList.Add(new KeyValuePair<string, Comment>(parentComment, comment)); } else if (isReplace) { // Grab the id that we are replacing and the comment to replace it. replaceList.Add(new KeyValuePair<string, Comment>(m_fullCommentList[insertIndex].Id, comment)); // Replace the current item m_fullCommentList[insertIndex] = comment; } else { // Add it to the end of the main list m_fullCommentList.Add(comment); // If we are adding it to the end of the main list it is safe to add it to the end of the UI list. Comments.Add(comment); } insertIndex++; } // Now deal with the insert list. foreach (KeyValuePair<string, Comment> insertPair in insertList) { // If the key is empty string we are inserting into the head if (String.IsNullOrWhiteSpace(insertPair.Key)) { Comments.Insert(0, insertPair.Value); } else { // Try to find the parent comment. for (int i = 0; i < Comments.Count; i++) { Comment comment = Comments[i]; if (comment.Id.Equals(insertPair.Key)) { // We found the parent, it is not collapsed we should insert this comment after it. if (comment.ShowFullComment) { Comments.Insert(i + 1, insertPair.Value); } // We are done, break out of this parent search. break; } } } } // Now deal with the replace list. for (int replaceCount = 0; replaceCount < replaceList.Count; replaceCount++) { KeyValuePair<string, Comment> replacePair = replaceList[replaceCount]; // Try to find the comment we will replace; Note if is very important that we start at the current replace point // because this comment might have been added before this count already due to a perviouse replace. In that case // we don't want to accidentally find that one instead of this one. for (int i = replaceCount; i < Comments.Count; i++) { Comment comment = Comments[i]; if (comment.Id.Equals(replacePair.Key)) { // If the id is the same we are updating. If we replace the comment the UI will freak out, // so just update the UI values if (comment.Id.Equals(replacePair.Value.Id)) { Comments[i].Author = replacePair.Value.Author; Comments[i].Score = replacePair.Value.Score; Comments[i].TimeString = replacePair.Value.TimeString; Comments[i].CollapsedCommentCount = replacePair.Value.CollapsedCommentCount; Comments[i].Body = replacePair.Value.Body; Comments[i].Likes = replacePair.Value.Likes; } else { // Replace the comment with this one Comments[i] = replacePair.Value; } // We are done, break out of the search for the match. break; } } } } } } }); }
private async void CommentCollector_OnCollectionUpdated(object sender, OnCollectionUpdatedArgs<Comment> e) { // Dispatch to the UI thread await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { // Setup the insert int insertIndex = e.StartingPosition; // Lock the list lock (m_post.Comments) { lock(m_fullCommentList) { // This is tricky because the comment list in the post is a subset of the main list due to collapse. // Thus items are missing or moved in that list. // How we will do it is the following. We will make all of actions to the main list. If the operation is // "add at the end" we will do it to both lists because it is safe no matter what the state of the comment list. // If we have an insert or replace we will build two lists. Once the main list is updated we will then address updating // the comment list properly. // This list tracks any inserts we need to do. The key is the parent comment id, the value is the comment to // be inserted. List<KeyValuePair<string, Comment>> insertList = new List<KeyValuePair<string, Comment>>(); // This list tracks any replaces we need to do. The key is the parent comment id, the value is the comment to // be inserted. List<KeyValuePair<string, Comment>> replaceList = new List<KeyValuePair<string, Comment>>(); // First update the main list foreach (Comment comment in e.ChangedItems) { if(m_targetComment != null && comment.Id.Equals(m_targetComment)) { comment.IsHighlighted = true; } // Check if this is a add or replace if not an insert bool isReplace = insertIndex < m_fullCommentList.Count; // If we are inserting just insert it where it should be. if (e.IsInsert) { m_fullCommentList.Insert(insertIndex, comment); // Make sure we have a parent, if not use empty string string parentComment = insertIndex > 0 ? m_fullCommentList[insertIndex - 1].Id : string.Empty; insertList.Add(new KeyValuePair<string, Comment>(parentComment, comment)); } else if (isReplace) { // Grab the id that we are replacing and the comment to replace it. replaceList.Add(new KeyValuePair<string, Comment>(m_fullCommentList[insertIndex].Id, comment)); // Replace the current item m_fullCommentList[insertIndex] = comment; } else { // Add it to the end of the main list m_fullCommentList.Add(comment); // If we are adding it to the end of the main list it is safe to add it to the end of the UI list. m_post.Comments.Add(comment); } insertIndex++; } // Now deal with the insert list. foreach(KeyValuePair<string, Comment> insertPair in insertList) { // If the key is empty string we are inserting into the head if(String.IsNullOrWhiteSpace(insertPair.Key)) { m_post.Comments.Insert(0, insertPair.Value); } else { // Try to find the parent comment. for(int i = 0; i < m_post.Comments.Count; i++) { Comment comment = m_post.Comments[i]; if (comment.Id.Equals(insertPair.Key)) { // We found the parent, it is not collapsed we should insert this comment after it. if(comment.ShowFullComment) { m_post.Comments.Insert(i + 1, insertPair.Value); } // We are done, break out of this parent search. break; } } } } // Now deal with the replace list. foreach (KeyValuePair<string, Comment> replacePair in replaceList) { // Try to find the comment we will replace for (int i = 0; i < m_post.Comments.Count; i++) { Comment comment = m_post.Comments[i]; if (comment.Id.Equals(replacePair.Key)) { // If the id is the same we are updating. If we replace the comment the UI will freak out, // so just update the UI values if (comment.Id.Equals(replacePair.Value.Id)) { m_post.Comments[i].Author = comment.Author; m_post.Comments[i].Score = comment.Score; m_post.Comments[i].TimeString = comment.TimeString; m_post.Comments[i].CollapsedCommentCount = comment.CollapsedCommentCount; m_post.Comments[i].Body = comment.Body; m_post.Comments[i].Likes = comment.Likes; } else { // Replace the comment with this one m_post.Comments[i] = replacePair.Value; } // We are done, break out of the search for the match. break; } } } } } }); }
/// <summary> /// Fired when the comment sort is changed. /// </summary> public void ChangeCommentSort() { // Show loading m_post.FlipViewShowLoadingMoreComments = true; // Do this in a background thread Task.Run(() => { // Kill the current collector if (m_commentCollector != null) { m_commentCollector.OnCollectionUpdated -= CommentCollector_OnCollectionUpdated; m_commentCollector.OnCollectorStateChange -= CommentCollector_OnCollectorStateChange; } m_commentCollector = null; // Get a new collector with the new sort m_commentCollector = new DeferredCollector<Comment>(CommentCollector.GetCollector(m_post, App.BaconMan)); // Sub to collection callbacks for the comments. m_commentCollector.OnCollectionUpdated += CommentCollector_OnCollectionUpdated; m_commentCollector.OnCollectorStateChange += CommentCollector_OnCollectorStateChange; // Force our collector to update. if (!m_commentCollector.LoadAllItems(true, m_post.CurrentCommentShowingCount)) { // If update returns false it isn't going to update because it has a cache. So just show the // cache. OnCollectionUpdatedArgs<Comment> args = new OnCollectionUpdatedArgs<Comment>() { ChangedItems = m_commentCollector.GetCurrentItems(true), IsFreshUpdate = true, IsInsert = false, StartingPosition = 0 }; CommentCollector_OnCollectionUpdated(null, args); } }); }
/// <summary> /// Fired when the collection list has been updated. /// </summary> /// <param name="startingPos"></param> /// <param name="changedPosts"></param> private void Collector_OnCollectionUpdated(object sender , OnCollectionUpdatedArgs<Post> args) { // Update the posts UpdatePosts(args.StartingPosition, args.ChangedItems); }
/// <summary> /// Attempts to prefetch comments. Returns true if it is going, or false it not. /// </summary> /// <returns></returns> public bool PreFetchComments() { // Only attempt to do this once. if(m_attemptedToLoadComments) { return false; } m_attemptedToLoadComments = true; // Do this in a background thread Task.Run(() => { // Ensure we have a collector EnsureCollector(); // We have to ask for all the comments here bc we can't extend. if (!m_commentCollector.PreLoadItems(false, m_post.CurrentCommentShowingCount)) { // If update returns false it isn't going to update because it has a cache. So just show the // cache. OnCollectionUpdatedArgs<Comment> args = new OnCollectionUpdatedArgs<Comment>() { ChangedItems = m_commentCollector.GetCurrentItems(false), IsFreshUpdate = true, IsInsert = false, StartingPosition = 0 }; CommentCollector_OnCollectionUpdated(null, args); } }); return true; }