From 1b85fb0c15fade4fff0f755157f0f0972cf60cac Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Wed, 1 Nov 2023 14:29:15 +0800 Subject: [PATCH] Add feeds, better delete handling --- .../Share/Views/EditLabelsSheet.swift | 2 +- .../App/Views/Home/HomeFeedDisplayText.swift | 2 + .../App/Views/Labels/ApplyLabelsView.swift | 8 +- .../App/Views/Labels/LabelsViewModel.swift | 10 ++- ...{SearchBar.swift => LabelsEntryView.swift} | 76 ++++++++----------- .../Sources/Models/LinkedItemFilter.swift | 8 ++ 6 files changed, 54 insertions(+), 52 deletions(-) rename apple/OmnivoreKit/Sources/App/Views/{SearchBar.swift => LabelsEntryView.swift} (72%) diff --git a/apple/OmnivoreKit/Sources/App/AppExtensions/Share/Views/EditLabelsSheet.swift b/apple/OmnivoreKit/Sources/App/AppExtensions/Share/Views/EditLabelsSheet.swift index 834081a7f..c9ca6c639 100644 --- a/apple/OmnivoreKit/Sources/App/AppExtensions/Share/Views/EditLabelsSheet.swift +++ b/apple/OmnivoreKit/Sources/App/AppExtensions/Share/Views/EditLabelsSheet.swift @@ -38,7 +38,7 @@ public struct EditLabelsSheet: View { if let idx = labelsViewModel.selectedLabels.firstIndex(of: label) { labelsViewModel.selectedLabels.remove(at: idx) } else { - labelsViewModel.labelSearchFilter = "" + labelsViewModel.labelSearchFilter = ZWSP labelsViewModel.selectedLabels.append(label) } diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedDisplayText.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedDisplayText.swift index eb57e0d4f..745d37a77 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedDisplayText.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedDisplayText.swift @@ -11,6 +11,8 @@ extension LinkedItemFilter { return LocalText.readLaterGeneric case .newsletters: return LocalText.newslettersGeneric + case .feeds: + return "Feeds" case .recommended: return "Recommended" case .all: diff --git a/apple/OmnivoreKit/Sources/App/Views/Labels/ApplyLabelsView.swift b/apple/OmnivoreKit/Sources/App/Views/Labels/ApplyLabelsView.swift index b16b41ffe..9b6129bd6 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Labels/ApplyLabelsView.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Labels/ApplyLabelsView.swift @@ -72,7 +72,7 @@ struct ApplyLabelsView: View { viewModel.selectedLabels.remove(at: idx) } } else { - viewModel.labelSearchFilter = "" + viewModel.labelSearchFilter = ZWSP viewModel.selectedLabels.append(label) } }, @@ -204,9 +204,11 @@ struct ApplyLabelsView: View { extension Sequence where Element == LinkedItemLabel { func applySearchFilter(_ searchFilter: String) -> [LinkedItemLabel] { - if searchFilter.isEmpty { + if searchFilter.isEmpty || searchFilter == ZWSP { return map { $0 } // return the identity of the sequence } - return filter { ($0.name ?? "").lowercased().contains(searchFilter.lowercased()) } + let index = searchFilter.index(searchFilter.startIndex, offsetBy: 1) + let trimmed = searchFilter.suffix(from: index).lowercased() + return filter { ($0.name ?? "").lowercased().contains(trimmed) } } } diff --git a/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsViewModel.swift b/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsViewModel.swift index b39875853..11b652f16 100644 --- a/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsViewModel.swift +++ b/apple/OmnivoreKit/Sources/App/Views/Labels/LabelsViewModel.swift @@ -11,7 +11,7 @@ import SwiftUI @Published var unselectedLabels = Set() @Published var labels = [LinkedItemLabel]() @Published var showCreateLabelModal = false - @Published var labelSearchFilter = "" + @Published var labelSearchFilter = ZWSP public init() {} @@ -35,7 +35,9 @@ import SwiftUI await loadLabelsFromStore(dataService: dataService) for label in labels { if selLabels.contains(label) { - selectedLabels.append(label) + if !selectedLabels.contains(label) { + selectedLabels.append(label) + } } else { unselectedLabels.insert(label) } @@ -49,7 +51,9 @@ import SwiftUI } for label in self.labels { if selLabels.contains(label) { - self.selectedLabels.append(label) + if !self.selectedLabels.contains(label) { + self.selectedLabels.append(label) + } } else { self.unselectedLabels.insert(label) } diff --git a/apple/OmnivoreKit/Sources/App/Views/SearchBar.swift b/apple/OmnivoreKit/Sources/App/Views/LabelsEntryView.swift similarity index 72% rename from apple/OmnivoreKit/Sources/App/Views/SearchBar.swift rename to apple/OmnivoreKit/Sources/App/Views/LabelsEntryView.swift index 6be364265..9cb8bab3f 100644 --- a/apple/OmnivoreKit/Sources/App/Views/SearchBar.swift +++ b/apple/OmnivoreKit/Sources/App/Views/LabelsEntryView.swift @@ -3,6 +3,8 @@ import Services import SwiftUI import Views +let ZWSP = "\u{200B}" + @MainActor protocol Entry { func item(parent: LabelsEntryView) -> AnyView @@ -24,14 +26,11 @@ private struct LabelEntry: Entry { public struct LabelsEntryView: View { @Binding var searchTerm: String @State var viewModel: LabelsViewModel - @State var lastSelected = false - @State var justInserted = false let entries: [Entry] @State private var totalHeight = CGFloat.zero @FocusState private var textFieldFocused: Bool - @FocusState private var neverFocused: Bool public init( searchTerm: Binding, @@ -44,22 +43,21 @@ public struct LabelsEntryView: View { } func onTextSubmit() { - if searchTerm.count < 1 { + let index = searchTerm.index(searchTerm.startIndex, offsetBy: 1) + let trimmed = searchTerm.suffix(from: index).lowercased() + + if trimmed.count < 1 { return } - // first see if there is a matching label - let term = searchTerm.lowercased() - if let label = viewModel.labels.first(where: { $0.name?.lowercased() == term }) { - justInserted = true - searchTerm = "" + if let label = viewModel.labels.first(where: { $0.name?.lowercased() == trimmed }) { if !viewModel.selectedLabels.contains(label) { viewModel.selectedLabels.append(label) } + + searchTerm = ZWSP DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { - lastSelected = false textFieldFocused = true - justInserted = false } } } @@ -78,32 +76,20 @@ public struct LabelsEntryView: View { .padding(5) .font(Font.system(size: 14)) .multilineTextAlignment(.leading) - .onChange(of: searchTerm, perform: { newValue in - print("NEW VALUE: ", newValue.count) + .onChange(of: searchTerm, perform: { _ in if searchTerm.count >= 64 { searchTerm = String(searchTerm.prefix(64)) } if searchTerm.isEmpty { - // When we insert a new item we set the text to "" so this block is triggered - // we need to ignore that special case. - if justInserted { - justInserted = false - return - } - if lastSelected { - if viewModel.selectedLabels.count > 0 { - lastSelected = false - viewModel.selectedLabels.removeLast() - DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { - textFieldFocused = true - } + if viewModel.selectedLabels.count > 0 { + viewModel.selectedLabels.removeLast() + searchTerm = ZWSP + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { + textFieldFocused = true } } else { - lastSelected = true - searchTerm = "\u{200B}" + searchTerm = ZWSP } - } else if searchTerm != "\u{200B}" { - lastSelected = false } }) .onSubmit { @@ -112,21 +98,21 @@ public struct LabelsEntryView: View { return result } - func onTextDelete() -> Bool { if searchTerm.isEmpty { - if lastSelected { - if viewModel.selectedLabels.count > 0 { - viewModel.selectedLabels.removeLast() - DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) { - textFieldFocused = true - } - } - } else { - lastSelected = true - } - return true - } - return false - } +// func onTextDelete() -> Bool { if searchTerm.isEmpty { +// if lastSelected { +// if viewModel.selectedLabels.count > 0 { +// viewModel.selectedLabels.removeLast() +// DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) { +// textFieldFocused = true +// } +// } +// } else { +// lastSelected = true +// } +// return true +// } +// return false +// } public var body: some View { // HStack(spacing: 0) { diff --git a/apple/OmnivoreKit/Sources/Models/LinkedItemFilter.swift b/apple/OmnivoreKit/Sources/Models/LinkedItemFilter.swift index b9e819a32..be54b26ef 100644 --- a/apple/OmnivoreKit/Sources/Models/LinkedItemFilter.swift +++ b/apple/OmnivoreKit/Sources/Models/LinkedItemFilter.swift @@ -2,6 +2,7 @@ import Foundation public enum LinkedItemFilter: String, CaseIterable { case inbox + case feeds case readlater case newsletters case recommended @@ -17,6 +18,8 @@ public extension LinkedItemFilter { switch self { case .inbox: return "in:inbox" + case .feeds: + return "label:RSS" case .readlater: return "in:library" case .newsletters: @@ -76,6 +79,11 @@ public extension LinkedItemFilter { format: "SUBQUERY(labels, $label, $label.name == \"Newsletter\").@count > 0" ) return NSCompoundPredicate(andPredicateWithSubpredicates: [notInArchivePredicate, newsletterLabelPredicate]) + case .feeds: + let feedLabelPredicate = NSPredicate( + format: "SUBQUERY(labels, $label, $label.name == \"RSS\").@count > 0" + ) + return NSCompoundPredicate(andPredicateWithSubpredicates: [notInArchivePredicate, feedLabelPredicate]) case .recommended: // non-archived or deleted items with the Newsletter label let recommendedPredicate = NSPredicate(