First, remove old articles, then add new ones. Closes #4

This commit is contained in:
relikd
2019-04-01 13:29:04 +02:00
parent 6192f76605
commit 935325af04
3 changed files with 58 additions and 31 deletions

View File

@@ -6,6 +6,8 @@ and this project does NOT adhere to [Semantic Versioning](https://semver.org/spe
## [Unreleased] ## [Unreleased]
### Fixed
- Article order got mixed up for some feeds (issue: #4)
## [0.9.3] - 2019-03-14 ## [0.9.3] - 2019-03-14
@@ -50,7 +52,7 @@ and this project does NOT adhere to [Semantic Versioning](https://semver.org/spe
Initial release Initial release
[Unreleased]: https://github.com/relikd/baRSS/compare/v0.9.2...HEAD [Unreleased]: https://github.com/relikd/baRSS/compare/v0.9.3...HEAD
[0.9.3]: https://github.com/relikd/baRSS/compare/v0.9.2...v0.9.3 [0.9.3]: https://github.com/relikd/baRSS/compare/v0.9.2...v0.9.3
[0.9.2]: https://github.com/relikd/baRSS/compare/v0.9.1...v0.9.2 [0.9.2]: https://github.com/relikd/baRSS/compare/v0.9.1...v0.9.2
[0.9.1]: https://github.com/relikd/baRSS/compare/v0.9...v0.9.1 [0.9.1]: https://github.com/relikd/baRSS/compare/v0.9...v0.9.1

View File

@@ -92,9 +92,10 @@
self.group.name = obj.title; self.group.name = obj.title;
// Add and remove articles // Add and remove articles
NSMutableSet<FeedArticle*> *oldSet = [self.articles mutableCopy]; NSMutableSet<FeedArticle*> *localSet = [self.articles mutableCopy];
NSInteger diff = [self addMissingArticles:obj withOldSet:oldSet]; // will remove items that should be kept NSInteger diff = 0;
diff -= [self deleteArticlesWithOldSet:oldSet]; // remove old, outdated articles diff -= [self deleteArticles:localSet withRemoteSet:obj.articles]; // remove old, outdated articles
diff += [self insertArticles:localSet withRemoteSet:obj.articles]; // insert new in correct order
// Get new total article count and post unread-count-change notification // Get new total article count and post unread-count-change notification
if (flag && diff != 0) { if (flag && diff != 0) {
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationTotalUnreadCountChanged object:@(diff)]; [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationTotalUnreadCountChanged object:@(diff)];
@@ -108,20 +109,20 @@
New articles should be in ascending order without any gaps in between. New articles should be in ascending order without any gaps in between.
If new article is disjunct from the article before, assume a deleted article re-appeared and mark it as read. If new article is disjunct from the article before, assume a deleted article re-appeared and mark it as read.
@param oldSet Input will be used to identify new articles. @param localSet Use result set @c localSet of method call @c deleteArticles:withRemoteSet:.
Output contains articles that aren't present in the feed anymore and should be deleted. @param remoteSet Readonly copy of @c RSParsedFeed.articles.
*/ */
- (NSInteger)addMissingArticles:(RSParsedFeed*)obj withOldSet:(NSMutableSet<FeedArticle*>*)oldSet { - (NSUInteger)insertArticles:(NSMutableSet<FeedArticle*>*)localSet withRemoteSet:(NSArray<RSParsedArticle*>*)remoteSet {
NSInteger newOnes = 0; NSUInteger newOnes = 0;
int32_t currentIndex = [[self.articles valueForKeyPath:@"@min.sortIndex"] intValue]; int32_t currentIndex = [[localSet valueForKeyPath:@"@min.sortIndex"] intValue];
FeedArticle *lastInserted = nil; FeedArticle *lastInserted = nil;
BOOL hasGapBetweenNewArticles = NO; BOOL hasGapBetweenNewArticles = NO;
for (RSParsedArticle *article in [obj.articles reverseObjectEnumerator]) { for (RSParsedArticle *article in [remoteSet reverseObjectEnumerator]) {
// reverse enumeration ensures correct article order // reverse enumeration ensures correct article order
FeedArticle *storedArticle = [self findArticle:article inSet:oldSet]; FeedArticle *storedArticle = [self findRemoteArticle:article inLocalSet:localSet];
if (storedArticle) { if (storedArticle) {
[oldSet removeObject:storedArticle]; [localSet removeObject:storedArticle];
if (storedArticle.sortIndex != currentIndex) { if (storedArticle.sortIndex != currentIndex) {
storedArticle.sortIndex = currentIndex; storedArticle.sortIndex = currentIndex;
} }
@@ -147,19 +148,26 @@
} }
/** /**
Delete all articles from core data, that are still in the oldSet. Delete all articles from core data, that aren't present anymore.
@param localSet Input a copy of @c self.articles. Output the same set minus deleted articles.
@param remoteSet Readonly copy of @c RSParsedFeed.articles.
*/ */
- (NSUInteger)deleteArticlesWithOldSet:(NSMutableSet<FeedArticle*>*)oldSet { - (NSUInteger)deleteArticles:(NSMutableSet<FeedArticle*>*)localSet withRemoteSet:(NSArray<RSParsedArticle*>*)remoteSet {
if (!oldSet || oldSet.count == 0)
return 0;
NSUInteger c = 0; NSUInteger c = 0;
for (FeedArticle *fa in oldSet) { NSMutableSet<FeedArticle*> *deletingSet = [NSMutableSet setWithCapacity:localSet.count];
if (fa.unread) ++c; for (FeedArticle *fa in localSet) {
// TODO: keep unread articles? if (![self findLocalArticle:fa inRemoteSet:remoteSet]) {
[self.managedObjectContext deleteObject:fa]; if (fa.unread) ++c;
// TODO: keep unread articles?
[self.managedObjectContext deleteObject:fa];
[deletingSet addObject:fa];
}
}
if (deletingSet.count > 0) {
[localSet minusSet:deletingSet];
[self removeArticles:deletingSet];
} }
if (oldSet.count > 0)
[self removeArticles:oldSet];
return c; return c;
} }
@@ -177,17 +185,34 @@
} }
/** /**
Iterate over oldSet and return the one where @c link and @c guid matches. Or @c nil if no matching article found. Iterate over localSet and return the one where @c link and @c guid matches. Or @c nil if no matching article found.
*/ */
- (FeedArticle*)findArticle:(RSParsedArticle*)article inSet:(NSSet<FeedArticle*>*)oldSet { - (FeedArticle*)findRemoteArticle:(RSParsedArticle*)remote inLocalSet:(NSSet<FeedArticle*>*)localSet {
NSString *searchLink = article.link; NSString *searchLink = remote.link;
NSString *searchGuid = article.guid; NSString *searchGuid = remote.guid;
BOOL linkIsNil = (searchLink == nil); BOOL linkIsNil = (searchLink == nil);
BOOL guidIsNil = (searchGuid == nil); BOOL guidIsNil = (searchGuid == nil);
for (FeedArticle *old in oldSet) { for (FeedArticle *art in localSet) {
if ((linkIsNil && old.link == nil) || [old.link isEqualToString:searchLink]) { if ((linkIsNil && art.link == nil) || [art.link isEqualToString:searchLink]) {
if ((guidIsNil && old.guid == nil) || [old.guid isEqualToString:searchGuid]) if ((guidIsNil && art.guid == nil) || [art.guid isEqualToString:searchGuid])
return old; return art;
}
}
return nil;
}
/**
Iterate over remoteSet and return the one where @c link and @c guid matches. Or @c nil if no matching article found.
*/
- (RSParsedArticle*)findLocalArticle:(FeedArticle*)local inRemoteSet:(NSArray<RSParsedArticle*>*)remoteSet {
NSString *searchLink = local.link;
NSString *searchGuid = local.guid;
BOOL linkIsNil = (searchLink == nil);
BOOL guidIsNil = (searchGuid == nil);
for (RSParsedArticle *art in remoteSet) {
if ((linkIsNil && art.link == nil) || [art.link isEqualToString:searchLink]) {
if ((guidIsNil && art.guid == nil) || [art.guid isEqualToString:searchGuid])
return art;
} }
} }
return nil; return nil;

View File

@@ -32,7 +32,7 @@
</dict> </dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1153</string> <string>1172</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string> <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>LSUIElement</key> <key>LSUIElement</key>