Added folder (tag) delete for Feedbin
This commit is contained in:
parent
b7e2df1a68
commit
d6ae740305
|
@ -419,7 +419,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||||
}
|
}
|
||||||
|
|
||||||
public func renameFolder(_ folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
public func renameFolder(_ folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
delegate.renameFolder(folder, to: name, completion: completion)
|
delegate.renameFolder(for: self, with: folder, to: name, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func importOPML(_ opmlDocument: RSOPMLDocument) {
|
public func importOPML(_ opmlDocument: RSOPMLDocument) {
|
||||||
|
@ -597,12 +597,16 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||||
postChildrenDidChangeNotification()
|
postChildrenDidChangeNotification()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deleteFolder(_ folder: Folder) {
|
public func deleteFolder(_ folder: Folder, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
|
delegate.deleteFolder(for: self, with: folder, completion: completion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteFolder(_ folder: Folder) {
|
||||||
folders?.remove(folder)
|
folders?.remove(folder)
|
||||||
structureDidChange()
|
structureDidChange()
|
||||||
postChildrenDidChangeNotification()
|
postChildrenDidChangeNotification()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Debug
|
// MARK: - Debug
|
||||||
|
|
||||||
public func debugDropConditionalGetInfo() {
|
public func debugDropConditionalGetInfo() {
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
51D5875B227F630B00900287 /* tags_add.json in Resources */ = {isa = PBXBuildFile; fileRef = 51D58758227F630B00900287 /* tags_add.json */; };
|
51D5875B227F630B00900287 /* tags_add.json in Resources */ = {isa = PBXBuildFile; fileRef = 51D58758227F630B00900287 /* tags_add.json */; };
|
||||||
51D5875C227F630B00900287 /* tags_initial.json in Resources */ = {isa = PBXBuildFile; fileRef = 51D58759227F630B00900287 /* tags_initial.json */; };
|
51D5875C227F630B00900287 /* tags_initial.json in Resources */ = {isa = PBXBuildFile; fileRef = 51D58759227F630B00900287 /* tags_initial.json */; };
|
||||||
51D5875E227F643C00900287 /* AccountFolderSyncTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D5875D227F643C00900287 /* AccountFolderSyncTest.swift */; };
|
51D5875E227F643C00900287 /* AccountFolderSyncTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D5875D227F643C00900287 /* AccountFolderSyncTest.swift */; };
|
||||||
51D587642280594700900287 /* FeedbinRenameTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D5875F22804FD200900287 /* FeedbinRenameTag.swift */; };
|
|
||||||
841973FE1F6DD1BC006346C4 /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841973EF1F6DD19E006346C4 /* RSCore.framework */; };
|
841973FE1F6DD1BC006346C4 /* RSCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841973EF1F6DD19E006346C4 /* RSCore.framework */; };
|
||||||
841973FF1F6DD1C5006346C4 /* RSParser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841973FA1F6DD1AC006346C4 /* RSParser.framework */; };
|
841973FF1F6DD1C5006346C4 /* RSParser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841973FA1F6DD1AC006346C4 /* RSParser.framework */; };
|
||||||
841974011F6DD1EC006346C4 /* Folder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841974001F6DD1EC006346C4 /* Folder.swift */; };
|
841974011F6DD1EC006346C4 /* Folder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841974001F6DD1EC006346C4 /* Folder.swift */; };
|
||||||
|
@ -103,7 +102,6 @@
|
||||||
51D58758227F630B00900287 /* tags_add.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tags_add.json; sourceTree = "<group>"; };
|
51D58758227F630B00900287 /* tags_add.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tags_add.json; sourceTree = "<group>"; };
|
||||||
51D58759227F630B00900287 /* tags_initial.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tags_initial.json; sourceTree = "<group>"; };
|
51D58759227F630B00900287 /* tags_initial.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tags_initial.json; sourceTree = "<group>"; };
|
||||||
51D5875D227F643C00900287 /* AccountFolderSyncTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountFolderSyncTest.swift; sourceTree = "<group>"; };
|
51D5875D227F643C00900287 /* AccountFolderSyncTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountFolderSyncTest.swift; sourceTree = "<group>"; };
|
||||||
51D5875F22804FD200900287 /* FeedbinRenameTag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinRenameTag.swift; sourceTree = "<group>"; };
|
|
||||||
841973E81F6DD19E006346C4 /* RSCore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSCore.xcodeproj; path = ../RSCore/RSCore.xcodeproj; sourceTree = "<group>"; };
|
841973E81F6DD19E006346C4 /* RSCore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSCore.xcodeproj; path = ../RSCore/RSCore.xcodeproj; sourceTree = "<group>"; };
|
||||||
841973F41F6DD1AC006346C4 /* RSParser.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSParser.xcodeproj; path = ../RSParser/RSParser.xcodeproj; sourceTree = "<group>"; };
|
841973F41F6DD1AC006346C4 /* RSParser.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RSParser.xcodeproj; path = ../RSParser/RSParser.xcodeproj; sourceTree = "<group>"; };
|
||||||
841974001F6DD1EC006346C4 /* Folder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Folder.swift; sourceTree = "<group>"; };
|
841974001F6DD1EC006346C4 /* Folder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Folder.swift; sourceTree = "<group>"; };
|
||||||
|
@ -214,7 +212,6 @@
|
||||||
84245C841FDDD8CB0074AFBB /* FeedbinFeed.swift */,
|
84245C841FDDD8CB0074AFBB /* FeedbinFeed.swift */,
|
||||||
84D0962421741B8500D77525 /* FeedbinSavedSearch.swift */,
|
84D0962421741B8500D77525 /* FeedbinSavedSearch.swift */,
|
||||||
51D58754227F53BE00900287 /* FeedbinTag.swift */,
|
51D58754227F53BE00900287 /* FeedbinTag.swift */,
|
||||||
51D5875F22804FD200900287 /* FeedbinRenameTag.swift */,
|
|
||||||
84D09622217418DC00D77525 /* FeedbinTagging.swift */,
|
84D09622217418DC00D77525 /* FeedbinTagging.swift */,
|
||||||
);
|
);
|
||||||
path = Feedbin;
|
path = Feedbin;
|
||||||
|
@ -457,7 +454,6 @@
|
||||||
files = (
|
files = (
|
||||||
84C8B3F41F89DE430053CCA6 /* DataExtensions.swift in Sources */,
|
84C8B3F41F89DE430053CCA6 /* DataExtensions.swift in Sources */,
|
||||||
84C3654A1F899F3B001EC85C /* CombinedRefreshProgress.swift in Sources */,
|
84C3654A1F899F3B001EC85C /* CombinedRefreshProgress.swift in Sources */,
|
||||||
51D587642280594700900287 /* FeedbinRenameTag.swift in Sources */,
|
|
||||||
8469F81C1F6DD15E0084783E /* Account.swift in Sources */,
|
8469F81C1F6DD15E0084783E /* Account.swift in Sources */,
|
||||||
84D096212174169100D77525 /* FeedbinArticleIDArray.swift in Sources */,
|
84D096212174169100D77525 /* FeedbinArticleIDArray.swift in Sources */,
|
||||||
5144EA4E227B829A00D19003 /* FeedbinAccountDelegate.swift in Sources */,
|
5144EA4E227B829A00D19003 /* FeedbinAccountDelegate.swift in Sources */,
|
||||||
|
|
|
@ -21,8 +21,9 @@ protocol AccountDelegate {
|
||||||
|
|
||||||
func refreshAll(for: Account, completion: (() -> Void)?)
|
func refreshAll(for: Account, completion: (() -> Void)?)
|
||||||
|
|
||||||
func renameFolder(_ folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void)
|
func renameFolder(for: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void)
|
||||||
|
func deleteFolder(for: Account, with folder: Folder, completion: @escaping (Result<Void, Error>) -> Void)
|
||||||
|
|
||||||
// Called at the end of account’s init method.
|
// Called at the end of account’s init method.
|
||||||
func accountDidInitialize(_ account: Account)
|
func accountDidInitialize(_ account: Account)
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ final class TestTransport: Transport {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func send(request: URLRequest, data: Data, completion: @escaping (Result<(HTTPHeaders, Data?), Error>) -> Void) {
|
func send(request: URLRequest, payload: Data, completion: @escaping (Result<(HTTPHeaders, Data?), Error>) -> Void) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ public protocol Container: class {
|
||||||
func childFolder(with: String) -> Folder?
|
func childFolder(with: String) -> Folder?
|
||||||
|
|
||||||
func deleteFeed(_ feed: Feed)
|
func deleteFeed(_ feed: Feed)
|
||||||
func deleteFolder(_ folder: Folder)
|
func deleteFolder(_ folder: Folder, completion: @escaping (Result<Void, Error>) -> Void)
|
||||||
|
|
||||||
func addFeed(_ feed: Feed)
|
func addFeed(_ feed: Feed)
|
||||||
func addFeeds(_ feeds: Set<Feed>)
|
func addFeeds(_ feeds: Set<Feed>)
|
||||||
|
|
|
@ -52,8 +52,9 @@ final class FeedbinAPICaller: NSObject {
|
||||||
let callURL = feedbinBaseURL.appendingPathComponent("tags.json")
|
let callURL = feedbinBaseURL.appendingPathComponent("tags.json")
|
||||||
let conditionalGet = accountMetadata?.conditionalGetInfo[AccountMetadata.ConditionalGetKeys.tags]
|
let conditionalGet = accountMetadata?.conditionalGetInfo[AccountMetadata.ConditionalGetKeys.tags]
|
||||||
let request = URLRequest(url: callURL, credentials: credentials, conditionalGet: conditionalGet)
|
let request = URLRequest(url: callURL, credentials: credentials, conditionalGet: conditionalGet)
|
||||||
|
|
||||||
transport.getJSON(request: request, resultType: [FeedbinTag].self) { [weak self] result in
|
transport.send(request: request, resultType: [FeedbinTag].self) { [weak self] result in
|
||||||
|
|
||||||
switch result {
|
switch result {
|
||||||
case .success(let (headers, tags)):
|
case .success(let (headers, tags)):
|
||||||
self?.storeConditionalGet(metadata: self?.accountMetadata, key: AccountMetadata.ConditionalGetKeys.tags, headers: headers)
|
self?.storeConditionalGet(metadata: self?.accountMetadata, key: AccountMetadata.ConditionalGetKeys.tags, headers: headers)
|
||||||
|
@ -70,7 +71,26 @@ final class FeedbinAPICaller: NSObject {
|
||||||
let callURL = feedbinBaseURL.appendingPathComponent("tags.json")
|
let callURL = feedbinBaseURL.appendingPathComponent("tags.json")
|
||||||
let request = URLRequest(url: callURL, credentials: credentials)
|
let request = URLRequest(url: callURL, credentials: credentials)
|
||||||
let payload = FeedbinRenameTag(oldName: oldName, newName: newName)
|
let payload = FeedbinRenameTag(oldName: oldName, newName: newName)
|
||||||
transport.postJSON(request: request, payload: payload, completion: completion)
|
transport.send(request: request, method: HTTPMethod.post, payload: payload, completion: completion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteTag(name: String, completion: @escaping (Result<[FeedbinTagging]?, Error>) -> Void) {
|
||||||
|
|
||||||
|
let callURL = feedbinBaseURL.appendingPathComponent("tags.json")
|
||||||
|
let request = URLRequest(url: callURL, credentials: credentials)
|
||||||
|
let payload = FeedbinDeleteTag(name: name)
|
||||||
|
|
||||||
|
transport.send(request: request, method: HTTPMethod.delete, payload: payload, resultType: [FeedbinTagging].self) { result in
|
||||||
|
|
||||||
|
switch result {
|
||||||
|
case .success(let (_, taggings)):
|
||||||
|
completion(.success(taggings))
|
||||||
|
case .failure(let error):
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func renameFolder(_ folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
|
|
||||||
caller.renameTag(oldName: folder.name ?? "", newName: name) { result in
|
caller.renameTag(oldName: folder.name ?? "", newName: name) { result in
|
||||||
switch result {
|
switch result {
|
||||||
|
@ -62,6 +62,28 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deleteFolder(for account: Account, with folder: Folder, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
|
|
||||||
|
// Feedbin uses tags and if at least one feed isn't tagged, then the folder doesn't exist on their system
|
||||||
|
guard folder.hasAtLeastOneFeed() else {
|
||||||
|
account.deleteFolder(folder)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
caller.deleteTag(name: folder.name ?? "") { result in
|
||||||
|
switch result {
|
||||||
|
case .success:
|
||||||
|
account.deleteFolder(folder)
|
||||||
|
// TODO: Take the serialized taggings and reestablish the folder to feed relationships. Deleting
|
||||||
|
// a tag on Feedbin doesn't any feeds.
|
||||||
|
completion(.success(()))
|
||||||
|
case .failure(let error):
|
||||||
|
completion(.failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func accountDidInitialize(_ account: Account) {
|
func accountDidInitialize(_ account: Account) {
|
||||||
credentials = try? account.retrieveBasicCredentials()
|
credentials = try? account.retrieveBasicCredentials()
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
//
|
|
||||||
// FeedbinRenameTag.swift
|
|
||||||
// Account
|
|
||||||
//
|
|
||||||
// Created by Maurice Parker on 5/6/19.
|
|
||||||
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
struct FeedbinRenameTag: Codable {
|
|
||||||
|
|
||||||
let oldName: String
|
|
||||||
let newName: String
|
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
|
||||||
case oldName = "old_name"
|
|
||||||
case newName = "new_name"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -19,3 +19,25 @@ struct FeedbinTag: Codable, Equatable, Hashable {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct FeedbinRenameTag: Codable {
|
||||||
|
|
||||||
|
let oldName: String
|
||||||
|
let newName: String
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case oldName = "old_name"
|
||||||
|
case newName = "new_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FeedbinDeleteTag: Codable {
|
||||||
|
|
||||||
|
let name: String
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case name
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -100,8 +100,8 @@ public final class Folder: DisplayNameProvider, Renamable, Container, UnreadCoun
|
||||||
postChildrenDidChangeNotification()
|
postChildrenDidChangeNotification()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deleteFolder(_ folder: Folder) {
|
public func deleteFolder(_ folder: Folder, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
// Nothing to do
|
completion(.success(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Hashable
|
// MARK: - Hashable
|
||||||
|
|
|
@ -28,11 +28,16 @@ final class LocalAccountDelegate: AccountDelegate {
|
||||||
completion?()
|
completion?()
|
||||||
}
|
}
|
||||||
|
|
||||||
func renameFolder(_ folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
folder.name = name
|
folder.name = name
|
||||||
completion(.success(()))
|
completion(.success(()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deleteFolder(for account: Account, with folder: Folder, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||||
|
account.deleteFolder(folder)
|
||||||
|
completion(.success(()))
|
||||||
|
}
|
||||||
|
|
||||||
func accountDidInitialize(_ account: Account) {
|
func accountDidInitialize(_ account: Account) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,17 +47,18 @@ class ScriptableAccount: NSObject, UniqueIdScriptingObject, ScriptingObjectConta
|
||||||
return self.classDescription as! NSScriptClassDescription
|
return self.classDescription as! NSScriptClassDescription
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteElement(_ element:ScriptingObject) {
|
func deleteElement(_ element:ScriptingObject) {
|
||||||
if let scriptableFolder = element as? ScriptableFolder {
|
if let scriptableFolder = element as? ScriptableFolder {
|
||||||
BatchUpdate.shared.perform {
|
BatchUpdate.shared.perform {
|
||||||
account.deleteFolder(scriptableFolder.folder)
|
account.deleteFolder(scriptableFolder.folder) { result in
|
||||||
}
|
}
|
||||||
} else if let scriptableFeed = element as? ScriptableFeed {
|
}
|
||||||
BatchUpdate.shared.perform {
|
} else if let scriptableFeed = element as? ScriptableFeed {
|
||||||
account.deleteFeed(scriptableFeed.feed)
|
BatchUpdate.shared.perform {
|
||||||
}
|
account.deleteFeed(scriptableFeed.feed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc(isLocationRequiredToCreateForKey:)
|
@objc(isLocationRequiredToCreateForKey:)
|
||||||
func isLocationRequiredToCreate(forKey key:String) -> Bool {
|
func isLocationRequiredToCreate(forKey key:String) -> Bool {
|
||||||
|
|
|
@ -53,7 +53,7 @@ class ScriptableFolder: NSObject, UniqueIdScriptingObject, ScriptingObjectContai
|
||||||
func deleteElement(_ element:ScriptingObject) {
|
func deleteElement(_ element:ScriptingObject) {
|
||||||
if let scriptableFolder = element as? ScriptableFolder {
|
if let scriptableFolder = element as? ScriptableFolder {
|
||||||
BatchUpdate.shared.perform {
|
BatchUpdate.shared.perform {
|
||||||
folder.deleteFolder(scriptableFolder.folder)
|
folder.deleteFolder(scriptableFolder.folder) { result in }
|
||||||
}
|
}
|
||||||
} else if let scriptableFeed = element as? ScriptableFeed {
|
} else if let scriptableFeed = element as? ScriptableFeed {
|
||||||
BatchUpdate.shared.perform {
|
BatchUpdate.shared.perform {
|
||||||
|
|
|
@ -142,7 +142,18 @@ private struct SidebarItemSpecifier {
|
||||||
container.deleteFeed(feed)
|
container.deleteFeed(feed)
|
||||||
}
|
}
|
||||||
else if let folder = folder {
|
else if let folder = folder {
|
||||||
container.deleteFolder(folder)
|
container.deleteFolder(folder) { result in
|
||||||
|
switch result {
|
||||||
|
case .success():
|
||||||
|
break
|
||||||
|
case .failure(let error):
|
||||||
|
#if os(macOS)
|
||||||
|
NSApplication.shared.presentError(error)
|
||||||
|
#else
|
||||||
|
UIApplication.shared.presentError(error)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 72c45431fbba0bf1c17d11555c8f75ea963bcb5b
|
Subproject commit d1d5eba957eefec54b9a8c8648024a389c2271f0
|
Loading…
Reference in New Issue