mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Merge branch 'main' into bsc-662-catch-up
This commit is contained in:
@@ -14,7 +14,7 @@ enum CloudKitAccountViewControllerError: LocalizedError {
|
||||
case iCloudDriveMissing
|
||||
|
||||
var errorDescription: String? {
|
||||
return NSLocalizedString("Unable to add iCloud Account. Please make sure you have iCloud and iCloud enabled in System Preferences.", comment: "Unable to add iCloud Account.")
|
||||
return NSLocalizedString("Unable to add iCloud Account. Please make sure you have iCloud and iCloud Drive enabled in System Preferences.", comment: "Unable to add iCloud Account.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina5_9" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
@@ -19,35 +19,35 @@
|
||||
<tableViewSection id="3tl-Mb-Eno">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="Cell" rowHeight="44" id="lyJ-rf-8GA">
|
||||
<rect key="frame" x="16" y="18" width="343" height="44"/>
|
||||
<rect key="frame" x="20" y="18" width="335" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="lyJ-rf-8GA" id="eNS-Rp-w0A">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="URL" textAlignment="natural" adjustsFontForContentSizeCategory="YES" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="eRp-AP-WFq">
|
||||
<rect key="frame" x="20" y="4" width="323" height="36"/>
|
||||
<rect key="frame" x="20" y="4" width="295" height="36"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<textInputTraits key="textInputTraits" keyboardType="URL"/>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="eRp-AP-WFq" firstAttribute="top" secondItem="eNS-Rp-w0A" secondAttribute="top" constant="4" id="80p-a2-3NC"/>
|
||||
<constraint firstAttribute="trailing" secondItem="eRp-AP-WFq" secondAttribute="trailing" id="Xue-v3-aqR"/>
|
||||
<constraint firstAttribute="trailing" secondItem="eRp-AP-WFq" secondAttribute="trailing" constant="20" symbolic="YES" id="Xue-v3-aqR"/>
|
||||
<constraint firstItem="eRp-AP-WFq" firstAttribute="leading" secondItem="eNS-Rp-w0A" secondAttribute="leading" constant="20" symbolic="YES" id="bHJ-7l-Pl3"/>
|
||||
<constraint firstAttribute="bottom" secondItem="eRp-AP-WFq" secondAttribute="bottom" constant="4" id="fs0-iw-zTo"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" rowHeight="44" id="Pxz-fv-QhQ">
|
||||
<rect key="frame" x="16" y="62" width="343" height="44"/>
|
||||
<rect key="frame" x="20" y="62" width="335" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Pxz-fv-QhQ" id="8aP-2A-8jc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Title (Optional)" textAlignment="natural" adjustsFontForContentSizeCategory="YES" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="u7n-VL-Ho9">
|
||||
<rect key="frame" x="20" y="4" width="303" height="36"/>
|
||||
<rect key="frame" x="20" y="4" width="295" height="36"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="words"/>
|
||||
</textField>
|
||||
@@ -61,10 +61,10 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" rowHeight="44" id="rlc-34-flT">
|
||||
<rect key="frame" x="16" y="106" width="343" height="44"/>
|
||||
<rect key="frame" x="20" y="106" width="335" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="rlc-34-flT" id="ZbC-Z6-dtq">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Folder" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RtT-rR-5LA">
|
||||
@@ -74,7 +74,7 @@
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="htg-Nn-3xi">
|
||||
<rect key="frame" x="281" y="11.666666666666664" width="42" height="21"/>
|
||||
<rect key="frame" x="273" y="11.666666666666664" width="42" height="21"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -112,7 +112,7 @@
|
||||
</barButtonItem>
|
||||
<barButtonItem id="qP4-8x-XbO">
|
||||
<view key="customView" contentMode="scaleToFill" id="9ct-kH-nAp">
|
||||
<rect key="frame" x="300.33333333333331" y="12" width="20" height="20"/>
|
||||
<rect key="frame" x="299" y="12" width="20" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="3ph-Td-s1Z">
|
||||
@@ -144,7 +144,7 @@
|
||||
<objects>
|
||||
<navigationController storyboardIdentifier="AddWebFeedFolderNavViewController" id="WDg-F7-gfk" customClass="ModalNavigationController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="akM-T1-shZ">
|
||||
<rect key="frame" x="0.0" y="44" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="47" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
@@ -164,7 +164,7 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="AccountCell" id="bp5-2u-4S4" customClass="AddComboTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="28" width="375" height="43.666667938232422"/>
|
||||
<rect key="frame" x="0.0" y="50" width="375" height="43.666667938232422"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="bp5-2u-4S4" id="9HE-eR-YIp">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.666667938232422"/>
|
||||
@@ -199,7 +199,7 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="FolderCell" id="S24-c1-0Ir" customClass="AddComboTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="71.666667938232422" width="375" height="43.666667938232422"/>
|
||||
<rect key="frame" x="0.0" y="93.666667938232422" width="375" height="43.666667938232422"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="S24-c1-0Ir" id="bA3-AB-H1n">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="43.666667938232422"/>
|
||||
@@ -256,7 +256,7 @@
|
||||
<objects>
|
||||
<navigationController storyboardIdentifier="AddWebFeedViewControllerNav" id="4Ej-aI-tUP" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="Fot-QF-7Rn">
|
||||
<rect key="frame" x="0.0" y="44" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="47" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
@@ -278,14 +278,14 @@
|
||||
<tableViewSection id="12M-tp-EeV">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="44" id="XJI-0M-cAh">
|
||||
<rect key="frame" x="16" y="18" width="343" height="44"/>
|
||||
<rect key="frame" x="20" y="18" width="335" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="XJI-0M-cAh" id="tIS-Tx-i17">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Name" textAlignment="natural" adjustsFontForContentSizeCategory="YES" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="lZK-wx-jbo">
|
||||
<rect key="frame" x="20" y="4" width="303" height="36"/>
|
||||
<rect key="frame" x="20" y="4" width="295" height="36"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="words"/>
|
||||
</textField>
|
||||
@@ -303,10 +303,10 @@
|
||||
<tableViewSection id="bX9-Y2-S2D">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="44" id="uU0-Jh-goT">
|
||||
<rect key="frame" x="16" y="98" width="343" height="44"/>
|
||||
<rect key="frame" x="20" y="98" width="335" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="uU0-Jh-goT" id="y2g-dW-fPZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Account" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YRf-I7-nkL">
|
||||
@@ -316,7 +316,7 @@
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mxj-Bw-Jfx">
|
||||
<rect key="frame" x="281" y="12" width="42" height="20"/>
|
||||
<rect key="frame" x="273" y="12" width="42" height="20"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -333,14 +333,14 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="140" id="zRi-p6-4KU">
|
||||
<rect key="frame" x="16" y="142" width="343" height="140"/>
|
||||
<rect key="frame" x="20" y="142" width="335" height="140"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="zRi-p6-4KU" id="wek-Qh-OXr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="140"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="140"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<pickerView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eGY-V8-gzJ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="343" height="140"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="140"/>
|
||||
</pickerView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
@@ -388,7 +388,7 @@
|
||||
<objects>
|
||||
<navigationController storyboardIdentifier="AddFolderViewControllerNav" id="edk-IE-nce" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="Pi1-Bc-YXQ">
|
||||
<rect key="frame" x="0.0" y="44" width="375" height="44"/>
|
||||
<rect key="frame" x="0.0" y="47" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
|
||||
@@ -54,10 +54,8 @@ class AddFeedViewController: UITableViewController {
|
||||
activityIndicator.isHidden = true
|
||||
activityIndicator.color = .label
|
||||
|
||||
if initialFeed == nil, let urlString = UIPasteboard.general.string {
|
||||
if urlString.mayBeURL {
|
||||
initialFeed = urlString.normalizedURL
|
||||
}
|
||||
if initialFeed == nil && UIPasteboard.general.hasURLs, let url = UIPasteboard.general.url {
|
||||
initialFeed = url.absoluteString.normalizedURL
|
||||
}
|
||||
|
||||
urlTextField.autocorrectionType = .no
|
||||
|
||||
@@ -325,4 +325,9 @@ struct AppAssets {
|
||||
}
|
||||
}
|
||||
|
||||
static var notificationSoundBlipFileName: String = {
|
||||
// https://freesound.org/people/cabled_mess/sounds/350862/
|
||||
return "notificationSoundBlip.mp3"
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ final class AppDefaults {
|
||||
static let articleFullscreenEnabled = "articleFullscreenEnabled"
|
||||
static let hasUsedFullScreenPreviously = "hasUsedFullScreenPreviously"
|
||||
static let confirmMarkAllAsRead = "confirmMarkAllAsRead"
|
||||
static let lastRefresh = "lastRefresh"
|
||||
static let addWebFeedAccountID = "addWebFeedAccountID"
|
||||
static let addWebFeedFolderName = "addWebFeedFolderName"
|
||||
static let addFolderAccountID = "addFolderAccountID"
|
||||
@@ -196,15 +195,6 @@ final class AppDefaults {
|
||||
}
|
||||
}
|
||||
|
||||
var lastRefresh: Date? {
|
||||
get {
|
||||
return AppDefaults.date(for: Key.lastRefresh)
|
||||
}
|
||||
set {
|
||||
AppDefaults.setDate(for: Key.lastRefresh, newValue)
|
||||
}
|
||||
}
|
||||
|
||||
var timelineNumberOfLines: Int {
|
||||
get {
|
||||
return AppDefaults.int(for: Key.timelineNumberOfLines)
|
||||
|
||||
@@ -10,6 +10,7 @@ import UIKit
|
||||
import RSCore
|
||||
import RSWeb
|
||||
import Account
|
||||
import Articles
|
||||
import BackgroundTasks
|
||||
import Secrets
|
||||
import WidgetKit
|
||||
@@ -73,7 +74,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
||||
FeedProviderManager.shared.delegate = ExtensionPointManager.shared
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(accountRefreshDidFinish(_:)), name: .AccountRefreshDidFinish, object: nil)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
@@ -150,10 +150,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
||||
}
|
||||
}
|
||||
|
||||
@objc func accountRefreshDidFinish(_ note: Notification) {
|
||||
AppDefaults.shared.lastRefresh = Date()
|
||||
}
|
||||
|
||||
// MARK: - API
|
||||
|
||||
func manualRefresh(errorHandler: @escaping (Error) -> ()) {
|
||||
@@ -172,10 +168,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
||||
|
||||
func prepareAccountsForBackground() {
|
||||
extensionFeedAddRequestFile.suspend()
|
||||
widgetDataEncoder.encodeIfNecessary()
|
||||
syncTimer?.invalidate()
|
||||
scheduleBackgroundFeedRefresh()
|
||||
syncArticleStatus()
|
||||
widgetDataEncoder.encode()
|
||||
waitForSyncTasksToFinish()
|
||||
}
|
||||
|
||||
@@ -183,7 +179,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
||||
extensionFeedAddRequestFile.resume()
|
||||
syncTimer?.update()
|
||||
|
||||
if let lastRefresh = AppDefaults.shared.lastRefresh {
|
||||
if let lastRefresh = AccountManager.shared.lastArticleFetchEndTime {
|
||||
if Date() > lastRefresh.addingTimeInterval(15 * 60) {
|
||||
AccountManager.shared.refreshAll(errorHandler: ErrorHandler.log)
|
||||
} else {
|
||||
@@ -219,6 +215,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
|
||||
|
||||
}
|
||||
|
||||
func presentThemeImportError(_ error: Error) {
|
||||
let windowScene = {
|
||||
let scenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }
|
||||
return scenes.filter { $0.activationState == .foregroundActive }.first ?? scenes.first
|
||||
}()
|
||||
guard let sceneDelegate = windowScene?.delegate as? SceneDelegate else { return }
|
||||
sceneDelegate.presentError(error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: App Initialization
|
||||
@@ -294,7 +299,7 @@ private extension AppDelegate {
|
||||
return
|
||||
}
|
||||
|
||||
if AccountManager.shared.refreshInProgress || isSyncArticleStatusRunning {
|
||||
if AccountManager.shared.refreshInProgress || isSyncArticleStatusRunning || widgetDataEncoder.isRunning {
|
||||
logger.info("Waiting for sync to finish...")
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
|
||||
self?.waitToComplete(completion: completion)
|
||||
@@ -423,55 +428,40 @@ private extension AppDelegate {
|
||||
private extension AppDelegate {
|
||||
|
||||
func handleMarkAsRead(userInfo: [AnyHashable: Any]) {
|
||||
guard let articlePathUserInfo = userInfo[UserInfoKey.articlePath] as? [AnyHashable : Any],
|
||||
let accountID = articlePathUserInfo[ArticlePathKey.accountID] as? String,
|
||||
let articleID = articlePathUserInfo[ArticlePathKey.articleID] as? String else {
|
||||
return
|
||||
}
|
||||
resumeDatabaseProcessingIfNecessary()
|
||||
let account = AccountManager.shared.existingAccount(with: accountID)
|
||||
guard account != nil else {
|
||||
logger.debug("No account found from notification.")
|
||||
return
|
||||
}
|
||||
let article = try? account!.fetchArticles(.articleIDs([articleID]))
|
||||
guard article != nil else {
|
||||
logger.debug("No account found from search using \(articleID, privacy: .public)")
|
||||
return
|
||||
}
|
||||
account!.markArticles(article!, statusKey: .read, flag: true) { _ in }
|
||||
self.prepareAccountsForBackground()
|
||||
account!.syncArticleStatus(completion: { [weak self] _ in
|
||||
if !AccountManager.shared.isSuspended {
|
||||
self?.prepareAccountsForBackground()
|
||||
self?.suspendApplication()
|
||||
}
|
||||
})
|
||||
markArticle(userInfo: userInfo, statusKey: .read)
|
||||
}
|
||||
|
||||
func handleMarkAsStarred(userInfo: [AnyHashable: Any]) {
|
||||
markArticle(userInfo: userInfo, statusKey: .starred)
|
||||
}
|
||||
|
||||
func markArticle(userInfo: [AnyHashable: Any], statusKey: ArticleStatus.Key) {
|
||||
guard let articlePathUserInfo = userInfo[UserInfoKey.articlePath] as? [AnyHashable : Any],
|
||||
let accountID = articlePathUserInfo[ArticlePathKey.accountID] as? String,
|
||||
let articleID = articlePathUserInfo[ArticlePathKey.articleID] as? String else {
|
||||
return
|
||||
}
|
||||
|
||||
resumeDatabaseProcessingIfNecessary()
|
||||
let account = AccountManager.shared.existingAccount(with: accountID)
|
||||
guard account != nil else {
|
||||
|
||||
guard let account = AccountManager.shared.existingAccount(with: accountID) else {
|
||||
logger.debug("No account found from notification.")
|
||||
return
|
||||
}
|
||||
let article = try? account!.fetchArticles(.articleIDs([articleID]))
|
||||
guard article != nil else {
|
||||
|
||||
guard let articles = try? account.fetchArticles(.articleIDs([articleID])), !articles.isEmpty else {
|
||||
logger.debug("No article found from search using \(articleID, privacy: .public)")
|
||||
return
|
||||
}
|
||||
account!.markArticles(article!, statusKey: .starred, flag: true) { _ in }
|
||||
account!.syncArticleStatus(completion: { [weak self] _ in
|
||||
if !AccountManager.shared.isSuspended {
|
||||
self?.prepareAccountsForBackground()
|
||||
self?.suspendApplication()
|
||||
}
|
||||
})
|
||||
|
||||
account.mark(articles: articles, statusKey: statusKey, flag: true) { [weak self] _ in
|
||||
account.syncArticleStatus(completion: { [weak self] _ in
|
||||
if !AccountManager.shared.isSuspended {
|
||||
self?.prepareAccountsForBackground()
|
||||
self?.suspendApplication()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@ import WebKit
|
||||
import Account
|
||||
import Articles
|
||||
import SafariServices
|
||||
import RSCore
|
||||
|
||||
class ArticleViewController: UIViewController, MainControllerIdentifiable {
|
||||
class ArticleViewController: UIViewController, MainControllerIdentifiable, Logging {
|
||||
|
||||
typealias State = (extractedArticle: ExtractedArticle?,
|
||||
isShowingExtractedArticle: Bool,
|
||||
@@ -87,6 +88,8 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable {
|
||||
return keyboardManager.keyCommands
|
||||
}
|
||||
|
||||
private var lastKnownDisplayMode: UISplitViewController.DisplayMode?
|
||||
|
||||
var currentUnreadCount: Int = 0 {
|
||||
didSet {
|
||||
updateUnreadCountIndicator()
|
||||
@@ -102,7 +105,6 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(reloadDueToThemeChange(_:)), name: .CurrentArticleThemeDidChangeNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(configureAppearanceMenu(_:)), name: .ArticleThemeNamesDidChangeNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(updateUnreadCountIndicator(_:)), name: UIDevice.orientationDidChangeNotification, object: nil)
|
||||
|
||||
articleExtractorButton.addTarget(self, action: #selector(toggleArticleExtractor(_:)), for: .touchUpInside)
|
||||
toolbarItems?.insert(UIBarButtonItem(customView: articleExtractorButton), at: 6)
|
||||
@@ -258,7 +260,7 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable {
|
||||
identifier: nil,
|
||||
discoverabilityTitle: nil,
|
||||
attributes: [],
|
||||
state: ArticleThemesManager.shared.currentThemeName == themeName ? .on : .off,
|
||||
state: ArticleThemesManager.shared.currentTheme.name == themeName ? .on : .off,
|
||||
handler: { action in
|
||||
ArticleThemesManager.shared.currentThemeName = themeName
|
||||
})
|
||||
@@ -270,7 +272,7 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable {
|
||||
identifier: nil,
|
||||
discoverabilityTitle: nil,
|
||||
attributes: [],
|
||||
state: ArticleThemesManager.shared.currentThemeName == AppDefaults.defaultThemeName ? .on : .off,
|
||||
state: ArticleThemesManager.shared.currentTheme.name == AppDefaults.defaultThemeName ? .on : .off,
|
||||
handler: { _ in
|
||||
ArticleThemesManager.shared.currentThemeName = AppDefaults.defaultThemeName
|
||||
})
|
||||
@@ -343,42 +345,6 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable {
|
||||
configureAppearanceMenu()
|
||||
}
|
||||
|
||||
|
||||
/// Updates the indicator count in the navigation bar.
|
||||
/// For iPhone, this indicator is visible if the unread count is > 0.
|
||||
/// For iPad, this indicator is visible if it is in `portrait` or `unknown`
|
||||
/// orientation, **and** the unread count is > 0.
|
||||
/// - Parameter sender: `Any` (optional)
|
||||
@objc
|
||||
public func updateUnreadCountIndicator(_ sender: Any? = nil) {
|
||||
if UIDevice.current.userInterfaceIdiom == .phone {
|
||||
if currentUnreadCount > 0 {
|
||||
let unreadCountView = MasterTimelineUnreadCountView(frame: .zero)
|
||||
unreadCountView.unreadCount = currentUnreadCount
|
||||
unreadCountView.setFrameIfNotEqual(CGRect(x: 0, y: 0, width: unreadCountView.intrinsicContentSize.width, height: unreadCountView.intrinsicContentSize.height))
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: unreadCountView)
|
||||
} else {
|
||||
navigationItem.leftBarButtonItem = nil
|
||||
}
|
||||
} else {
|
||||
|
||||
if UIDevice.current.orientation.isPortrait || !UIDevice.current.orientation.isValidInterfaceOrientation {
|
||||
if currentUnreadCount > 0 {
|
||||
let unreadCountView = MasterTimelineUnreadCountView(frame: .zero)
|
||||
unreadCountView.unreadCount = currentUnreadCount
|
||||
unreadCountView.setFrameIfNotEqual(CGRect(x: 0, y: 0, width: unreadCountView.intrinsicContentSize.width, height: unreadCountView.intrinsicContentSize.height))
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: unreadCountView)
|
||||
} else {
|
||||
navigationItem.leftBarButtonItem = nil
|
||||
}
|
||||
} else {
|
||||
navigationItem.leftBarButtonItem = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: Notifications
|
||||
|
||||
@objc dynamic func unreadCountDidChange(_ notification: Notification) {
|
||||
@@ -486,6 +452,12 @@ class ArticleViewController: UIViewController, MainControllerIdentifiable {
|
||||
func setScrollPosition(isShowingExtractedArticle: Bool, articleWindowScrollY: Int) {
|
||||
currentWebViewController?.setScrollPosition(isShowingExtractedArticle: isShowingExtractedArticle, articleWindowScrollY: articleWindowScrollY)
|
||||
}
|
||||
|
||||
public func splitViewControllerWillChangeTo(displayMode: UISplitViewController.DisplayMode) {
|
||||
lastKnownDisplayMode = displayMode
|
||||
updateUnreadCountIndicator()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: Find in Article
|
||||
@@ -644,4 +616,15 @@ private extension ArticleViewController {
|
||||
return controller
|
||||
}
|
||||
|
||||
func updateUnreadCountIndicator() {
|
||||
if currentUnreadCount > 0 && (traitCollection.userInterfaceIdiom == .phone || lastKnownDisplayMode == .secondaryOnly) {
|
||||
let unreadCountView = MasterTimelineUnreadCountView(frame: .zero)
|
||||
unreadCountView.unreadCount = currentUnreadCount
|
||||
unreadCountView.setFrameIfNotEqual(CGRect(x: 0, y: 0, width: unreadCountView.intrinsicContentSize.width, height: unreadCountView.intrinsicContentSize.height))
|
||||
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: unreadCountView)
|
||||
} else {
|
||||
navigationItem.leftBarButtonItem = nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ class OpenInBrowserActivity: UIActivity {
|
||||
}
|
||||
|
||||
override var activityImage: UIImage? {
|
||||
return UIImage(systemName: "globe", withConfiguration: UIImage.SymbolConfiguration(pointSize: 20, weight: .regular))
|
||||
return AppAssets.safariImage
|
||||
}
|
||||
|
||||
override var activityType: UIActivity.ActivityType? {
|
||||
|
||||
@@ -386,12 +386,8 @@ extension WebViewController: WKNavigationDelegate {
|
||||
} else if components?.scheme == "mailto" {
|
||||
decisionHandler(.cancel)
|
||||
|
||||
guard let emailAddress = url.percentEncodedEmailAddress else {
|
||||
return
|
||||
}
|
||||
|
||||
if UIApplication.shared.canOpenURL(emailAddress) {
|
||||
UIApplication.shared.open(emailAddress, options: [.universalLinksOnly : false], completionHandler: nil)
|
||||
if UIApplication.shared.canOpenURL(url) {
|
||||
UIApplication.shared.open(url, options: [.universalLinksOnly : false], completionHandler: nil)
|
||||
} else {
|
||||
let alert = UIAlertController(title: NSLocalizedString("Error", comment: "Error"), message: NSLocalizedString("This device cannot send emails.", comment: "This device cannot send emails."), preferredStyle: .alert)
|
||||
alert.addAction(.init(title: NSLocalizedString("Dismiss", comment: "Dismiss"), style: .cancel, handler: nil))
|
||||
|
||||
@@ -128,14 +128,17 @@ class MasterFeedTableViewCell : VibrantTableViewCell {
|
||||
self.disclosureButton?.accessibilityLabel = NSLocalizedString("Collapse Folder", comment: "Collapse Folder")
|
||||
self.disclosureButton?.imageView?.transform = CGAffineTransform(rotationAngle: 1.570796)
|
||||
} else {
|
||||
self.disclosureButton?.accessibilityLabel = NSLocalizedString("Expand Folder", comment: "Expand Folder")
|
||||
self.disclosureButton?.accessibilityLabel = NSLocalizedString("Expand Folder", comment: "Expand Folder")
|
||||
self.disclosureButton?.imageView?.transform = CGAffineTransform(rotationAngle: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func applyThemeProperties() {
|
||||
super.applyThemeProperties()
|
||||
override func updateConfiguration(using state: UICellConfigurationState) {
|
||||
backgroundConfiguration = UIBackgroundConfiguration.listSidebarCell().updated(for: state)
|
||||
if state.isSelected {
|
||||
backgroundConfiguration?.backgroundColor = AppAssets.secondaryAccentColor
|
||||
}
|
||||
}
|
||||
|
||||
override func willTransition(to state: UITableViewCell.StateMask) {
|
||||
@@ -171,8 +174,10 @@ class MasterFeedTableViewCell : VibrantTableViewCell {
|
||||
|
||||
let iconTintColor: UIColor
|
||||
if isHighlighted || isSelected {
|
||||
disclosureButton?.tintColor = AppAssets.vibrantTextColor
|
||||
iconTintColor = AppAssets.vibrantTextColor
|
||||
} else {
|
||||
disclosureButton?.tintColor = AppAssets.secondaryAccentColor
|
||||
if let preferredColor = iconImage?.preferredColor {
|
||||
iconTintColor = UIColor(cgColor: preferredColor)
|
||||
} else {
|
||||
|
||||
@@ -18,33 +18,63 @@ extension MasterFeedViewController: UITableViewDropDelegate {
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal {
|
||||
guard let destIndexPath = destinationIndexPath, destIndexPath.section > 0, tableView.hasActiveDrag else {
|
||||
guard tableView.hasActiveDrag else {
|
||||
return UITableViewDropProposal(operation: .forbidden)
|
||||
}
|
||||
|
||||
guard let sourceNode = session.localDragSession?.items.first?.localObject as? Node,
|
||||
let sourceWebFeed = sourceNode.representedObject as? WebFeed else {
|
||||
return UITableViewDropProposal(operation: .forbidden)
|
||||
}
|
||||
|
||||
guard let destFeed = coordinator.nodeFor(destIndexPath)?.representedObject as? Feed,
|
||||
let destAccount = destFeed.account,
|
||||
let destCell = tableView.cellForRow(at: destIndexPath) else {
|
||||
return UITableViewDropProposal(operation: .forbidden)
|
||||
}
|
||||
|
||||
var successOperation = UIDropOperation.move
|
||||
|
||||
if let destinationIndexPath = destinationIndexPath,
|
||||
let sourceIndexPath = coordinator.indexPathFor(sourceNode),
|
||||
destinationIndexPath.section != sourceIndexPath.section {
|
||||
successOperation = .copy
|
||||
}
|
||||
|
||||
guard let correctedIndexPath = correctDestinationIndexPath(session: session) else {
|
||||
// We didn't hit the corrected indexPath, but this at least it gets the section right
|
||||
guard let section = destinationIndexPath?.section,
|
||||
let account = coordinator.nodeFor(section)?.representedObject as? Account,
|
||||
!account.hasChildWebFeed(withURL: sourceWebFeed.url) else {
|
||||
return UITableViewDropProposal(operation: .forbidden)
|
||||
}
|
||||
|
||||
return UITableViewDropProposal(operation: successOperation, intent: .insertAtDestinationIndexPath)
|
||||
}
|
||||
|
||||
guard correctedIndexPath.section > 0 else {
|
||||
return UITableViewDropProposal(operation: .forbidden)
|
||||
}
|
||||
|
||||
guard let correctDestNode = coordinator.nodeFor(correctedIndexPath),
|
||||
let correctDestFeed = correctDestNode.representedObject as? Feed,
|
||||
let correctDestAccount = correctDestFeed.account else {
|
||||
return UITableViewDropProposal(operation: .forbidden)
|
||||
}
|
||||
|
||||
// Validate account specific behaviors...
|
||||
if destAccount.behaviors.contains(.disallowFeedInMultipleFolders),
|
||||
let sourceNode = session.localDragSession?.items.first?.localObject as? Node,
|
||||
let sourceWebFeed = sourceNode.representedObject as? WebFeed,
|
||||
sourceWebFeed.account?.accountID != destAccount.accountID && destAccount.hasWebFeed(withURL: sourceWebFeed.url) {
|
||||
if correctDestAccount.behaviors.contains(.disallowFeedInMultipleFolders),
|
||||
sourceWebFeed.account?.accountID != correctDestAccount.accountID && correctDestAccount.hasWebFeed(withURL: sourceWebFeed.url) {
|
||||
return UITableViewDropProposal(operation: .forbidden)
|
||||
}
|
||||
|
||||
// Determine the correct drop proposal
|
||||
if destFeed is Folder {
|
||||
if session.location(in: destCell).y >= 0 {
|
||||
return UITableViewDropProposal(operation: .move, intent: .insertIntoDestinationIndexPath)
|
||||
if let correctFolder = correctDestFeed as? Folder {
|
||||
if correctFolder.hasChildWebFeed(withURL: sourceWebFeed.url) {
|
||||
return UITableViewDropProposal(operation: .forbidden)
|
||||
} else {
|
||||
return UITableViewDropProposal(operation: .move, intent: .unspecified)
|
||||
return UITableViewDropProposal(operation: successOperation, intent: .insertIntoDestinationIndexPath)
|
||||
}
|
||||
} else {
|
||||
return UITableViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
|
||||
if let parentContainer = correctDestNode.parent?.representedObject as? Container, !parentContainer.hasChildWebFeed(withURL: sourceWebFeed.url) {
|
||||
return UITableViewDropProposal(operation: successOperation, intent: .insertAtDestinationIndexPath)
|
||||
} else {
|
||||
return UITableViewDropProposal(operation: .forbidden)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -52,33 +82,23 @@ extension MasterFeedViewController: UITableViewDropDelegate {
|
||||
func tableView(_ tableView: UITableView, performDropWith dropCoordinator: UITableViewDropCoordinator) {
|
||||
guard let dragItem = dropCoordinator.items.first?.dragItem,
|
||||
let dragNode = dragItem.localObject as? Node,
|
||||
let source = dragNode.parent?.representedObject as? Container,
|
||||
let destIndexPath = dropCoordinator.destinationIndexPath else {
|
||||
return
|
||||
}
|
||||
|
||||
let isFolderDrop: Bool = {
|
||||
if coordinator.nodeFor(destIndexPath)?.representedObject is Folder, let propCell = tableView.cellForRow(at: destIndexPath) {
|
||||
return dropCoordinator.session.location(in: propCell).y >= 0
|
||||
}
|
||||
return false
|
||||
}()
|
||||
let source = dragNode.parent?.representedObject as? Container else {
|
||||
return
|
||||
}
|
||||
|
||||
// Based on the drop we have to determine a node to start looking for a parent container.
|
||||
let destNode: Node? = {
|
||||
guard let destIndexPath = correctDestinationIndexPath(session: dropCoordinator.session) else { return nil }
|
||||
|
||||
if isFolderDrop {
|
||||
return coordinator.nodeFor(destIndexPath)
|
||||
} else {
|
||||
if destIndexPath.row == 0 {
|
||||
return coordinator.nodeFor(IndexPath(row: 0, section: destIndexPath.section))
|
||||
} else if destIndexPath.row > 0 {
|
||||
return coordinator.nodeFor(IndexPath(row: destIndexPath.row - 1, section: destIndexPath.section))
|
||||
if coordinator.nodeFor(destIndexPath)?.representedObject is Folder {
|
||||
if dropCoordinator.proposal.intent == .insertAtDestinationIndexPath {
|
||||
return coordinator.nodeFor(destIndexPath.section)
|
||||
} else {
|
||||
return nil
|
||||
return coordinator.nodeFor(destIndexPath)
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
}()
|
||||
|
||||
// Now we start looking for the parent container
|
||||
@@ -86,8 +106,11 @@ extension MasterFeedViewController: UITableViewDropDelegate {
|
||||
if let container = (destNode?.representedObject as? Container) ?? (destNode?.parent?.representedObject as? Container) {
|
||||
return container
|
||||
} else {
|
||||
// We didn't hit the corrected indexPath, but this at least gets the section right
|
||||
guard let section = dropCoordinator.destinationIndexPath?.section else { return nil }
|
||||
|
||||
// If we got here, we are trying to drop on an empty section header. Go and find the Account for this section
|
||||
return coordinator.rootNode.childAtIndex(destIndexPath.section)?.representedObject as? Account
|
||||
return coordinator.nodeFor(section)?.representedObject as? Account
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -96,10 +119,25 @@ extension MasterFeedViewController: UITableViewDropDelegate {
|
||||
if source.account == destination.account {
|
||||
moveWebFeedInAccount(feed: webFeed, sourceContainer: source, destinationContainer: destination)
|
||||
} else {
|
||||
moveWebFeedBetweenAccounts(feed: webFeed, sourceContainer: source, destinationContainer: destination)
|
||||
copyWebFeedBetweenAccounts(feed: webFeed, sourceContainer: source, destinationContainer: destination)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension MasterFeedViewController {
|
||||
|
||||
func correctDestinationIndexPath(session: UIDropSession) -> IndexPath? {
|
||||
let location = session.location(in: tableView)
|
||||
|
||||
var correctDestination: IndexPath?
|
||||
tableView.performUsingPresentationValues {
|
||||
correctDestination = tableView.indexPathForRow(at: location)
|
||||
}
|
||||
|
||||
return correctDestination
|
||||
}
|
||||
|
||||
func moveWebFeedInAccount(feed: WebFeed, sourceContainer: Container, destinationContainer: Container) {
|
||||
guard sourceContainer !== destinationContainer else { return }
|
||||
|
||||
@@ -115,7 +153,7 @@ extension MasterFeedViewController: UITableViewDropDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func moveWebFeedBetweenAccounts(feed: WebFeed, sourceContainer: Container, destinationContainer: Container) {
|
||||
func copyWebFeedBetweenAccounts(feed: WebFeed, sourceContainer: Container, destinationContainer: Container) {
|
||||
|
||||
if let existingFeed = destinationContainer.account?.existingWebFeed(withURL: feed.url) {
|
||||
|
||||
@@ -123,15 +161,7 @@ extension MasterFeedViewController: UITableViewDropDelegate {
|
||||
destinationContainer.account?.addWebFeed(existingFeed, to: destinationContainer) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
sourceContainer.account?.removeWebFeed(feed, from: sourceContainer) { result in
|
||||
BatchUpdate.shared.end()
|
||||
switch result {
|
||||
case .success:
|
||||
break
|
||||
case .failure(let error):
|
||||
self.presentError(error)
|
||||
}
|
||||
}
|
||||
BatchUpdate.shared.end()
|
||||
case .failure(let error):
|
||||
BatchUpdate.shared.end()
|
||||
self.presentError(error)
|
||||
@@ -144,15 +174,7 @@ extension MasterFeedViewController: UITableViewDropDelegate {
|
||||
destinationContainer.account?.createWebFeed(url: feed.url, name: feed.editedName, container: destinationContainer, validateFeed: false) { result in
|
||||
switch result {
|
||||
case .success:
|
||||
sourceContainer.account?.removeWebFeed(feed, from: sourceContainer) { result in
|
||||
BatchUpdate.shared.end()
|
||||
switch result {
|
||||
case .success:
|
||||
break
|
||||
case .failure(let error):
|
||||
self.presentError(error)
|
||||
}
|
||||
}
|
||||
BatchUpdate.shared.end()
|
||||
case .failure(let error):
|
||||
BatchUpdate.shared.end()
|
||||
self.presentError(error)
|
||||
@@ -164,3 +186,11 @@ extension MasterFeedViewController: UITableViewDropDelegate {
|
||||
|
||||
|
||||
}
|
||||
|
||||
private extension Container {
|
||||
|
||||
func hasChildWebFeed(withURL url: String) -> Bool {
|
||||
return topLevelWebFeeds.contains(where: { $0.url == url })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
import Account
|
||||
import Articles
|
||||
import RSCore
|
||||
@@ -16,13 +17,15 @@ import SafariServices
|
||||
class MasterFeedViewController: UITableViewController, UndoableCommandRunner, MainControllerIdentifiable {
|
||||
|
||||
@IBOutlet weak var filterButton: UIBarButtonItem!
|
||||
private var refreshProgressView: RefreshProgressView?
|
||||
@IBOutlet weak var addNewItemButton: UIBarButtonItem! {
|
||||
didSet {
|
||||
addNewItemButton.primaryAction = nil
|
||||
}
|
||||
}
|
||||
|
||||
let refreshProgressModel = RefreshProgressModel()
|
||||
lazy var progressBarViewController = UIHostingController(rootView: RefreshProgressView(progressBarMode: refreshProgressModel))
|
||||
|
||||
var mainControllerIdentifer = MainControllerIdentifier.masterFeed
|
||||
|
||||
weak var coordinator: SceneCoordinator!
|
||||
@@ -71,11 +74,17 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner, Ma
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange), name: UIContentSizeCategory.didChangeNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(configureContextMenu(_:)), name: .ActiveExtensionPointsDidChange, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(displayNameDidChange(_:)), name: .DisplayNameDidChange, object: nil)
|
||||
|
||||
refreshControl = UIRefreshControl()
|
||||
refreshControl!.addTarget(self, action: #selector(refreshAccounts(_:)), for: .valueChanged)
|
||||
refreshControl!.tintColor = .clear
|
||||
|
||||
progressBarViewController.view.backgroundColor = .clear
|
||||
progressBarViewController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
let refreshProgressItemButton = UIBarButtonItem(customView: progressBarViewController.view)
|
||||
toolbarItems?.insert(refreshProgressItemButton, at: 2)
|
||||
|
||||
configureToolbar()
|
||||
becomeFirstResponder()
|
||||
}
|
||||
|
||||
@@ -139,6 +148,13 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner, Ma
|
||||
}
|
||||
}
|
||||
|
||||
@objc func displayNameDidChange(_ note: Notification) {
|
||||
guard let object = note.object as? AnyObject else {
|
||||
return
|
||||
}
|
||||
reloadCell(for: object)
|
||||
}
|
||||
|
||||
@objc func contentSizeCategoryDidChange(_ note: Notification) {
|
||||
resetEstimatedRowHeight()
|
||||
tableView.reloadData()
|
||||
@@ -515,7 +531,9 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner, Ma
|
||||
|
||||
func updateFeedSelection(animations: Animations) {
|
||||
if let indexPath = coordinator.currentFeedIndexPath {
|
||||
tableView.selectRowAndScrollIfNotVisible(at: indexPath, animations: animations)
|
||||
if indexPath != tableView.indexPathForSelectedRow {
|
||||
tableView.selectRowAndScrollIfNotVisible(at: indexPath, animations: animations)
|
||||
}
|
||||
} else {
|
||||
if let indexPath = tableView.indexPathForSelectedRow {
|
||||
if animations.contains(.select) {
|
||||
@@ -587,7 +605,7 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner, Ma
|
||||
} else {
|
||||
setFilterButtonToInactive()
|
||||
}
|
||||
refreshProgressView?.update()
|
||||
refreshProgressModel.update()
|
||||
addNewItemButton?.isEnabled = !AccountManager.shared.activeAccounts.isEmpty
|
||||
|
||||
configureContextMenu()
|
||||
@@ -720,16 +738,6 @@ extension MasterFeedViewController: MasterFeedTableViewCellDelegate {
|
||||
|
||||
private extension MasterFeedViewController {
|
||||
|
||||
func configureToolbar() {
|
||||
guard let refreshProgressView = Bundle.main.loadNibNamed("RefreshProgressView", owner: self, options: nil)?[0] as? RefreshProgressView else {
|
||||
return
|
||||
}
|
||||
|
||||
self.refreshProgressView = refreshProgressView
|
||||
let refreshProgressItemButton = UIBarButtonItem(customView: refreshProgressView)
|
||||
toolbarItems?.insert(refreshProgressItemButton, at: 2)
|
||||
}
|
||||
|
||||
func setFilterButtonToActive() {
|
||||
filterButton?.image = AppAssets.filterActiveImage
|
||||
filterButton?.accLabelText = NSLocalizedString("Selected - Filter Read Feeds", comment: "Selected - Filter Read Feeds")
|
||||
@@ -831,6 +839,12 @@ private extension MasterFeedViewController {
|
||||
completion(cell as! MasterFeedTableViewCell, indexPath)
|
||||
}
|
||||
}
|
||||
|
||||
private func reloadCell(for object: AnyObject) {
|
||||
guard let indexPath = coordinator.indexPathFor(object) else { return }
|
||||
tableView.reloadRows(at: [indexPath], with: .none)
|
||||
restoreSelectionIfNecessary(adjustScroll: false)
|
||||
}
|
||||
|
||||
private func reloadAllVisibleCells(completion: (() -> Void)? = nil) {
|
||||
guard let indexPaths = tableView.indexPathsForVisibleRows else { return }
|
||||
@@ -1050,8 +1064,7 @@ private extension MasterFeedViewController {
|
||||
return nil
|
||||
}
|
||||
|
||||
let localizedMenuText = NSLocalizedString("Mark All as Read in “%@”", comment: "Command")
|
||||
let title = NSString.localizedStringWithFormat(localizedMenuText as NSString, webFeed.nameForDisplay) as String
|
||||
let title = NSLocalizedString("Mark All as Read", comment: "Command")
|
||||
let cancel = {
|
||||
completion(true)
|
||||
}
|
||||
@@ -1131,8 +1144,7 @@ private extension MasterFeedViewController {
|
||||
return nil
|
||||
}
|
||||
|
||||
let localizedMenuText = NSLocalizedString("Mark All as Read", comment: "Command")
|
||||
let title = NSString.localizedStringWithFormat(localizedMenuText as NSString, feed.nameForDisplay) as String
|
||||
let title = NSLocalizedString("Mark All as Read", comment: "Command")
|
||||
let action = UIAction(title: title, image: AppAssets.markAllAsReadImage) { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, sourceType: contentView) { [weak self] in
|
||||
if let articles = try? feed.fetchUnreadArticles() {
|
||||
@@ -1233,8 +1245,7 @@ private extension MasterFeedViewController {
|
||||
return nil
|
||||
}
|
||||
|
||||
let localizedMenuText = NSLocalizedString("Mark All as Read in “%@”", comment: "Command")
|
||||
let title = NSString.localizedStringWithFormat(localizedMenuText as NSString, account.nameForDisplay) as String
|
||||
let title = NSLocalizedString("Mark All as Read", comment: "Command")
|
||||
let action = UIAction(title: title, image: AppAssets.markAllAsReadImage) { [weak self] action in
|
||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, sourceType: contentView) { [weak self] in
|
||||
// If you don't have this delay the screen flashes when it executes this code
|
||||
|
||||
@@ -1,27 +1,82 @@
|
||||
//
|
||||
// RefeshProgressView.swift
|
||||
// NetNewsWire-iOS
|
||||
// ProgressBarView.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Maurice Parker on 10/24/19.
|
||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||
// Created by Maurice Parker on 11/11/22.
|
||||
// Copyright © 2022 Ranchero Software. All rights reserved.
|
||||
//
|
||||
// IndetermineProgressView inspired by https://daringsnowball.net/articles/indeterminate-linear-progress-view/
|
||||
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
import Account
|
||||
|
||||
class RefreshProgressView: UIView {
|
||||
struct RefreshProgressView: View {
|
||||
|
||||
@IBOutlet weak var progressView: UIProgressView!
|
||||
@IBOutlet weak var label: UILabel!
|
||||
static let width: CGFloat = 100
|
||||
static let height: CGFloat = 5
|
||||
|
||||
override func awakeFromNib() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(progressDidChange(_:)), name: .AccountRefreshProgressDidChange, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil)
|
||||
update()
|
||||
scheduleUpdateRefreshLabel()
|
||||
@ObservedObject var refreshProgressModel: RefreshProgressModel
|
||||
@State private var offset: CGFloat = 0
|
||||
|
||||
isAccessibilityElement = true
|
||||
accessibilityTraits = [.updatesFrequently, .notEnabled]
|
||||
init(progressBarMode: RefreshProgressModel) {
|
||||
self.refreshProgressModel = progressBarMode
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
if refreshProgressModel.isRefreshing {
|
||||
if refreshProgressModel.isIndeterminate {
|
||||
indeterminateProgressView
|
||||
} else {
|
||||
ProgressView(value: refreshProgressModel.progress)
|
||||
.progressViewStyle(LinearProgressViewStyle())
|
||||
.frame(width: Self.width, height: Self.height)
|
||||
}
|
||||
} else {
|
||||
Text(refreshProgressModel.label)
|
||||
.accessibilityLabel(refreshProgressModel.label)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.frame(width: 200, height: 44)
|
||||
}
|
||||
|
||||
var indeterminateProgressView: some View {
|
||||
Rectangle()
|
||||
.foregroundColor(.gray.opacity(0.15))
|
||||
.overlay(
|
||||
Rectangle()
|
||||
.foregroundColor(Color.accentColor)
|
||||
.frame(width: Self.width * 0.26, height: Self.height)
|
||||
.clipShape(Capsule())
|
||||
.offset(x: -Self.width * 0.6, y: 0)
|
||||
.offset(x: Self.width * 1.2 * self.offset, y: 0)
|
||||
.animation(.default.repeatForever().speed(0.265), value: self.offset)
|
||||
.onAppear {
|
||||
withAnimation {
|
||||
self.offset = 1
|
||||
}
|
||||
}
|
||||
.onDisappear {
|
||||
self.offset = 0
|
||||
}
|
||||
)
|
||||
.clipShape(Capsule())
|
||||
.frame(width: Self.width, height: Self.height)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class RefreshProgressModel: ObservableObject {
|
||||
|
||||
@Published var isRefreshing = false
|
||||
@Published var isIndeterminate = false
|
||||
@Published var progress = 0.0
|
||||
@Published var label = String()
|
||||
|
||||
init() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(progressDidChange(_:)), name: .AccountRefreshProgressDidChange, object: nil)
|
||||
}
|
||||
|
||||
func update() {
|
||||
@@ -31,52 +86,32 @@ class RefreshProgressView: UIView {
|
||||
updateRefreshLabel()
|
||||
}
|
||||
}
|
||||
|
||||
override func didMoveToSuperview() {
|
||||
progressChanged(animated: false)
|
||||
}
|
||||
|
||||
|
||||
@objc func progressDidChange(_ note: Notification) {
|
||||
progressChanged(animated: true)
|
||||
}
|
||||
|
||||
@objc func contentSizeCategoryDidChange(_ note: Notification) {
|
||||
// This hack is probably necessary because custom views in the toolbar don't get
|
||||
// notifications that the content size changed.
|
||||
label.font = UIFont.preferredFont(forTextStyle: .footnote)
|
||||
}
|
||||
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private extension RefreshProgressView {
|
||||
|
||||
private extension RefreshProgressModel {
|
||||
|
||||
func progressChanged(animated: Bool) {
|
||||
// Layout may crash if not in the view hierarchy.
|
||||
// https://github.com/Ranchero-Software/NetNewsWire/issues/1764
|
||||
let isInViewHierarchy = self.superview != nil
|
||||
|
||||
let progress = AccountManager.shared.combinedRefreshProgress
|
||||
|
||||
if progress.isComplete {
|
||||
if isInViewHierarchy {
|
||||
progressView.setProgress(1, animated: animated)
|
||||
}
|
||||
let combinedRefreshProgress = AccountManager.shared.combinedRefreshProgress
|
||||
isIndeterminate = combinedRefreshProgress.isIndeterminate
|
||||
|
||||
if combinedRefreshProgress.isComplete {
|
||||
isRefreshing = false
|
||||
progress = 1
|
||||
|
||||
func completeLabel() {
|
||||
// Check that there are no pending downloads.
|
||||
if AccountManager.shared.combinedRefreshProgress.isComplete {
|
||||
self.updateRefreshLabel()
|
||||
self.label.isHidden = false
|
||||
self.progressView.isHidden = true
|
||||
if self.superview != nil {
|
||||
self.progressView.setProgress(0, animated: animated)
|
||||
}
|
||||
updateRefreshLabel()
|
||||
progress = 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,19 +123,16 @@ private extension RefreshProgressView {
|
||||
completeLabel()
|
||||
}
|
||||
} else {
|
||||
label.isHidden = true
|
||||
progressView.isHidden = false
|
||||
if isInViewHierarchy {
|
||||
let percent = Float(progress.numberCompleted) / Float(progress.numberOfTasks)
|
||||
isRefreshing = true
|
||||
let percent = Double(combinedRefreshProgress.numberCompleted) / Double(combinedRefreshProgress.numberOfTasks)
|
||||
|
||||
// Don't let the progress bar go backwards unless we need to go back more than 25%
|
||||
if percent > progressView.progress || progressView.progress - percent > 0.25 {
|
||||
progressView.setProgress(percent, animated: animated)
|
||||
}
|
||||
// Don't let the progress bar go backwards unless we need to go back more than 25%
|
||||
if percent > progress || (progress - percent) > 0.25 {
|
||||
progress = percent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func updateRefreshLabel() {
|
||||
if let accountLastArticleFetchEndTime = AccountManager.shared.lastArticleFetchEndTime {
|
||||
|
||||
@@ -111,17 +143,15 @@ private extension RefreshProgressView {
|
||||
let refreshed = relativeDateTimeFormatter.localizedString(for: accountLastArticleFetchEndTime, relativeTo: Date())
|
||||
let localizedRefreshText = NSLocalizedString("Updated %@", comment: "Updated")
|
||||
let refreshText = NSString.localizedStringWithFormat(localizedRefreshText as NSString, refreshed) as String
|
||||
label.text = refreshText
|
||||
label = refreshText
|
||||
|
||||
} else {
|
||||
label.text = NSLocalizedString("Updated Just Now", comment: "Updated Just Now")
|
||||
label = NSLocalizedString("Updated Just Now", comment: "Updated Just Now")
|
||||
}
|
||||
|
||||
} else {
|
||||
label.text = ""
|
||||
label = ""
|
||||
}
|
||||
|
||||
accessibilityLabel = label.text
|
||||
}
|
||||
|
||||
func scheduleUpdateRefreshLabel() {
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="ejl-zC-eNy" customClass="RefreshProgressView" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="461" height="90"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="Ds3-59-ooT" customClass="RoundedProgressView" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="180.5" y="42.5" width="100" height="5"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="100" id="ReS-sT-7EN"/>
|
||||
<constraint firstAttribute="height" constant="5" id="oDX-bb-24H"/>
|
||||
</constraints>
|
||||
</progressView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7mJ-VZ-zqU">
|
||||
<rect key="frame" x="214" y="34" width="33" height="22"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
|
||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="sNo-8i-tO3"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="Ds3-59-ooT" firstAttribute="centerX" secondItem="ejl-zC-eNy" secondAttribute="centerX" id="5Rv-6l-HSL"/>
|
||||
<constraint firstItem="Ds3-59-ooT" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="ejl-zC-eNy" secondAttribute="leading" id="Bck-uf-0G7"/>
|
||||
<constraint firstItem="7mJ-VZ-zqU" firstAttribute="bottom" secondItem="sNo-8i-tO3" secondAttribute="bottom" id="DVn-hI-PhH"/>
|
||||
<constraint firstItem="7mJ-VZ-zqU" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="sNo-8i-tO3" secondAttribute="leading" id="Sbp-yf-ts9"/>
|
||||
<constraint firstItem="7mJ-VZ-zqU" firstAttribute="centerY" secondItem="ejl-zC-eNy" secondAttribute="centerY" id="Shb-X2-Fwc"/>
|
||||
<constraint firstItem="7mJ-VZ-zqU" firstAttribute="centerX" secondItem="ejl-zC-eNy" secondAttribute="centerX" id="lFg-fm-YmV"/>
|
||||
<constraint firstItem="sNo-8i-tO3" firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="7mJ-VZ-zqU" secondAttribute="trailing" id="mZ2-XG-Kvg"/>
|
||||
<constraint firstItem="Ds3-59-ooT" firstAttribute="centerY" secondItem="ejl-zC-eNy" secondAttribute="centerY" id="tIh-lb-KbY"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Ds3-59-ooT" secondAttribute="trailing" id="vSU-N6-Sk5"/>
|
||||
</constraints>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outlet property="label" destination="7mJ-VZ-zqU" id="MHr-r4-qop"/>
|
||||
<outlet property="progressView" destination="Ds3-59-ooT" id="TjM-db-LxM"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-75" y="-117"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<systemColor name="secondaryLabelColor">
|
||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
import RSCore
|
||||
import Account
|
||||
import Articles
|
||||
@@ -21,7 +22,9 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
||||
|
||||
@IBOutlet weak var markAllAsReadButton: UIBarButtonItem!
|
||||
|
||||
private var refreshProgressView: RefreshProgressView!
|
||||
let refreshProgressModel = RefreshProgressModel()
|
||||
lazy var progressBarViewController = UIHostingController(rootView: RefreshProgressView(progressBarMode: refreshProgressModel))
|
||||
|
||||
private var refreshProgressItemButton: UIBarButtonItem!
|
||||
private var firstUnreadButton: UIBarButtonItem!
|
||||
|
||||
@@ -95,13 +98,14 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
||||
|
||||
refreshControl = UIRefreshControl()
|
||||
refreshControl!.addTarget(self, action: #selector(refreshAccounts(_:)), for: .valueChanged)
|
||||
refreshControl!.tintColor = .clear
|
||||
|
||||
progressBarViewController.view.backgroundColor = .clear
|
||||
progressBarViewController.view.translatesAutoresizingMaskIntoConstraints = false
|
||||
refreshProgressItemButton = UIBarButtonItem(customView: progressBarViewController.view)
|
||||
|
||||
configureToolbar()
|
||||
|
||||
refreshProgressView = Bundle.main.loadNibNamed("RefreshProgressView", owner: self, options: nil)?[0] as? RefreshProgressView
|
||||
refreshProgressItemButton = UIBarButtonItem(customView: refreshProgressView!)
|
||||
|
||||
|
||||
resetUI(resetScroll: true)
|
||||
|
||||
// Load the table and then scroll to the saved position if available
|
||||
@@ -243,7 +247,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
||||
}
|
||||
|
||||
func updateUI() {
|
||||
refreshProgressView?.update()
|
||||
refreshProgressModel.update()
|
||||
updateTitleUnreadCount()
|
||||
updateToolbar()
|
||||
}
|
||||
@@ -614,12 +618,6 @@ private extension MasterTimelineViewController {
|
||||
return
|
||||
}
|
||||
|
||||
guard let refreshProgressView = Bundle.main.loadNibNamed("RefreshProgressView", owner: self, options: nil)?[0] as? RefreshProgressView else {
|
||||
return
|
||||
}
|
||||
|
||||
self.refreshProgressView = refreshProgressView
|
||||
let refreshProgressItemButton = UIBarButtonItem(customView: refreshProgressView)
|
||||
toolbarItems?.insert(refreshProgressItemButton, at: 2)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf2513
|
||||
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 LucidaGrande-Bold;}
|
||||
{\colortbl;\red255\green255\blue255;\red0\green0\blue0;\red10\green96\blue255;}
|
||||
{\*\expandedcolortbl;;\cssrgb\c0\c0\c0;\cssrgb\c0\c47843\c100000\cname systemBlueColor;}
|
||||
\margl1440\margr1440\vieww8340\viewh9300\viewkind0
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\li363\fi-364\pardirnatural\partightenfactor0
|
||||
|
||||
\f0\b\fs28 \cf2 By Brent Simmons and the Ranchero Software team
|
||||
\fs22 \
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0
|
||||
{\field{\*\fldinst{HYPERLINK "https://netnewswire.com/"}}{\fldrslt
|
||||
\fs28 \cf3 netnewswire.com}}}
|
||||
BIN
iOS/Resources/Assets.xcassets/About.imageset/AppIcon-1024px 1.png
vendored
Normal file
BIN
iOS/Resources/Assets.xcassets/About.imageset/AppIcon-1024px 1.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 930 KiB |
BIN
iOS/Resources/Assets.xcassets/About.imageset/AppIcon-1024px.png
vendored
Normal file
BIN
iOS/Resources/Assets.xcassets/About.imageset/AppIcon-1024px.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 930 KiB |
22
iOS/Resources/Assets.xcassets/About.imageset/Contents.json
vendored
Normal file
22
iOS/Resources/Assets.xcassets/About.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "AppIcon-1024px 1.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "AppIcon-1024px.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf2513
|
||||
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
|
||||
{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
|
||||
{\*\expandedcolortbl;;\cssrgb\c0\c0\c0\cname textColor;}
|
||||
\margl1440\margr1440\vieww14220\viewh13280\viewkind0
|
||||
\deftab720
|
||||
\pard\pardeftab720\sa60\partightenfactor0
|
||||
|
||||
\f0\fs22 \cf2 Lead developer: {\field{\*\fldinst{HYPERLINK "https://github.com/vincode-io"}}{\fldrslt Maurice Parker}}\
|
||||
App icon: {\field{\*\fldinst{HYPERLINK "https://twitter.com/BradEllis"}}{\fldrslt Brad Ellis}}\
|
||||
Feedly syncing: {\field{\*\fldinst{HYPERLINK "https://twitter.com/kielgillard"}}{\fldrslt Kiel Gillard}}\
|
||||
NewsBlur syncing: {\field{\*\fldinst{HYPERLINK "https://twitter.com/quanganhdo"}}{\fldrslt Anh Do}}\
|
||||
Under-the-hood magic and CSS stylin\'92s: {\field{\*\fldinst{HYPERLINK "https://github.com/wevah"}}{\fldrslt Nate Weaver}}\
|
||||
Newsfoot (JS footnote displayer): {\field{\*\fldinst{HYPERLINK "https://github.com/brehaut/"}}{\fldrslt Andrew Brehaut}}\
|
||||
Help book: {\field{\*\fldinst{HYPERLINK "https://nostodnayr.net/"}}{\fldrslt Ryan Dotson}}\
|
||||
And featuring contributions from {\field{\*\fldinst{HYPERLINK "https://github.com/danielpunkass"}}{\fldrslt Daniel Jalkut}}, {\field{\*\fldinst{HYPERLINK "https://rhonabwy.com/"}}{\fldrslt Joe Heck}}, {\field{\*\fldinst{HYPERLINK "https://github.com/olofhellman"}}{\fldrslt Olof Hellman}}, {\field{\*\fldinst{HYPERLINK "https://blog.rizwan.dev/"}}{\fldrslt Rizwan Mohamed Ibrahim}}, {\field{\*\fldinst{HYPERLINK "https://mynameisstuart.com/"}}{\fldrslt Stuart Breckenridge}}, {\field{\*\fldinst{HYPERLINK "https://twitter.com/philviso"}}{\fldrslt Phil Viso}}, and {\field{\*\fldinst{HYPERLINK "https://github.com/Ranchero-Software/NetNewsWire/graphs/contributors"}}{\fldrslt many more}}!\
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf2513
|
||||
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
|
||||
{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
|
||||
{\*\expandedcolortbl;;\cssrgb\c0\c0\c0\cname textColor;}
|
||||
\margl1440\margr1440\vieww9000\viewh8400\viewkind0
|
||||
\deftab720
|
||||
\pard\pardeftab720\sa60\partightenfactor0
|
||||
|
||||
\f0\fs22 \cf2 NetNewsWire 6 is dedicated to everyone working to save democracy around the world.}
|
||||
@@ -1,11 +0,0 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf2511
|
||||
\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
|
||||
{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
|
||||
{\*\expandedcolortbl;;\cssrgb\c0\c0\c0\cname textColor;}
|
||||
\margl1440\margr1440\vieww11780\viewh11640\viewkind0
|
||||
\deftab720
|
||||
\pard\pardeftab720\li365\fi-366\sa60\partightenfactor0
|
||||
|
||||
\f0\fs22 \cf2 Thanks to Sheila and my family; thanks to my friends in Seattle and around the globe; thanks to the ever-patient and ever-awesome NetNewsWire beta testers. \
|
||||
\pard\tx0\pardeftab720\li360\fi-361\sa60\partightenfactor0
|
||||
\cf2 Thanks to {\field{\*\fldinst{HYPERLINK "https://shapeof.com/"}}{\fldrslt Gus Mueller}} for {\field{\*\fldinst{HYPERLINK "https://github.com/ccgus/fmdb"}}{\fldrslt FMDB}} by {\field{\*\fldinst{HYPERLINK "http://flyingmeat.com/"}}{\fldrslt Flying Meat Software}}. Thanks to {\field{\*\fldinst{HYPERLINK "https://github.com"}}{\fldrslt GitHub}} and {\field{\*\fldinst{HYPERLINK "https://slack.com"}}{\fldrslt Slack}} for making open source collaboration easy and fun. Thanks to {\field{\*\fldinst{HYPERLINK "https://benubois.com/"}}{\fldrslt Ben Ubois}} at {\field{\*\fldinst{HYPERLINK "https://feedbin.com/"}}{\fldrslt Feedbin}} for all the extra help with syncing and article rendering \'97\'a0and for {\field{\*\fldinst{HYPERLINK "https://feedbin.com/blog/2019/03/11/the-future-of-full-content/"}}{\fldrslt hosting the server for the Reader view}}.}
|
||||
@@ -25,6 +25,11 @@ class RootSplitViewController: UISplitViewController {
|
||||
coordinator.resetFocus()
|
||||
}
|
||||
|
||||
override func show(_ column: UISplitViewController.Column) {
|
||||
guard !coordinator.isNavigationDisabled else { return }
|
||||
super.show(column)
|
||||
}
|
||||
|
||||
// MARK: Keyboard Shortcuts
|
||||
|
||||
@objc func scrollOrGoToNextUnread(_ sender: Any?) {
|
||||
|
||||
@@ -40,9 +40,11 @@ struct FeedNode: Hashable {
|
||||
var node: Node
|
||||
var feedID: FeedIdentifier
|
||||
|
||||
init(_ node: Node) {
|
||||
init?(_ node: Node) {
|
||||
guard let feed = node.representedObject as? Feed else { return nil }
|
||||
|
||||
self.node = node
|
||||
self.feedID = (node.representedObject as! Feed).feedID!
|
||||
self.feedID = feed.feedID!
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
@@ -108,6 +110,8 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
private var directlyMarkedAsUnreadArticles = Set<Article>()
|
||||
|
||||
var prefersStatusBarHidden = false
|
||||
|
||||
private let treeControllerDelegate = WebFeedTreeControllerDelegate()
|
||||
@@ -127,6 +131,8 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
return activity
|
||||
}
|
||||
|
||||
var isNavigationDisabled = false
|
||||
|
||||
var isRootSplitCollapsed: Bool {
|
||||
return rootSplitViewController.isCollapsed
|
||||
}
|
||||
@@ -289,15 +295,24 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
|
||||
self.masterFeedViewController = rootSplitViewController.viewController(for: .primary) as? MasterFeedViewController
|
||||
self.masterFeedViewController.coordinator = self
|
||||
self.masterFeedViewController?.navigationController?.delegate = self
|
||||
|
||||
if let navController = self.masterFeedViewController?.navigationController {
|
||||
navController.delegate = self
|
||||
configureNavigationController(navController)
|
||||
}
|
||||
|
||||
self.masterTimelineViewController = rootSplitViewController.viewController(for: .supplementary) as? MasterTimelineViewController
|
||||
self.masterTimelineViewController?.coordinator = self
|
||||
self.masterTimelineViewController?.navigationController?.delegate = self
|
||||
if let navController = self.masterTimelineViewController?.navigationController {
|
||||
navController.delegate = self
|
||||
configureNavigationController(navController)
|
||||
}
|
||||
|
||||
self.articleViewController = rootSplitViewController.viewController(for: .secondary) as? ArticleViewController
|
||||
self.articleViewController?.coordinator = self
|
||||
|
||||
if let navController = self.articleViewController?.navigationController {
|
||||
configureNavigationController(navController)
|
||||
}
|
||||
|
||||
for sectionNode in treeController.rootNode.childNodes {
|
||||
markExpanded(sectionNode)
|
||||
shadowTable.append((sectionID: "", feedNodes: [FeedNode]()))
|
||||
@@ -317,7 +332,8 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(accountDidDownloadArticles(_:)), name: .AccountDidDownloadArticles, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(importDownloadedTheme(_:)), name: .didEndDownloadingTheme, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(themeDownloadDidFail(_:)), name: .didFailToImportThemeWithError, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(markStatusCommandDidDirectMarking(_:)), name: .MarkStatusCommandDidDirectMarking, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(markStatusCommandDidUndoDirectMarking(_:)), name: .MarkStatusCommandDidUndoDirectMarking, object: nil)
|
||||
}
|
||||
|
||||
func restoreWindowState(_ activity: NSUserActivity?) {
|
||||
@@ -534,16 +550,28 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
}
|
||||
}
|
||||
|
||||
@objc func themeDownloadDidFail(_ note: Notification) {
|
||||
@objc func markStatusCommandDidDirectMarking(_ note: Notification) {
|
||||
guard let userInfo = note.userInfo,
|
||||
let error = userInfo["error"] as? Error else {
|
||||
return
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
self.rootSplitViewController.presentError(error, dismiss: nil)
|
||||
let articles = userInfo[Account.UserInfoKey.articles] as? Set<Article>,
|
||||
let statusKey = userInfo[Account.UserInfoKey.statusKey] as? ArticleStatus.Key,
|
||||
let flag = userInfo[Account.UserInfoKey.statusFlag] as? Bool else { return }
|
||||
|
||||
if statusKey == .read && flag == false {
|
||||
directlyMarkedAsUnreadArticles.formUnion(articles)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func markStatusCommandDidUndoDirectMarking(_ note: Notification) {
|
||||
guard let userInfo = note.userInfo,
|
||||
let articles = userInfo[Account.UserInfoKey.articles] as? Set<Article>,
|
||||
let statusKey = userInfo[Account.UserInfoKey.statusKey] as? ArticleStatus.Key,
|
||||
let flag = userInfo[Account.UserInfoKey.statusFlag] as? Bool else { return }
|
||||
|
||||
if statusKey == .read && flag == false {
|
||||
directlyMarkedAsUnreadArticles.subtract(articles)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: API
|
||||
|
||||
func suspend() {
|
||||
@@ -603,6 +631,10 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
return shadowTable[section].feedNodes.count
|
||||
}
|
||||
|
||||
func nodeFor(_ section: Int) -> Node? {
|
||||
return treeController.rootNode.childAtIndex(section)
|
||||
}
|
||||
|
||||
func nodeFor(_ indexPath: IndexPath) -> Node? {
|
||||
guard indexPath.section < shadowTable.count && indexPath.row < shadowTable[indexPath.section].feedNodes.count else {
|
||||
return nil
|
||||
@@ -610,9 +642,18 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
return shadowTable[indexPath.section].feedNodes[indexPath.row].node
|
||||
}
|
||||
|
||||
func indexPathFor(_ object: AnyObject) -> IndexPath? {
|
||||
guard let node = treeController.rootNode.descendantNodeRepresentingObject(object) else {
|
||||
return nil
|
||||
}
|
||||
return indexPathFor(node)
|
||||
}
|
||||
|
||||
func indexPathFor(_ node: Node) -> IndexPath? {
|
||||
guard let feedNode = FeedNode(node) else { return nil }
|
||||
|
||||
for i in 0..<shadowTable.count {
|
||||
if let row = shadowTable[i].feedNodes.firstIndex(of: FeedNode(node)) {
|
||||
if let row = shadowTable[i].feedNodes.firstIndex(of: feedNode) {
|
||||
return IndexPath(row: row, section: i)
|
||||
}
|
||||
}
|
||||
@@ -927,6 +968,11 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
return
|
||||
}
|
||||
|
||||
isNavigationDisabled = true
|
||||
defer {
|
||||
isNavigationDisabled = false
|
||||
}
|
||||
|
||||
if selectPrevUnreadArticleInTimeline() {
|
||||
return
|
||||
}
|
||||
@@ -943,6 +989,11 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
return
|
||||
}
|
||||
|
||||
isNavigationDisabled = true
|
||||
defer {
|
||||
isNavigationDisabled = false
|
||||
}
|
||||
|
||||
if selectNextUnreadArticleInTimeline() {
|
||||
return
|
||||
}
|
||||
@@ -954,7 +1005,6 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
selectNextUnreadFeed() {
|
||||
self.selectNextUnreadArticleInTimeline()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func scrollOrGoToNextUnread() {
|
||||
@@ -972,7 +1022,9 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
}
|
||||
|
||||
func markAllAsRead(_ articles: [Article], completion: (() -> Void)? = nil) {
|
||||
markArticlesWithUndo(articles, statusKey: .read, flag: true, completion: completion)
|
||||
var markableArticles = Set(articles)
|
||||
markableArticles.subtract(directlyMarkedAsUnreadArticles)
|
||||
markArticlesWithUndo(markableArticles, statusKey: .read, flag: true, directlyMarked: false, completion: completion)
|
||||
}
|
||||
|
||||
func markAllAsReadInTimeline(completion: (() -> Void)? = nil) {
|
||||
@@ -1020,13 +1072,13 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
|
||||
func markAsReadForCurrentArticle() {
|
||||
if let article = currentArticle {
|
||||
markArticlesWithUndo([article], statusKey: .read, flag: true)
|
||||
markArticlesWithUndo([article], statusKey: .read, flag: true, directlyMarked: true)
|
||||
}
|
||||
}
|
||||
|
||||
func markAsUnreadForCurrentArticle() {
|
||||
if let article = currentArticle {
|
||||
markArticlesWithUndo([article], statusKey: .read, flag: false)
|
||||
markArticlesWithUndo([article], statusKey: .read, flag: false, directlyMarked: true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1038,7 +1090,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
|
||||
func toggleRead(_ article: Article) {
|
||||
guard !article.status.read || article.isAvailableToMarkUnread else { return }
|
||||
markArticlesWithUndo([article], statusKey: .read, flag: !article.status.read)
|
||||
markArticlesWithUndo([article], statusKey: .read, flag: !article.status.read, directlyMarked: true)
|
||||
}
|
||||
|
||||
func toggleStarredForCurrentArticle() {
|
||||
@@ -1048,7 +1100,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
}
|
||||
|
||||
func toggleStar(_ article: Article) {
|
||||
markArticlesWithUndo([article], statusKey: .starred, flag: !article.status.starred)
|
||||
markArticlesWithUndo([article], statusKey: .starred, flag: !article.status.starred, directlyMarked: true)
|
||||
}
|
||||
|
||||
func timelineFeedIsEqualTo(_ feed: WebFeed) -> Bool {
|
||||
@@ -1085,9 +1137,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
|
||||
rebuildBackingStores(initialLoad: initialLoad, completion: {
|
||||
self.treeControllerDelegate.resetFilterExceptions()
|
||||
self.selectFeed(nil) {
|
||||
self.selectFeed(webFeed, animations: animations, completion: completion)
|
||||
}
|
||||
self.selectFeed(webFeed, animations: animations, completion: completion)
|
||||
})
|
||||
|
||||
}
|
||||
@@ -1259,13 +1309,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
|
||||
}
|
||||
|
||||
func importTheme(filename: String) {
|
||||
do {
|
||||
try ArticleThemeImporter.importTheme(controller: rootSplitViewController, filename: filename)
|
||||
} catch {
|
||||
NotificationCenter.default.post(name: .didFailToImportThemeWithError, object: nil, userInfo: ["error" : error])
|
||||
logger.error("Failed to import theme with error: \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
|
||||
ArticleThemeImporter.importTheme(controller: rootSplitViewController, filename: filename)
|
||||
}
|
||||
|
||||
/// This will dismiss the foremost view controller if the user
|
||||
@@ -1314,6 +1358,10 @@ extension SceneCoordinator: UISplitViewControllerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func splitViewController(_ svc: UISplitViewController, willChangeTo displayMode: UISplitViewController.DisplayMode) {
|
||||
articleViewController?.splitViewControllerWillChangeTo(displayMode: displayMode)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: UINavigationControllerDelegate
|
||||
@@ -1370,9 +1418,43 @@ extension SceneCoordinator: UINavigationControllerDelegate {
|
||||
|
||||
private extension SceneCoordinator {
|
||||
|
||||
func markArticlesWithUndo(_ articles: [Article], statusKey: ArticleStatus.Key, flag: Bool, completion: (() -> Void)? = nil) {
|
||||
func configureNavigationController(_ navController: UINavigationController) {
|
||||
|
||||
let scrollEdge = UINavigationBarAppearance()
|
||||
scrollEdge.configureWithOpaqueBackground()
|
||||
scrollEdge.shadowColor = nil
|
||||
scrollEdge.shadowImage = UIImage()
|
||||
|
||||
let standard = UINavigationBarAppearance()
|
||||
standard.shadowColor = .opaqueSeparator
|
||||
standard.shadowImage = UIImage()
|
||||
|
||||
navController.navigationBar.standardAppearance = standard
|
||||
navController.navigationBar.compactAppearance = standard
|
||||
navController.navigationBar.scrollEdgeAppearance = scrollEdge
|
||||
navController.navigationBar.compactScrollEdgeAppearance = scrollEdge
|
||||
|
||||
navController.navigationBar.tintColor = AppAssets.primaryAccentColor
|
||||
|
||||
let toolbarAppearance = UIToolbarAppearance()
|
||||
navController.toolbar.standardAppearance = toolbarAppearance
|
||||
navController.toolbar.compactAppearance = toolbarAppearance
|
||||
navController.toolbar.scrollEdgeAppearance = toolbarAppearance
|
||||
navController.toolbar.tintColor = AppAssets.primaryAccentColor
|
||||
}
|
||||
|
||||
func markArticlesWithUndo(_ articles: [Article], statusKey: ArticleStatus.Key, flag: Bool, directlyMarked: Bool, completion: (() -> Void)? = nil) {
|
||||
markArticlesWithUndo(Set(articles), statusKey: statusKey, flag: flag, directlyMarked: directlyMarked, completion: completion)
|
||||
}
|
||||
|
||||
func markArticlesWithUndo(_ articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool, directlyMarked: Bool, completion: (() -> Void)? = nil) {
|
||||
guard let undoManager = undoManager,
|
||||
let markReadCommand = MarkStatusCommand(initialArticles: articles, statusKey: statusKey, flag: flag, undoManager: undoManager, completion: completion) else {
|
||||
let markReadCommand = MarkStatusCommand(initialArticles: articles,
|
||||
statusKey: statusKey,
|
||||
flag: flag,
|
||||
directlyMarked: directlyMarked,
|
||||
undoManager: undoManager,
|
||||
completion: completion) else {
|
||||
completion?()
|
||||
return
|
||||
}
|
||||
@@ -1478,10 +1560,12 @@ private extension SceneCoordinator {
|
||||
|
||||
if isExpanded(sectionNode) {
|
||||
for node in sectionNode.childNodes {
|
||||
feedNodes.append(FeedNode(node))
|
||||
guard let feedNode = FeedNode(node) else { continue }
|
||||
feedNodes.append(feedNode)
|
||||
if isExpanded(node) {
|
||||
for child in node.childNodes {
|
||||
feedNodes.append(FeedNode(child))
|
||||
guard let childNode = FeedNode(child) else { continue }
|
||||
feedNodes.append(childNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1588,13 +1672,6 @@ private extension SceneCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
func indexPathFor(_ object: AnyObject) -> IndexPath? {
|
||||
guard let node = treeController.rootNode.descendantNodeRepresentingObject(object) else {
|
||||
return nil
|
||||
}
|
||||
return indexPathFor(node)
|
||||
}
|
||||
|
||||
func setTimelineFeed(_ feed: Feed?, animated: Bool, completion: (() -> Void)? = nil) {
|
||||
timelineFeed = feed
|
||||
|
||||
@@ -1895,6 +1972,7 @@ private extension SceneCoordinator {
|
||||
|
||||
func emptyTheTimeline() {
|
||||
if !articles.isEmpty {
|
||||
directlyMarkedAsUnreadArticles = Set<Article>()
|
||||
replaceArticles(with: Set<Article>(), animated: false)
|
||||
}
|
||||
}
|
||||
@@ -1965,8 +2043,10 @@ private extension SceneCoordinator {
|
||||
// To be called when we need to do an entire fetch, but an async delay is okay.
|
||||
// Example: we have the Today feed selected, and the calendar day just changed.
|
||||
cancelPendingAsyncFetches()
|
||||
|
||||
emptyTheTimeline()
|
||||
|
||||
guard let timelineFeed = timelineFeed else {
|
||||
emptyTheTimeline()
|
||||
completion()
|
||||
return
|
||||
}
|
||||
@@ -1982,7 +2062,6 @@ private extension SceneCoordinator {
|
||||
self?.replaceArticles(with: articles, animated: animated)
|
||||
completion()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func fetchUnsortedArticlesAsync(for representedObjects: [Any], completion: @escaping ArticleSetBlock) {
|
||||
|
||||
@@ -28,6 +28,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, Logging {
|
||||
coordinator = SceneCoordinator(rootSplitViewController: rootViewController)
|
||||
rootViewController.coordinator = coordinator
|
||||
rootViewController.delegate = coordinator
|
||||
rootViewController.showsSecondaryOnlyButton = true
|
||||
|
||||
coordinator.restoreWindowState(session.stateRestorationActivity)
|
||||
|
||||
@@ -95,6 +96,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, Logging {
|
||||
coordinator.cleanUp(conditional: conditional)
|
||||
}
|
||||
|
||||
func presentError(_ error: Error) {
|
||||
self.window!.rootViewController?.presentError(error)
|
||||
}
|
||||
|
||||
// Handle Opening of URLs
|
||||
|
||||
func scene(_ scene: UIScene, openURLContexts urlContexts: Set<UIOpenURLContext>) {
|
||||
@@ -185,14 +190,12 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, Logging {
|
||||
NotificationCenter.default.post(name: .didBeginDownloadingTheme, object: nil)
|
||||
}
|
||||
let task = URLSession.shared.downloadTask(with: request) { [weak self] location, response, error in
|
||||
guard
|
||||
let location = location else { return }
|
||||
guard let self, let location else { return }
|
||||
|
||||
do {
|
||||
try ArticleThemeDownloader.shared.handleFile(at: location)
|
||||
} catch {
|
||||
NotificationCenter.default.post(name: .didFailToImportThemeWithError, object: nil, userInfo: ["error": error])
|
||||
self?.logger.error("Failed to import theme with error: \(error.localizedDescription, privacy: .public)")
|
||||
self.presentError(error)
|
||||
}
|
||||
}
|
||||
task.resume()
|
||||
@@ -204,7 +207,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate, Logging {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
108
iOS/Settings/AboutView.swift
Normal file
108
iOS/Settings/AboutView.swift
Normal file
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// AboutView.swift
|
||||
// NetNewsWire-iOS
|
||||
//
|
||||
// Created by Stuart Breckenridge on 02/10/2022.
|
||||
// Copyright © 2022 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct AboutView: View, LoadableAboutData {
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Section(header: aboutHeaderView) {}
|
||||
Section(header: Text("Primary Contributors")) {
|
||||
ForEach(0..<about.PrimaryContributors.count, id: \.self) { i in
|
||||
contributorView(about.PrimaryContributors[i])
|
||||
}
|
||||
}
|
||||
Section(header: Text("Additional Contributors")) {
|
||||
ForEach(0..<about.AdditionalContributors.count, id: \.self) { i in
|
||||
contributorView(about.AdditionalContributors[i])
|
||||
}
|
||||
}
|
||||
Section(header: Text("Thanks"), footer: thanks, content: {})
|
||||
Section(footer: copyright, content: {})
|
||||
}
|
||||
.listStyle(.insetGrouped)
|
||||
.navigationTitle(Text("About"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
|
||||
var aboutHeaderView: some View {
|
||||
HStack {
|
||||
Spacer()
|
||||
VStack(alignment: .center, spacing: 8) {
|
||||
Image("About")
|
||||
.resizable()
|
||||
.frame(width: 75, height: 75)
|
||||
|
||||
Text(Bundle.main.appName)
|
||||
.font(.headline)
|
||||
|
||||
Text("\(Bundle.main.versionNumber) (\(Bundle.main.buildNumber))")
|
||||
.foregroundColor(.secondary)
|
||||
.font(.callout)
|
||||
|
||||
Text("By Brent Simmons and the Ranchero Software team.")
|
||||
.font(.subheadline)
|
||||
|
||||
Text("[netnewswire.com](https://netnewswire.com)")
|
||||
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.textCase(.none)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
|
||||
func contributorView(_ appCredit: AboutData.Contributor) -> some View {
|
||||
HStack {
|
||||
Text(appCredit.name)
|
||||
Spacer()
|
||||
if let role = appCredit.role {
|
||||
Text(role)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
.multilineTextAlignment(.trailing)
|
||||
}
|
||||
if let _ = appCredit.url {
|
||||
Image(systemName: "info.circle")
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.onTapGesture {
|
||||
guard let url = appCredit.url else { return }
|
||||
if let creditURL = URL(string: url) {
|
||||
UIApplication.shared.open(creditURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var thanks: some View {
|
||||
Text(about.ThanksMarkdown)
|
||||
.multilineTextAlignment(.center)
|
||||
.font(.callout)
|
||||
}
|
||||
|
||||
var copyright: some View {
|
||||
HStack {
|
||||
Spacer()
|
||||
Text(verbatim: "Copyright © Brent Simmons 2002 - \(Calendar.current.component(.year, from: .now))")
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct AboutView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationView {
|
||||
AboutView()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
//
|
||||
// AboutViewController.swift
|
||||
// NetNewsWire-iOS
|
||||
//
|
||||
// Created by Maurice Parker on 4/25/19.
|
||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class AboutViewController: UITableViewController {
|
||||
|
||||
@IBOutlet weak var aboutTextView: UITextView!
|
||||
@IBOutlet weak var creditsTextView: UITextView!
|
||||
@IBOutlet weak var acknowledgmentsTextView: UITextView!
|
||||
@IBOutlet weak var thanksTextView: UITextView!
|
||||
@IBOutlet weak var dedicationTextView: UITextView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
super.viewDidLoad()
|
||||
|
||||
configureCell(file: "About", textView: aboutTextView)
|
||||
configureCell(file: "Credits", textView: creditsTextView)
|
||||
configureCell(file: "Thanks", textView: thanksTextView)
|
||||
configureCell(file: "Dedication", textView: dedicationTextView)
|
||||
|
||||
let buildLabel = NonIntrinsicLabel(frame: CGRect(x: 32.0, y: 0.0, width: 0.0, height: 0.0))
|
||||
buildLabel.font = UIFont.systemFont(ofSize: 11.0)
|
||||
buildLabel.textColor = UIColor.gray
|
||||
buildLabel.text = NSLocalizedString("Copyright © 2002-2022 Brent Simmons", comment: "Copyright")
|
||||
buildLabel.numberOfLines = 0
|
||||
buildLabel.sizeToFit()
|
||||
buildLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
let wrapperView = UIView(frame: CGRect(x: 0, y: 0, width: buildLabel.frame.width, height: buildLabel.frame.height + 10.0))
|
||||
wrapperView.translatesAutoresizingMaskIntoConstraints = false
|
||||
wrapperView.addSubview(buildLabel)
|
||||
tableView.tableFooterView = wrapperView
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
||||
return UITableView.automaticDimension
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private extension AboutViewController {
|
||||
|
||||
func configureCell(file: String, textView: UITextView) {
|
||||
let url = Bundle.main.url(forResource: file, withExtension: "rtf")!
|
||||
let string = try! NSAttributedString(url: url, options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.rtf], documentAttributes: nil)
|
||||
textView.attributedText = string
|
||||
textView.textColor = UIColor.label
|
||||
textView.adjustsFontForContentSizeCategory = true
|
||||
textView.font = .preferredFont(forTextStyle: .body)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,8 +11,14 @@ import RSCore
|
||||
|
||||
struct ArticleThemeImporter: Logging {
|
||||
|
||||
static func importTheme(controller: UIViewController, filename: String) throws {
|
||||
let theme = try ArticleTheme(path: filename, isAppTheme: false)
|
||||
static func importTheme(controller: UIViewController, filename: String) {
|
||||
let theme: ArticleTheme
|
||||
do {
|
||||
theme = try ArticleTheme(path: filename, isAppTheme: false)
|
||||
} catch {
|
||||
controller.presentError(error)
|
||||
return
|
||||
}
|
||||
|
||||
let localizedTitleText = NSLocalizedString("Install theme “%@” by %@?", comment: "Theme message text")
|
||||
let title = NSString.localizedStringWithFormat(localizedTitleText as NSString, theme.name, theme.creatorName) as String
|
||||
@@ -29,7 +35,7 @@ struct ArticleThemeImporter: Logging {
|
||||
let visitSiteTitle = NSLocalizedString("Show Website", comment: "Show Website")
|
||||
let visitSiteAction = UIAlertAction(title: visitSiteTitle, style: .default) { action in
|
||||
UIApplication.shared.open(url)
|
||||
try? Self.importTheme(controller: controller, filename: filename)
|
||||
Self.importTheme(controller: controller, filename: filename)
|
||||
}
|
||||
alertController.addAction(visitSiteAction)
|
||||
}
|
||||
|
||||
@@ -72,9 +72,9 @@ class ArticleThemesTableViewController: UITableViewController, Logging {
|
||||
|
||||
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
|
||||
guard let cell = tableView.cellForRow(at: indexPath),
|
||||
let themeName = cell.textLabel?.text,
|
||||
let theme = ArticleThemesManager.shared.articleThemeWithThemeName(themeName),
|
||||
!theme.isAppTheme else { return nil }
|
||||
let themeName = cell.textLabel?.text else { return nil }
|
||||
|
||||
guard let theme = try? ArticleThemesManager.shared.articleThemeWithThemeName(themeName), !theme.isAppTheme else { return nil }
|
||||
|
||||
let deleteTitle = NSLocalizedString("Delete", comment: "Delete")
|
||||
let deleteAction = UIContextualAction(style: .normal, title: deleteTitle) { [weak self] (action, view, completion) in
|
||||
@@ -114,12 +114,7 @@ extension ArticleThemesTableViewController: UIDocumentPickerDelegate {
|
||||
|
||||
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
|
||||
guard let url = urls.first else { return }
|
||||
do {
|
||||
try ArticleThemeImporter.importTheme(controller: self, filename: url.standardizedFileURL.path)
|
||||
} catch {
|
||||
NotificationCenter.default.post(name: .didFailToImportThemeWithError, object: nil, userInfo: ["error": error])
|
||||
logger.error("Did fail to import theme: \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
try ArticleThemeImporter.importTheme(controller: self, filename: url.standardizedFileURL.path)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="9cW-lu-HoC">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="9cW-lu-HoC">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
|
||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
@@ -20,14 +21,14 @@
|
||||
<tableViewSection headerTitle="Notifications, Badge, Data, & More" id="Bmb-Oi-RZK">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="F9H-Kr-npj" style="IBUITableViewCellStyleDefault" id="zvg-7C-BlH" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="49.5" width="374" height="44"/>
|
||||
<rect key="frame" x="20" y="55.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="zvg-7C-BlH" id="Tqk-Tu-E6K">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Open System Settings" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="F9H-Kr-npj">
|
||||
<rect key="frame" x="20" y="0.0" width="334" height="44"/>
|
||||
<rect key="frame" x="20" y="0.0" width="334" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
@@ -37,14 +38,14 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="l7X-8L-61m" style="IBUITableViewCellStyleDefault" id="xdC-t4-59D" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="93.5" width="374" height="44"/>
|
||||
<rect key="frame" x="20" y="99" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="xdC-t4-59D" id="aDf-bJ-EHn">
|
||||
<rect key="frame" x="0.0" y="0.0" width="345.5" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="343.5" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="New Article Notifications" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="l7X-8L-61m">
|
||||
<rect key="frame" x="20" y="0.0" width="317.5" height="43.5"/>
|
||||
<rect key="frame" x="20" y="0.0" width="315.5" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
@@ -58,14 +59,14 @@
|
||||
<tableViewSection headerTitle="Accounts" id="0ac-Ze-Dh4">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="6sn-wY-hHH" style="IBUITableViewCellStyleDefault" id="XHc-rQ-7FK" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="187.5" width="374" height="44"/>
|
||||
<rect key="frame" x="20" y="198.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="XHc-rQ-7FK" id="nmL-EM-Bsi">
|
||||
<rect key="frame" x="0.0" y="0.0" width="345.5" height="44"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="343.5" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Add Account" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="6sn-wY-hHH">
|
||||
<rect key="frame" x="20" y="0.0" width="317.5" height="44"/>
|
||||
<rect key="frame" x="20" y="0.0" width="315.5" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
@@ -79,14 +80,14 @@
|
||||
<tableViewSection headerTitle="Extensions" id="oRB-NZ-WpG">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="QFr-Rs-eW2" style="IBUITableViewCellStyleDefault" id="6QJ-fX-278" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="281.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="298" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="6QJ-fX-278" id="PDs-8c-XUa">
|
||||
<rect key="frame" x="0.0" y="0.0" width="345.5" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="343.5" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Add Extension" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="QFr-Rs-eW2">
|
||||
<rect key="frame" x="20" y="0.0" width="317.5" height="43.5"/>
|
||||
<rect key="frame" x="20" y="0.0" width="315.5" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
@@ -100,7 +101,7 @@
|
||||
<tableViewSection headerTitle="Feeds" id="hAC-uA-RbS">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="4Hg-B3-zAE" style="IBUITableViewCellStyleDefault" id="glf-Pg-s3P" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="375" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="397.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="glf-Pg-s3P" id="bPA-43-Oqh">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
@@ -117,7 +118,7 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="25J-iX-3at" style="IBUITableViewCellStyleDefault" id="qke-Ha-PXl" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="418.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="441" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="qke-Ha-PXl" id="pZi-ck-RV5">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
@@ -134,7 +135,7 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="dXN-Mw-yf2" style="IBUITableViewCellStyleDefault" id="F0L-Ut-reX" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="462" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="484.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="F0L-Ut-reX" id="5SX-M2-2jR">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
@@ -155,14 +156,14 @@
|
||||
<tableViewSection headerTitle="Timeline" id="9Pk-Y8-JVJ">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="MpA-w1-Wwh" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="555.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="584" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="MpA-w1-Wwh" id="GhU-ib-Mz8">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" text="Sort Oldest to Newest" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="c9W-IF-u6i" customClass="VibrantLabel" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="11" width="142.5" height="21.5"/>
|
||||
<rect key="frame" x="20" y="11" width="167.5" height="21.5"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -188,14 +189,14 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="f7r-AZ-aDn" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="599" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="627.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="f7r-AZ-aDn" id="KHC-cc-tOC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" text="Group by Feed" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cit-i1-0Hp" customClass="VibrantLabel" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="11" width="95.5" height="21.5"/>
|
||||
<rect key="frame" x="20" y="11" width="112.5" height="21.5"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -221,14 +222,14 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="5wo-fM-0l6" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="642.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="671" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="5wo-fM-0l6" id="XAn-lK-LoN">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" text="Refresh to Clear Read Articles" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="KtJ-tk-DlD">
|
||||
<rect key="frame" x="20" y="11" width="193.5" height="21.5"/>
|
||||
<rect key="frame" x="20" y="11" width="227.5" height="21.5"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -254,14 +255,14 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="8Gj-qz-NMY" customClass="VibrantBasicTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="686" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="714.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="8Gj-qz-NMY" id="OTe-tG-sb4">
|
||||
<rect key="frame" x="0.0" y="0.0" width="345.5" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="343.5" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Timeline Layout" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YHt-eS-KrX">
|
||||
<rect key="frame" x="20" y="13.5" width="101.5" height="17"/>
|
||||
<rect key="frame" x="20" y="11.5" width="119.5" height="20.5"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -281,20 +282,20 @@
|
||||
<tableViewSection headerTitle="Articles" id="TRr-Ew-IvU">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="WFP-zj-Pve" customClass="VibrantBasicTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="779.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="814" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="WFP-zj-Pve" id="DCX-wc-LSo">
|
||||
<rect key="frame" x="0.0" y="0.0" width="345.5" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="343.5" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Theme" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bbw-L9-a3X">
|
||||
<rect key="frame" x="20" y="13.5" width="45" height="17"/>
|
||||
<rect key="frame" x="20" y="11.5" width="53" height="20.5"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Default" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DUf-DZ-3Nm">
|
||||
<rect key="frame" x="291" y="13.5" width="46.5" height="17"/>
|
||||
<rect key="frame" x="280.5" y="11.5" width="55" height="20.5"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -313,14 +314,14 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="SXs-NQ-y3U" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="823" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="857.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="SXs-NQ-y3U" id="BpI-Hz-KH2">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" text="Confirm Mark All as Read" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5tY-5k-v2g">
|
||||
<rect key="frame" x="20" y="11" width="163" height="21.5"/>
|
||||
<rect key="frame" x="20" y="11" width="191.5" height="21.5"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -346,20 +347,20 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="EYf-v1-lNi" customClass="VibrantBasicTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="866.5" width="374" height="44.5"/>
|
||||
<rect key="frame" x="20" y="901" width="374" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="EYf-v1-lNi" id="7nz-0Y-HaW">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="44.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="48"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Open Links in NetNewsWire" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wm4-Y1-7nX">
|
||||
<rect key="frame" x="20" y="14" width="279" height="17.5"/>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" text="Open Links in NetNewsWire" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wm4-Y1-7nX">
|
||||
<rect key="frame" x="20" y="14" width="279" height="21"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dhR-L2-PX3" userLabel="Open Links in NetNewsWire">
|
||||
<rect key="frame" x="307" y="7" width="51" height="31"/>
|
||||
<rect key="frame" x="307" y="8.5" width="51" height="31"/>
|
||||
<color key="onTintColor" name="primaryAccentColor"/>
|
||||
<connections>
|
||||
<action selector="switchBrowserPreference:" destination="a0p-rk-skQ" eventType="valueChanged" id="hLC-cV-Wjj"/>
|
||||
@@ -384,19 +385,19 @@
|
||||
<tableViewSection headerTitle="Appearance" id="TkH-4v-yhk">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="EvG-yE-gDF" customClass="VibrantBasicTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="961" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="1005" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="EvG-yE-gDF" id="wBN-zJ-6pN">
|
||||
<rect key="frame" x="0.0" y="0.0" width="345.5" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="343.5" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Color Palette" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2Fp-li-dGP">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Color Palette" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2Fp-li-dGP">
|
||||
<rect key="frame" x="20" y="13.5" width="83.5" height="17"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Automatic" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="16m-Ns-Y8V">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Automatic" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="16m-Ns-Y8V">
|
||||
<rect key="frame" x="272" y="13.5" width="65.5" height="17"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
@@ -420,14 +421,14 @@
|
||||
<tableViewSection headerTitle="Help" id="CS8-fJ-ghn">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="uGk-2d-oFc" style="IBUITableViewCellStyleDefault" id="Tle-IV-D40" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="1054.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="1063" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Tle-IV-D40" id="IJD-ZB-8Wm">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="NetNewsWire Help" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="uGk-2d-oFc">
|
||||
<rect key="frame" x="8" y="0.0" width="358" height="43.5"/>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" ambiguous="YES" insetsLayoutMarginsFromSafeArea="NO" text="NetNewsWire Help" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="uGk-2d-oFc">
|
||||
<rect key="frame" x="20" y="0.0" width="334" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
@@ -437,13 +438,13 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="6G3-yV-Eyh" style="IBUITableViewCellStyleDefault" id="Tbf-fE-nfx" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="1098" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="1148" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Tbf-fE-nfx" id="beV-vI-g3r">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Website" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="6G3-yV-Eyh">
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" ambiguous="YES" insetsLayoutMarginsFromSafeArea="NO" text="Website" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="6G3-yV-Eyh">
|
||||
<rect key="frame" x="8" y="0.0" width="358" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
@@ -454,13 +455,13 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="NeD-y8-KrM" style="IBUITableViewCellStyleDefault" id="TIX-yK-rC6" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="1141.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="1191.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="TIX-yK-rC6" id="qr8-EN-Ofg">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Release Notes" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="NeD-y8-KrM">
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" ambiguous="YES" insetsLayoutMarginsFromSafeArea="NO" text="Release Notes" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="NeD-y8-KrM">
|
||||
<rect key="frame" x="8" y="0.0" width="358" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
@@ -471,7 +472,7 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="lfL-bQ-sOp" style="IBUITableViewCellStyleDefault" id="mFn-fE-zqa" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="1185" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="1235" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="mFn-fE-zqa" id="jTe-mf-MRj">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
@@ -488,7 +489,7 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="DDJ-8P-3YY" style="IBUITableViewCellStyleDefault" id="iGs-ze-4gQ" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="1228.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="1278.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="iGs-ze-4gQ" id="EqZ-rF-N0l">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
@@ -505,7 +506,7 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="DsV-Qv-X4K" style="IBUITableViewCellStyleDefault" id="taJ-sg-wnU" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="1272" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="1322" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="taJ-sg-wnU" id="axB-si-1KM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
@@ -522,7 +523,7 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="zMz-hU-UYU" style="IBUITableViewCellStyleDefault" id="OXi-cg-ab9" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="1315.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="1365.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="OXi-cg-ab9" id="npR-a0-9wv">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
@@ -539,7 +540,7 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="T7x-zl-6Yf" style="IBUITableViewCellStyleDefault" id="VpI-0o-3Px" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="1359" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="1409" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VpI-0o-3Px" id="xRH-i4-vne">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
@@ -556,14 +557,14 @@
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="76A-Ng-kfs" style="IBUITableViewCellStyleDefault" id="jK8-tv-hBD" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="1402.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="1452.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="jK8-tv-hBD" id="I7Q-GQ-u8Y">
|
||||
<rect key="frame" x="0.0" y="0.0" width="357.5" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="355.5" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" ambiguous="YES" insetsLayoutMarginsFromSafeArea="NO" text="About NetNewsWire" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="76A-Ng-kfs">
|
||||
<rect key="frame" x="8" y="0.0" width="341.5" height="43.5"/>
|
||||
<rect key="frame" x="8" y="0.0" width="339.5" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
@@ -610,14 +611,14 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SettingsAccountTableViewCell" rowHeight="55" id="UFl-6I-ucw" customClass="SettingsComboTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="49.5" width="374" height="55"/>
|
||||
<rect key="frame" x="20" y="55.5" width="374" height="55"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="UFl-6I-ucw" id="99i-Ge-guB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="55"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="iTt-HT-Ane">
|
||||
<rect key="frame" x="20" y="15" width="131" height="25"/>
|
||||
<rect key="frame" x="20" y="15" width="147.5" height="25"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="accountLocal" translatesAutoresizingMaskIntoConstraints="NO" id="tb2-dO-AhR">
|
||||
<rect key="frame" x="0.0" y="0.0" width="25" height="25"/>
|
||||
@@ -628,7 +629,7 @@
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="On My iPhone" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="116-rt-msI">
|
||||
<rect key="frame" x="41" y="0.0" width="90" height="25"/>
|
||||
<rect key="frame" x="41" y="0.0" width="106.5" height="25"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -663,7 +664,7 @@
|
||||
<objects>
|
||||
<tableViewController storyboardIdentifier="AboutViewController" title="About" id="K5w-58-sQW" customClass="AboutViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="insetGrouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="ybg-ki-AbJ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="808"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="804"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<sections>
|
||||
<tableViewSection id="apW-l0-gWz">
|
||||
@@ -717,7 +718,7 @@
|
||||
<tableViewSection headerTitle="CREDITS" id="O1X-Iq-ibE">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="62" id="ZY4-id-Iia">
|
||||
<rect key="frame" x="20" y="192" width="374" height="62"/>
|
||||
<rect key="frame" x="20" y="198" width="374" height="62"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ZY4-id-Iia" id="IPw-QQ-LYI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="62"/>
|
||||
@@ -743,7 +744,7 @@
|
||||
<tableViewSection headerTitle="THANKS" id="Sgx-f1-hsT">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="62" id="bLz-mu-psL">
|
||||
<rect key="frame" x="20" y="304" width="374" height="62"/>
|
||||
<rect key="frame" x="20" y="316" width="374" height="62"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="bLz-mu-psL" id="cxy-IZ-zFZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="62"/>
|
||||
@@ -769,7 +770,7 @@
|
||||
<tableViewSection headerTitle="DEDICATION" id="nbm-Bs-te6">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="62" id="aab-HD-ce6">
|
||||
<rect key="frame" x="20" y="416" width="374" height="62"/>
|
||||
<rect key="frame" x="20" y="434" width="374" height="62"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="aab-HD-ce6" id="6pH-5O-3V8">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="62"/>
|
||||
@@ -815,11 +816,11 @@
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="TimelineCustomizerViewController" title="Timeline Layout" id="amD-xZ-U3A" customClass="TimelineCustomizerViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="2Fb-t4-5QE">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="808"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="804"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Q4t-3M-goU">
|
||||
<rect key="frame" x="20" y="54.5" width="374" height="44"/>
|
||||
<rect key="frame" x="20" y="56" width="374" height="44"/>
|
||||
<subviews>
|
||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="1" minValue="1" maxValue="3" translatesAutoresizingMaskIntoConstraints="NO" id="AW6-CH-AXP" customClass="TickMarkSlider" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="18" y="7" width="338" height="31"/>
|
||||
@@ -839,19 +840,19 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ICON SIZE" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VLq-TU-3d6">
|
||||
<rect key="frame" x="40" y="32" width="59.5" height="14.5"/>
|
||||
<rect key="frame" x="40" y="32" width="64" height="16"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
|
||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="NUMBER OF LINES" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mER-Fl-iHI">
|
||||
<rect key="frame" x="40" y="130.5" width="108" height="14.5"/>
|
||||
<rect key="frame" x="40" y="132" width="116" height="16"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
|
||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oQi-VX-CMV">
|
||||
<rect key="frame" x="20" y="153" width="374" height="44"/>
|
||||
<rect key="frame" x="20" y="156" width="374" height="44"/>
|
||||
<subviews>
|
||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="1" minValue="1" maxValue="6" translatesAutoresizingMaskIntoConstraints="NO" id="AIu-s5-Hvq" customClass="TickMarkSlider" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="18" y="7" width="338" height="31"/>
|
||||
@@ -871,7 +872,7 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ou4-Yv-dXA">
|
||||
<rect key="frame" x="57" y="229" width="300" height="128"/>
|
||||
<rect key="frame" x="57" y="232" width="300" height="128"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="300" id="BfC-yc-CAa"/>
|
||||
<constraint firstAttribute="height" constant="128" id="wxz-ZX-8fe"/>
|
||||
@@ -918,7 +919,7 @@
|
||||
<objects>
|
||||
<navigationController storyboardIdentifier="SettingsNavigationViewController" id="9cW-lu-HoC" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="rtV-Ed-zwR">
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="48" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
@@ -942,7 +943,7 @@
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" id="Zaq-yo-L5h" customClass="MasterTimelineTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="44.5" width="300" height="43.5"/>
|
||||
<rect key="frame" x="0.0" y="50" width="300" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Zaq-yo-L5h" id="fD5-nw-z0z">
|
||||
<rect key="frame" x="0.0" y="0.0" width="300" height="43.5"/>
|
||||
@@ -974,12 +975,12 @@
|
||||
<objects>
|
||||
<tableViewController storyboardIdentifier="ArticleThemesTableViewController" title="Article Themes" id="fO4-og-e41" customClass="ArticleThemesTableViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="insetGrouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="I8p-P9-C8h">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="808"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="804"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" textLabel="6tf-Xb-7b8" style="IBUITableViewCellStyleDefault" id="BIC-Zk-QMD" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="49.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="55.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="BIC-Zk-QMD" id="7xj-8Y-ejz">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
@@ -1017,14 +1018,14 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="SettingsExtensionTableViewCell" rowHeight="55" id="SPQ-gc-wuP" customClass="SettingsComboTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="49.5" width="374" height="55"/>
|
||||
<rect key="frame" x="20" y="55.5" width="374" height="55"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="SPQ-gc-wuP" id="38G-tD-Eks">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="55"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="gMc-YX-gQa">
|
||||
<rect key="frame" x="20" y="15" width="104" height="25"/>
|
||||
<rect key="frame" x="20" y="15" width="115" height="25"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="gear" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="fQm-sU-5TF">
|
||||
<rect key="frame" x="0.0" y="0.0" width="25" height="25.5"/>
|
||||
@@ -1035,7 +1036,7 @@
|
||||
</constraints>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Extension" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zuQ-ty-Tf1">
|
||||
<rect key="frame" x="41" y="0.0" width="63" height="25"/>
|
||||
<rect key="frame" x="41" y="0.0" width="74" height="25"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -1078,27 +1079,27 @@
|
||||
<color key="backgroundColor" systemColor="systemGroupedBackgroundColor"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="NotificationsCell" id="guK-h7-1U7" customClass="NotificationsTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="49.5" width="374" height="40"/>
|
||||
<rect key="frame" x="20" y="55.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="guK-h7-1U7" id="7Rd-Ur-EwD">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="40"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ggq-dZ-hv7">
|
||||
<rect key="frame" x="307" y="4.5" width="51" height="31"/>
|
||||
<rect key="frame" x="307" y="6.5" width="51" height="31"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="49" id="O0E-7e-Q9P"/>
|
||||
</constraints>
|
||||
<color key="onTintColor" name="AccentColor"/>
|
||||
</switch>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="78k-PU-gKA">
|
||||
<rect key="frame" x="58" y="11" width="241" height="17.5"/>
|
||||
<rect key="frame" x="58" y="11" width="241" height="21"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="bell.fill" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="Vha-ij-dDN">
|
||||
<rect key="frame" x="20" y="8" width="25" height="24.5"/>
|
||||
<rect key="frame" x="20" y="10" width="25" height="24.5"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="25" id="cpy-hb-TiY"/>
|
||||
<constraint firstAttribute="width" constant="25" id="xvC-Ma-Mfj"/>
|
||||
@@ -1123,7 +1124,7 @@
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="OpenSettingsCell" textLabel="5OE-bg-gWy" style="IBUITableViewCellStyleDefault" id="LXf-Fb-We7" customClass="VibrantBasicTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="89.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="99" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="LXf-Fb-We7" id="k2T-id-bci">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
@@ -1170,7 +1171,7 @@
|
||||
<objects>
|
||||
<navigationController storyboardIdentifier="EnableExtensionPointNavigationViewController" id="mA0-Yf-esc" customClass="ModalNavigationController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="iXJ-DA-pQC">
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="48" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
@@ -1192,14 +1193,14 @@
|
||||
<tableViewSection id="rqj-gU-4He">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="ALK-Z6-aOR" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="18" width="374" height="39.5"/>
|
||||
<rect key="frame" x="20" y="18" width="374" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="ALK-Z6-aOR" id="Rqf-t4-F8q">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="39.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="VCu-Yi-0ts">
|
||||
<rect key="frame" x="20" y="11" width="334" height="17.5"/>
|
||||
<rect key="frame" x="20" y="11" width="334" height="21"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@@ -1218,7 +1219,7 @@
|
||||
<tableViewSection id="7Nq-pj-Wqz">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="eZ5-P9-opw" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="93.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="97" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="eZ5-P9-opw" id="RlA-Zq-tRl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
@@ -1273,12 +1274,12 @@
|
||||
<objects>
|
||||
<tableViewController storyboardIdentifier="ColorPaletteTableViewController" title="Color Palette" id="4je-jl-or5" customClass="ColorPaletteTableViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="insetGrouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="nt4-zl-48k">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="808"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="804"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" systemColor="groupTableViewBackgroundColor"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="Cell" textLabel="lFx-ni-1UR" style="IBUITableViewCellStyleDefault" id="Dzq-cs-s7M" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="49.5" width="374" height="43.5"/>
|
||||
<rect key="frame" x="20" y="55.5" width="374" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Dzq-cs-s7M" id="eAg-RP-lRc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
|
||||
@@ -1310,8 +1311,8 @@
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="accountLocal" width="119" height="102"/>
|
||||
<image name="bell.fill" catalog="system" width="128" height="124"/>
|
||||
<image name="gear" catalog="system" width="128" height="119"/>
|
||||
<image name="bell.fill" catalog="system" width="123" height="128"/>
|
||||
<image name="gear" catalog="system" width="128" height="122"/>
|
||||
<namedColor name="AccentColor">
|
||||
<color red="0.030999999493360519" green="0.41600000858306885" blue="0.93300002813339233" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</namedColor>
|
||||
@@ -1325,7 +1326,7 @@
|
||||
<color red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="labelColor">
|
||||
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</systemColor>
|
||||
<systemColor name="secondaryLabelColor">
|
||||
<color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
||||
@@ -86,18 +86,6 @@ class SettingsViewController: UITableViewController, Logging {
|
||||
colorPaletteDetailLabel.text = String(describing: AppDefaults.userInterfaceColorPalette)
|
||||
openLinksInNetNewsWire.isOn = !AppDefaults.shared.useSystemBrowser
|
||||
|
||||
let buildLabel = NonIntrinsicLabel(frame: CGRect(x: 32.0, y: 0.0, width: 0.0, height: 0.0))
|
||||
buildLabel.font = UIFont.systemFont(ofSize: 11.0)
|
||||
buildLabel.textColor = UIColor.gray
|
||||
buildLabel.text = "\(Bundle.main.appName) \(Bundle.main.versionNumber) (Build \(Bundle.main.buildNumber))"
|
||||
buildLabel.sizeToFit()
|
||||
buildLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
||||
let wrapperView = UIView(frame: CGRect(x: 0, y: 0, width: buildLabel.frame.width, height: buildLabel.frame.height + 10.0))
|
||||
wrapperView.translatesAutoresizingMaskIntoConstraints = false
|
||||
wrapperView.addSubview(buildLabel)
|
||||
tableView.tableFooterView = wrapperView
|
||||
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
@@ -283,8 +271,8 @@ class SettingsViewController: UITableViewController, Logging {
|
||||
openURL("https://netnewswire.com/slack")
|
||||
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
|
||||
case 8:
|
||||
let timeline = UIStoryboard.settings.instantiateController(ofType: AboutViewController.self)
|
||||
self.navigationController?.pushViewController(timeline, animated: true)
|
||||
let hosting = UIHostingController(rootView: AboutView())
|
||||
self.navigationController?.pushViewController(hosting, animated: true)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// Bundle-Extensions.swift
|
||||
// NetNewsWire-iOS
|
||||
//
|
||||
// Created by Maurice Parker on 4/26/19.
|
||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Bundle {
|
||||
|
||||
var appName: String {
|
||||
return infoDictionary?["CFBundleName"] as! String
|
||||
}
|
||||
|
||||
var versionNumber: String {
|
||||
return infoDictionary?["CFBundleShortVersionString"] as! String
|
||||
}
|
||||
|
||||
var buildNumber: String {
|
||||
return infoDictionary?["CFBundleVersion"] as! String
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
//
|
||||
// RoundedProgressView.swift
|
||||
// NetNewsWire
|
||||
//
|
||||
// Created by Maurice Parker on 10/29/19.
|
||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class RoundedProgressView: UIProgressView {
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
subviews.forEach { subview in
|
||||
subview.layer.masksToBounds = true
|
||||
subview.layer.cornerRadius = bounds.height / 2.0
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user