diff --git a/Mac/Base.lproj/MainWindow.storyboard b/Mac/Base.lproj/MainWindow.storyboard index d6444a8d3..7d5f2c5dc 100644 --- a/Mac/Base.lproj/MainWindow.storyboard +++ b/Mac/Base.lproj/MainWindow.storyboard @@ -1,7 +1,7 @@ - + - + @@ -486,11 +486,11 @@ - - - - - - + + + + + + diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index c3d2ec254..c6282b4a3 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -8,8 +8,10 @@ /* Begin PBXBuildFile section */ 51126DA4225FDE2F00722696 /* RSImage-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */; }; + 5115CAF42266301400B21BCE /* AddContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51121B5A22661FEF00BC0EC1 /* AddContainerViewController.swift */; }; 5127B238222B4849006D641D /* DetailKeyboardDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5127B236222B4849006D641D /* DetailKeyboardDelegate.swift */; }; 5127B23A222B4849006D641D /* DetailKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */; }; + 517D9075226639F500323654 /* AddAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 517D906B2266392900323654 /* AddAccountViewController.swift */; }; 519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519B8D322143397200FA689C /* SharingServiceDelegate.swift */; }; 51C451A9226377C200C03939 /* ArticlesDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8407167F2262A61100344432 /* ArticlesDatabase.framework */; }; 51C451AA226377C200C03939 /* ArticlesDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8407167F2262A61100344432 /* ArticlesDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -54,10 +56,9 @@ 51C4527C2265091600C03939 /* MasterTimelineCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452752265091600C03939 /* MasterTimelineCellLayout.swift */; }; 51C4527F2265092C00C03939 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C4527E2265092C00C03939 /* DetailViewController.swift */; }; 51C452852265093600C03939 /* AddFeedFolderPickerData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452812265093600C03939 /* AddFeedFolderPickerData.swift */; }; - 51C452862265093600C03939 /* AddFeed.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51C452822265093600C03939 /* AddFeed.storyboard */; }; + 51C452862265093600C03939 /* Add.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51C452822265093600C03939 /* Add.storyboard */; }; 51C452872265093600C03939 /* FolderTreeControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452832265093600C03939 /* FolderTreeControllerDelegate.swift */; }; 51C452882265093600C03939 /* AddFeedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C452842265093600C03939 /* AddFeedViewController.swift */; }; - 51C4528C2265095F00C03939 /* AddFolder.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51C4528A2265095F00C03939 /* AddFolder.storyboard */; }; 51C4528D2265095F00C03939 /* AddFolderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C4528B2265095F00C03939 /* AddFolderViewController.swift */; }; 51C4528E2265099C00C03939 /* SmartFeedsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CC88171FE59CBF00644329 /* SmartFeedsController.swift */; }; 51C4528F226509BD00C03939 /* UnreadFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2D5391FC2308B00998D64 /* UnreadFeed.swift */; }; @@ -597,9 +598,11 @@ /* Begin PBXFileReference section */ 51121AA12265430A00BC0EC1 /* NetNewsWire_iOS_target.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOS_target.xcconfig; sourceTree = ""; }; + 51121B5A22661FEF00BC0EC1 /* AddContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContainerViewController.swift; sourceTree = ""; }; 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RSImage-Extensions.swift"; sourceTree = ""; }; 5127B236222B4849006D641D /* DetailKeyboardDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailKeyboardDelegate.swift; sourceTree = ""; }; 5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = DetailKeyboardShortcuts.plist; sourceTree = ""; }; + 517D906B2266392900323654 /* AddAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountViewController.swift; sourceTree = ""; }; 519B8D322143397200FA689C /* SharingServiceDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingServiceDelegate.swift; sourceTree = ""; }; 51C4524E226506F400C03939 /* UIStoryboard-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStoryboard-Extensions.swift"; sourceTree = ""; }; 51C4524F226506F400C03939 /* UIImage-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage-Extensions.swift"; sourceTree = ""; }; @@ -622,10 +625,9 @@ 51C452752265091600C03939 /* MasterTimelineCellLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterTimelineCellLayout.swift; sourceTree = ""; }; 51C4527E2265092C00C03939 /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; 51C452812265093600C03939 /* AddFeedFolderPickerData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFeedFolderPickerData.swift; sourceTree = ""; }; - 51C452822265093600C03939 /* AddFeed.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = AddFeed.storyboard; sourceTree = ""; }; + 51C452822265093600C03939 /* Add.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Add.storyboard; sourceTree = ""; }; 51C452832265093600C03939 /* FolderTreeControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FolderTreeControllerDelegate.swift; sourceTree = ""; }; 51C452842265093600C03939 /* AddFeedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFeedViewController.swift; sourceTree = ""; }; - 51C4528A2265095F00C03939 /* AddFolder.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = AddFolder.storyboard; sourceTree = ""; }; 51C4528B2265095F00C03939 /* AddFolderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddFolderViewController.swift; sourceTree = ""; }; 51C452B32265141B00C03939 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/WebKit.framework; sourceTree = DEVELOPER_DIR; }; 51C452B72265178500C03939 /* styleSheet.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = styleSheet.css; sourceTree = ""; }; @@ -932,12 +934,12 @@ 51C4526F2265091600C03939 /* Cell */ = { isa = PBXGroup; children = ( - 51C452702265091600C03939 /* MultilineUILabelSizer.swift */, - 51C452712265091600C03939 /* MasterTimelineCellData.swift */, 51C452722265091600C03939 /* MasterTimelineTableViewCell.swift */, - 51C452732265091600C03939 /* SingleLineUILabelSizer.swift */, - 51C452742265091600C03939 /* MasterUnreadIndicatorView.swift */, + 51C452712265091600C03939 /* MasterTimelineCellData.swift */, 51C452752265091600C03939 /* MasterTimelineCellLayout.swift */, + 51C452742265091600C03939 /* MasterUnreadIndicatorView.swift */, + 51C452732265091600C03939 /* SingleLineUILabelSizer.swift */, + 51C452702265091600C03939 /* MultilineUILabelSizer.swift */, ); path = Cell; sourceTree = ""; @@ -950,24 +952,18 @@ path = Detail; sourceTree = ""; }; - 51C452802265093600C03939 /* Add Feed */ = { + 51C452802265093600C03939 /* Add */ = { isa = PBXGroup; children = ( - 51C452812265093600C03939 /* AddFeedFolderPickerData.swift */, - 51C452822265093600C03939 /* AddFeed.storyboard */, - 51C452832265093600C03939 /* FolderTreeControllerDelegate.swift */, + 51C452822265093600C03939 /* Add.storyboard */, + 51121B5A22661FEF00BC0EC1 /* AddContainerViewController.swift */, 51C452842265093600C03939 /* AddFeedViewController.swift */, - ); - path = "Add Feed"; - sourceTree = ""; - }; - 51C452892265095F00C03939 /* Add Folder */ = { - isa = PBXGroup; - children = ( - 51C4528A2265095F00C03939 /* AddFolder.storyboard */, + 51C452812265093600C03939 /* AddFeedFolderPickerData.swift */, + 51C452832265093600C03939 /* FolderTreeControllerDelegate.swift */, 51C4528B2265095F00C03939 /* AddFolderViewController.swift */, + 517D906B2266392900323654 /* AddAccountViewController.swift */, ); - path = "Add Folder"; + path = Add; sourceTree = ""; }; 51C452A822650DA100C03939 /* Article Rendering */ = { @@ -1513,8 +1509,7 @@ 51C4525D226508F600C03939 /* Master */, 51C4526D2265091600C03939 /* Timeline */, 51C4527D2265092C00C03939 /* Detail */, - 51C452802265093600C03939 /* Add Feed */, - 51C452892265095F00C03939 /* Add Folder */, + 51C452802265093600C03939 /* Add */, 51C45245226506C800C03939 /* Extensions */, 84C9FC9A2262A1A900D921D6 /* Resources */, ); @@ -2023,9 +2018,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 51C452862265093600C03939 /* AddFeed.storyboard in Resources */, + 51C452862265093600C03939 /* Add.storyboard in Resources */, 84C9FCA12262A1B300D921D6 /* Main.storyboard in Resources */, - 51C4528C2265095F00C03939 /* AddFolder.storyboard in Resources */, 84C9FCA42262A1B800D921D6 /* LaunchScreen.storyboard in Resources */, 51C452AB22650DC600C03939 /* template.html in Resources */, 84A3EE61223B667F00557320 /* DefaultFeeds.opml in Resources */, @@ -2149,6 +2143,7 @@ 51C452A622650A3500C03939 /* Node-Extensions.swift in Sources */, 51C45294226509C800C03939 /* SearchFeedDelegate.swift in Sources */, 51C452A022650A1900C03939 /* FeedIconDownloader.swift in Sources */, + 517D9075226639F500323654 /* AddAccountViewController.swift in Sources */, 51C4529E22650A1900C03939 /* ImageDownloader.swift in Sources */, 51C45292226509C800C03939 /* TodayFeedDelegate.swift in Sources */, 84F3EE1B20DEC97E003FADEB /* HTMLFeedFinder.swift in Sources */, @@ -2169,6 +2164,7 @@ 51C4529C22650A1000C03939 /* SingleFaviconDownloader.swift in Sources */, 51C45290226509C100C03939 /* PseudoFeed.swift in Sources */, 51C452A922650DC600C03939 /* ArticleRenderer.swift in Sources */, + 5115CAF42266301400B21BCE /* AddContainerViewController.swift in Sources */, 51C45297226509E300C03939 /* DefaultFeedsImporter.swift in Sources */, 51C452AC22650FD200C03939 /* AppNotifications.swift in Sources */, 51C452762265091600C03939 /* MasterTimelineViewController.swift in Sources */, @@ -2583,7 +2579,6 @@ CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = 9C84TZ7Q6Z; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -2653,7 +2648,6 @@ CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = 9C84TZ7Q6Z; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -2715,7 +2709,6 @@ CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = 9C84TZ7Q6Z; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -2785,7 +2778,6 @@ CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = 9C84TZ7Q6Z; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -2814,7 +2806,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = D5907CDD2002F0BE005947E5 /* NetNewsWire_project_debug.xcconfig */; buildSettings = { - DEVELOPMENT_TEAM = M8L2WTLA8W; + IPHONEOS_DEPLOYMENT_TARGET = 12.2; MACOSX_DEPLOYMENT_TARGET = 10.14; }; name = Debug; @@ -2823,7 +2815,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = D5907CDC2002F0BE005947E5 /* NetNewsWire_project_release.xcconfig */; buildSettings = { - DEVELOPMENT_TEAM = M8L2WTLA8W; + IPHONEOS_DEPLOYMENT_TARGET = 12.2; MACOSX_DEPLOYMENT_TARGET = 10.14; }; name = Release; diff --git a/iOS/Add Feed/AddFeed.storyboard b/iOS/Add Feed/AddFeed.storyboard deleted file mode 100644 index 29ad674a8..000000000 --- a/iOS/Add Feed/AddFeed.storyboard +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iOS/Add Folder/AddFolder.storyboard b/iOS/Add Folder/AddFolder.storyboard deleted file mode 100644 index 32af9d0f8..000000000 --- a/iOS/Add Folder/AddFolder.storyboard +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iOS/Add/Add.storyboard b/iOS/Add/Add.storyboard new file mode 100644 index 000000000..c622165bd --- /dev/null +++ b/iOS/Add/Add.storyboard @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOS/Add/AddAccountViewController.swift b/iOS/Add/AddAccountViewController.swift new file mode 100644 index 000000000..1c6ab89c6 --- /dev/null +++ b/iOS/Add/AddAccountViewController.swift @@ -0,0 +1,30 @@ +// +// AddAccountViewController.swift +// NetNewsWire +// +// Created by Maurice Parker on 4/16/19. +// Copyright © 2019 Ranchero Software, LLC. All rights reserved. +// + +import UIKit + +class AddAccountViewController: UITableViewController, AddContainerViewControllerChild { + var delegate: AddContainerViewControllerChildDelegate? + + override func viewDidLoad() { + super.viewDidLoad() + + // I couldn't figure out the gap at the top of the UITableView, so I took a hammer to it. + tableView.contentInset = UIEdgeInsets(top: -28, left: 0, bottom: 0, right: 0) + + } + + func cancel() { + + } + + func add() { + + } + +} diff --git a/iOS/Add/AddContainerViewController.swift b/iOS/Add/AddContainerViewController.swift new file mode 100644 index 000000000..4c3eb6523 --- /dev/null +++ b/iOS/Add/AddContainerViewController.swift @@ -0,0 +1,149 @@ +// +// AddContainerViewController.swift +// NetNewsWire +// +// Created by Maurice Parker on 4/16/19. +// Copyright © 2019 Ranchero Software, LLC. All rights reserved. +// + +import UIKit + +protocol AddContainerViewControllerChild: UIViewController { + var delegate: AddContainerViewControllerChildDelegate? {get set} + func cancel() + func add() +} + +protocol AddContainerViewControllerChildDelegate: UIViewController { + func readyToAdd(state: Bool) + func processingDidBegin() + func processingDidEnd() +} + +class AddContainerViewController: UIViewController { + + @IBOutlet weak var cancelButton: UIBarButtonItem! + @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView! + @IBOutlet weak var addButton: UIBarButtonItem! + @IBOutlet weak var typeSelectorSegmentedControl: UISegmentedControl! + @IBOutlet weak var containerView: UIView! + + private var currentViewController: AddContainerViewControllerChild? + + override func viewDidLoad() { + + super.viewDidLoad() + activityIndicatorView.isHidden = true + + switchToFeed() + + } + + @IBAction func typeSelectorChanged(_ sender: UISegmentedControl) { + + switch sender.selectedSegmentIndex { + case 0: + switchToFeed() + case 1: + switchToFolder() + default: + switchToAccount() + } + + } + + @IBAction func cancel(_ sender: Any) { + currentViewController?.cancel() + dismiss(animated: true) + } + + @IBAction func add(_ sender: Any) { + currentViewController?.add() + } + +} + +extension AddContainerViewController: AddContainerViewControllerChildDelegate { + + func readyToAdd(state: Bool) { + addButton.isEnabled = state + } + + func processingDidBegin() { + addButton.isEnabled = false + typeSelectorSegmentedControl.isEnabled = false + activityIndicatorView.isHidden = false + activityIndicatorView.startAnimating() + } + + func processingDidEnd() { + addButton.isEnabled = true + typeSelectorSegmentedControl.isEnabled = true + activityIndicatorView.isHidden = true + activityIndicatorView.stopAnimating() + dismiss(animated: true) + } + +} + +private extension AddContainerViewController { + + func switchToFeed() { + guard !(currentViewController is AddFeedViewController) else { + return + } + resetUI() + hideCurrentController() + displayContentController(UIStoryboard.add.instantiateController(ofType: AddFeedViewController.self)) + } + + func switchToFolder() { + guard !(currentViewController is AddFolderViewController) else { + return + } + resetUI() + hideCurrentController() + displayContentController(UIStoryboard.add.instantiateController(ofType: AddFolderViewController.self)) + } + + func switchToAccount() { + guard !(currentViewController is AddAccountViewController) else { + return + } + resetUI() + hideCurrentController() + displayContentController(UIStoryboard.add.instantiateController(ofType: AddAccountViewController.self)) + } + + func resetUI() { + addButton.isEnabled = false + } + + func displayContentController(_ controller: AddContainerViewControllerChild) { + + currentViewController = controller + controller.delegate = self + + addChild(controller) + + containerView.addSubview(controller.view) + controller.view.translatesAutoresizingMaskIntoConstraints = false + controller.view.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true + controller.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true + controller.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true + controller.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true + + controller.didMove(toParent: self) + + } + + func hideCurrentController() { + guard let currentViewController = currentViewController else { + return + } + currentViewController.willMove(toParent: nil) + currentViewController.view.removeFromSuperview() + currentViewController.removeFromParent() + } + +} diff --git a/iOS/Add Feed/AddFeedFolderPickerData.swift b/iOS/Add/AddFeedFolderPickerData.swift similarity index 86% rename from iOS/Add Feed/AddFeedFolderPickerData.swift rename to iOS/Add/AddFeedFolderPickerData.swift index 92dbe1c73..70d3d0293 100644 --- a/iOS/Add Feed/AddFeedFolderPickerData.swift +++ b/iOS/Add/AddFeedFolderPickerData.swift @@ -1,4 +1,11 @@ -//Copyright © 2019 Vincode, Inc. All rights reserved. +// +// AddFeedFolderPickerData.swift +// NetNewsWire +// +// Created by Maurice Parker on 4/16/19. +// Copyright © 2019 Ranchero Software, LLC. All rights reserved. +// + import Foundation import Account diff --git a/iOS/Add Feed/AddFeedViewController.swift b/iOS/Add/AddFeedViewController.swift similarity index 78% rename from iOS/Add Feed/AddFeedViewController.swift rename to iOS/Add/AddFeedViewController.swift index 7257624f9..4a359bfa8 100644 --- a/iOS/Add Feed/AddFeedViewController.swift +++ b/iOS/Add/AddFeedViewController.swift @@ -1,4 +1,10 @@ -//Copyright © 2019 Vincode, Inc. All rights reserved. +// +// AddFeedViewController.swift +// NetNewsWire +// +// Created by Maurice Parker on 4/16/19. +// Copyright © 2019 Ranchero Software, LLC. All rights reserved. +// import UIKit import Account @@ -6,11 +12,7 @@ import RSCore import RSTree import RSParser -class AddFeedViewController: UITableViewController { - - @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView! - @IBOutlet weak var cancelButton: UIBarButtonItem! - @IBOutlet weak var addButton: UIBarButtonItem! +class AddFeedViewController: UITableViewController, AddContainerViewControllerChild { @IBOutlet weak var urlTextField: UITextField! @IBOutlet weak var nameTextField: UITextField! @@ -29,35 +31,41 @@ class AddFeedViewController: UITableViewController { private var titleFromFeed: String? private var userCancelled = false + + var delegate: AddContainerViewControllerChildDelegate? override func viewDidLoad() { super.viewDidLoad() - activityIndicatorView.isHidden = true - urlTextField.autocorrectionType = .no urlTextField.autocapitalizationType = .none pickerData = AddFeedFolderPickerData() folderPickerView.dataSource = self folderPickerView.delegate = self + folderPickerView.showsSelectionIndicator = true folderLabel.text = pickerData.containerNames[0] + + // I couldn't figure out the gap at the top of the UITableView, so I took a hammer to it. + tableView.contentInset = UIEdgeInsets(top: -28, left: 0, bottom: 0, right: 0) - } - - @IBAction func cancel(_ sender: Any) { - userCancelled = true - dismiss(animated: true) + NotificationCenter.default.addObserver(self, selector: #selector(textDidChange(_:)), name: UITextField.textDidChangeNotification, object: urlTextField) + } - @IBAction func add(_ sender: Any) { + func cancel() { + userCancelled = true + delegate?.processingDidEnd() + } + + func add() { let urlString = urlTextField.text ?? "" let normalizedURLString = (urlString as NSString).rs_normalizedURL() guard !normalizedURLString.isEmpty, let url = URL(string: normalizedURLString) else { - dismiss(animated: true) + delegate?.processingDidEnd() return } @@ -83,12 +91,16 @@ class AddFeedViewController: UITableViewController { return } - beginShowingProgress() - + delegate?.processingDidBegin() + feedFinder = FeedFinder(url: url, delegate: self) } + @objc func textDidChange(_ note: Notification) { + delegate?.readyToAdd(state: urlTextField.text?.rs_stringMayBeURL() ?? false) + } + } extension AddFeedViewController: UIPickerViewDataSource, UIPickerViewDelegate { @@ -111,42 +123,28 @@ extension AddFeedViewController: UIPickerViewDataSource, UIPickerViewDelegate { } -extension AddFeedViewController: UITextFieldDelegate { - - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - updateUI() - return true - } - - func textFieldDidEndEditing(_ textField: UITextField) { - updateUI() - } - -} - extension AddFeedViewController: FeedFinderDelegate { public func feedFinder(_ feedFinder: FeedFinder, didFindFeeds feedSpecifiers: Set) { if userCancelled { - endShowingProgress() return } if let error = feedFinder.initialDownloadError { if feedFinder.initialDownloadStatusCode == 404 { - endShowingProgress() showNoFeedsErrorMessage() + delegate?.processingDidEnd() } else { - endShowingProgress() showInitialDownloadError(error) + delegate?.processingDidEnd() } return } guard let bestFeedSpecifier = FeedSpecifier.bestFeed(in: feedSpecifiers) else { - endShowingProgress() showNoFeedsErrorMessage() + delegate?.processingDidEnd() return } @@ -160,7 +158,7 @@ extension AddFeedViewController: FeedFinderDelegate { } } else { // Shouldn't happen. - endShowingProgress() + delegate?.processingDidEnd() showNoFeedsErrorMessage() } @@ -170,22 +168,6 @@ extension AddFeedViewController: FeedFinderDelegate { private extension AddFeedViewController { - private func updateUI() { - addButton.isEnabled = urlTextField.text?.rs_stringMayBeURL() ?? false - } - - private func beginShowingProgress() { - activityIndicatorView.isHidden = false - activityIndicatorView.startAnimating() - addButton.isEnabled = false - } - - private func endShowingProgress() { - activityIndicatorView.isHidden = true - activityIndicatorView.stopAnimating() - addButton.isEnabled = true - } - private func showAlreadySubscribedError() { let title = NSLocalizedString("Already subscribed", comment: "Feed finder") let message = NSLocalizedString("Can’t add this feed because you’ve already subscribed to it.", comment: "Feed finder") @@ -208,27 +190,29 @@ private extension AddFeedViewController { func addFeedIfPossible(_ parsedFeed: ParsedFeed?) { if userCancelled { - endShowingProgress() return } guard let account = userEnteredAccount else { assertionFailure("Expected account.") + delegate?.processingDidEnd() return } + guard let feedURLString = foundFeedURLString else { assertionFailure("Expected feedURLString.") + delegate?.processingDidEnd() return } if account.hasFeed(withURL: feedURLString) { - endShowingProgress() showAlreadySubscribedError() + delegate?.processingDidEnd() return } guard let feed = account.createFeed(with: titleFromFeed, editedName: userEnteredTitle, url: feedURLString) else { - endShowingProgress() + delegate?.processingDidEnd() return } @@ -239,9 +223,8 @@ private extension AddFeedViewController { account.addFeed(feed, to: userEnteredFolder) NotificationCenter.default.post(name: .UserDidAddFeed, object: self, userInfo: [UserInfoKey.feed: feed]) - endShowingProgress() - dismiss(animated: true) - + delegate?.processingDidEnd() + } } diff --git a/iOS/Add Folder/AddFolderViewController.swift b/iOS/Add/AddFolderViewController.swift similarity index 60% rename from iOS/Add Folder/AddFolderViewController.swift rename to iOS/Add/AddFolderViewController.swift index 9eee0bbcf..c91abda0f 100644 --- a/iOS/Add Folder/AddFolderViewController.swift +++ b/iOS/Add/AddFolderViewController.swift @@ -1,18 +1,25 @@ -//Copyright © 2019 Vincode, Inc. All rights reserved. +// +// AddFolderViewController.swift +// NetNewsWire +// +// Created by Maurice Parker on 4/16/19. +// Copyright © 2019 Ranchero Software, LLC. All rights reserved. +// import UIKit import Account import RSCore -class AddFolderViewController: UITableViewController { +class AddFolderViewController: UITableViewController, AddContainerViewControllerChild { - @IBOutlet weak var addButton: UIBarButtonItem! @IBOutlet weak var nameTextField: UITextField! @IBOutlet weak var accountLabel: UILabel! @IBOutlet weak var accountPickerView: UIPickerView! private var accounts: [Account]! + var delegate: AddContainerViewControllerChildDelegate? + override func viewDidLoad() { super.viewDidLoad() @@ -23,21 +30,27 @@ class AddFolderViewController: UITableViewController { accountPickerView.dataSource = self accountPickerView.delegate = self + // I couldn't figure out the gap at the top of the UITableView, so I took a hammer to it. + tableView.contentInset = UIEdgeInsets(top: -28, left: 0, bottom: 0, right: 0) + + NotificationCenter.default.addObserver(self, selector: #selector(textDidChange(_:)), name: UITextField.textDidChangeNotification, object: nameTextField) + } - @IBAction func cancel(_ sender: Any) { - dismiss(animated: true) + func cancel() { + delegate?.processingDidEnd() } - @IBAction func add(_ sender: Any) { - + func add() { let account = accounts[accountPickerView.selectedRow(inComponent: 0)] if let folderName = nameTextField.text { account.ensureFolder(with: folderName) } - - dismiss(animated: true) - + delegate?.processingDidEnd() + } + + @objc func textDidChange(_ note: Notification) { + delegate?.readyToAdd(state: !(nameTextField.text?.isEmpty ?? false)) } } @@ -61,24 +74,3 @@ extension AddFolderViewController: UIPickerViewDataSource, UIPickerViewDelegate } } - -extension AddFolderViewController: UITextFieldDelegate { - - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - updateUI() - return true - } - - func textFieldDidEndEditing(_ textField: UITextField) { - updateUI() - } - -} - -private extension AddFolderViewController { - - private func updateUI() { - addButton.isEnabled = !(nameTextField.text?.isEmpty ?? false) - } - -} diff --git a/iOS/Add Feed/FolderTreeControllerDelegate.swift b/iOS/Add/FolderTreeControllerDelegate.swift similarity index 100% rename from iOS/Add Feed/FolderTreeControllerDelegate.swift rename to iOS/Add/FolderTreeControllerDelegate.swift diff --git a/iOS/Base.lproj/Main.storyboard b/iOS/Base.lproj/Main.storyboard index 39c689e13..37d4b8323 100644 --- a/iOS/Base.lproj/Main.storyboard +++ b/iOS/Base.lproj/Main.storyboard @@ -29,7 +29,7 @@ - + @@ -92,13 +92,13 @@ - + - + @@ -160,13 +160,13 @@ - + - + @@ -187,18 +187,11 @@ - - - - - - - - - - - - + + + + + @@ -208,13 +201,13 @@ - + - + @@ -268,7 +261,6 @@ - diff --git a/iOS/Extensions/UIStoryboard-Extensions.swift b/iOS/Extensions/UIStoryboard-Extensions.swift index df0f99c0a..66bfc485a 100644 --- a/iOS/Extensions/UIStoryboard-Extensions.swift +++ b/iOS/Extensions/UIStoryboard-Extensions.swift @@ -14,6 +14,10 @@ extension UIStoryboard { return UIStoryboard(name: "Main", bundle: nil) } + static var add: UIStoryboard { + return UIStoryboard(name: "Add", bundle: nil) + } + func instantiateController(ofType type: T.Type = T.self) -> T where T: UIViewController { let storyboardId = String(describing: type) diff --git a/iOS/Master/MasterViewController.swift b/iOS/Master/MasterViewController.swift index d40e51be1..762e2f9ca 100644 --- a/iOS/Master/MasterViewController.swift +++ b/iOS/Master/MasterViewController.swift @@ -175,15 +175,8 @@ class MasterViewController: UITableViewController { // MARK: Actions - @IBAction func addFeed(_ sender: UIBarButtonItem) { - let feedViewController = UIStoryboard(name: "AddFeed", bundle: nil).instantiateViewController(withIdentifier: "AddFeedNavigationController") - feedViewController.modalPresentationStyle = .popover - feedViewController.popoverPresentationController?.barButtonItem = sender - self.present(feedViewController, animated: true) - } - - @IBAction func addFolder(_ sender: UIBarButtonItem) { - let feedViewController = UIStoryboard(name: "AddFolder", bundle: nil).instantiateViewController(withIdentifier: "AddFolderNavigationController") + @IBAction func add(_ sender: UIBarButtonItem) { + let feedViewController = UIStoryboard.add.instantiateInitialViewController()! feedViewController.modalPresentationStyle = .popover feedViewController.popoverPresentationController?.barButtonItem = sender self.present(feedViewController, animated: true) diff --git a/iOS/Resources/Info.plist b/iOS/Resources/Info.plist index 590538118..f88866a9c 100644 --- a/iOS/Resources/Info.plist +++ b/iOS/Resources/Info.plist @@ -20,15 +20,15 @@ 1 LSRequiresIPhoneOS - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main NSAppTransportSecurity NSAllowsArbitraryLoads + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main UIRequiredDeviceCapabilities arm64 @@ -56,5 +56,27 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UTExportedTypeDeclarations + + + UTTypeConformsTo + + public.xml + + UTTypeDescription + OPML + UTTypeIconFiles + + UTTypeIdentifier + org.opml.opml + UTTypeTagSpecification + + public.filename-extension + + opml + + + + diff --git a/iOS/Timeline/Cell/MasterTimelineTableViewCell.swift b/iOS/Timeline/Cell/MasterTimelineTableViewCell.swift index 1211a1eb9..96a72fe78 100644 --- a/iOS/Timeline/Cell/MasterTimelineTableViewCell.swift +++ b/iOS/Timeline/Cell/MasterTimelineTableViewCell.swift @@ -18,8 +18,10 @@ class MasterTimelineTableViewCell: UITableViewCell { private let dateView = MasterTimelineTableViewCell.singleLineUILabel() private let feedNameView = MasterTimelineTableViewCell.singleLineUILabel() - private lazy var avatarImageView = { - return UIImageView(image: AppAssets.feedImage) + private lazy var avatarImageView: UIImageView = { + let imageView = UIImageView(image: AppAssets.feedImage) + imageView.contentMode = .scaleAspectFit + return imageView }() private lazy var starView = {