sync article labels with serevr

This commit is contained in:
Satindar Dhillon 2022-04-05 13:45:39 -07:00
parent f34631525b
commit 3742ee0330
7 changed files with 108 additions and 10 deletions

View file

@ -2,6 +2,7 @@ import Combine
import Models
import Services
import SwiftUI
import Views
final class ApplyLabelsViewModel: ObservableObject {
private var hasLoadedInitialLabels = false
@ -25,10 +26,20 @@ final class ApplyLabelsViewModel: ObservableObject {
)
.store(in: &subscriptions)
}
func saveChanges(itemID: String, dataService: DataService, onComplete: @escaping ([FeedItemLabel]) -> Void) {
dataService.updateArticleLabelsPublisher(itemID: itemID, labelIDs: selectedLabels.map(\.id)).sink(
receiveCompletion: { _ in },
receiveValue: { onComplete($0) }
)
.store(in: &subscriptions)
}
}
struct ApplyLabelsView: View {
let item: FeedItem
let commitLabelChanges: ([FeedItemLabel]) -> Void
@EnvironmentObject var dataService: DataService
@Environment(\.presentationMode) private var presentationMode
@StateObject var viewModel = ApplyLabelsViewModel()
@ -39,7 +50,11 @@ struct ApplyLabelsView: View {
EmptyView()
} else {
List(viewModel.labels, id: \.self, selection: $viewModel.selectedLabels) { label in
Text(label.name)
if let textChip = TextChip(feedItemLabel: label) {
textChip
} else {
Text(label.name)
}
}
.environment(\.editMode, .constant(EditMode.active))
.navigationTitle("Apply Labels")
@ -54,8 +69,10 @@ struct ApplyLabelsView: View {
ToolbarItem(placement: .navigationBarTrailing) {
Button(
action: {
print("saving")
presentationMode.wrappedValue.dismiss()
viewModel.saveChanges(itemID: item.id, dataService: dataService) { labels in
commitLabelChanges(labels)
presentationMode.wrappedValue.dismiss()
}
},
label: { Text("Save") }
)

View file

@ -167,8 +167,10 @@ import Views
}
}
}
.sheet(item: $viewModel.itemUnderLabelEdit, onDismiss: { print("edit label modal dismissed") }) { item in
ApplyLabelsView(item: item)
.sheet(item: $viewModel.itemUnderLabelEdit) { item in
ApplyLabelsView(item: item) { labels in
viewModel.updateLabels(itemID: item.id, labels: labels)
}
}
}
}

View file

@ -183,4 +183,11 @@ final class HomeFeedViewModel: ObservableObject {
items[index].readingProgress = progress
}
}
func updateLabels(itemID: String, labels: [FeedItemLabel]) {
guard let item = items.first(where: { $0.id == itemID }) else { return }
if let index = items.firstIndex(of: item) {
items[index].labels = labels
}
}
}

View file

@ -28,7 +28,7 @@ public struct FeedItem: Identifiable, Hashable, Decodable {
public let slug: String
public let isArchived: Bool
public let contentReader: String?
public let labels: [FeedItemLabel]
public var labels: [FeedItemLabel]
public init(
id: String,

View file

@ -0,0 +1,57 @@
import Combine
import Foundation
import Models
import SwiftGraphQL
public extension DataService {
func updateArticleLabelsPublisher(itemID: String, labelIDs: [String]) -> AnyPublisher<[FeedItemLabel], BasicError> {
enum MutationResult {
case saved(feedItem: [FeedItemLabel])
case error(errorCode: Enums.SetLabelsErrorCode)
}
let selection = Selection<MutationResult, Unions.SetLabelsResult> {
try $0.on(
setLabelsSuccess: .init { .saved(feedItem: try $0.labels(selection: feedItemLabelSelection.list)) },
setLabelsError: .init { .error(errorCode: try $0.errorCodes().first ?? .badRequest) }
)
}
let mutation = Selection.Mutation {
try $0.setLabels(
input: InputObjects.SetLabelsInput(
linkId: itemID,
labelIds: labelIDs
),
selection: selection
)
}
let path = appEnvironment.graphqlPath
let headers = networker.defaultHeaders
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)))
}
switch payload.data {
case let .saved(labels):
promise(.success(labels))
case .error:
promise(.failure(.message(messageText: "failed to set labels")))
}
case .failure:
promise(.failure(.message(messageText: "failed to set labels")))
}
}
}
}
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
}

View file

@ -164,8 +164,9 @@ public struct GridCard: View {
if FeatureFlag.enableLabels {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
TextChip(text: "label", color: .red)
TextChip(text: "longer label", color: .blue)
ForEach(item.labels, id: \.self) {
TextChip(feedItemLabel: $0)
}
Spacer()
}
.frame(height: 30)

View file

@ -1,11 +1,25 @@
import Models
import SwiftUI
import Utils
public struct TextChip: View {
public init(text: String, color: Color) {
self.text = text
self.color = color
}
public init?(feedItemLabel: FeedItemLabel) {
guard let color = Color(hex: feedItemLabel.color) else { return nil }
self.text = feedItemLabel.name
self.color = color
}
struct TextChip: View {
let text: String
let color: Color
let cornerRadius = 20.0
var body: some View {
public var body: some View {
Text(text)
.padding(.horizontal, 10)
.padding(.vertical, 5)