mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2025-02-02 12:06:58 +01:00
Enhance SyncStatus so that it can communicate new, updated, and deleted
This commit is contained in:
parent
e6b42a8e0a
commit
6870133d60
@ -112,7 +112,12 @@ final class CloudKitAccountDelegate: AccountDelegate {
|
||||
|
||||
func processWithArticles(_ articles: Set<Article>) {
|
||||
|
||||
self.articlesZone.modifyArticles(articles) { result in
|
||||
let articlesDict = articles.reduce(into: [String: Article]()) { result, article in
|
||||
result[article.articleID] = article
|
||||
}
|
||||
let statusedArticles = syncStatuses.map { ($0, articlesDict[$0.articleID]) }
|
||||
|
||||
self.articlesZone.modifyArticles(statusedArticles) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.database.deleteSelectedForProcessing(syncStatuses.map({ $0.articleID }) )
|
||||
@ -428,7 +433,7 @@ final class CloudKitAccountDelegate: AccountDelegate {
|
||||
|
||||
func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) -> Set<Article>? {
|
||||
let syncStatuses = articles.map { article in
|
||||
return SyncStatus(articleID: article.articleID, key: statusKey, flag: flag)
|
||||
return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag)
|
||||
}
|
||||
database.insertStatuses(syncStatuses)
|
||||
|
||||
@ -586,10 +591,6 @@ private extension CloudKitAccountDelegate {
|
||||
|
||||
func combinedRefresh(_ account: Account, _ webFeeds: Set<WebFeed>, completion: @escaping () -> Void) {
|
||||
|
||||
var newArticles = Set<Article>()
|
||||
var updatedArticles = Set<Article>()
|
||||
var deletedArticles = Set<Article>()
|
||||
|
||||
var refresherWebFeeds = Set<WebFeed>()
|
||||
let group = DispatchGroup()
|
||||
|
||||
@ -605,14 +606,10 @@ private extension CloudKitAccountDelegate {
|
||||
account.update(webFeed.webFeedID, with: parsedItems) { result in
|
||||
switch result {
|
||||
case .success(let articleChanges):
|
||||
|
||||
newArticles.formUnion(articleChanges.newArticles ?? Set<Article>())
|
||||
updatedArticles.formUnion(articleChanges.updatedArticles ?? Set<Article>())
|
||||
deletedArticles.formUnion(articleChanges.deletedArticles ?? Set<Article>())
|
||||
|
||||
self.storeArticleChanges(new: articleChanges.newArticles, updated: articleChanges.updatedArticles, deleted: articleChanges.deletedArticles) {
|
||||
self.refreshProgress.completeTask()
|
||||
group.leave()
|
||||
|
||||
}
|
||||
case .failure(let error):
|
||||
os_log(.error, log: self.log, "CloudKit Feed refresh update error: %@.", error.localizedDescription)
|
||||
self.refreshProgress.completeTask()
|
||||
@ -634,14 +631,13 @@ private extension CloudKitAccountDelegate {
|
||||
|
||||
group.enter()
|
||||
refresher.refreshFeeds(refresherWebFeeds) { refresherNewArticles, refresherUpdatedArticles, refresherDeletedArticles in
|
||||
newArticles.formUnion(refresherNewArticles)
|
||||
updatedArticles.formUnion(refresherUpdatedArticles)
|
||||
deletedArticles.formUnion(refresherDeletedArticles)
|
||||
self.storeArticleChanges(new: refresherNewArticles, updated: refresherUpdatedArticles, deleted: refresherDeletedArticles) {
|
||||
group.leave()
|
||||
}
|
||||
}
|
||||
|
||||
group.notify(queue: DispatchQueue.main) {
|
||||
self.processRecords(new: newArticles, updated: updatedArticles, deleted: deletedArticles) {
|
||||
self.refreshArticleStatus(for: account) { _ in
|
||||
self.articlesZone.fetchChangesInZone() { _ in
|
||||
self.refreshProgress.completeTask()
|
||||
completion()
|
||||
@ -651,53 +647,6 @@ private extension CloudKitAccountDelegate {
|
||||
|
||||
}
|
||||
|
||||
func processRecords(new: Set<Article>, updated: Set<Article>, deleted: Set<Article>, completion: @escaping () -> Void) {
|
||||
|
||||
self.articlesZone.deleteArticles(deleted) { result in
|
||||
self.refreshProgress.completeTask()
|
||||
switch result {
|
||||
case .success:
|
||||
self.articlesZone.modifyArticles(updated) { result in
|
||||
self.refreshProgress.completeTask()
|
||||
switch result {
|
||||
case .success:
|
||||
self.saveNewArticles(new) {
|
||||
completion()
|
||||
}
|
||||
case .failure(let error):
|
||||
os_log(.error, log: self.log, "CloudKit modify articles error: %@.", error.localizedDescription)
|
||||
completion()
|
||||
}
|
||||
}
|
||||
case .failure(let error):
|
||||
os_log(.error, log: self.log, "CloudKit delete articles error: %@.", error.localizedDescription)
|
||||
completion()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func saveNewArticles(_ articles: Set<Article>, completion: @escaping () -> Void) {
|
||||
let group = DispatchGroup()
|
||||
|
||||
let articleGroups = Array(articles).chunked(into: 300).map { Set($0) }
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(articleGroups.count)
|
||||
|
||||
for articleGroup in articleGroups {
|
||||
group.enter()
|
||||
self.articlesZone.saveNewArticles(articleGroup) { result in
|
||||
self.refreshProgress.completeTask()
|
||||
group.leave()
|
||||
if case .failure(let error) = result {
|
||||
os_log(.error, log: self.log, "CloudKit new articles error: %@.", error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
group.notify(queue: DispatchQueue.main) {
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
func createProviderWebFeed(for account: Account, urlComponents: URLComponents, editedName: String?, container: Container, feedProvider: FeedProvider, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
refreshProgress.addToNumberOfTasksAndRemaining(6)
|
||||
|
||||
@ -731,21 +680,7 @@ private extension CloudKitAccountDelegate {
|
||||
account.update(urlString, with: parsedItems) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
|
||||
account.fetchArticlesAsync(.webFeed(feed)) { result in
|
||||
switch result {
|
||||
case .success(let articles):
|
||||
self.processRecords(new: articles, updated: Set<Article>(), deleted: Set<Article>()) {
|
||||
self.articlesZone.fetchChangesInZone() { _ in
|
||||
self.refreshProgress.clear()
|
||||
completion(.success(feed))
|
||||
}
|
||||
}
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
self.sendNewArticlesToTheCloud(account, feed, completion: completion)
|
||||
case .failure(let error):
|
||||
self.refreshProgress.clear()
|
||||
completion(.failure(error))
|
||||
@ -812,23 +747,8 @@ private extension CloudKitAccountDelegate {
|
||||
self.refreshProgress.completeTask()
|
||||
switch result {
|
||||
case .success(let externalID):
|
||||
|
||||
feed.externalID = externalID
|
||||
|
||||
account.fetchArticlesAsync(.webFeed(feed)) { result in
|
||||
switch result {
|
||||
case .success(let articles):
|
||||
self.processRecords(new: articles, updated: Set<Article>(), deleted: Set<Article>()) {
|
||||
self.articlesZone.fetchChangesInZone() { _ in
|
||||
self.refreshProgress.clear()
|
||||
completion(.success(feed))
|
||||
}
|
||||
}
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
self.sendNewArticlesToTheCloud(account, feed, completion: completion)
|
||||
case .failure(let error):
|
||||
self.refreshProgress.clear()
|
||||
completion(.failure(error))
|
||||
@ -859,6 +779,31 @@ private extension CloudKitAccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func sendNewArticlesToTheCloud(_ account: Account, _ feed: WebFeed, completion: @escaping (Result<WebFeed, Error>) -> Void) {
|
||||
account.fetchArticlesAsync(.webFeed(feed)) { result in
|
||||
switch result {
|
||||
case .success(let articles):
|
||||
self.storeArticleChanges(new: articles, updated: Set<Article>(), deleted: Set<Article>()) {
|
||||
self.refreshArticleStatus(for: account) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.articlesZone.fetchChangesInZone() { _ in
|
||||
self.refreshProgress.clear()
|
||||
completion(.success(feed))
|
||||
}
|
||||
case .failure(let error):
|
||||
self.refreshProgress.clear()
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
case .failure(let error):
|
||||
self.refreshProgress.clear()
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func processAccountError(_ account: Account, _ error: Error) {
|
||||
if case CloudKitZoneError.userDeletedZone = error {
|
||||
account.removeFeeds(account.topLevelWebFeeds)
|
||||
@ -868,6 +813,42 @@ private extension CloudKitAccountDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func storeArticleChanges(new: Set<Article>?, updated: Set<Article>?, deleted: Set<Article>?, completion: @escaping () -> Void) {
|
||||
let group = DispatchGroup()
|
||||
|
||||
group.enter()
|
||||
insertSyncStatuses(articles: new, statusKey: .new, flag: true) {
|
||||
group.leave()
|
||||
}
|
||||
|
||||
group.enter()
|
||||
insertSyncStatuses(articles: updated, statusKey: .new, flag: false) {
|
||||
group.leave()
|
||||
}
|
||||
|
||||
group.enter()
|
||||
insertSyncStatuses(articles: deleted, statusKey: .deleted, flag: true) {
|
||||
group.leave()
|
||||
}
|
||||
|
||||
group.notify(queue: DispatchQueue.main) {
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
func insertSyncStatuses(articles: Set<Article>?, statusKey: SyncStatus.Key, flag: Bool, completion: @escaping () -> Void) {
|
||||
guard let articles = articles else {
|
||||
completion()
|
||||
return
|
||||
}
|
||||
let syncStatuses = articles.map { article in
|
||||
return SyncStatus(articleID: article.articleID, key: statusKey, flag: flag)
|
||||
}
|
||||
database.insertStatuses(syncStatuses) { _ in
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension CloudKitAccountDelegate: LocalAccountRefresherDelegate {
|
||||
|
@ -12,6 +12,7 @@ import RSParser
|
||||
import RSWeb
|
||||
import CloudKit
|
||||
import Articles
|
||||
import SyncDatabase
|
||||
|
||||
final class CloudKitArticlesZone: CloudKitZone {
|
||||
|
||||
@ -95,40 +96,50 @@ final class CloudKitArticlesZone: CloudKitZone {
|
||||
delete(ckQuery: ckQuery, completion: completion)
|
||||
}
|
||||
|
||||
func deleteArticles(_ articles: Set<Article>, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
guard !articles.isEmpty else {
|
||||
func modifyArticles(_ statusArticles: [(status: SyncStatus, article: Article?)], completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
guard !statusArticles.isEmpty else {
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
||||
let recordIDs = articles.map { CKRecord.ID(recordName: $0.articleID, zoneID: Self.zoneID) }
|
||||
delete(recordIDs: recordIDs, completion: completion)
|
||||
var newRecords = [CKRecord]()
|
||||
var modifyRecords = [CKRecord]()
|
||||
var deleteRecordIDs = [CKRecord.ID]()
|
||||
|
||||
for statusArticle in statusArticles {
|
||||
switch (statusArticle.status.key, statusArticle.status.flag) {
|
||||
case (.new, true):
|
||||
// create status
|
||||
if let article = statusArticle.article {
|
||||
newRecords.append(contentsOf: makeArticleRecords(article))
|
||||
}
|
||||
case (.starred, true), (.read, false):
|
||||
// create status
|
||||
if let article = statusArticle.article {
|
||||
modifyRecords.append(contentsOf: makeArticleRecords(article))
|
||||
}
|
||||
case (.deleted, true):
|
||||
deleteRecordIDs.append(CKRecord.ID(recordName: statusArticle.status.articleID, zoneID: Self.zoneID))
|
||||
default:
|
||||
print()
|
||||
// create status
|
||||
// delete article record
|
||||
}
|
||||
}
|
||||
|
||||
func modifyArticles(_ articles: Set<Article>, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
guard !articles.isEmpty else {
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
||||
var records = [CKRecord]()
|
||||
|
||||
let saveArticles = articles.filter { $0.status.read == false || $0.status.starred == true }
|
||||
for saveArticle in saveArticles {
|
||||
records.append(contentsOf: makeArticleRecords(saveArticle))
|
||||
}
|
||||
|
||||
let hollowArticles = articles.subtracting(saveArticles)
|
||||
for hollowArticle in hollowArticles {
|
||||
records.append(contentsOf: makeHollowArticleRecords(hollowArticle))
|
||||
}
|
||||
|
||||
self.modify(recordsToSave: records, recordIDsToDelete: []) { result in
|
||||
saveIfNew(newRecords) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.modify(recordsToSave: modifyRecords, recordIDsToDelete: deleteRecordIDs) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
completion(.success(()))
|
||||
case .failure(let error):
|
||||
self.handleSendArticleStatusError(error, articles: articles, completion: completion)
|
||||
self.handleSendArticleStatusError(error, statusArticles: statusArticles, completion: completion)
|
||||
}
|
||||
}
|
||||
case .failure(let error):
|
||||
self.handleSendArticleStatusError(error, statusArticles: statusArticles, completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -137,12 +148,12 @@ final class CloudKitArticlesZone: CloudKitZone {
|
||||
|
||||
private extension CloudKitArticlesZone {
|
||||
|
||||
func handleSendArticleStatusError(_ error: Error, articles: Set<Article>, completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
func handleSendArticleStatusError(_ error: Error, statusArticles: [(status: SyncStatus, article: Article?)], completion: @escaping ((Result<Void, Error>) -> Void)) {
|
||||
if case CloudKitZoneError.userDeletedZone = error {
|
||||
self.createZoneRecord() { result in
|
||||
switch result {
|
||||
case .success:
|
||||
self.modifyArticles(articles, completion: completion)
|
||||
self.modifyArticles(statusArticles, completion: completion)
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
|
@ -261,9 +261,12 @@ final class FeedWranglerAPICaller: NSObject {
|
||||
switch status.key {
|
||||
case .read:
|
||||
return URLQueryItem(name: "read", value: status.flag.description)
|
||||
|
||||
case .starred:
|
||||
return URLQueryItem(name: "starred", value: status.flag.description)
|
||||
case .deleted:
|
||||
return nil
|
||||
case .new:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
queryItems.append(URLQueryItem(name: "feed_item_id", value: articleID))
|
||||
|
@ -436,7 +436,7 @@ final class FeedWranglerAccountDelegate: AccountDelegate {
|
||||
}
|
||||
|
||||
func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) -> Set<Article>? {
|
||||
let syncStatuses = articles.map { SyncStatus(articleID: $0.articleID, key: statusKey, flag: flag)}
|
||||
let syncStatuses = articles.map { SyncStatus(articleID: $0.articleID, key: SyncStatus.Key(statusKey), flag: flag)}
|
||||
database.insertStatuses(syncStatuses)
|
||||
|
||||
database.selectPendingCount { result in
|
||||
|
@ -119,10 +119,10 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||
database.selectForProcessing { result in
|
||||
|
||||
func processStatuses(_ syncStatuses: [SyncStatus]) {
|
||||
let createUnreadStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.read && $0.flag == false }
|
||||
let deleteUnreadStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.read && $0.flag == true }
|
||||
let createStarredStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.starred && $0.flag == true }
|
||||
let deleteStarredStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.starred && $0.flag == false }
|
||||
let createUnreadStatuses = syncStatuses.filter { $0.key == SyncStatus.Key.read && $0.flag == false }
|
||||
let deleteUnreadStatuses = syncStatuses.filter { $0.key == SyncStatus.Key.read && $0.flag == true }
|
||||
let createStarredStatuses = syncStatuses.filter { $0.key == SyncStatus.Key.starred && $0.flag == true }
|
||||
let deleteStarredStatuses = syncStatuses.filter { $0.key == SyncStatus.Key.starred && $0.flag == false }
|
||||
|
||||
let group = DispatchGroup()
|
||||
var errorOccurred = false
|
||||
@ -537,7 +537,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||
func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) -> Set<Article>? {
|
||||
|
||||
let syncStatuses = articles.map { article in
|
||||
return SyncStatus(articleID: article.articleID, key: statusKey, flag: flag)
|
||||
return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag)
|
||||
}
|
||||
database.insertStatuses(syncStatuses)
|
||||
|
||||
|
@ -489,7 +489,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
||||
func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) -> Set<Article>? {
|
||||
|
||||
let syncStatuses = articles.map { article in
|
||||
return SyncStatus(articleID: article.articleID, key: statusKey, flag: flag)
|
||||
return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag)
|
||||
}
|
||||
|
||||
database.insertStatuses(syncStatuses)
|
||||
|
@ -47,7 +47,7 @@ final class FeedlySendArticleStatusesOperation: FeedlyOperation {
|
||||
private extension FeedlySendArticleStatusesOperation {
|
||||
|
||||
func processStatuses(_ pending: [SyncStatus]) {
|
||||
let statuses: [(status: ArticleStatus.Key, flag: Bool, action: FeedlyMarkAction)] = [
|
||||
let statuses: [(status: SyncStatus.Key, flag: Bool, action: FeedlyMarkAction)] = [
|
||||
(.read, false, .unread),
|
||||
(.read, true, .read),
|
||||
(.starred, true, .saved),
|
||||
|
@ -131,16 +131,16 @@ final class NewsBlurAccountDelegate: AccountDelegate {
|
||||
|
||||
func processStatuses(_ syncStatuses: [SyncStatus]) {
|
||||
let createUnreadStatuses = syncStatuses.filter {
|
||||
$0.key == ArticleStatus.Key.read && $0.flag == false
|
||||
$0.key == SyncStatus.Key.read && $0.flag == false
|
||||
}
|
||||
let deleteUnreadStatuses = syncStatuses.filter {
|
||||
$0.key == ArticleStatus.Key.read && $0.flag == true
|
||||
$0.key == SyncStatus.Key.read && $0.flag == true
|
||||
}
|
||||
let createStarredStatuses = syncStatuses.filter {
|
||||
$0.key == ArticleStatus.Key.starred && $0.flag == true
|
||||
$0.key == SyncStatus.Key.starred && $0.flag == true
|
||||
}
|
||||
let deleteStarredStatuses = syncStatuses.filter {
|
||||
$0.key == ArticleStatus.Key.starred && $0.flag == false
|
||||
$0.key == SyncStatus.Key.starred && $0.flag == false
|
||||
}
|
||||
|
||||
let group = DispatchGroup()
|
||||
@ -575,7 +575,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
|
||||
|
||||
func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) -> Set<Article>? {
|
||||
let syncStatuses = articles.map { article in
|
||||
return SyncStatus(articleID: article.articleID, key: statusKey, flag: flag)
|
||||
return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag)
|
||||
}
|
||||
database.insertStatuses(syncStatuses)
|
||||
|
||||
|
@ -123,10 +123,10 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
|
||||
database.selectForProcessing { result in
|
||||
|
||||
func processStatuses(_ syncStatuses: [SyncStatus]) {
|
||||
let createUnreadStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.read && $0.flag == false }
|
||||
let deleteUnreadStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.read && $0.flag == true }
|
||||
let createStarredStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.starred && $0.flag == true }
|
||||
let deleteStarredStatuses = syncStatuses.filter { $0.key == ArticleStatus.Key.starred && $0.flag == false }
|
||||
let createUnreadStatuses = syncStatuses.filter { $0.key == SyncStatus.Key.read && $0.flag == false }
|
||||
let deleteUnreadStatuses = syncStatuses.filter { $0.key == SyncStatus.Key.read && $0.flag == true }
|
||||
let createStarredStatuses = syncStatuses.filter { $0.key == SyncStatus.Key.starred && $0.flag == true }
|
||||
let deleteStarredStatuses = syncStatuses.filter { $0.key == SyncStatus.Key.starred && $0.flag == false }
|
||||
|
||||
let group = DispatchGroup()
|
||||
|
||||
@ -412,7 +412,7 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
|
||||
func markArticles(for account: Account, articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool) -> Set<Article>? {
|
||||
|
||||
let syncStatuses = articles.map { article in
|
||||
return SyncStatus(articleID: article.articleID, key: statusKey, flag: flag)
|
||||
return SyncStatus(articleID: article.articleID, key: SyncStatus.Key(statusKey), flag: flag)
|
||||
}
|
||||
database.insertStatuses(syncStatuses)
|
||||
|
||||
|
@ -12,12 +12,29 @@ import RSDatabase
|
||||
|
||||
public struct SyncStatus: Hashable, Equatable {
|
||||
|
||||
public enum Key: String {
|
||||
case read = "read"
|
||||
case starred = "starred"
|
||||
case deleted = "deleted"
|
||||
case new = "new"
|
||||
|
||||
public init(_ articleStatusKey: ArticleStatus.Key) {
|
||||
switch articleStatusKey {
|
||||
case .read:
|
||||
self = Self.read
|
||||
case .starred:
|
||||
self = Self.starred
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public let articleID: String
|
||||
public let key: ArticleStatus.Key
|
||||
public let key: SyncStatus.Key
|
||||
public let flag: Bool
|
||||
public let selected: Bool
|
||||
|
||||
public init(articleID: String, key: ArticleStatus.Key, flag: Bool, selected: Bool = false) {
|
||||
public init(articleID: String, key: SyncStatus.Key, flag: Bool, selected: Bool = false) {
|
||||
self.articleID = articleID
|
||||
self.key = key
|
||||
self.flag = flag
|
||||
|
@ -155,7 +155,7 @@ private extension SyncStatusTable {
|
||||
func statusWithRow(_ row: FMResultSet) -> SyncStatus? {
|
||||
guard let articleID = row.string(forColumn: DatabaseKey.articleID),
|
||||
let rawKey = row.string(forColumn: DatabaseKey.key),
|
||||
let key = ArticleStatus.Key(rawValue: rawKey) else {
|
||||
let key = SyncStatus.Key(rawValue: rawKey) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user