Merge pull request #1347 from jbennett/add-feed-wrangler-ios

Allow Feed Wrangler accounts on iOS
This commit is contained in:
Maurice Parker 2019-11-25 08:18:42 -06:00 committed by GitHub
commit 964cdfcb55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 398 additions and 11 deletions

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
3B3A32A5238B820900314204 /* FeedWranglerAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B3A328B238B820900314204 /* FeedWranglerAccountViewController.swift */; };
3B826DCB2385C84800FC1ADB /* AccountsFeedWrangler.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3B826DB02385C84800FC1ADB /* AccountsFeedWrangler.xib */; };
3B826DCC2385C84800FC1ADB /* AccountsFeedWranglerWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B826DCA2385C84800FC1ADB /* AccountsFeedWranglerWindowController.swift */; };
3B826DCD2385C89600FC1ADB /* AccountsFeedWrangler.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3B826DB02385C84800FC1ADB /* AccountsFeedWrangler.xib */; };
@ -1219,6 +1220,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
3B3A328B238B820900314204 /* FeedWranglerAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedWranglerAccountViewController.swift; sourceTree = "<group>"; };
3B826DB02385C84800FC1ADB /* AccountsFeedWrangler.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AccountsFeedWrangler.xib; sourceTree = "<group>"; };
3B826DCA2385C84800FC1ADB /* AccountsFeedWranglerWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsFeedWranglerWindowController.swift; sourceTree = "<group>"; };
49F40DEF2335B71000552BF4 /* newsfoot.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = newsfoot.js; sourceTree = "<group>"; };
@ -1807,6 +1809,7 @@
516A093F2361240900EAE89B /* Account.storyboard */,
51A1698F235E10D600EB091F /* LocalAccountViewController.swift */,
51A16996235E10D700EB091F /* FeedbinAccountViewController.swift */,
3B3A328B238B820900314204 /* FeedWranglerAccountViewController.swift */,
);
path = Account;
sourceTree = "<group>";
@ -3947,6 +3950,7 @@
51C452772265091600C03939 /* MultilineUILabelSizer.swift in Sources */,
51C452A522650A2D00C03939 /* SmallIconProvider.swift in Sources */,
516A09392360A2AE00EAE89B /* SettingsAccountTableViewCell.swift in Sources */,
3B3A32A5238B820900314204 /* FeedWranglerAccountViewController.swift in Sources */,
51D5948722668EFA00DFC836 /* MarkStatusCommand.swift in Sources */,
51A1699C235E10D700EB091F /* AddAccountViewController.swift in Sources */,
51A16999235E10D700EB091F /* LocalAccountViewController.swift in Sources */,

View File

@ -2,7 +2,7 @@
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15509"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@ -39,6 +39,155 @@
</objects>
<point key="canvasLocation" x="3177" y="-528"/>
</scene>
<!--Feed Wrangler-->
<scene sceneID="66V-IF-sys">
<objects>
<tableViewController id="fPs-Pp-Qk4" customClass="FeedWranglerAccountViewController" 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="pvq-Hi-fuC">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<sections>
<tableViewSection id="aBu-yB-8do">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="7kE-yi-fSC">
<rect key="frame" x="20" y="18" width="374" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="7kE-yi-fSC" id="03i-i5-FcH">
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Email" textAlignment="natural" adjustsFontForContentSizeCategory="YES" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="o06-fe-i3S">
<rect key="frame" x="20" y="11.5" width="334" height="21"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<textInputTraits key="textInputTraits" spellCheckingType="no" keyboardType="emailAddress" textContentType="username"/>
</textField>
</subviews>
<constraints>
<constraint firstItem="o06-fe-i3S" firstAttribute="centerY" secondItem="03i-i5-FcH" secondAttribute="centerY" id="CZh-l6-1rR"/>
<constraint firstItem="o06-fe-i3S" firstAttribute="leading" secondItem="03i-i5-FcH" secondAttribute="leading" constant="20" id="ELy-L4-kqa"/>
<constraint firstAttribute="trailing" secondItem="o06-fe-i3S" secondAttribute="trailing" constant="20" id="Zqt-e6-Hyi"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="DZE-9N-drH">
<rect key="frame" x="20" y="61.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="DZE-9N-drH" id="R0T-Op-v3i">
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Password" textAlignment="natural" adjustsFontForContentSizeCategory="YES" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Z6i-nX-CwJ">
<rect key="frame" x="20" y="11.5" width="283" height="21"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<textInputTraits key="textInputTraits" secureTextEntry="YES" textContentType="password"/>
</textField>
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="lBg-Pn-8ao">
<rect key="frame" x="311" y="5.5" width="43" height="33"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<state key="normal" title="Show"/>
<connections>
<action selector="showHidePassword:" destination="fPs-Pp-Qk4" eventType="touchUpInside" id="nEJ-ls-ZGH"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="lBg-Pn-8ao" firstAttribute="leading" secondItem="Z6i-nX-CwJ" secondAttribute="trailing" constant="8" symbolic="YES" id="Ljx-ZV-dqS"/>
<constraint firstItem="Z6i-nX-CwJ" firstAttribute="leading" secondItem="R0T-Op-v3i" secondAttribute="leading" constant="20" id="MJf-rd-h8l"/>
<constraint firstAttribute="trailing" secondItem="lBg-Pn-8ao" secondAttribute="trailing" constant="20" symbolic="YES" id="QbM-sI-Grd"/>
<constraint firstItem="lBg-Pn-8ao" firstAttribute="centerY" secondItem="R0T-Op-v3i" secondAttribute="centerY" id="jZb-uf-0i9"/>
<constraint firstItem="Z6i-nX-CwJ" firstAttribute="centerY" secondItem="R0T-Op-v3i" secondAttribute="centerY" id="zbK-Fj-UdZ"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection id="91x-2Y-RyC">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="DdI-cc-rL4">
<rect key="frame" x="20" y="141" width="374" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="DdI-cc-rL4" id="VUw-ck-1xk">
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="kKc-mk-vsU" customClass="VibrantButton" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="374" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="Ucm-6X-Jvf"/>
</constraints>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<state key="normal" title="Action">
<color key="titleColor" name="secondaryAccentColor"/>
</state>
<connections>
<action selector="action:" destination="fPs-Pp-Qk4" eventType="touchUpInside" id="K0L-le-dSs"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="kKc-mk-vsU" firstAttribute="centerY" secondItem="VUw-ck-1xk" secondAttribute="centerY" id="6Kf-JS-VU9"/>
<constraint firstAttribute="trailing" secondItem="kKc-mk-vsU" secondAttribute="trailing" id="hLa-MZ-Dc6"/>
<constraint firstItem="kKc-mk-vsU" firstAttribute="leading" secondItem="VUw-ck-1xk" secondAttribute="leading" id="iec-dp-dkS"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
<connections>
<outlet property="dataSource" destination="fPs-Pp-Qk4" id="C5c-gU-SJN"/>
<outlet property="delegate" destination="fPs-Pp-Qk4" id="gf8-01-E1Y"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Feed Wrangler" id="D6L-4j-gVo">
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="zbP-iL-kfC">
<connections>
<action selector="cancel:" destination="fPs-Pp-Qk4" id="C0j-OR-yQ2"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" id="ojY-jN-yDr">
<view key="customView" contentMode="scaleToFill" id="6k3-VP-uPP">
<rect key="frame" x="374" y="12" width="20" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" style="medium" translatesAutoresizingMaskIntoConstraints="NO" id="mVm-hL-hqw">
<rect key="frame" x="36" y="6" width="20" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</view>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="actionButton" destination="kKc-mk-vsU" id="TXr-cm-Oyp"/>
<outlet property="activityIndicator" destination="mVm-hL-hqw" id="8Og-kO-70M"/>
<outlet property="cancelBarButtonItem" destination="zbP-iL-kfC" id="TT3-iu-IvG"/>
<outlet property="emailTextField" destination="o06-fe-i3S" id="WHW-3E-trH"/>
<outlet property="passwordTextField" destination="Z6i-nX-CwJ" id="p36-53-RsD"/>
<outlet property="showHideButton" destination="lBg-Pn-8ao" id="GgE-Nx-gFL"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Hsf-Kf-Hxa" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3870" y="145"/>
</scene>
<!--Modal Navigation Controller-->
<scene sceneID="q8q-hQ-uMk">
<objects>
<navigationController storyboardIdentifier="FeedWranglerAccountNavigationViewController" id="p2l-Ub-oeO" customClass="ModalNavigationController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="D1T-5x-xpV">
<rect key="frame" x="0.0" y="44" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="fPs-Pp-Qk4" kind="relationship" relationship="rootViewController" id="7Qk-Xc-9XZ"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="V1s-8K-v9X" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3870" y="-528"/>
</scene>
<!--On My Device-->
<scene sceneID="J93-FN-Yey">
<objects>

View File

@ -0,0 +1,173 @@
//
// FeedWranglerAccountViewController.swift
// NetNewsWire
//
// Created by Jonathan Bennett on 2019-11-24.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import UIKit
import Account
import RSWeb
class FeedWranglerAccountViewController: UITableViewController {
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
@IBOutlet weak var cancelBarButtonItem: UIBarButtonItem!
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var passwordTextField: UITextField!
@IBOutlet weak var showHideButton: UIButton!
@IBOutlet weak var actionButton: UIButton!
weak var account: Account?
weak var delegate: AddAccountDismissDelegate?
override func viewDidLoad() {
super.viewDidLoad()
activityIndicator.isHidden = true
emailTextField.delegate = self
passwordTextField.delegate = self
if let account = account, let credentials = try? account.retrieveCredentials(type: .feedWranglerBasic) {
actionButton.setTitle(NSLocalizedString("Update Credentials", comment: "Update Credentials"), for: .normal)
emailTextField.text = credentials.username
passwordTextField.text = credentials.secret
} else {
actionButton.setTitle(NSLocalizedString("Add Account", comment: "Update Credentials"), for: .normal)
}
NotificationCenter.default.addObserver(self, selector: #selector(textDidChange(_:)), name: UITextField.textDidChangeNotification, object: emailTextField)
NotificationCenter.default.addObserver(self, selector: #selector(textDidChange(_:)), name: UITextField.textDidChangeNotification, object: passwordTextField)
tableView.register(ImageHeaderView.self, forHeaderFooterViewReuseIdentifier: "SectionHeader")
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return section == 0 ? ImageHeaderView.rowHeight : super.tableView(tableView, heightForHeaderInSection: section)
}
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 {
let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "SectionHeader") as! ImageHeaderView
headerView.imageView.image = AppAssets.image(for: .feedWrangler)
return headerView
} else {
return super.tableView(tableView, viewForHeaderInSection: section)
}
}
@IBAction func cancel(_ sender: Any) {
dismiss(animated: true, completion: nil)
delegate?.dismiss()
}
@IBAction func showHidePassword(_ sender: Any) {
if passwordTextField.isSecureTextEntry {
passwordTextField.isSecureTextEntry = false
showHideButton.setTitle(NSLocalizedString("Hide", comment: "Button Label"), for: .normal)
} else {
passwordTextField.isSecureTextEntry = true
showHideButton.setTitle(NSLocalizedString("Show", comment: "Button Label"), for: .normal)
}
}
@IBAction func action(_ sender: Any) {
guard let email = emailTextField.text, let password = passwordTextField.text else {
showError(NSLocalizedString("Username & password required.", comment: "Credentials Error"))
return
}
startAnimatingActivityIndicator()
disableNavigation()
// When you fill in the email address via auto-complete it adds extra whitespace
let trimmedEmail = email.trimmingCharacters(in: .whitespaces)
let credentials = Credentials(type: .feedWranglerBasic, username: trimmedEmail, secret: password)
Account.validateCredentials(type: .feedWrangler, credentials: credentials) { result in
self.stopAnimtatingActivityIndicator()
self.enableNavigation()
switch result {
case .success(let validatedCredentials):
guard let validatedCredentials = validatedCredentials else {
self.showError(NSLocalizedString("Invalid email/password combination.", comment: "Credentials Error"))
return
}
var newAccount = false
if self.account == nil {
self.account = AccountManager.shared.createAccount(type: .feedWrangler)
newAccount = true
}
do {
try self.account?.removeCredentials(type: .feedWranglerBasic)
try self.account?.removeCredentials(type: .feedWranglerToken)
try self.account?.storeCredentials(credentials)
try self.account?.storeCredentials(validatedCredentials)
if newAccount {
self.account?.refreshAll { result in
switch result {
case .success:
break
case .failure(let error):
self.presentError(error)
}
}
}
self.dismiss(animated: true, completion: nil)
self.delegate?.dismiss()
} catch {
self.showError(NSLocalizedString("Keychain error while storing credentials.", comment: "Credentials Error"))
}
case .failure:
self.showError(NSLocalizedString("Network error. Try again later.", comment: "Credentials Error"))
}
}
}
@objc func textDidChange(_ note: Notification) {
actionButton.isEnabled = !(emailTextField.text?.isEmpty ?? false) && !(passwordTextField.text?.isEmpty ?? false)
}
private func showError(_ message: String) {
presentError(title: "Error", message: message)
}
private func enableNavigation() {
self.cancelBarButtonItem.isEnabled = true
self.actionButton.isEnabled = true
}
private func disableNavigation() {
cancelBarButtonItem.isEnabled = false
actionButton.isEnabled = false
}
private func startAnimatingActivityIndicator() {
activityIndicator.isHidden = false
activityIndicator.startAnimating()
}
private func stopAnimtatingActivityIndicator() {
self.activityIndicator.isHidden = true
self.activityIndicator.stopAnimating()
}
}
extension FeedWranglerAccountViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}

View File

@ -26,6 +26,10 @@ struct AppAssets {
static var accountFeedlyImage: UIImage = {
return UIImage(named: "accountFeedly")!
}()
static var accountFeedWranglerImage: UIImage = {
return UIImage(named: "accountFeedWrangler")!
}()
static var accountFreshRSSImage: UIImage = {
return UIImage(named: "accountFreshRSS")!
@ -214,6 +218,8 @@ struct AppAssets {
return AppAssets.accountFeedbinImage
case .feedly:
return AppAssets.accountFeedlyImage
case .feedWrangler:
return AppAssets.accountFeedWranglerImage
case .freshRSS:
return AppAssets.accountFreshRSSImage
default:

View File

@ -0,0 +1,15 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "outline-512.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -43,6 +43,12 @@ class AddAccountViewController: UITableViewController, AddAccountDismissDelegate
addAccount.delegate = self
addAccount.presentationAnchor = self.view.window!
OperationQueue.main.addOperation(addAccount)
case 3:
let navController = UIStoryboard.account.instantiateViewController(withIdentifier: "FeedWranglerAccountNavigationViewController") as! UINavigationController
navController.modalPresentationStyle = .currentContext
let addViewController = navController.topViewController as! FeedWranglerAccountViewController
addViewController.delegate = self
present(navController, animated: true)
default:
break
}

View File

@ -2,7 +2,7 @@
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15505" 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="15509"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15510"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@ -19,7 +19,7 @@
<tableViewSection headerTitle="Notifications, Badge, Data, &amp; 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="0.0" y="55.5" width="374" height="44"/>
<rect key="frame" x="20" y="55.5" width="374" height="44"/>
<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"/>
@ -267,7 +267,7 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="Pm8-6D-fdE" style="IBUITableViewCellStyleDefault" id="3cU-BG-6kK" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="20" y="819.5" width="374" height="44"/>
<rect key="frame" x="0.0" y="819.5" width="374" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="3cU-BG-6kK" id="Qm0-SY-0vx">
<rect key="frame" x="0.0" y="0.0" width="374" height="44"/>
@ -284,7 +284,7 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="TEA-EG-V6d" style="IBUITableViewCellStyleDefault" id="4yc-ig-I61" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="20" y="863.5" width="374" height="44"/>
<rect key="frame" x="0.0" y="863.5" width="374" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="4yc-ig-I61" id="uQl-VP-9p9">
<rect key="frame" x="0.0" y="0.0" width="374" height="44"/>
@ -301,7 +301,7 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="Q9a-Pi-uCc" style="IBUITableViewCellStyleDefault" id="mSW-A7-8lf" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="20" y="907.5" width="374" height="44"/>
<rect key="frame" x="0.0" y="907.5" width="374" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="mSW-A7-8lf" id="shF-ro-Zpx">
<rect key="frame" x="0.0" y="0.0" width="374" height="44"/>
@ -318,14 +318,14 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" textLabel="dWz-1o-EpJ" style="IBUITableViewCellStyleDefault" id="2MG-qn-idJ" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="20" y="951.5" width="374" height="44"/>
<rect key="frame" x="0.0" y="951.5" width="374" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="2MG-qn-idJ" id="gP9-ry-keC">
<rect key="frame" x="0.0" y="0.0" width="374" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Technotes" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="dWz-1o-EpJ">
<rect key="frame" x="20" y="0.0" width="334" height="44"/>
<rect key="frame" x="15" y="0.0" width="351" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
@ -335,14 +335,14 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="2o6-8W-nyK" style="IBUITableViewCellStyleDefault" id="he9-Ql-yfa" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="20" y="995.5" width="374" height="44"/>
<rect key="frame" x="0.0" y="995.5" width="374" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="he9-Ql-yfa" id="q6L-C8-H9a">
<rect key="frame" x="0.0" y="0.0" width="343" height="44"/>
<rect key="frame" x="0.0" y="0.0" width="355" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="About NetNewsWire" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="2o6-8W-nyK">
<rect key="frame" x="20" y="0.0" width="315" height="44"/>
<rect key="frame" x="15" y="0.0" width="332" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
@ -485,6 +485,39 @@
</constraints>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" rowHeight="56" id="sKj-1P-BwI" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="20" y="185" width="374" height="56"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="sKj-1P-BwI" id="PdS-21-hdl">
<rect key="frame" x="0.0" y="0.0" width="374" height="56"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="TmQ-Hs-znP">
<rect key="frame" x="20" y="12" width="223.5" height="32"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="accountFeedWrangler" translatesAutoresizingMaskIntoConstraints="NO" id="pIU-f0-h1H">
<rect key="frame" x="0.0" y="0.0" width="32" height="32"/>
<color key="tintColor" systemColor="labelColor" cocoaTouchSystemColor="darkTextColor"/>
<constraints>
<constraint firstAttribute="height" constant="32" id="zA7-8h-8WG"/>
<constraint firstAttribute="width" constant="32" id="ze0-RG-buU"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Feed Wrangler" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dur-Qf-YYi">
<rect key="frame" x="48" y="0.0" width="175.5" height="32"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle1"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstItem="TmQ-Hs-znP" firstAttribute="leading" secondItem="PdS-21-hdl" secondAttribute="leading" constant="20" symbolic="YES" id="IFO-xv-Y0K"/>
<constraint firstItem="TmQ-Hs-znP" firstAttribute="centerY" secondItem="PdS-21-hdl" secondAttribute="centerY" id="oQy-rL-HV3"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
@ -842,6 +875,7 @@
</scene>
</scenes>
<resources>
<image name="accountFeedWrangler" width="512" height="512"/>
<image name="accountFeedbin" width="120" height="102"/>
<image name="accountFeedly" width="138" height="123"/>
<image name="accountLocal" width="99" height="77"/>