forked from shadowfacts/Tusker
Fetch filters and store in CoreData
This commit is contained in:
parent
0247c50650
commit
c9fa11cc3b
|
@ -8,7 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
public class Filter: Decodable {
|
||||
public struct Filter: Decodable {
|
||||
public let id: String
|
||||
public let phrase: String
|
||||
private let context: [String]
|
||||
|
@ -51,6 +51,7 @@ extension Filter {
|
|||
case notifications
|
||||
case `public`
|
||||
case thread
|
||||
case account
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
D61F759229365C6C00C0B37F /* CollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61F759129365C6C00C0B37F /* CollectionViewController.swift */; };
|
||||
D61F75942936F0DA00C0B37F /* FollowedHashtag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61F75932936F0DA00C0B37F /* FollowedHashtag.swift */; };
|
||||
D61F75962937037800C0B37F /* ToggleFollowHashtagService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61F75952937037800C0B37F /* ToggleFollowHashtagService.swift */; };
|
||||
D61F759B29384F9C00C0B37F /* FilterMO.swift in Sources */ = {isa = PBXBuildFile; fileRef = D61F759A29384F9C00C0B37F /* FilterMO.swift */; };
|
||||
D620483423D3801D008A63EF /* LinkTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483323D3801D008A63EF /* LinkTextView.swift */; };
|
||||
D620483623D38075008A63EF /* ContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483523D38075008A63EF /* ContentTextView.swift */; };
|
||||
D620483823D38190008A63EF /* StatusContentTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D620483723D38190008A63EF /* StatusContentTextView.swift */; };
|
||||
|
@ -420,6 +421,7 @@
|
|||
D61F759129365C6C00C0B37F /* CollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewController.swift; sourceTree = "<group>"; };
|
||||
D61F75932936F0DA00C0B37F /* FollowedHashtag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowedHashtag.swift; sourceTree = "<group>"; };
|
||||
D61F75952937037800C0B37F /* ToggleFollowHashtagService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleFollowHashtagService.swift; sourceTree = "<group>"; };
|
||||
D61F759A29384F9C00C0B37F /* FilterMO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterMO.swift; sourceTree = "<group>"; };
|
||||
D620483323D3801D008A63EF /* LinkTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkTextView.swift; sourceTree = "<group>"; };
|
||||
D620483523D38075008A63EF /* ContentTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentTextView.swift; sourceTree = "<group>"; };
|
||||
D620483723D38190008A63EF /* StatusContentTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusContentTextView.swift; sourceTree = "<group>"; };
|
||||
|
@ -886,6 +888,7 @@
|
|||
D6B9366E2828452F00237D0E /* SavedHashtag.swift */,
|
||||
D6B9366C2828444F00237D0E /* SavedInstance.swift */,
|
||||
D61F75932936F0DA00C0B37F /* FollowedHashtag.swift */,
|
||||
D61F759A29384F9C00C0B37F /* FilterMO.swift */,
|
||||
D60E2F2D244248BF005F8713 /* MastodonCachePersistentStore.swift */,
|
||||
D6B936702829F72900237D0E /* NSManagedObjectContext+Helpers.swift */,
|
||||
);
|
||||
|
@ -1824,6 +1827,7 @@
|
|||
D69693FA25859A8000F4E116 /* ComposeSceneDelegate.swift in Sources */,
|
||||
D6A3BC8A2321F79B00FD64D5 /* AccountTableViewCell.swift in Sources */,
|
||||
D66A77BB233838DC0058F1EC /* UIFont+Traits.swift in Sources */,
|
||||
D61F759B29384F9C00C0B37F /* FilterMO.swift in Sources */,
|
||||
D68FEC4F232C5BC300C84F23 /* SegmentedPageViewController.swift in Sources */,
|
||||
D64AAE9126C80DC600FC57FB /* ToastView.swift in Sources */,
|
||||
D62275AA24F1E01C00B82A16 /* ComposeTextView.swift in Sources */,
|
||||
|
|
|
@ -50,6 +50,7 @@ class MastodonController: ObservableObject {
|
|||
@Published private(set) var lists: [List] = []
|
||||
@Published private(set) var customEmojis: [Emoji]?
|
||||
@Published private(set) var followedHashtags: [FollowedHashtag] = []
|
||||
@Published private(set) var filters: [FilterMO] = []
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
|
@ -154,6 +155,7 @@ class MastodonController: ObservableObject {
|
|||
_ = try await (ownAccount, ownInstance)
|
||||
|
||||
loadLists()
|
||||
async let _ = await loadFilters()
|
||||
}
|
||||
|
||||
func getOwnAccount(completion: ((Result<Account, Client.Error>) -> Void)? = nil) {
|
||||
|
@ -350,6 +352,20 @@ class MastodonController: ObservableObject {
|
|||
followedHashtags = (try? persistentContainer.viewContext.fetch(FollowedHashtag.fetchRequest())) ?? []
|
||||
}
|
||||
|
||||
@MainActor
|
||||
func loadFilters() async {
|
||||
filters = (try? persistentContainer.viewContext.fetch(FilterMO.fetchRequest())) ?? []
|
||||
|
||||
let req = Client.getFilters()
|
||||
if let (filters, _) = try? await run(req) {
|
||||
self.persistentContainer.updateFilters(filters) {
|
||||
if case .success(let filters) = $0 {
|
||||
self.filters = filters
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private struct ListComparator: SortComparator {
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// FilterMO.swift
|
||||
// Tusker
|
||||
//
|
||||
// Created by Shadowfacts on 11/30/22.
|
||||
// Copyright © 2022 Shadowfacts. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
import Pachyderm
|
||||
|
||||
@objc(FilterMO)
|
||||
public final class FilterMO: NSManagedObject {
|
||||
|
||||
@nonobjc public class func fetchRequest() -> NSFetchRequest<FilterMO> {
|
||||
return NSFetchRequest(entityName: "Filter")
|
||||
}
|
||||
|
||||
@NSManaged public var id: String
|
||||
@NSManaged public var phrase: String
|
||||
@NSManaged private var context: String
|
||||
@NSManaged public var expiresAt: Date?
|
||||
@NSManaged public var irreversible: Bool
|
||||
@NSManaged public var wholeWord: Bool
|
||||
|
||||
private var _contexts: [Filter.Context]?
|
||||
var contexts: [Filter.Context] {
|
||||
get {
|
||||
if let _contexts {
|
||||
return _contexts
|
||||
} else {
|
||||
_contexts = context.split(separator: ",").compactMap { .init(rawValue: String($0)) }
|
||||
return _contexts!
|
||||
}
|
||||
}
|
||||
set {
|
||||
_contexts = newValue
|
||||
context = newValue.map(\.rawValue).joined(separator: ",")
|
||||
}
|
||||
}
|
||||
|
||||
public override func didChangeValue(forKey key: String) {
|
||||
super.didChangeValue(forKey: key)
|
||||
if key == "context" {
|
||||
_contexts = nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension FilterMO {
|
||||
convenience init(apiFilter filter: Filter, context: NSManagedObjectContext) {
|
||||
self.init(context: context)
|
||||
self.updateFrom(apiFilter: filter)
|
||||
}
|
||||
|
||||
func updateFrom(apiFilter filter: Filter) {
|
||||
self.id = filter.id
|
||||
self.phrase = filter.phrase
|
||||
self.contexts = filter.contexts
|
||||
self.expiresAt = filter.expiresAt
|
||||
self.irreversible = filter.irreversible
|
||||
self.wholeWord = filter.wholeWord
|
||||
}
|
||||
}
|
|
@ -299,6 +299,29 @@ class MastodonCachePersistentStore: NSPersistentContainer {
|
|||
}
|
||||
}
|
||||
|
||||
func updateFilters(_ filters: [Filter], completion: @escaping (Result<[FilterMO], Error>) -> Void) {
|
||||
viewContext.perform {
|
||||
do {
|
||||
var all = try self.viewContext.fetch(FilterMO.fetchRequest())
|
||||
|
||||
let toDelete = all.filter { existing in !filters.contains(where: { $0.id == existing.id }) }.map(\.objectID)
|
||||
if !toDelete.isEmpty {
|
||||
try self.viewContext.execute(NSBatchDeleteRequest(objectIDs: toDelete))
|
||||
}
|
||||
|
||||
for filter in filters where !all.contains(where: { $0.id == filter.id }) {
|
||||
let mo = FilterMO(apiFilter: filter, context: self.viewContext)
|
||||
all.append(mo)
|
||||
}
|
||||
|
||||
self.save(context: self.viewContext)
|
||||
completion(.success(all))
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func managedObjectsDidChange(_ notification: Foundation.Notification) {
|
||||
let changes = hasChangedSavedHashtagsOrInstances(notification)
|
||||
if changes.hashtags {
|
||||
|
|
|
@ -28,6 +28,14 @@
|
|||
</uniquenessConstraint>
|
||||
</uniquenessConstraints>
|
||||
</entity>
|
||||
<entity name="Filter" representedClassName="FilterMO" syncable="YES">
|
||||
<attribute name="context" attributeType="String"/>
|
||||
<attribute name="expiresAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="id" attributeType="String"/>
|
||||
<attribute name="irreversible" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="phrase" attributeType="String"/>
|
||||
<attribute name="wholeWord" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
</entity>
|
||||
<entity name="FollowedHashtag" representedClassName="FollowedHashtag" syncable="YES">
|
||||
<attribute name="name" attributeType="String"/>
|
||||
<attribute name="url" attributeType="URI"/>
|
||||
|
|
Loading…
Reference in New Issue