use credata for updating item labels

This commit is contained in:
Satindar Dhillon 2022-04-27 18:06:57 -07:00
parent d7bc70fcd1
commit acb1ae6c53
4 changed files with 45 additions and 78 deletions

View file

@ -48,7 +48,7 @@ import Views
loadItems(isRefresh: true)
}
.sheet(item: $viewModel.itemUnderLabelEdit) { item in
ApplyLabelsView(mode: .item(item)) { _ in }
ApplyLabelsView(mode: .item(item))
}
}
.navigationTitle("Home")
@ -111,9 +111,7 @@ import Views
}
.padding(.horizontal)
.sheet(isPresented: $showLabelsSheet) {
ApplyLabelsView(mode: .list(viewModel.selectedLabels)) { labels in
viewModel.selectedLabels = labels
}
ApplyLabelsView(mode: .list(viewModel.selectedLabels))
}
}
if prefersListLayout {

View file

@ -28,7 +28,6 @@ struct ApplyLabelsView: View {
}
let mode: Mode
let commitLabelChanges: ([LinkedItemLabel]) -> Void
@EnvironmentObject var dataService: DataService
@Environment(\.presentationMode) private var presentationMode
@ -100,14 +99,11 @@ struct ApplyLabelsView: View {
action: {
switch mode {
case let .item(feedItem):
viewModel.saveItemLabelChanges(itemID: feedItem.unwrappedID, dataService: dataService) { labels in
commitLabelChanges(labels)
presentationMode.wrappedValue.dismiss()
}
viewModel.saveItemLabelChanges(itemID: feedItem.unwrappedID, dataService: dataService)
case .list:
commitLabelChanges(viewModel.selectedLabels)
presentationMode.wrappedValue.dismiss()
break
}
presentationMode.wrappedValue.dismiss()
},
label: { Text(mode.confirmButtonText).foregroundColor(.appGrayTextContrast) }
)

View file

@ -74,23 +74,8 @@ import Views
.store(in: &subscriptions)
}
func saveItemLabelChanges(
itemID: String,
dataService: DataService,
onComplete: @escaping ([LinkedItemLabel]) -> Void
) {
isLoading = true
dataService.updateArticleLabelsPublisher(itemID: itemID, labelIDs: selectedLabels.map(\.unwrappedID)).sink(
receiveCompletion: { [weak self] _ in
self?.isLoading = false
},
receiveValue: { labelIDs in
onComplete(
labelIDs.compactMap { dataService.viewContext.object(with: $0) as? LinkedItemLabel }
)
}
)
.store(in: &subscriptions)
func saveItemLabelChanges(itemID: String, dataService: DataService) {
dataService.updateItemLabels(itemID: itemID, labelNames: selectedLabels.map(\.unwrappedName))
}
func addLabelToItem(_ label: LinkedItemLabel) {

View file

@ -1,15 +1,33 @@
import Combine
import CoreData
import Foundation
import Models
import SwiftGraphQL
public extension DataService {
// swiftlint:disable:next function_body_length
func updateArticleLabelsPublisher(
itemID: String,
labelIDs: [String]
) -> AnyPublisher<[NSManagedObjectID], BasicError> {
extension DataService {
public func updateItemLabels(itemID: String, labelNames: [String]) {
backgroundContext.perform { [weak self] in
guard let self = self else { return }
guard let linkedItem = LinkedItem.lookup(byID: itemID, inContext: self.backgroundContext) else { return }
if let existingLabels = linkedItem.labels {
linkedItem.removeFromLabels(existingLabels)
}
var labelIDs = [String]()
for labelName in labelNames {
if let labelObject = LinkedItemLabel.lookup(byName: labelName, inContext: self.backgroundContext) {
linkedItem.addToLabels(labelObject)
labelIDs.append(labelObject.unwrappedID)
}
}
// Send update to server
self.syncLabelUpdates(itemID: itemID, labelIDs: labelIDs)
}
}
func syncLabelUpdates(itemID: String, labelIDs: [String]) {
enum MutationResult {
case saved(feedItem: [InternalLinkedItemLabel])
case error(errorCode: Enums.SetLabelsErrorCode)
@ -34,54 +52,24 @@ public extension DataService {
let path = appEnvironment.graphqlPath
let headers = networker.defaultHeaders
let context = backgroundContext
return Deferred {
Future { promise in
send(mutation, to: path, headers: headers) { result in
switch result {
case let .success(payload):
if let graphqlError = payload.errors {
promise(.failure(.message(messageText: graphqlError.first.debugDescription)))
}
send(mutation, to: path, headers: headers) { result in
let data = try? result.get()
let syncStatus: ServerSyncStatus = data == nil ? .needsUpdate : .isNSync
switch payload.data {
case let .saved(labels):
self.backgroundContext.perform {
guard let linkedItem = LinkedItem.lookup(byID: itemID, inContext: self.backgroundContext) else {
promise(.failure(.message(messageText: "failed to set labels")))
return
}
context.perform {
guard let linkedItem = LinkedItem.lookup(byID: itemID, inContext: context) else { return }
linkedItem.serverSyncStatus = Int64(syncStatus.rawValue)
if let existingLabels = linkedItem.labels {
linkedItem.removeFromLabels(existingLabels)
}
for label in labels {
if let labelObject = LinkedItemLabel.lookup(byName: label.name, inContext: self.backgroundContext) {
linkedItem.addToLabels(labelObject)
}
}
do {
try self.backgroundContext.save()
logger.debug("Item labels updated")
let labelObjects = linkedItem.labels.asArray(of: LinkedItemLabel.self)
promise(.success(labelObjects.map(\.objectID)))
} catch {
self.backgroundContext.rollback()
logger.debug("Failed to update item labels: \(error.localizedDescription)")
promise(.failure(.message(messageText: "failed to set labels")))
}
}
case .error:
promise(.failure(.message(messageText: "failed to set labels")))
}
case .failure:
promise(.failure(.message(messageText: "failed to set labels")))
}
do {
try context.save()
logger.debug("Item labels updated succesfully")
} catch {
context.rollback()
logger.debug("Failed to update item labels: \(error.localizedDescription)")
}
}
}
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
}