mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2024-12-25 01:01:21 +01:00
Merge branch 'master' of https://github.com/brentsimmons/NetNewsWire
This commit is contained in:
commit
10633f31a9
@ -174,13 +174,17 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
|
||||
private lazy var opmlFile = OPMLFile(filename: (dataFolder as NSString).appendingPathComponent("Subscriptions.opml"), account: self)
|
||||
private lazy var metadataFile = AccountMetadataFile(filename: (dataFolder as NSString).appendingPathComponent("Settings.plist"), account: self)
|
||||
var metadata = AccountMetadata()
|
||||
var metadata = AccountMetadata() {
|
||||
didSet {
|
||||
delegate.accountMetadata = metadata
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var feedMetadataFile = FeedMetadataFile(filename: (dataFolder as NSString).appendingPathComponent("FeedMetadata.plist"), account: self)
|
||||
typealias FeedMetadataDictionary = [String: FeedMetadata]
|
||||
var feedMetadata = FeedMetadataDictionary()
|
||||
|
||||
private var startingUp = true
|
||||
var startingUp = true
|
||||
|
||||
public var unreadCount = 0 {
|
||||
didSet {
|
||||
@ -202,7 +206,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
}
|
||||
else {
|
||||
NotificationCenter.default.post(name: .AccountRefreshDidFinish, object: self)
|
||||
opmlFile.queueSaveToDiskIfNeeded()
|
||||
opmlFile.markAsDirty()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -364,6 +368,12 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
|
||||
}
|
||||
|
||||
public func saveIfNecessary() {
|
||||
metadataFile.saveIfNecessary()
|
||||
feedMetadataFile.saveIfNecessary()
|
||||
opmlFile.saveIfNecessary()
|
||||
}
|
||||
|
||||
func loadOPMLItems(_ items: [RSOPMLItem], parentFolder: Folder?) {
|
||||
var feedsToAdd = Set<Feed>()
|
||||
|
||||
@ -402,10 +412,11 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
|
||||
}
|
||||
|
||||
public func resetAllFeedMetadata() {
|
||||
public func resetFeedMetadataAndUnreadCounts() {
|
||||
for feed in flattenedFeeds() {
|
||||
feed.metadata = feedMetadata(feedURL: feed.url, feedID: feed.feedID)
|
||||
}
|
||||
fetchAllUnreadCounts()
|
||||
NotificationCenter.default.post(name: .FeedMetadataDidChange, object: self, userInfo: nil)
|
||||
}
|
||||
|
||||
|
@ -27,14 +27,14 @@ final class AccountMetadataFile {
|
||||
managedFile.markAsDirty()
|
||||
}
|
||||
|
||||
func queueSaveToDiskIfNeeded() {
|
||||
managedFile.queueSaveToDiskIfNeeded()
|
||||
}
|
||||
|
||||
func load() {
|
||||
managedFile.load()
|
||||
}
|
||||
|
||||
func saveIfNecessary() {
|
||||
managedFile.saveIfNecessary()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension AccountMetadataFile {
|
||||
|
@ -65,18 +65,7 @@ public final class Feed: DisplayNameProvider, Renamable, UnreadCountProvider, Ha
|
||||
}
|
||||
}
|
||||
|
||||
public var name: String? {
|
||||
get {
|
||||
return metadata.name
|
||||
}
|
||||
set {
|
||||
let oldNameForDisplay = nameForDisplay
|
||||
metadata.name = newValue
|
||||
if oldNameForDisplay != newValue {
|
||||
postDisplayNameDidChangeNotification()
|
||||
}
|
||||
}
|
||||
}
|
||||
public var name: String?
|
||||
|
||||
public var authors: Set<Author>? {
|
||||
get {
|
||||
|
@ -21,7 +21,6 @@ final class FeedMetadata: Codable {
|
||||
case homePageURL
|
||||
case iconURL
|
||||
case faviconURL
|
||||
case name
|
||||
case editedName
|
||||
case authors
|
||||
case contentHash
|
||||
@ -63,14 +62,6 @@ final class FeedMetadata: Codable {
|
||||
}
|
||||
}
|
||||
|
||||
var name: String? {
|
||||
didSet {
|
||||
if name != oldValue {
|
||||
valueDidChange(.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var editedName: String? {
|
||||
didSet {
|
||||
if editedName != oldValue {
|
||||
|
@ -27,14 +27,14 @@ final class FeedMetadataFile {
|
||||
managedFile.markAsDirty()
|
||||
}
|
||||
|
||||
func queueSaveToDiskIfNeeded() {
|
||||
managedFile.queueSaveToDiskIfNeeded()
|
||||
}
|
||||
|
||||
func load() {
|
||||
managedFile.load()
|
||||
}
|
||||
|
||||
func saveIfNecessary() {
|
||||
managedFile.saveIfNecessary()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension FeedMetadataFile {
|
||||
@ -49,7 +49,9 @@ private extension FeedMetadataFile {
|
||||
let decoder = PropertyListDecoder()
|
||||
account.feedMetadata = (try? decoder.decode(Account.FeedMetadataDictionary.self, from: fileData)) ?? Account.FeedMetadataDictionary()
|
||||
account.feedMetadata.values.forEach { $0.delegate = account }
|
||||
account.resetAllFeedMetadata()
|
||||
if !account.startingUp {
|
||||
account.resetFeedMetadataAndUnreadCounts()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -524,7 +524,6 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
||||
|
||||
func accountDidInitialize(_ account: Account) {
|
||||
credentials = try? account.retrieveCredentials(type: .basic)
|
||||
accountMetadata = account.metadata
|
||||
}
|
||||
|
||||
static func validateCredentials(transport: Transport, credentials: Credentials, endpoint: URL? = nil, completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||
|
@ -170,7 +170,6 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
||||
}
|
||||
|
||||
func accountDidInitialize(_ account: Account) {
|
||||
// accountMetadata = account.metadata
|
||||
credentials = try? account.retrieveCredentials(type: .oauthAccessToken)
|
||||
|
||||
syncStrategy = FeedlySyncStrategy(account: account, caller: caller, log: log)
|
||||
|
@ -52,7 +52,12 @@ final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlySyncOperation
|
||||
let url = collectionFeed.id
|
||||
let metadata = FeedMetadata(feedID: url)
|
||||
// TODO: More metadata
|
||||
metadata.name = collectionFeed.title
|
||||
|
||||
// Kiel, I'm commenting this out as we shouldn't be storing the name
|
||||
// in the feed metadata. It should be stored in the OPML file.
|
||||
// You can just set the name directly on the feed itself.
|
||||
// metadata.name = collectionFeed.title
|
||||
|
||||
let feed = Feed(account: account, url: url, metadata: metadata)
|
||||
|
||||
// So the same feed isn't created more than once.
|
||||
|
@ -28,14 +28,14 @@ final class OPMLFile {
|
||||
managedFile.markAsDirty()
|
||||
}
|
||||
|
||||
func queueSaveToDiskIfNeeded() {
|
||||
managedFile.queueSaveToDiskIfNeeded()
|
||||
}
|
||||
|
||||
func load() {
|
||||
managedFile.load()
|
||||
}
|
||||
|
||||
func saveIfNecessary() {
|
||||
managedFile.saveIfNecessary()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension OPMLFile {
|
||||
|
@ -411,7 +411,6 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
|
||||
}
|
||||
|
||||
func accountDidInitialize(_ account: Account) {
|
||||
accountMetadata = account.metadata
|
||||
credentials = try? account.retrieveCredentials(type: .readerAPIKey)
|
||||
}
|
||||
|
||||
|
@ -11,4 +11,4 @@ INFOPLIST_FILE = Info.plist
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.Account
|
||||
PRODUCT_NAME = $(TARGET_NAME:c99extidentifier)
|
||||
CLANG_ENABLE_MODULES = YES
|
||||
|
||||
APPLICATION_EXTENSION_API_ONLY = YES
|
||||
|
@ -345,6 +345,7 @@
|
||||
844BEE701F0AB3C9004AB7CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
@ -357,6 +358,7 @@
|
||||
844BEE711F0AB3C9004AB7CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
|
@ -11,4 +11,4 @@ INFOPLIST_FILE = Info.plist
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.Articles
|
||||
PRODUCT_NAME = $(TARGET_NAME)
|
||||
CLANG_ENABLE_MODULES = YES
|
||||
|
||||
APPLICATION_EXTENSION_API_ONLY = YES
|
||||
|
@ -13,4 +13,4 @@ INFOPLIST_FILE = Info.plist
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.ArticlesDatabase
|
||||
PRODUCT_NAME = $(TARGET_NAME)
|
||||
CLANG_ENABLE_MODULES = YES
|
||||
|
||||
APPLICATION_EXTENSION_API_ONLY = YES
|
||||
|
@ -13,4 +13,4 @@ INFOPLIST_FILE = Info.plist
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.ranchero.SyncDatabase
|
||||
PRODUCT_NAME = $(TARGET_NAME)
|
||||
CLANG_ENABLE_MODULES = YES
|
||||
|
||||
APPLICATION_EXTENSION_API_ONLY = YES
|
||||
|
@ -74,7 +74,6 @@
|
||||
51554C25228B71910055115A /* SyncDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
51554C30228B71A10055115A /* SyncDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; };
|
||||
51554C31228B71A10055115A /* SyncDatabase.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 51554C01228B6EB50055115A /* SyncDatabase.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
515ADE4022E11FAE006B2460 /* SystemMessageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515ADE3F22E11FAE006B2460 /* SystemMessageViewController.swift */; };
|
||||
515D4FC123257A3200EE1167 /* FolderTreeControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97A11ED9F180007D329B /* FolderTreeControllerDelegate.swift */; };
|
||||
515D4FCA23257CB500EE1167 /* Node-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97971ED9EFAA007D329B /* Node-Extensions.swift */; };
|
||||
515D4FCC2325815A00EE1167 /* SafariExt.js in Resources */ = {isa = PBXBuildFile; fileRef = 515D4FCB2325815A00EE1167 /* SafariExt.js */; };
|
||||
@ -815,7 +814,6 @@
|
||||
514B7C8223205EFB00BAC947 /* RootSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootSplitViewController.swift; sourceTree = "<group>"; };
|
||||
514B7D1E23219F3C00BAC947 /* AddControllerType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddControllerType.swift; sourceTree = "<group>"; };
|
||||
51554BFC228B6EB50055115A /* SyncDatabase.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = SyncDatabase.xcodeproj; path = Frameworks/SyncDatabase/SyncDatabase.xcodeproj; sourceTree = SOURCE_ROOT; };
|
||||
515ADE3F22E11FAE006B2460 /* SystemMessageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemMessageViewController.swift; sourceTree = "<group>"; };
|
||||
515D4FCB2325815A00EE1167 /* SafariExt.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = SafariExt.js; sourceTree = "<group>"; };
|
||||
515D4FCD2325909200EE1167 /* NetNewsWire_iOS_ShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NetNewsWire_iOS_ShareExtension.entitlements; sourceTree = "<group>"; };
|
||||
515D4FCE2325B3D000EE1167 /* NetNewsWire_iOSshareextension_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSshareextension_target.xcconfig; sourceTree = "<group>"; };
|
||||
@ -1382,7 +1380,6 @@
|
||||
children = (
|
||||
51C4527E2265092C00C03939 /* DetailViewController.swift */,
|
||||
517630222336657E00E15FFF /* DetailViewControllerWebViewProvider.swift */,
|
||||
515ADE3F22E11FAE006B2460 /* SystemMessageViewController.swift */,
|
||||
);
|
||||
path = Detail;
|
||||
sourceTree = "<group>";
|
||||
@ -2710,7 +2707,6 @@
|
||||
51EAED96231363EF00A9EEE3 /* NonIntrinsicButton.swift in Sources */,
|
||||
51C4527B2265091600C03939 /* MasterUnreadIndicatorView.swift in Sources */,
|
||||
5152E1022324900D00E5C7AD /* SettingsAddAccountView.swift in Sources */,
|
||||
515ADE4022E11FAE006B2460 /* SystemMessageViewController.swift in Sources */,
|
||||
51F85BF92274AA7B00C787DC /* UIBarButtonItem-Extensions.swift in Sources */,
|
||||
51B62E68233186730085F949 /* MasterTimelineAvatarView.swift in Sources */,
|
||||
51C45296226509D300C03939 /* OPMLExporter.swift in Sources */,
|
||||
|
@ -113,39 +113,7 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="FJe-Yq-33r" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1619" y="-87"/>
|
||||
</scene>
|
||||
<!--System Message-->
|
||||
<scene sceneID="tbo-yR-QVH">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="SystemMessageViewController" title="System Message" id="Xld-e9-xoL" customClass="SystemMessageViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="5hz-HK-J2Q">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="System Message" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6C9-Jb-ZZR">
|
||||
<rect key="frame" x="141.5" y="437.5" width="131" height="21"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<constraints>
|
||||
<constraint firstItem="6C9-Jb-ZZR" firstAttribute="centerX" secondItem="5hz-HK-J2Q" secondAttribute="centerX" id="9iO-I1-FtK"/>
|
||||
<constraint firstItem="6C9-Jb-ZZR" firstAttribute="centerY" secondItem="5hz-HK-J2Q" secondAttribute="centerY" id="jXm-OI-Igs"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="zOb-OV-HXy"/>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="2kf-IY-WDY"/>
|
||||
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
|
||||
<connections>
|
||||
<outlet property="messageLabel" destination="6C9-Jb-ZZR" id="HeR-Qv-yfz"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="rgH-br-nLG" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="872" y="-87"/>
|
||||
<point key="canvasLocation" x="2320" y="-759"/>
|
||||
</scene>
|
||||
<!--Timeline-->
|
||||
<scene sceneID="fag-XH-avP">
|
||||
|
@ -12,6 +12,14 @@ import Account
|
||||
import Articles
|
||||
import SafariServices
|
||||
|
||||
enum DetailViewState: Equatable {
|
||||
case noSelection
|
||||
case multipleSelection
|
||||
case loading
|
||||
case article(Article)
|
||||
case extracted(Article, ExtractedArticle)
|
||||
}
|
||||
|
||||
class DetailViewController: UIViewController {
|
||||
|
||||
@IBOutlet private weak var nextUnreadBarButtonItem: UIBarButtonItem!
|
||||
@ -26,6 +34,26 @@ class DetailViewController: UIViewController {
|
||||
|
||||
weak var coordinator: SceneCoordinator!
|
||||
|
||||
var state: DetailViewState = .noSelection {
|
||||
didSet {
|
||||
if state != oldValue {
|
||||
updateUI()
|
||||
reloadHTML()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var currentArticle: Article? {
|
||||
switch state {
|
||||
case .article(let article):
|
||||
return article
|
||||
case .extracted(let article, _):
|
||||
return article
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private let keyboardManager = KeyboardManager(type: .detail)
|
||||
override var keyCommands: [UIKeyCommand]? {
|
||||
return keyboardManager.keyCommands
|
||||
@ -66,7 +94,7 @@ class DetailViewController: UIViewController {
|
||||
|
||||
func updateUI() {
|
||||
|
||||
guard let article = coordinator.currentArticle else {
|
||||
guard let article = currentArticle else {
|
||||
nextUnreadBarButtonItem.isEnabled = false
|
||||
prevArticleBarButtonItem.isEnabled = false
|
||||
nextArticleBarButtonItem.isEnabled = false
|
||||
@ -95,12 +123,22 @@ class DetailViewController: UIViewController {
|
||||
}
|
||||
|
||||
func reloadHTML() {
|
||||
guard let article = coordinator.currentArticle, let webView = webView else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let style = ArticleStylesManager.shared.currentStyle
|
||||
let rendering = ArticleRenderer.articleHTML(article: article, style: style)
|
||||
let rendering: ArticleRenderer.Rendering
|
||||
|
||||
switch state {
|
||||
case .noSelection:
|
||||
rendering = ArticleRenderer.noSelectionHTML(style: style)
|
||||
case .multipleSelection:
|
||||
rendering = ArticleRenderer.multipleSelectionHTML(style: style)
|
||||
case .loading:
|
||||
rendering = ArticleRenderer.loadingHTML(style: style)
|
||||
case .article(let article):
|
||||
rendering = ArticleRenderer.articleHTML(article: article, style: style)
|
||||
case .extracted(let article, let extractedArticle):
|
||||
rendering = ArticleRenderer.articleHTML(article: article, extractedArticle: extractedArticle, style: style)
|
||||
}
|
||||
|
||||
let templateData = TemplateData(style: rendering.style, body: rendering.html)
|
||||
|
||||
@ -111,7 +149,8 @@ class DetailViewController: UIViewController {
|
||||
render = "render(\(json));"
|
||||
}
|
||||
|
||||
webView.evaluateJavaScript(render)
|
||||
webView?.evaluateJavaScript(render)
|
||||
|
||||
}
|
||||
|
||||
// MARK: Notifications
|
||||
@ -124,7 +163,7 @@ class DetailViewController: UIViewController {
|
||||
guard let articles = note.userInfo?[Account.UserInfoKey.articles] as? Set<Article> else {
|
||||
return
|
||||
}
|
||||
if articles.count == 1 && articles.first?.articleID == coordinator.currentArticle?.articleID {
|
||||
if articles.count == 1 && articles.first?.articleID == currentArticle?.articleID {
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
@ -164,11 +203,11 @@ class DetailViewController: UIViewController {
|
||||
}
|
||||
|
||||
@IBAction func showActivityDialog(_ sender: Any) {
|
||||
guard let currentArticle = coordinator.currentArticle, let preferredLink = currentArticle.preferredLink, let url = URL(string: preferredLink) else {
|
||||
guard let preferredLink = currentArticle?.preferredLink, let url = URL(string: preferredLink) else {
|
||||
return
|
||||
}
|
||||
|
||||
let itemSource = ArticleActivityItemSource(url: url, subject: currentArticle.title)
|
||||
let itemSource = ArticleActivityItemSource(url: url, subject: currentArticle!.title)
|
||||
let activityViewController = UIActivityViewController(activityItems: [itemSource], applicationActivities: nil)
|
||||
activityViewController.popoverPresentationController?.barButtonItem = actionBarButtonItem
|
||||
present(activityViewController, animated: true)
|
||||
@ -180,10 +219,6 @@ class DetailViewController: UIViewController {
|
||||
}
|
||||
|
||||
// MARK: API
|
||||
func updateArticleSelection() {
|
||||
updateUI()
|
||||
reloadHTML()
|
||||
}
|
||||
|
||||
func focus() {
|
||||
webView.becomeFirstResponder()
|
||||
@ -241,7 +276,8 @@ extension DetailViewController: WKNavigationDelegate {
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
self.updateArticleSelection()
|
||||
self.updateUI()
|
||||
self.reloadHTML()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
//
|
||||
// SystemMessageViewController.swift
|
||||
// NetNewsWire-iOS
|
||||
//
|
||||
// Created by Maurice Parker on 7/18/19.
|
||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SystemMessageViewController: UIViewController {
|
||||
|
||||
@IBOutlet weak var messageLabel: UILabel!
|
||||
var message: String = NSLocalizedString("No Selection", comment: "No Selection")
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
messageLabel.text = message
|
||||
}
|
||||
|
||||
}
|
@ -223,7 +223,7 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
|
||||
|
||||
if let self = self {
|
||||
|
||||
let alert = UIAlertController(title: feed.name, message: nil, preferredStyle: .actionSheet)
|
||||
let alert = UIAlertController(title: feed.nameForDisplay, message: nil, preferredStyle: .actionSheet)
|
||||
if let popoverController = alert.popoverPresentationController {
|
||||
popoverController.sourceView = view
|
||||
popoverController.sourceRect = CGRect(x: view.frame.size.width/2, y: view.frame.size.height/2, width: 1, height: 1)
|
||||
|
@ -13,6 +13,7 @@ import Articles
|
||||
|
||||
class MasterTimelineViewController: UITableViewController, UndoableCommandRunner {
|
||||
|
||||
private var titleView: MasterTimelineTitleView?
|
||||
private var numberOfTextLines = 0
|
||||
|
||||
@IBOutlet weak var markAllAsReadButton: UIBarButtonItem!
|
||||
@ -342,6 +343,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
||||
}
|
||||
|
||||
@objc func faviconDidBecomeAvailable(_ note: Notification) {
|
||||
titleView?.imageView.image = coordinator.timelineFavicon
|
||||
if coordinator.showAvatars {
|
||||
queueReloadAvailableCells()
|
||||
}
|
||||
@ -455,6 +457,7 @@ private extension MasterTimelineViewController {
|
||||
|
||||
title = coordinator.timelineName
|
||||
if let titleView = Bundle.main.loadNibNamed("MasterTimelineTitleView", owner: self, options: nil)?[0] as? MasterTimelineTitleView {
|
||||
self.titleView = titleView
|
||||
titleView.imageView.image = coordinator.timelineFavicon
|
||||
titleView.label.text = coordinator.timelineName
|
||||
navigationItem.titleView = titleView
|
||||
|
@ -289,8 +289,10 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
||||
masterFeedViewController.coordinator = self
|
||||
masterNavigationController.pushViewController(masterFeedViewController, animated: false)
|
||||
|
||||
let noSelectionController = fullyWrappedSystemMesssageController(showButton: true)
|
||||
rootSplitViewController.showDetailViewController(noSelectionController, sender: self)
|
||||
let detailViewController = UIStoryboard.main.instantiateController(ofType: DetailViewController.self)
|
||||
detailViewController.coordinator = self
|
||||
let detailNavigationController = addNavControllerIfNecessary(detailViewController, showButton: false)
|
||||
rootSplitViewController.showDetailViewController(detailNavigationController, sender: self)
|
||||
|
||||
configureThreePanelMode(for: size)
|
||||
|
||||
@ -560,8 +562,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
||||
masterNavigationController.popViewController(animated: !automated)
|
||||
}
|
||||
} else {
|
||||
let systemMessageViewController = UIStoryboard.main.instantiateController(ofType: SystemMessageViewController.self)
|
||||
installDetailController(systemMessageViewController, automated: automated)
|
||||
detailViewController?.state = .noSelection
|
||||
}
|
||||
masterTimelineViewController?.updateArticleSelection(animate: !automated)
|
||||
return
|
||||
@ -577,11 +578,12 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
||||
masterTimelineViewController?.updateArticleSelection(animate: false)
|
||||
}
|
||||
|
||||
detailViewController?.updateArticleSelection()
|
||||
detailViewController?.state = .article(article!)
|
||||
|
||||
if let article = currentArticle {
|
||||
markArticles(Set([article]), statusKey: .read, flag: true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func beginSearching() {
|
||||
@ -852,60 +854,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
||||
extension SceneCoordinator: UISplitViewControllerDelegate {
|
||||
|
||||
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
|
||||
|
||||
// Check to see if the system is currently configured for three panel mode
|
||||
if let subSplit = secondaryViewController as? UISplitViewController {
|
||||
|
||||
// Take the timeline controller out of the subsplit and throw it on the master navigation stack
|
||||
if let masterTimelineNav = subSplit.viewControllers.first as? UINavigationController, let masterTimeline = masterTimelineNav.topViewController {
|
||||
masterNavigationController.pushViewController(masterTimeline, animated: false)
|
||||
}
|
||||
|
||||
// Take the detail view (ignoring system message controllers) and put it on the master navigation stack
|
||||
if let detailNav = subSplit.viewControllers.last as? UINavigationController, let detail = detailNav.topViewController as? DetailViewController {
|
||||
masterNavigationController.pushViewController(detail, animated: false)
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// If the timeline controller has been initialized and only the feeds controller is on the stack, we add the timeline controller
|
||||
if let timeline = masterTimelineViewController, masterNavigationController.viewControllers.count == 1 {
|
||||
masterNavigationController.pushViewController(timeline, animated: false)
|
||||
}
|
||||
|
||||
// Take the detail view (ignoring system message controllers) and put it on the master navigation stack
|
||||
if let detailNav = secondaryViewController as? UINavigationController, let detail = detailNav.topViewController as? DetailViewController {
|
||||
// I have no idea why, I have to wire up the left bar button item for this, but not when I am transitioning from three panel mode
|
||||
detail.navigationItem.leftBarButtonItem = rootSplitViewController.displayModeButtonItem
|
||||
detail.navigationItem.leftItemsSupplementBackButton = true
|
||||
masterNavigationController.pushViewController(detail, animated: false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
func splitViewController(_ splitViewController: UISplitViewController, separateSecondaryFrom primaryViewController: UIViewController) -> UIViewController? {
|
||||
|
||||
if isThreePanelMode {
|
||||
return transitionToThreePanelMode()
|
||||
}
|
||||
|
||||
if let detail = masterNavigationController.viewControllers.last as? DetailViewController {
|
||||
|
||||
// If we have a detail controller on the stack, remove it and return it.
|
||||
masterNavigationController.viewControllers.removeLast()
|
||||
let detailNav = addNavControllerIfNecessary(detail, showButton: true)
|
||||
return detailNav
|
||||
|
||||
} else {
|
||||
|
||||
// Display a no selection controller since we don't have any detail selected
|
||||
return fullyWrappedSystemMesssageController(showButton: true)
|
||||
|
||||
}
|
||||
return currentArticle == nil
|
||||
}
|
||||
|
||||
}
|
||||
@ -1449,12 +1398,6 @@ private extension SceneCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
func fullyWrappedSystemMesssageController(showButton: Bool) -> UIViewController {
|
||||
let systemMessageViewController = UIStoryboard.main.instantiateController(ofType: SystemMessageViewController.self)
|
||||
let navController = addNavControllerIfNecessary(systemMessageViewController, showButton: showButton)
|
||||
return navController
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func transitionToThreePanelMode() -> UIViewController {
|
||||
|
||||
@ -1466,7 +1409,9 @@ private extension SceneCoordinator {
|
||||
if let result = detailViewController {
|
||||
return result
|
||||
} else {
|
||||
return UIStoryboard.main.instantiateController(ofType: SystemMessageViewController.self)
|
||||
let detailController = UIStoryboard.main.instantiateController(ofType: DetailViewController.self)
|
||||
detailController.coordinator = self
|
||||
return detailController
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -119,6 +119,7 @@ class ShareViewController: SLComposeServiceViewController, ShareFolderPickerCont
|
||||
|
||||
switch result {
|
||||
case .success:
|
||||
account!.saveIfNecessary()
|
||||
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
|
||||
case .failure(let error):
|
||||
self.presentError(error) {
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit ced48ad15ebc762fea50beb618eed3cf10721148
|
||||
Subproject commit 388b58e2fde1a93233767f4dba61d236838b6900
|
@ -1 +1 @@
|
||||
Subproject commit 7b44768308dc6970ee78470d0ea1e5287badc2bc
|
||||
Subproject commit feb02ec73674fc572914f429e38428809c8d2281
|
@ -1 +1 @@
|
||||
Subproject commit 9e86cf613b40b6a3389b6248be9427d90debbf9f
|
||||
Subproject commit 6d0b05ccd661dac745dc4db402b5078e25c86b56
|
@ -1 +1 @@
|
||||
Subproject commit d333739a776236aae32b3868415729499021cec3
|
||||
Subproject commit 1a856651f1643abc5d52f4ef416077b9c41bf7e4
|
@ -1 +1 @@
|
||||
Subproject commit b1230d5aae49ee6c908fe694cd4f77b98d17cc42
|
||||
Subproject commit c55f96018ef1c81db35376065e1f094840162943
|
Loading…
Reference in New Issue
Block a user