mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
sync article labels with serevr
This commit is contained in:
parent
f34631525b
commit
3742ee0330
7 changed files with 108 additions and 10 deletions
|
|
@ -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") }
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue