mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Create NewsBlur local package.
This commit is contained in:
@@ -14,6 +14,7 @@ dependencies.append(contentsOf: [
|
||||
.package(path: "../ArticlesDatabase"),
|
||||
.package(path: "../Secrets"),
|
||||
.package(path: "../SyncDatabase"),
|
||||
.package(path: "../SyncClients/NewsBlur"),
|
||||
])
|
||||
#else
|
||||
dependencies.append(contentsOf: [
|
||||
@@ -47,6 +48,7 @@ let package = Package(
|
||||
"ArticlesDatabase",
|
||||
"Secrets",
|
||||
"SyncDatabase",
|
||||
"NewsBlur"
|
||||
],
|
||||
linkerSettings: [
|
||||
.unsafeFlags(["-Xlinker", "-no_application_extension"])
|
||||
|
||||
@@ -13,6 +13,7 @@ import RSDatabase
|
||||
import RSParser
|
||||
import RSWeb
|
||||
import SyncDatabase
|
||||
import NewsBlur
|
||||
|
||||
extension NewsBlurAccountDelegate {
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import RSParser
|
||||
import RSWeb
|
||||
import SyncDatabase
|
||||
import Secrets
|
||||
import NewsBlur
|
||||
|
||||
final class NewsBlurAccountDelegate: AccountDelegate, Logging {
|
||||
|
||||
@@ -34,7 +35,9 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging {
|
||||
|
||||
init(dataFolder: String, transport: Transport?) {
|
||||
if let transport = transport {
|
||||
caller = NewsBlurAPICaller(transport: transport)
|
||||
caller = NewsBlurAPICaller(transport: transport) { url, credentials in
|
||||
URLRequest(url: url, credentials: credentials)
|
||||
}
|
||||
} else {
|
||||
let sessionConfiguration = URLSessionConfiguration.default
|
||||
sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalCacheData
|
||||
@@ -50,7 +53,9 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
|
||||
let session = URLSession(configuration: sessionConfiguration)
|
||||
caller = NewsBlurAPICaller(transport: session)
|
||||
caller = NewsBlurAPICaller(transport: session) { url, credentials in
|
||||
URLRequest(url: url, credentials: credentials)
|
||||
}
|
||||
}
|
||||
|
||||
database = SyncDatabase(databaseFilePath: dataFolder.appending("/DB.sqlite3"))
|
||||
@@ -644,7 +649,9 @@ final class NewsBlurAccountDelegate: AccountDelegate, Logging {
|
||||
}
|
||||
|
||||
class func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil, completion: @escaping (Result<Credentials?, Error>) -> ()) {
|
||||
let caller = NewsBlurAPICaller(transport: transport)
|
||||
let caller = NewsBlurAPICaller(transport: transport) { url, credentials in
|
||||
URLRequest(url: url, credentials: credentials)
|
||||
}
|
||||
caller.credentials = credentials
|
||||
caller.validateCredentials() { result in
|
||||
DispatchQueue.main.async {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import Foundation
|
||||
import RSWeb
|
||||
import Secrets
|
||||
import NewsBlur
|
||||
|
||||
public extension URLRequest {
|
||||
|
||||
|
||||
@@ -1379,6 +1379,7 @@
|
||||
848363072262A3DD00DA1D35 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
8483630A2262A3F000DA1D35 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Mac/Base.lproj/RenameSheet.xib; sourceTree = SOURCE_ROOT; };
|
||||
8483630D2262A3FE00DA1D35 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Mac/Base.lproj/MainWindow.storyboard; sourceTree = SOURCE_ROOT; };
|
||||
8486EC3E2A9BE083007EF90D /* NewsBlur */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = NewsBlur; path = SyncClients/NewsBlur; sourceTree = "<group>"; };
|
||||
848B937121C8C5540038DC0D /* CrashReporter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CrashReporter.swift; sourceTree = "<group>"; };
|
||||
848D578D21543519005FFAD5 /* PasteboardFeed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteboardFeed.swift; sourceTree = "<group>"; };
|
||||
848F6AE41FC29CFA002D422E /* FaviconDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaviconDownloader.swift; sourceTree = "<group>"; };
|
||||
@@ -2501,6 +2502,7 @@
|
||||
849C64611ED37A5D003D8FC0 /* Products */,
|
||||
51C452B22265141B00C03939 /* Frameworks */,
|
||||
51CD32C624D2DEF9009ABAEF /* Account */,
|
||||
8486EC3E2A9BE083007EF90D /* NewsBlur */,
|
||||
51CD32C424D2CF1D009ABAEF /* Articles */,
|
||||
51CD32C324D2CD57009ABAEF /* ArticlesDatabase */,
|
||||
51CD32C724D2E06C009ABAEF /* Secrets */,
|
||||
|
||||
9
SyncClients/NewsBlur/.gitignore
vendored
Normal file
9
SyncClients/NewsBlur/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/config/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
||||
36
SyncClients/NewsBlur/Package.swift
Normal file
36
SyncClients/NewsBlur/Package.swift
Normal file
@@ -0,0 +1,36 @@
|
||||
// swift-tools-version: 5.8
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "NewsBlur",
|
||||
platforms: [.macOS(.v13), .iOS(.v16)],
|
||||
products: [
|
||||
// Products define the executables and libraries a package produces, and make them visible to other packages.
|
||||
.library(
|
||||
name: "NewsBlur",
|
||||
targets: ["NewsBlur"]),
|
||||
],
|
||||
dependencies: [
|
||||
.package(path: "../Secrets"),
|
||||
.package(url: "https://github.com/Ranchero-Software/RSWeb.git", .upToNextMajor(from: "1.0.0")),
|
||||
.package(url: "https://github.com/Ranchero-Software/RSCore.git", .upToNextMajor(from: "2.0.1")),
|
||||
.package(url: "https://github.com/Ranchero-Software/RSParser.git", .upToNextMajor(from: "2.0.2"))
|
||||
],
|
||||
targets: [
|
||||
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
|
||||
// Targets can depend on other targets in this package, and on products in packages this package depends on.
|
||||
.target(
|
||||
name: "NewsBlur",
|
||||
dependencies: [
|
||||
"Secrets",
|
||||
"RSWeb",
|
||||
"RSParser",
|
||||
"RSCore"
|
||||
]),
|
||||
.testTarget(
|
||||
name: "NewsBlurTests",
|
||||
dependencies: ["NewsBlur"]),
|
||||
]
|
||||
)
|
||||
3
SyncClients/NewsBlur/README.md
Normal file
3
SyncClients/NewsBlur/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# NewsBlur
|
||||
|
||||
A description of this package.
|
||||
@@ -10,23 +10,23 @@ import Foundation
|
||||
import RSCore
|
||||
import RSParser
|
||||
|
||||
typealias NewsBlurFolder = NewsBlurFeedsResponse.Folder
|
||||
public typealias NewsBlurFolder = NewsBlurFeedsResponse.Folder
|
||||
|
||||
struct NewsBlurFeed: Hashable, Codable {
|
||||
let name: String
|
||||
let feedID: Int
|
||||
let feedURL: String
|
||||
let homePageURL: String?
|
||||
let faviconURL: String?
|
||||
public struct NewsBlurFeed: Hashable, Codable {
|
||||
public let name: String
|
||||
public let feedID: Int
|
||||
public let feedURL: String
|
||||
public let homePageURL: String?
|
||||
public let faviconURL: String?
|
||||
}
|
||||
|
||||
struct NewsBlurFeedsResponse: Decodable {
|
||||
public struct NewsBlurFeedsResponse: Decodable {
|
||||
let feeds: [NewsBlurFeed]
|
||||
let folders: [Folder]
|
||||
|
||||
struct Folder: Hashable, Codable {
|
||||
let name: String
|
||||
let feedIDs: [Int]
|
||||
public struct Folder: Hashable, Codable {
|
||||
public let name: String
|
||||
public let feedIDs: [Int]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,9 @@ struct NewsBlurAddURLResponse: Decodable {
|
||||
let feed: NewsBlurFeed?
|
||||
}
|
||||
|
||||
struct NewsBlurFolderRelationship {
|
||||
let folderName: String
|
||||
let feedID: Int
|
||||
public struct NewsBlurFolderRelationship {
|
||||
public let folderName: String
|
||||
public let feedID: Int
|
||||
}
|
||||
|
||||
extension NewsBlurFeed {
|
||||
@@ -56,7 +56,7 @@ extension NewsBlurFeedsResponse {
|
||||
// TODO: flat_folders_with_inactive
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
// Tricky part: Some feeds listed in `feeds` don't exist in `folders` for some reason
|
||||
@@ -89,7 +89,7 @@ extension NewsBlurFeedsResponse {
|
||||
}
|
||||
|
||||
extension NewsBlurFeedsResponse.Folder {
|
||||
var asRelationships: [NewsBlurFolderRelationship] {
|
||||
public var asRelationships: [NewsBlurFolderRelationship] {
|
||||
return feedIDs.map { NewsBlurFolderRelationship(folderName: name, feedID: $0) }
|
||||
}
|
||||
}
|
||||
@@ -10,23 +10,23 @@ import Foundation
|
||||
import RSCore
|
||||
import RSParser
|
||||
|
||||
typealias NewsBlurStory = NewsBlurStoriesResponse.Story
|
||||
public typealias NewsBlurStory = NewsBlurStoriesResponse.Story
|
||||
|
||||
struct NewsBlurStoriesResponse: Decodable {
|
||||
public struct NewsBlurStoriesResponse: Decodable {
|
||||
let stories: [Story]
|
||||
|
||||
struct Story: Decodable {
|
||||
let storyID: String
|
||||
let feedID: Int
|
||||
let title: String?
|
||||
let url: String?
|
||||
let authorName: String?
|
||||
let contentHTML: String?
|
||||
var imageURL: String? {
|
||||
public struct Story: Decodable {
|
||||
public let storyID: String
|
||||
public let feedID: Int
|
||||
public let title: String?
|
||||
public let url: String?
|
||||
public let authorName: String?
|
||||
public let contentHTML: String?
|
||||
public var imageURL: String? {
|
||||
return imageURLs?.first?.value
|
||||
}
|
||||
var tags: [String]?
|
||||
var datePublished: Date? {
|
||||
public var tags: [String]?
|
||||
public var datePublished: Date? {
|
||||
let interval = (publishedTimestamp as NSString).doubleValue
|
||||
return Date(timeIntervalSince1970: interval)
|
||||
}
|
||||
@@ -10,17 +10,22 @@ import Foundation
|
||||
import RSCore
|
||||
import RSParser
|
||||
|
||||
typealias NewsBlurStoryHash = NewsBlurStoryHashesResponse.StoryHash
|
||||
public typealias NewsBlurStoryHash = NewsBlurStoryHashesResponse.StoryHash
|
||||
|
||||
struct NewsBlurStoryHashesResponse: Decodable {
|
||||
public struct NewsBlurStoryHashesResponse: Decodable {
|
||||
typealias StoryHashDictionary = [String: [StoryHash]]
|
||||
|
||||
var unread: [StoryHash]?
|
||||
var starred: [StoryHash]?
|
||||
|
||||
struct StoryHash: Hashable, Codable {
|
||||
var hash: String
|
||||
var timestamp: Date
|
||||
public struct StoryHash: Hashable, Codable {
|
||||
public var hash: String
|
||||
public var timestamp: Date
|
||||
|
||||
public init(hash: String, timestamp: Date) {
|
||||
self.hash = hash
|
||||
self.timestamp = timestamp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +35,7 @@ extension NewsBlurStoryHashesResponse {
|
||||
case starred = "starred_story_hashes"
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
// Parse unread
|
||||
6
SyncClients/NewsBlur/Sources/NewsBlur/NewsBlur.swift
Normal file
6
SyncClients/NewsBlur/Sources/NewsBlur/NewsBlur.swift
Normal file
@@ -0,0 +1,6 @@
|
||||
public struct NewsBlur {
|
||||
public private(set) var text = "Hello, World!"
|
||||
|
||||
public init() {
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,12 @@ protocol NewsBlurDataConvertible {
|
||||
var asData: Data? { get }
|
||||
}
|
||||
|
||||
enum NewsBlurError: LocalizedError {
|
||||
public enum NewsBlurError: LocalizedError {
|
||||
case general(message: String)
|
||||
case invalidParameter
|
||||
case unknown
|
||||
|
||||
var errorDescription: String? {
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .general(let message):
|
||||
return message
|
||||
@@ -108,7 +108,7 @@ extension NewsBlurAPICaller {
|
||||
return
|
||||
}
|
||||
|
||||
let request = URLRequest(url: callURL, credentials: credentials)
|
||||
let request = createURLRequest(callURL, credentials)
|
||||
|
||||
transport.send(request: request) { result in
|
||||
if self.suspended {
|
||||
@@ -138,7 +138,7 @@ extension NewsBlurAPICaller {
|
||||
return
|
||||
}
|
||||
|
||||
let request = URLRequest(url: callURL, credentials: credentials)
|
||||
let request = createURLRequest(callURL, credentials)
|
||||
|
||||
transport.send(
|
||||
request: request,
|
||||
@@ -171,7 +171,7 @@ extension NewsBlurAPICaller {
|
||||
return
|
||||
}
|
||||
|
||||
var request = URLRequest(url: callURL, credentials: credentials)
|
||||
var request = createURLRequest(callURL, credentials)
|
||||
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: HTTPRequestHeader.contentType)
|
||||
request.httpBody = payload.asData
|
||||
|
||||
@@ -209,7 +209,7 @@ extension NewsBlurAPICaller {
|
||||
return
|
||||
}
|
||||
|
||||
var request = URLRequest(url: callURL, credentials: credentials)
|
||||
var request = createURLRequest(callURL, credentials)
|
||||
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: HTTPRequestHeader.contentType)
|
||||
|
||||
transport.send(
|
||||
@@ -10,32 +10,32 @@ import Foundation
|
||||
import RSWeb
|
||||
import Secrets
|
||||
|
||||
final class NewsBlurAPICaller: NSObject {
|
||||
static let SessionIdCookie = "newsblur_sessionid"
|
||||
public final class NewsBlurAPICaller {
|
||||
public static let SessionIdCookie = "newsblur_sessionid"
|
||||
|
||||
let baseURL = URL(string: "https://www.newsblur.com/")!
|
||||
var transport: Transport!
|
||||
let createURLRequest: ((URL, Credentials?) -> URLRequest)
|
||||
var suspended = false
|
||||
|
||||
var credentials: Credentials?
|
||||
weak var accountMetadata: AccountMetadata?
|
||||
public var credentials: Credentials?
|
||||
|
||||
init(transport: Transport!) {
|
||||
super.init()
|
||||
public init(transport: Transport!, createURLRequest: @escaping (URL, Credentials?) -> URLRequest) {
|
||||
self.transport = transport
|
||||
self.createURLRequest = createURLRequest
|
||||
}
|
||||
|
||||
/// Cancels all pending requests rejects any that come in later
|
||||
func suspend() {
|
||||
public func suspend() {
|
||||
transport.cancelAll()
|
||||
suspended = true
|
||||
}
|
||||
|
||||
func resume() {
|
||||
public func resume() {
|
||||
suspended = false
|
||||
}
|
||||
|
||||
func validateCredentials(completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||
public func validateCredentials(completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||
requestData(endpoint: "api/login", resultType: NewsBlurLoginResponse.self) { result in
|
||||
switch result {
|
||||
case .success((let response, let payload)):
|
||||
@@ -68,11 +68,11 @@ final class NewsBlurAPICaller: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
func logout(completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func logout(completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
requestData(endpoint: "api/logout", completion: completion)
|
||||
}
|
||||
|
||||
func retrieveFeeds(completion: @escaping (Result<([NewsBlurFeed]?, [NewsBlurFolder]?), Error>) -> Void) {
|
||||
public func retrieveFeeds(completion: @escaping (Result<([NewsBlurFeed]?, [NewsBlurFolder]?), Error>) -> Void) {
|
||||
let url = baseURL
|
||||
.appendingPathComponent("reader/feeds")
|
||||
.appendingQueryItems([
|
||||
@@ -112,21 +112,21 @@ final class NewsBlurAPICaller: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
func retrieveUnreadStoryHashes(completion: @escaping (Result<[NewsBlurStoryHash]?, Error>) -> Void) {
|
||||
public func retrieveUnreadStoryHashes(completion: @escaping (Result<[NewsBlurStoryHash]?, Error>) -> Void) {
|
||||
retrieveStoryHashes(
|
||||
endpoint: "reader/unread_story_hashes",
|
||||
completion: completion
|
||||
)
|
||||
}
|
||||
|
||||
func retrieveStarredStoryHashes(completion: @escaping (Result<[NewsBlurStoryHash]?, Error>) -> Void) {
|
||||
public func retrieveStarredStoryHashes(completion: @escaping (Result<[NewsBlurStoryHash]?, Error>) -> Void) {
|
||||
retrieveStoryHashes(
|
||||
endpoint: "reader/starred_story_hashes",
|
||||
completion: completion
|
||||
)
|
||||
}
|
||||
|
||||
func retrieveStories(feedID: String, page: Int, completion: @escaping (Result<([NewsBlurStory]?, Date?), Error>) -> Void) {
|
||||
public func retrieveStories(feedID: String, page: Int, completion: @escaping (Result<([NewsBlurStory]?, Date?), Error>) -> Void) {
|
||||
let url = baseURL
|
||||
.appendingPathComponent("reader/feed/\(feedID)")
|
||||
.appendingQueryItems([
|
||||
@@ -147,7 +147,7 @@ final class NewsBlurAPICaller: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
func retrieveStories(hashes: [NewsBlurStoryHash], completion: @escaping (Result<([NewsBlurStory]?, Date?), Error>) -> Void) {
|
||||
public func retrieveStories(hashes: [NewsBlurStoryHash], completion: @escaping (Result<([NewsBlurStory]?, Date?), Error>) -> Void) {
|
||||
let url = baseURL
|
||||
.appendingPathComponent("reader/river_stories")
|
||||
.appendingQueryItem(.init(name: "include_hidden", value: "false"))?
|
||||
@@ -165,7 +165,7 @@ final class NewsBlurAPICaller: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
func markAsUnread(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func markAsUnread(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/mark_story_hash_as_unread",
|
||||
payload: NewsBlurStoryStatusChange(hashes: hashes),
|
||||
@@ -173,7 +173,7 @@ final class NewsBlurAPICaller: NSObject {
|
||||
)
|
||||
}
|
||||
|
||||
func markAsRead(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func markAsRead(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/mark_story_hashes_as_read",
|
||||
payload: NewsBlurStoryStatusChange(hashes: hashes),
|
||||
@@ -181,7 +181,7 @@ final class NewsBlurAPICaller: NSObject {
|
||||
)
|
||||
}
|
||||
|
||||
func star(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func star(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/mark_story_hash_as_starred",
|
||||
payload: NewsBlurStoryStatusChange(hashes: hashes),
|
||||
@@ -189,7 +189,7 @@ final class NewsBlurAPICaller: NSObject {
|
||||
)
|
||||
}
|
||||
|
||||
func unstar(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func unstar(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/mark_story_hash_as_unstarred",
|
||||
payload: NewsBlurStoryStatusChange(hashes: hashes),
|
||||
@@ -197,7 +197,7 @@ final class NewsBlurAPICaller: NSObject {
|
||||
)
|
||||
}
|
||||
|
||||
func addFolder(named name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func addFolder(named name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/add_folder",
|
||||
payload: NewsBlurFolderChange.add(name),
|
||||
@@ -205,7 +205,7 @@ final class NewsBlurAPICaller: NSObject {
|
||||
)
|
||||
}
|
||||
|
||||
func renameFolder(with folder: String, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func renameFolder(with folder: String, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/rename_folder",
|
||||
payload: NewsBlurFolderChange.rename(folder, name),
|
||||
@@ -213,7 +213,7 @@ final class NewsBlurAPICaller: NSObject {
|
||||
)
|
||||
}
|
||||
|
||||
func removeFolder(named name: String, feedIDs: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func removeFolder(named name: String, feedIDs: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/delete_folder",
|
||||
payload: NewsBlurFolderChange.delete(name, feedIDs),
|
||||
@@ -221,7 +221,7 @@ final class NewsBlurAPICaller: NSObject {
|
||||
)
|
||||
}
|
||||
|
||||
func addURL(_ url: String, folder: String?, completion: @escaping (Result<NewsBlurFeed?, Error>) -> Void) {
|
||||
public func addURL(_ url: String, folder: String?, completion: @escaping (Result<NewsBlurFeed?, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/add_url",
|
||||
payload: NewsBlurFeedChange.add(url, folder),
|
||||
@@ -236,7 +236,7 @@ final class NewsBlurAPICaller: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
func renameFeed(feedID: String, newName: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func renameFeed(feedID: String, newName: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/rename_feed",
|
||||
payload: NewsBlurFeedChange.rename(feedID, newName)
|
||||
@@ -250,7 +250,7 @@ final class NewsBlurAPICaller: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
func deleteFeed(feedID: String, folder: String? = nil, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func deleteFeed(feedID: String, folder: String? = nil, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/delete_feed",
|
||||
payload: NewsBlurFeedChange.delete(feedID, folder)
|
||||
@@ -264,7 +264,7 @@ final class NewsBlurAPICaller: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
func moveFeed(feedID: String, from: String?, to: String?, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func moveFeed(feedID: String, from: String?, to: String?, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/move_feed_to_folder",
|
||||
payload: NewsBlurFeedChange.move(feedID, from, to)
|
||||
11
SyncClients/NewsBlur/Tests/NewsBlurTests/NewsBlurTests.swift
Normal file
11
SyncClients/NewsBlur/Tests/NewsBlurTests/NewsBlurTests.swift
Normal file
@@ -0,0 +1,11 @@
|
||||
import XCTest
|
||||
@testable import NewsBlur
|
||||
|
||||
final class NewsBlurTests: XCTestCase {
|
||||
func testExample() throws {
|
||||
// This is an example of a functional test case.
|
||||
// Use XCTAssert and related functions to verify your tests produce the correct
|
||||
// results.
|
||||
XCTAssertEqual(NewsBlur().text, "Hello, World!")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user