NetNewsWire/Evergreen/MainWindow/AddFeed/AddFeedController.swift

256 lines
6.7 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// AddFeedController.swift
// Evergreen
//
// Created by Brent Simmons on 8/28/16.
// Copyright © 2016 Ranchero Software, LLC. All rights reserved.
//
import AppKit
import RSCore
import RSTree
import Data
import RSFeedFinder
import Account
import RSParser
// Run add-feed sheet.
// If it returns with URL and optional name,
// run FeedFinder plus modal progress window.
// If FeedFinder returns feed,
// add feed.
// Else,
// display error sheet.
class AddFeedController: AddFeedWindowControllerDelegate, FeedFinderDelegate {
private let hostWindow: NSWindow
private var addFeedWindowController: AddFeedWindowController?
private var userEnteredURL: URL?
private var userEnteredFolder: Folder?
private var userEnteredTitle: String?
private var userEnteredAccount: Account?
private var foundFeedURLString: String?
private var titleFromFeed: String?
private var feedFinder: FeedFinder?
private var isFindingFeed = false
private var bestFeedSpecifier: FeedSpecifier?
init(hostWindow: NSWindow) {
self.hostWindow = hostWindow
}
func showAddFeedSheet(_ urlString: String?, _ name: String?) {
let folderTreeControllerDelegate = FolderTreeControllerDelegate()
let rootNode = Node(representedObject: AccountManager.shared.localAccount, parent: nil)
rootNode.canHaveChildNodes = true
let folderTreeController = TreeController(delegate: folderTreeControllerDelegate, rootNode: rootNode)
addFeedWindowController = AddFeedWindowController(urlString: urlString ?? urlStringFromPasteboard, name: name, folderTreeController: folderTreeController, delegate: self)
addFeedWindowController!.runSheetOnWindow(hostWindow)
}
// MARK: AddFeedWindowControllerDelegate
func addFeedWindowController(_: AddFeedWindowController, userEnteredURL url: URL, userEnteredTitle title: String?, container: Container) {
closeAddFeedSheet(NSApplication.ModalResponse.OK)
guard let accountAndFolderSpecifier = accountAndFolderFromContainer(container) else {
return
}
let account = accountAndFolderSpecifier.account
let folder = accountAndFolderSpecifier.folder
if account.hasFeed(withURL: url.absoluteString) {
showAlreadySubscribedError(url.absoluteString)
return
}
userEnteredAccount = account
userEnteredURL = url
userEnteredFolder = folder
userEnteredTitle = title
findFeed()
}
func addFeedWindowControllerUserDidCancel(_: AddFeedWindowController) {
closeAddFeedSheet(NSApplication.ModalResponse.cancel)
}
// MARK: FeedFinderDelegate
public func feedFinder(_ feedFinder: FeedFinder, didFindFeeds feedSpecifiers: Set<FeedSpecifier>) {
isFindingFeed = false
endShowingProgress()
if let error = feedFinder.initialDownloadError {
if feedFinder.initialDownloadStatusCode == 404 {
showNoFeedsErrorMessage()
}
else {
showInitialDownloadError(error)
}
return
}
guard let bestFeedSpecifier = FeedSpecifier.bestFeed(in: feedSpecifiers) else {
showNoFeedsErrorMessage()
return
}
self.bestFeedSpecifier = bestFeedSpecifier
self.foundFeedURLString = bestFeedSpecifier.urlString
if let url = URL(string: bestFeedSpecifier.urlString) {
InitialFeedDownloader.download(url) { (parsedFeed) in
self.titleFromFeed = parsedFeed?.title
self.addFeedIfPossible(parsedFeed)
}
}
else {
// Shouldn't happen.
showNoFeedsErrorMessage()
}
}
}
private extension AddFeedController {
var urlStringFromPasteboard: String? {
get {
if let urlString = NSPasteboard.rs_urlString(from: NSPasteboard.general) {
return urlString.rs_normalizedURL()
}
return nil
}
}
struct AccountAndFolderSpecifier {
let account: Account
let folder: Folder?
}
func accountAndFolderFromContainer(_ container: Container) -> AccountAndFolderSpecifier? {
if let account = container as? Account {
return AccountAndFolderSpecifier(account: account, folder: nil)
}
if let folder = container as? Folder, let account = folder.account {
return AccountAndFolderSpecifier(account: account, folder: folder)
}
return nil
}
func closeAddFeedSheet(_ returnCode: NSApplication.ModalResponse) {
if let sheetWindow = addFeedWindowController?.window {
hostWindow.endSheet(sheetWindow, returnCode: returnCode)
}
}
func addFeedIfPossible(_ parsedFeed: ParsedFeed?) {
// Add feed if not already subscribed-to.
guard let account = userEnteredAccount else {
assertionFailure("Expected account.")
return
}
guard let feedURLString = foundFeedURLString else {
assertionFailure("Expected feedURLString.")
return
}
if account.hasFeed(withURL: feedURLString) {
showAlreadySubscribedError(feedURLString)
return
}
guard let feed = account.createFeed(with: titleFromFeed, editedName: userEnteredTitle, url: feedURLString) else {
return
}
if let parsedFeed = parsedFeed {
account.update(feed, with: parsedFeed, {})
}
if account.addFeed(feed, to: userEnteredFolder) {
NotificationCenter.default.post(name: .UserDidAddFeed, object: self, userInfo: [UserInfoKey.feed: feed])
}
}
// MARK: Find Feeds
func findFeed() {
guard let url = userEnteredURL else {
assertionFailure("Expected userEnteredURL.")
return
}
isFindingFeed = true
feedFinder = FeedFinder(url: url, delegate: self)
beginShowingProgress()
}
// MARK: Errors
func showAlreadySubscribedError(_ urlString: String) {
let alert = NSAlert()
alert.alertStyle = .informational
alert.messageText = NSLocalizedString("Already subscribed", comment: "Feed finder")
alert.informativeText = NSLocalizedString("Cant add this feed because youve already subscribed to it.", comment: "Feed finder")
alert.beginSheetModal(for: hostWindow)
}
func showInitialDownloadError(_ error: Error) {
let alert = NSAlert()
alert.alertStyle = .informational
alert.messageText = NSLocalizedString("Download Error", comment: "Feed finder")
let formatString = NSLocalizedString("Cant add this feed because of a download error: “%@”", comment: "Feed finder")
let errorText = NSString.localizedStringWithFormat(formatString as NSString, error.localizedDescription)
alert.informativeText = errorText as String
alert.beginSheetModal(for: hostWindow)
}
func showNoFeedsErrorMessage() {
let alert = NSAlert()
alert.alertStyle = .informational
alert.messageText = NSLocalizedString("Feed not found", comment: "Feed finder")
alert.informativeText = NSLocalizedString("Cant add a feed because no feed was found.", comment: "Feed finder")
alert.beginSheetModal(for: hostWindow)
}
// MARK: Progress
func beginShowingProgress() {
runIndeterminateProgressWithMessage(NSLocalizedString("Finding feed…", comment:"Feed finder"))
}
func endShowingProgress() {
stopIndeterminateProgress()
hostWindow.makeKeyAndOrderFront(self)
}
}