Merge branch 'ios-ui-notifications' of https://github.com/stuartbreckenridge/NetNewsWire into ios-ui-notifications

This commit is contained in:
Stuart Breckenridge
2022-02-11 06:16:07 +08:00
51 changed files with 1965 additions and 1397 deletions

View File

@@ -508,6 +508,9 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
} else {
if let title = item.titleFromAttributes, let folder = ensureFolder(with: title) {
folder.externalID = item.attributes?["nnw_externalID"] as? String
if let isSyncingPaused = item.attributes?["nnw_isSyncingPaused"] as? String, isSyncingPaused == "true" {
folder.isSyncingPaused = true
}
item.children?.forEach { itemChild in
if let feedSpecifier = itemChild.feedSpecifier {
folder.addWebFeed(newWebFeed(with: feedSpecifier))

View File

@@ -44,6 +44,7 @@ public final class Folder: Feed, Renamable, Container, Hashable {
static let untitledName = NSLocalizedString("Untitled ƒ", comment: "Folder name")
public let folderID: Int // not saved: per-run only
public var isSyncingPaused = false
public var externalID: String? = nil
static var incrementingID = 0
@@ -183,8 +184,16 @@ extension Folder: OPMLRepresentable {
}
}()
let attrPauseSyncing: String = {
if allowCustomAttributes && isSyncingPaused {
return " nnw_isSyncingPaused=\"true\""
} else {
return ""
}
}()
let escapedTitle = nameForDisplay.escapingSpecialXMLCharacters
var s = "<outline text=\"\(escapedTitle)\" title=\"\(escapedTitle)\"\(attrExternalID)>\n"
var s = "<outline text=\"\(escapedTitle)\" title=\"\(escapedTitle)\"\(attrExternalID)\(attrPauseSyncing)>\n"
s = s.prepending(tabCount: indentLevel)
var hasAtLeastOneChild = false

View File

@@ -192,6 +192,15 @@ public final class WebFeed: Feed, Renamable, Hashable {
}
}
public var isSyncingPaused: Bool {
get {
return metadata.isSyncingPaused ?? false
}
set {
metadata.isSyncingPaused = newValue
}
}
// MARK: - DisplayNameProvider
public var nameForDisplay: String {

View File

@@ -30,6 +30,7 @@ final class WebFeedMetadata: Codable {
case sinceToken
case externalID = "subscriptionID"
case folderRelationship
case isSyncingPaused
}
var webFeedID: String {
@@ -136,6 +137,14 @@ final class WebFeedMetadata: Codable {
}
}
}
var isSyncingPaused: Bool? {
didSet {
if isSyncingPaused != oldValue {
valueDidChange(.isSyncingPaused)
}
}
}
weak var delegate: WebFeedMetadataDelegate?

View File

@@ -150,8 +150,7 @@ struct AppAssets {
static var masterFolderImage: IconImage {
let image = NSImage(systemSymbolName: "folder", accessibilityDescription: nil)!
let preferredColor = NSColor(named: "AccentColor")!
let coloredImage = image.tinted(with: preferredColor)
return IconImage(coloredImage, isSymbol: true, isBackgroundSupressed: true, preferredColor: preferredColor.cgColor)
return IconImage(image, isSymbol: true, isBackgroundSupressed: true, preferredColor: preferredColor.cgColor)
}
static var markAllAsReadImage: RSImage = {
@@ -226,8 +225,7 @@ struct AppAssets {
static var starredFeedImage: IconImage = {
let image = NSImage(systemSymbolName: "star.fill", accessibilityDescription: nil)!
let preferredColor = NSColor(named: "StarColor")!
let coloredImage = image.tinted(with: preferredColor)
return IconImage(coloredImage, isSymbol: true, isBackgroundSupressed: true, preferredColor: preferredColor.cgColor)
return IconImage(image, isSymbol: true, isBackgroundSupressed: true, preferredColor: preferredColor.cgColor)
}()
static var timelineSeparatorColor: NSColor = {
@@ -245,15 +243,13 @@ struct AppAssets {
static var todayFeedImage: IconImage = {
let image = NSImage(systemSymbolName: "sun.max.fill", accessibilityDescription: nil)!
let preferredColor = NSColor.orange
let coloredImage = image.tinted(with: preferredColor)
return IconImage(coloredImage, isSymbol: true, isBackgroundSupressed: true, preferredColor: preferredColor.cgColor)
return IconImage(image, isSymbol: true, isBackgroundSupressed: true, preferredColor: preferredColor.cgColor)
}()
static var unreadFeedImage: IconImage = {
let image = NSImage(systemSymbolName: "largecircle.fill.circle", accessibilityDescription: nil)!
let preferredColor = NSColor(named: "AccentColor")!
let coloredImage = image.tinted(with: preferredColor)
return IconImage(coloredImage, isSymbol: true, isBackgroundSupressed: true, preferredColor: preferredColor.cgColor)
return IconImage(image, isSymbol: true, isBackgroundSupressed: true, preferredColor: preferredColor.cgColor)
}()
static var swipeMarkReadImage: RSImage = {

View File

@@ -396,7 +396,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
func createMainWindowController() -> MainWindowController {
let controller: MainWindowController
controller = windowControllerWithName("UnifiedWindow") as! MainWindowController
controller = windowControllerWithName("MainWindow") as! MainWindowController
if !(mainWindowController?.isOpen ?? false) {
mainWindowControllers.removeAll()
@@ -675,7 +675,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
@IBAction func showHelp(_ sender: Any?) {
Browser.open("https://netnewswire.com/help/mac/6.0/en/", inBackground: false)
Browser.open("https://netnewswire.com/help/mac/6.1/en/", inBackground: false)
}
@IBAction func donateToAppCampForGirls(_ sender: Any?) {
@@ -813,7 +813,7 @@ internal extension AppDelegate {
guard let window = mainWindowController?.window else { return }
do {
let theme = try ArticleTheme(path: filename)
let theme = try ArticleTheme(path: filename, isAppTheme: false)
let alert = NSAlert()
alert.alertStyle = .informational
@@ -829,7 +829,7 @@ internal extension AppDelegate {
attrs[.paragraphStyle] = titleParagraphStyle
let websiteText = NSMutableAttributedString()
websiteText.append(NSAttributedString(string: NSLocalizedString("Author's Website", comment: "Author's Website"), attributes: attrs))
websiteText.append(NSAttributedString(string: NSLocalizedString("Authors website:", comment: "Author's Website"), attributes: attrs))
websiteText.append(NSAttributedString(string: "\n"))

View File

@@ -11,241 +11,22 @@
<objects>
<windowController id="B8D-0N-5wS" customClass="MainWindowController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
<window key="window" title="NetNewsWire" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="IQv-IB-iLA">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" fullSizeContentView="YES"/>
<windowCollectionBehavior key="collectionBehavior" fullScreenPrimary="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<toolbar key="toolbar" implicitIdentifier="3C53153F-2D4C-441B-B551-D28ADBB5869C" explicitIdentifier="MainWindowToolbar" displayMode="iconOnly" sizeMode="regular" id="463-wM-1ZF">
<allowedToolbarItems>
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="d4b-Sp-qek"/>
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="YMs-P5-Xhn"/>
<toolbarItem implicitItemIdentifier="DD0FA79F-72C1-488B-B113-0D2DE89AA468" explicitItemIdentifier="search" label="Search" paletteLabel="Search" toolTip="Search Articles" id="1Ql-WJ-KYi">
<size key="minSize" width="96" height="22"/>
<size key="maxSize" width="320" height="28"/>
<searchField key="view" wantsLayer="YES" verticalHuggingPriority="750" id="Fcs-4u-xuP">
<rect key="frame" x="0.0" y="14" width="320" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<searchFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" usesSingleLineMode="YES" bezelStyle="round" id="syc-TO-rPc">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</searchFieldCell>
</searchField>
</toolbarItem>
<toolbarItem implicitItemIdentifier="C3050605-E4B0-40CB-BA19-F64DF68BCFFA" explicitItemIdentifier="share" label="Share" paletteLabel="Share" toolTip="Share" image="NSShareTemplate" id="nv0-Ju-lP7" customClass="RSToolbarItem" customModule="RSCore">
<size key="minSize" width="38" height="25"/>
<size key="maxSize" width="38" height="27"/>
<button key="view" verticalHuggingPriority="750" id="ypo-pI-PTN">
<rect key="frame" x="0.0" y="14" width="38" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="NSShareTemplate" imagePosition="overlaps" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="XW2-7k-h4r">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<connections>
<action selector="toolbarShowShareMenu:" target="Oky-zY-oP4" id="zUk-sS-frQ"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="3552D790-D29C-4BF2-AF02-5BEFE49C7FB9" explicitItemIdentifier="newFeed" label="New Feed" paletteLabel="New Feed" toolTip="New Feed" image="NSAddTemplate" id="Skp-5r-70Q" customClass="RSToolbarItem" customModule="RSCore">
<size key="minSize" width="38" height="25"/>
<size key="maxSize" width="38" height="27"/>
<button key="view" verticalHuggingPriority="750" id="rHO-y7-lG9">
<rect key="frame" x="11" y="14" width="38" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="NSAddTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="eHD-pU-GaN">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<connections>
<action selector="showAddWebFeedWindow:" target="Oky-zY-oP4" id="pEy-MV-Lnd"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="25C9E98A-867B-4EE2-BC1A-7B453D6B40BF" explicitItemIdentifier="newFolder" label="New Folder" paletteLabel="New Folder" toolTip="New Folder" image="newFolder" id="st0-Wp-nPK" customClass="RSToolbarItem" customModule="RSCore">
<size key="minSize" width="38" height="25"/>
<size key="maxSize" width="38" height="27"/>
<button key="view" verticalHuggingPriority="750" id="nvZ-IA-qOA">
<rect key="frame" x="15" y="14" width="38" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="newFolder" imagePosition="only" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" inset="2" id="Huj-Sy-XeN">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<connections>
<action selector="showAddFolderWindow:" target="Oky-zY-oP4" id="JH4-ym-YWq"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="D783290E-C822-40DF-8CB8-925D92EA4D83" explicitItemIdentifier="nextUnread" label="Next Unread" paletteLabel="Next Unread" toolTip="Go to Next Unread" image="nextUnread" id="p7Y-Vm-ILH" customClass="RSToolbarItem" customModule="RSCore">
<size key="minSize" width="38" height="25"/>
<size key="maxSize" width="38" height="27"/>
<button key="view" verticalHuggingPriority="750" id="1g8-XX-BhA" customClass="RSDarkModeAdaptingToolbarButton" customModule="RSCore">
<rect key="frame" x="18" y="14" width="38" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="nextUnread" imagePosition="only" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" inset="2" id="aBl-Z6-Tfa">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<connections>
<action selector="nextUnread:" target="Oky-zY-oP4" id="tR6-kc-nFc"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="4A460A5C-B005-4797-AA95-FD667F0A61C2" explicitItemIdentifier="markAllAsRead" label="Mark All as Read" paletteLabel="Mark All as Read" toolTip="Mark All as Read" image="markAllRead" id="lst-vn-0Iw" customClass="RSToolbarItem" customModule="RSCore">
<size key="minSize" width="38" height="25"/>
<size key="maxSize" width="38" height="27"/>
<button key="view" verticalHuggingPriority="750" id="0d4-hY-S6r">
<rect key="frame" x="29" y="14" width="38" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="markAllRead" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" inset="2" id="e9z-YJ-Rib">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<connections>
<action selector="markAllAsRead:" target="Oky-zY-oP4" id="qQg-Wj-NpN"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="540B93C9-F805-41C8-A638-3DC0825A020B" explicitItemIdentifier="markRead" label="Mark Read" paletteLabel="Mark Read" toolTip="Mark Read or Unread" image="markRead" id="N7D-g2-EPD" customClass="RSToolbarItem" customModule="RSCore">
<size key="minSize" width="38" height="25"/>
<size key="maxSize" width="38" height="27"/>
<button key="view" verticalHuggingPriority="750" id="Pe3-wh-G7e">
<rect key="frame" x="13" y="14" width="38" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="markRead" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" inset="2" id="2FV-93-DIY">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<connections>
<action selector="toggleRead:" target="B8D-0N-5wS" id="r02-sN-noB"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="09CE2FC7-B9B6-4A74-85B3-2DED57082923" explicitItemIdentifier="markStar" label="Star" paletteLabel="Star" toolTip="Star or Unstar" image="star" id="Gxg-WQ-ufC" customClass="RSToolbarItem" customModule="RSCore">
<size key="minSize" width="38" height="25"/>
<size key="maxSize" width="38" height="27"/>
<button key="view" verticalHuggingPriority="750" id="Ehx-31-ELo">
<rect key="frame" x="0.0" y="14" width="38" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="star" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" inset="2" id="xYM-n6-bee">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<connections>
<action selector="toggleStarred:" target="Oky-zY-oP4" id="44J-UK-89l"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="4DED27B7-8961-48F3-A995-9C961E2C0257" explicitItemIdentifier="openInBrowser" label="Open in Browser" paletteLabel="Open in Browser" toolTip="Open in Browser" image="openInBrowser" id="tid-SB-me3" customClass="RSToolbarItem" customModule="RSCore">
<size key="minSize" width="38" height="25"/>
<size key="maxSize" width="38" height="27"/>
<button key="view" verticalHuggingPriority="750" allowsExpansionToolTips="YES" id="pgp-lZ-j6S">
<rect key="frame" x="28" y="14" width="38" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="openInBrowser" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" inset="2" id="PNN-ND-sO0">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<connections>
<action selector="openArticleInBrowser:" target="Oky-zY-oP4" id="txK-8m-Gcm"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="94C3EB28-587B-4C5C-9647-F8A2A240A1FD" explicitItemIdentifier="refresh" label="Refresh" paletteLabel="Refresh" toolTip="Refresh" image="NSRefreshTemplate" id="QD0-SQ-OIM" customClass="RSToolbarItem" customModule="RSCore">
<size key="minSize" width="38" height="25"/>
<size key="maxSize" width="38" height="27"/>
<button key="view" verticalHuggingPriority="750" id="tRb-KW-Z3i">
<rect key="frame" x="5" y="14" width="38" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="NSRefreshTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="aGM-Q8-k4r">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<connections>
<action selector="refreshAll:" target="Oky-zY-oP4" id="KRz-Df-3zA"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="642D2379-B9AF-4990-8E09-A1115C60ED1A" explicitItemIdentifier="readerView" label="Reader" paletteLabel="Reader" toolTip="Reader View" id="6Vm-OW-3mR" customClass="RSToolbarItem" customModule="RSCore">
<size key="minSize" width="38" height="25"/>
<size key="maxSize" width="38" height="27"/>
<button key="view" verticalHuggingPriority="750" id="1b9-Tf-u5V" customClass="LegacyArticleExtractorButton" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="3" y="14" width="38" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="sXz-Xe-Kd7">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<connections>
<action selector="toggleArticleExtractor:" target="B8D-0N-5wS" id="ZKQ-SK-5YJ"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="ACB5604B-4543-4985-BA1A-54ADA9DF5845" explicitItemIdentifier="cleanUp" label="Clean UP" paletteLabel="Clean Up" toolTip="Clean Up" image="cleanUp" sizingBehavior="auto" id="SsT-iS-pKE" customClass="RSToolbarItem" customModule="RSCore">
<button key="view" verticalHuggingPriority="750" id="9At-yP-WNY">
<rect key="frame" x="7" y="14" width="42" height="25"/>
<autoresizingMask key="autoresizingMask"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="cleanUp" imagePosition="only" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Zwg-74-ZkZ">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<connections>
<action selector="cleanUp:" target="Oky-zY-oP4" id="UCH-DG-yk4"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="596363B5-CE41-417C-B8AB-11CC2C99BCA5" label="Article Theme" paletteLabel="Article Theme" sizingBehavior="auto" id="3Hc-al-vK2">
<nil key="toolTip"/>
<popUpButton key="view" verticalHuggingPriority="750" id="MFT-nb-eLG">
<rect key="frame" x="0.0" y="14" width="100" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="roundTextured" title="Item 1" bezelStyle="texturedRounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" selectedItem="xAs-IL-tMv" id="ior-Gb-LTq">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="1Ac-Uq-Yeu">
<items>
<menuItem title="Item 1" state="on" id="xAs-IL-tMv"/>
<menuItem title="Item 2" id="T8e-ib-OTb"/>
<menuItem title="Item 3" id="Gfy-76-Njz"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
</toolbarItem>
</allowedToolbarItems>
<defaultToolbarItems>
<toolbarItem reference="Skp-5r-70Q"/>
<toolbarItem reference="st0-Wp-nPK"/>
<toolbarItem reference="QD0-SQ-OIM"/>
<toolbarItem reference="YMs-P5-Xhn"/>
<toolbarItem reference="lst-vn-0Iw"/>
<toolbarItem reference="1Ql-WJ-KYi"/>
<toolbarItem reference="YMs-P5-Xhn"/>
<toolbarItem reference="p7Y-Vm-ILH"/>
<toolbarItem reference="Gxg-WQ-ufC"/>
<toolbarItem reference="N7D-g2-EPD"/>
<toolbarItem reference="6Vm-OW-3mR"/>
<toolbarItem reference="tid-SB-me3"/>
<toolbarItem reference="nv0-Ju-lP7"/>
</defaultToolbarItems>
<connections>
<outlet property="delegate" destination="B8D-0N-5wS" id="bgf-8m-klH"/>
</connections>
</toolbar>
<connections>
<outlet property="delegate" destination="B8D-0N-5wS" id="JSn-lq-Uwe"/>
</connections>
</window>
<connections>
<outlet property="articleThemePopUpButton" destination="MFT-nb-eLG" id="lHc-ej-PrT"/>
<segue destination="reS-fe-pD8" kind="relationship" relationship="window.shadowedContentViewController" id="WS2-WB-dc4"/>
</connections>
</windowController>
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-666" y="-124"/>
<point key="canvasLocation" x="-639" y="-140"/>
</scene>
<!--Split View Controller-->
<scene sceneID="vhK-r2-b3N">
@@ -309,20 +90,20 @@
<rect key="frame" x="0.0" y="0.0" width="240" height="307"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="26" horizontalPageScroll="10" verticalLineScroll="26" verticalPageScroll="10" hasHorizontalScroller="NO" horizontalScrollElasticity="none" translatesAutoresizingMaskIntoConstraints="NO" id="cJj-Wv-9ep">
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="28" horizontalPageScroll="10" verticalLineScroll="28" verticalPageScroll="10" hasHorizontalScroller="NO" horizontalScrollElasticity="none" translatesAutoresizingMaskIntoConstraints="NO" id="cJj-Wv-9ep">
<rect key="frame" x="0.0" y="0.0" width="240" height="307"/>
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="2eU-Wz-F9g">
<rect key="frame" x="0.0" y="0.0" width="240" height="307"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="firstColumnOnly" selectionHighlightStyle="sourceList" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="24" rowSizeStyle="systemDefault" viewBased="YES" floatsGroupRows="NO" indentationPerLevel="16" outlineTableColumn="ih9-mJ-EA7" id="cnV-kg-Dn2" customClass="SidebarOutlineView" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="241" height="307"/>
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="firstColumnOnly" selectionHighlightStyle="sourceList" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="28" rowSizeStyle="systemDefault" viewBased="YES" floatsGroupRows="NO" indentationPerLevel="13" outlineTableColumn="ih9-mJ-EA7" id="cnV-kg-Dn2" customClass="SidebarOutlineView" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="240" height="307"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="2"/>
<size key="intercellSpacing" width="3" height="0.0"/>
<color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn width="238" minWidth="23" maxWidth="1000" id="ih9-mJ-EA7">
<tableColumn width="208" minWidth="23" maxWidth="1000" id="ih9-mJ-EA7">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
@@ -335,7 +116,7 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
<prototypeCellViews>
<tableCellView identifier="HeaderCell" id="qkt-WA-5tB">
<rect key="frame" x="1" y="1" width="238" height="17"/>
<rect key="frame" x="11" y="0.0" width="217" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fNJ-z1-0Up">
@@ -353,7 +134,7 @@
</connections>
</tableCellView>
<tableCellView identifier="DataCell" id="HJn-Tm-YNO" customClass="SidebarCell" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="1" y="20" width="238" height="17"/>
<rect key="frame" x="11" y="17" width="217" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</tableCellView>
</prototypeCellViews>
@@ -469,7 +250,7 @@
<autoresizingMask key="autoresizingMask"/>
<subviews>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="lSU-OC-sEC">
<rect key="frame" x="8" y="176" width="51" height="19"/>
<rect key="frame" x="8" y="176" width="47" height="19"/>
<constraints>
<constraint firstAttribute="height" constant="18" id="DoO-KI-ena"/>
</constraints>
@@ -503,7 +284,7 @@
</popUpButtonCell>
</popUpButton>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="iA5-go-AO0">
<rect key="frame" x="350" y="179" width="13" height="14"/>
<rect key="frame" x="350" y="180" width="13" height="13"/>
<buttonCell key="cell" type="bevel" bezelStyle="rounded" image="filterInactive" imagePosition="overlaps" alignment="center" imageScaling="proportionallyDown" inset="2" id="j7d-36-DO5">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@@ -514,10 +295,10 @@
</connections>
</button>
<box verticalHuggingPriority="750" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="7p6-pA-iw6">
<rect key="frame" x="0.0" y="172" width="375" height="5"/>
<rect key="frame" x="0.0" y="195" width="375" height="5"/>
</box>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="Zpk-pq-9nW" customClass="TimelineContainerView" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="174"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="197"/>
</customView>
</subviews>
<constraints>
@@ -530,7 +311,7 @@
<constraint firstAttribute="trailing" secondItem="7p6-pA-iw6" secondAttribute="trailing" id="fG3-fe-Stb"/>
<constraint firstAttribute="bottom" secondItem="Zpk-pq-9nW" secondAttribute="bottom" id="fyv-EG-PC8"/>
<constraint firstItem="7p6-pA-iw6" firstAttribute="leading" secondItem="Dnl-L5-xFP" secondAttribute="leading" id="pZU-jW-B1h"/>
<constraint firstItem="7p6-pA-iw6" firstAttribute="top" secondItem="Dnl-L5-xFP" secondAttribute="top" constant="23" id="tUm-nX-Jce"/>
<constraint firstItem="7p6-pA-iw6" firstAttribute="top" secondItem="Dnl-L5-xFP" secondAttribute="top" id="tUm-nX-Jce"/>
<constraint firstItem="iA5-go-AO0" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="lSU-OC-sEC" secondAttribute="trailing" constant="8" id="yCg-gc-exN"/>
<constraint firstItem="lSU-OC-sEC" firstAttribute="top" secondItem="Dnl-L5-xFP" secondAttribute="top" constant="3" id="zay-ZJ-od3"/>
</constraints>
@@ -604,16 +385,6 @@
</scene>
</scenes>
<resources>
<image name="NSAddTemplate" width="11" height="11"/>
<image name="NSRefreshTemplate" width="11" height="15"/>
<image name="NSShareTemplate" width="11" height="16"/>
<image name="cleanUp" width="149" height="113"/>
<image name="filterInactive" width="13" height="13"/>
<image name="markAllRead" width="22" height="19"/>
<image name="markRead" width="19" height="19"/>
<image name="newFolder" width="19" height="19"/>
<image name="nextUnread" width="24" height="19"/>
<image name="openInBrowser" width="19" height="19"/>
<image name="star" width="19" height="19"/>
</resources>
</document>

View File

@@ -1,390 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="17701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17701"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Window Controller-->
<scene sceneID="R2V-B0-nI4">
<objects>
<windowController id="B8D-0N-5wS" customClass="MainWindowController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
<window key="window" title="NetNewsWire" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="IQv-IB-iLA">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" fullSizeContentView="YES"/>
<windowCollectionBehavior key="collectionBehavior" fullScreenPrimary="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<connections>
<outlet property="delegate" destination="B8D-0N-5wS" id="JSn-lq-Uwe"/>
</connections>
</window>
<connections>
<segue destination="reS-fe-pD8" kind="relationship" relationship="window.shadowedContentViewController" id="WS2-WB-dc4"/>
</connections>
</windowController>
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-639" y="-140"/>
</scene>
<!--Split View Controller-->
<scene sceneID="vhK-r2-b3N">
<objects>
<splitViewController id="wEf-EP-9Fq" sceneMemberID="viewController">
<splitViewItems>
<splitViewItem canCollapse="YES" holdingPriority="260" behavior="sidebar" id="XVW-Gk-g7U"/>
<splitViewItem holdingPriority="255" behavior="contentList" id="UkR-qu-7uT"/>
<splitViewItem id="EtR-h8-kPm"/>
</splitViewItems>
<splitView key="splitView" wantsLayer="YES" dividerStyle="thin" vertical="YES" id="3QF-bA-qOw">
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
<autoresizingMask key="autoresizingMask"/>
<connections>
<outlet property="delegate" destination="wEf-EP-9Fq" id="0ic-vQ-NKS"/>
</connections>
</splitView>
<connections>
<outlet property="splitView" destination="3QF-bA-qOw" id="YxK-5q-cOe"/>
<segue destination="XML-A3-pDn" kind="relationship" relationship="splitItems" id="Dul-5N-qJu"/>
<segue destination="36G-bQ-b96" kind="relationship" relationship="splitItems" id="yFZ-cm-NcZ"/>
<segue destination="Vho-7i-T8m" kind="relationship" relationship="splitItems" id="Foq-XC-qoZ"/>
</connections>
</splitViewController>
<customObject id="FnK-xf-eZm" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-607" y="805"/>
</scene>
<!--View Controller-->
<scene sceneID="ZPA-jO-OkH">
<objects>
<viewController id="reS-fe-pD8" sceneMemberID="viewController">
<customView key="view" wantsLayer="YES" id="hWY-jP-A4m">
<rect key="frame" x="0.0" y="0.0" width="581" height="300"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<containerView translatesAutoresizingMaskIntoConstraints="NO" id="K1o-Ws-XMQ">
<rect key="frame" x="0.0" y="0.0" width="581" height="300"/>
<connections>
<segue destination="wEf-EP-9Fq" kind="embed" id="IT3-aj-bSe"/>
</connections>
</containerView>
</subviews>
<constraints>
<constraint firstItem="K1o-Ws-XMQ" firstAttribute="top" secondItem="hWY-jP-A4m" secondAttribute="top" id="JPX-I3-QMN"/>
<constraint firstItem="K1o-Ws-XMQ" firstAttribute="leading" secondItem="hWY-jP-A4m" secondAttribute="leading" id="Vqi-IQ-2V0"/>
<constraint firstAttribute="trailing" secondItem="K1o-Ws-XMQ" secondAttribute="trailing" id="Y9X-7J-odJ"/>
<constraint firstAttribute="bottom" secondItem="K1o-Ws-XMQ" secondAttribute="bottom" id="spp-4y-rEm"/>
</constraints>
</customView>
</viewController>
<customObject id="6Eo-XA-2Zy" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-638.5" y="401"/>
</scene>
<!--Sidebar View Controller-->
<scene sceneID="Yae-mu-VsH">
<objects>
<viewController id="XML-A3-pDn" userLabel="Sidebar View Controller" customClass="SidebarViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" wantsLayer="YES" id="bJZ-bH-vgc">
<rect key="frame" x="0.0" y="0.0" width="240" height="307"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="28" horizontalPageScroll="10" verticalLineScroll="28" verticalPageScroll="10" hasHorizontalScroller="NO" horizontalScrollElasticity="none" translatesAutoresizingMaskIntoConstraints="NO" id="cJj-Wv-9ep">
<rect key="frame" x="0.0" y="0.0" width="240" height="307"/>
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="2eU-Wz-F9g">
<rect key="frame" x="0.0" y="0.0" width="240" height="307"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="firstColumnOnly" selectionHighlightStyle="sourceList" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="28" rowSizeStyle="systemDefault" viewBased="YES" floatsGroupRows="NO" indentationPerLevel="13" outlineTableColumn="ih9-mJ-EA7" id="cnV-kg-Dn2" customClass="SidebarOutlineView" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="240" height="307"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="0.0"/>
<color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn width="208" minWidth="23" maxWidth="1000" id="ih9-mJ-EA7">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="sXh-y7-12P">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
<prototypeCellViews>
<tableCellView identifier="HeaderCell" id="qkt-WA-5tB">
<rect key="frame" x="11" y="0.0" width="217" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fNJ-z1-0Up">
<rect key="frame" x="0.0" y="1" width="145" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="HEADER CELL" id="dRB-0K-qxz">
<font key="font" metaFont="smallSystemBold"/>
<color key="textColor" name="headerColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="fNJ-z1-0Up" id="jEh-Oo-s62"/>
</connections>
</tableCellView>
<tableCellView identifier="DataCell" id="HJn-Tm-YNO" customClass="SidebarCell" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="11" y="17" width="217" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<accessibility description="Feeds"/>
<connections>
<outlet property="delegate" destination="XML-A3-pDn" id="fPE-cv-p5c"/>
<outlet property="keyboardDelegate" destination="h5K-zR-cUa" id="BlT-aW-sea"/>
<outlet property="menu" destination="p3f-EZ-sSD" id="KTA-tl-UrO"/>
</connections>
</outlineView>
</subviews>
<nil key="backgroundColor"/>
</clipView>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="166" id="pzy-wh-tgi"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="vs5-5h-CXe">
<rect key="frame" x="-100" y="-100" width="238" height="15"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="FWV-kB-qct">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
</scrollView>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="HZs-Zf-G8s" customClass="SidebarStatusBarView" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="0.0" y="-28" width="240" height="28"/>
<subviews>
<box verticalHuggingPriority="750" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="agw-l1-HkL">
<rect key="frame" x="0.0" y="25" width="240" height="5"/>
</box>
<progressIndicator hidden="YES" wantsLayer="YES" maxValue="100" style="bar" translatesAutoresizingMaskIntoConstraints="NO" id="y9c-Xf-2fS">
<rect key="frame" x="20" y="3" width="40" height="20"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="1Yw-ER-8pT"/>
</constraints>
</progressIndicator>
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="iyL-pW-cT6">
<rect key="frame" x="62" y="6" width="160" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Label" id="dVE-XG-mlU">
<font key="font" metaFont="system"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="y9c-Xf-2fS" firstAttribute="centerY" secondItem="HZs-Zf-G8s" secondAttribute="centerY" constant="1" id="5Du-sw-hBK"/>
<constraint firstItem="agw-l1-HkL" firstAttribute="leading" secondItem="HZs-Zf-G8s" secondAttribute="leading" id="FVd-l8-q2q"/>
<constraint firstItem="iyL-pW-cT6" firstAttribute="centerY" secondItem="HZs-Zf-G8s" secondAttribute="centerY" id="Hht-GZ-3Ls"/>
<constraint firstAttribute="trailing" secondItem="agw-l1-HkL" secondAttribute="trailing" id="MaE-c5-LIY"/>
<constraint firstItem="iyL-pW-cT6" firstAttribute="leading" secondItem="y9c-Xf-2fS" secondAttribute="trailing" constant="4" id="TAM-VN-Syu"/>
<constraint firstItem="y9c-Xf-2fS" firstAttribute="leading" secondItem="HZs-Zf-G8s" secondAttribute="leading" constant="20" symbolic="YES" id="TV9-iE-nuE"/>
<constraint firstItem="agw-l1-HkL" firstAttribute="top" secondItem="HZs-Zf-G8s" secondAttribute="top" id="rBv-S6-j3b"/>
<constraint firstAttribute="height" constant="28" id="xOq-XX-qcd"/>
</constraints>
<connections>
<outlet property="bottomConstraint" destination="UN9-Wa-uxb" id="SYv-ax-8md"/>
<outlet property="heightConstraint" destination="xOq-XX-qcd" id="ktU-yd-g8x"/>
<outlet property="progressIndicator" destination="y9c-Xf-2fS" id="gaf-6e-siu"/>
<outlet property="progressLabel" destination="iyL-pW-cT6" id="Zpv-44-cfX"/>
</connections>
</customView>
</subviews>
<constraints>
<constraint firstItem="HZs-Zf-G8s" firstAttribute="top" secondItem="cJj-Wv-9ep" secondAttribute="bottom" id="0Zg-oW-o7U"/>
<constraint firstItem="cJj-Wv-9ep" firstAttribute="leading" secondItem="bJZ-bH-vgc" secondAttribute="leading" id="5Rs-9M-TKq"/>
<constraint firstItem="cJj-Wv-9ep" firstAttribute="top" secondItem="bJZ-bH-vgc" secondAttribute="top" id="A7C-VI-drt"/>
<constraint firstAttribute="trailing" secondItem="iyL-pW-cT6" secondAttribute="trailing" constant="20" id="Mnm-9S-Qpm"/>
<constraint firstAttribute="bottom" secondItem="HZs-Zf-G8s" secondAttribute="bottom" constant="-28" id="UN9-Wa-uxb"/>
<constraint firstAttribute="trailing" secondItem="HZs-Zf-G8s" secondAttribute="trailing" id="iNE-nb-QEB"/>
<constraint firstItem="HZs-Zf-G8s" firstAttribute="leading" secondItem="bJZ-bH-vgc" secondAttribute="leading" id="tPp-xB-CgB"/>
<constraint firstAttribute="trailing" secondItem="cJj-Wv-9ep" secondAttribute="trailing" id="vo7-3F-Fd3"/>
</constraints>
</view>
<connections>
<outlet property="outlineView" destination="cnV-kg-Dn2" id="FVf-OT-E3h"/>
</connections>
</viewController>
<customObject id="Jih-JO-hIE" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
<menu id="p3f-EZ-sSD">
<items>
<menuItem title="Item 1" id="ZDH-CV-Y2s">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Item 2" id="1F7-qu-7oN">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Item 3" id="r9E-FO-GoU">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
<connections>
<outlet property="delegate" destination="XML-A3-pDn" id="XJm-Ua-9UB"/>
</connections>
</menu>
<customObject id="h5K-zR-cUa" customClass="SidebarKeyboardDelegate" customModule="NetNewsWire" customModuleProvider="target">
<connections>
<outlet property="sidebarViewController" destination="XML-A3-pDn" id="kwd-Zc-HJm"/>
</connections>
</customObject>
</objects>
<point key="canvasLocation" x="-74" y="-186.5"/>
</scene>
<!--Timeline Container View Controller-->
<scene sceneID="zUD-i8-QYC">
<objects>
<viewController id="36G-bQ-b96" customClass="TimelineContainerViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="Dnl-L5-xFP">
<rect key="frame" x="0.0" y="0.0" width="375" height="198"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="lSU-OC-sEC">
<rect key="frame" x="8" y="176" width="47" height="19"/>
<constraints>
<constraint firstAttribute="height" constant="18" id="DoO-KI-ena"/>
</constraints>
<popUpButtonCell key="cell" type="recessed" title="Sort" bezelStyle="recessed" alignment="center" lineBreakMode="truncatingTail" borderStyle="border" tag="1" imageScaling="proportionallyDown" inset="2" pullsDown="YES" id="bl0-6I-cH2">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
<font key="font" metaFont="smallSystemBold"/>
<menu key="menu" id="dN0-S2-uqU">
<items>
<menuItem title="Sort" tag="1" hidden="YES" id="4BZ-ya-evy">
<attributedString key="attributedTitle"/>
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Newest Article on Top" state="on" tag="2" id="40c-kt-vhO">
<connections>
<action selector="sortByNewestArticleOnTop:" target="Ebq-4s-EwK" id="vYg-MZ-zve"/>
</connections>
</menuItem>
<menuItem title="Oldest Article on Top" tag="3" id="sOF-Ez-vIL">
<connections>
<action selector="sortByOldestArticleOnTop:" target="Ebq-4s-EwK" id="KFG-M7-blB"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="xQP-gm-iO9"/>
<menuItem title="Group by Feed" tag="4" id="YSR-5C-Yjd">
<connections>
<action selector="groupByFeedToggled:" target="Ebq-4s-EwK" id="4y9-5l-ToF"/>
</connections>
</menuItem>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="iA5-go-AO0">
<rect key="frame" x="350" y="180" width="13" height="13"/>
<buttonCell key="cell" type="bevel" bezelStyle="rounded" image="filterInactive" imagePosition="overlaps" alignment="center" imageScaling="proportionallyDown" inset="2" id="j7d-36-DO5">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<color key="contentTintColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<connections>
<action selector="toggleReadArticlesFilter:" target="Ebq-4s-EwK" id="tcC-72-Npk"/>
</connections>
</button>
<box verticalHuggingPriority="750" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="7p6-pA-iw6">
<rect key="frame" x="0.0" y="195" width="375" height="5"/>
</box>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="Zpk-pq-9nW" customClass="TimelineContainerView" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="197"/>
</customView>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="Zpk-pq-9nW" secondAttribute="trailing" id="67d-pI-I9C"/>
<constraint firstAttribute="trailing" secondItem="iA5-go-AO0" secondAttribute="trailing" constant="12" id="9Dl-n9-vRI"/>
<constraint firstItem="lSU-OC-sEC" firstAttribute="leading" secondItem="Dnl-L5-xFP" secondAttribute="leading" constant="8" id="Ceb-sA-ECJ"/>
<constraint firstItem="Zpk-pq-9nW" firstAttribute="top" secondItem="7p6-pA-iw6" secondAttribute="bottom" id="KCa-8b-a6y"/>
<constraint firstItem="lSU-OC-sEC" firstAttribute="centerY" secondItem="iA5-go-AO0" secondAttribute="centerY" id="OeL-Zp-iRT"/>
<constraint firstItem="Zpk-pq-9nW" firstAttribute="leading" secondItem="Dnl-L5-xFP" secondAttribute="leading" id="XF2-31-E1x"/>
<constraint firstAttribute="trailing" secondItem="7p6-pA-iw6" secondAttribute="trailing" id="fG3-fe-Stb"/>
<constraint firstAttribute="bottom" secondItem="Zpk-pq-9nW" secondAttribute="bottom" id="fyv-EG-PC8"/>
<constraint firstItem="7p6-pA-iw6" firstAttribute="leading" secondItem="Dnl-L5-xFP" secondAttribute="leading" id="pZU-jW-B1h"/>
<constraint firstItem="7p6-pA-iw6" firstAttribute="top" secondItem="Dnl-L5-xFP" secondAttribute="top" id="tUm-nX-Jce"/>
<constraint firstItem="iA5-go-AO0" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="lSU-OC-sEC" secondAttribute="trailing" constant="8" id="yCg-gc-exN"/>
<constraint firstItem="lSU-OC-sEC" firstAttribute="top" secondItem="Dnl-L5-xFP" secondAttribute="top" constant="3" id="zay-ZJ-od3"/>
</constraints>
</view>
<connections>
<outlet property="containerView" destination="Zpk-pq-9nW" id="Kye-yX-Wyn"/>
<outlet property="groupByFeedMenuItem" destination="YSR-5C-Yjd" id="1aN-9S-nE1"/>
<outlet property="newestToOldestMenuItem" destination="40c-kt-vhO" id="AGa-fX-EVy"/>
<outlet property="oldestToNewestMenuItem" destination="sOF-Ez-vIL" id="qSg-ST-ww9"/>
<outlet property="readFilteredButton" destination="iA5-go-AO0" id="kQg-2g-zNZ"/>
<outlet property="viewOptionsPopUpButton" destination="lSU-OC-sEC" id="Z8V-rm-n2m"/>
</connections>
</viewController>
<customObject id="Ebq-4s-EwK" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
<customObject id="ZOV-xh-WJE" customClass="TimelineKeyboardDelegate" customModule="NetNewsWire" customModuleProvider="target">
<connections>
<outlet property="timelineViewController" destination="36G-bQ-b96" id="rED-2Z-kh6"/>
</connections>
</customObject>
</objects>
<point key="canvasLocation" x="62" y="394"/>
</scene>
<!--Detail View Controller-->
<scene sceneID="HMt-bN-oMN">
<objects>
<viewController id="Vho-7i-T8m" userLabel="Detail View Controller" customClass="DetailViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
<customView key="view" id="cJ9-6s-66u" customClass="DetailContainerView" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="730" height="300"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<customView hidden="YES" alphaValue="0.90000000000000002" translatesAutoresizingMaskIntoConstraints="NO" id="xI5-lx-RD8" customClass="DetailStatusBarView" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="6" y="2" width="12" height="20"/>
<subviews>
<textField horizontalHuggingPriority="850" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="Dim-ed-Dcz" userLabel="URL Label">
<rect key="frame" x="4" y="2" width="4" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingMiddle" selectable="YES" allowsUndo="NO" sendsActionOnEndEditing="YES" alignment="left" usesSingleLineMode="YES" id="znU-Fh-L7H">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="Dim-ed-Dcz" firstAttribute="centerY" secondItem="xI5-lx-RD8" secondAttribute="centerY" id="Hna-uB-3F7"/>
<constraint firstAttribute="trailing" secondItem="Dim-ed-Dcz" secondAttribute="trailing" constant="6" id="O5q-ZN-DjZ"/>
<constraint firstAttribute="height" constant="20" id="Sfk-Ri-WoD"/>
<constraint firstItem="Dim-ed-Dcz" firstAttribute="leading" secondItem="xI5-lx-RD8" secondAttribute="leading" constant="6" id="Y9c-WR-ZBY"/>
</constraints>
<connections>
<outlet property="urlLabel" destination="Dim-ed-Dcz" id="8fY-oo-cGT"/>
</connections>
</customView>
</subviews>
<constraints>
<constraint firstItem="xI5-lx-RD8" firstAttribute="leading" secondItem="cJ9-6s-66u" secondAttribute="leading" constant="6" id="5vz-ys-CAo"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="xI5-lx-RD8" secondAttribute="trailing" constant="6" id="pbD-LN-Gk1"/>
<constraint firstAttribute="bottom" secondItem="xI5-lx-RD8" secondAttribute="bottom" constant="2" id="zsv-B0-ChW"/>
</constraints>
<connections>
<outlet property="detailStatusBarView" destination="xI5-lx-RD8" id="yIZ-aP-fKF"/>
</connections>
</customView>
<connections>
<outlet property="containerView" destination="cJ9-6s-66u" id="gXc-Pz-9sQ"/>
<outlet property="statusBarView" destination="xI5-lx-RD8" id="meP-4g-U63"/>
</connections>
</viewController>
<customObject id="vzM-Vn-mEn" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="68" y="946"/>
</scene>
</scenes>
<resources>
<image name="filterInactive" width="13" height="13"/>
</resources>
</document>

View File

@@ -14,6 +14,9 @@ final class IconView: NSView {
didSet {
if iconImage !== oldValue {
imageView.image = iconImage?.image
if let tintColor = iconImage?.preferredColor {
imageView.contentTintColor = NSColor(cgColor: tintColor)
}
if NSApplication.shared.effectiveAppearance.isDarkMode {
if self.iconImage?.isDark ?? false {

View File

@@ -1273,6 +1273,8 @@ private extension MainWindowController {
let widths = splitView.arrangedSubviews.map{ Int(floor($0.frame.width)) }
state[MainWindowController.mainWindowWidthsStateKey] = widths
state[UserInfoKey.isSidebarHidden] = sidebarSplitViewItem?.isCollapsed
}
func restoreSplitViewState(from state: [AnyHashable : Any]) {
@@ -1295,6 +1297,12 @@ private extension MainWindowController {
splitView.setPosition(CGFloat(sidebarWidth), ofDividerAt: 0)
splitView.setPosition(CGFloat(sidebarWidth + dividerThickness + timelineWidth), ofDividerAt: 1)
let isSidebarHidden = state[UserInfoKey.isSidebarHidden] as? Bool ?? false
if !(sidebarSplitViewItem?.isCollapsed ?? false) && isSidebarHidden {
sidebarSplitViewItem?.isCollapsed = true
}
}
func buildToolbarButton(_ itemIdentifier: NSToolbarItem.Identifier, _ title: String, _ image: NSImage, _ selector: String) -> NSToolbarItem {

View File

@@ -143,18 +143,17 @@ private extension SidebarCell {
var updatedIconImage = iconImage
if let iconImage = iconImage, iconImage.isSymbol {
var tintColor: CGColor
if backgroundStyle != .normal {
let image = iconImage.image.tinted(with: .white)
updatedIconImage = IconImage(image, isSymbol: iconImage.isSymbol, isBackgroundSupressed: iconImage.isBackgroundSupressed)
tintColor = NSColor.white.cgColor
} else {
if let preferredColor = iconImage.preferredColor {
let image = iconImage.image.tinted(with: NSColor(cgColor: preferredColor)!)
updatedIconImage = IconImage(image, isSymbol: iconImage.isSymbol, isBackgroundSupressed: iconImage.isBackgroundSupressed)
tintColor = preferredColor
} else {
let image = iconImage.image.tinted(with: .controlAccentColor)
updatedIconImage = IconImage(image, isSymbol: iconImage.isSymbol, isBackgroundSupressed: iconImage.isBackgroundSupressed)
tintColor = NSColor.controlAccentColor.cgColor
}
}
updatedIconImage = IconImage(iconImage.image, isSymbol: iconImage.isSymbol, isBackgroundSupressed: iconImage.isBackgroundSupressed, preferredColor: tintColor)
}
if let image = updatedIconImage {

View File

@@ -809,6 +809,12 @@ extension TimelineViewController: NSTableViewDataSource {
}
return ArticlePasteboardWriter(article: article)
}
func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
// Keeping -[NSTableViewDelegate tableView:heightOfRow:] implemented fixes
// an issue that the bottom inset of NSTableView disappears on macOS Monterey.
return tableView.rowHeight
}
}
// MARK: - NSTableViewDelegate

View File

@@ -80,6 +80,9 @@
5103A9F5242258C600410853 /* AccountsAddCloudKit.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5103A9DA242258C600410853 /* AccountsAddCloudKit.xib */; };
5103A9F724225E4C00410853 /* AccountsAddCloudKitWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5103A9F624225E4C00410853 /* AccountsAddCloudKitWindowController.swift */; };
5103A9F824225E4C00410853 /* AccountsAddCloudKitWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5103A9F624225E4C00410853 /* AccountsAddCloudKitWindowController.swift */; };
51077C5827A86D16000C71DB /* Hyperlegible.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = 51077C5727A86D16000C71DB /* Hyperlegible.nnwtheme */; };
51077C5927A86D16000C71DB /* Hyperlegible.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = 51077C5727A86D16000C71DB /* Hyperlegible.nnwtheme */; };
51077C5A27A86D16000C71DB /* Hyperlegible.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = 51077C5727A86D16000C71DB /* Hyperlegible.nnwtheme */; };
5108F6B62375E612001ABC45 /* CacheCleaner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6B52375E612001ABC45 /* CacheCleaner.swift */; };
5108F6B72375E612001ABC45 /* CacheCleaner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6B52375E612001ABC45 /* CacheCleaner.swift */; };
5108F6D22375EED2001ABC45 /* TimelineCustomizerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5108F6D12375EED2001ABC45 /* TimelineCustomizerViewController.swift */; };
@@ -254,6 +257,9 @@
517630042336215100E15FFF /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 517630032336215100E15FFF /* main.js */; };
517630052336215100E15FFF /* main.js in Resources */ = {isa = PBXBuildFile; fileRef = 517630032336215100E15FFF /* main.js */; };
517630232336657E00E15FFF /* WebViewProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 517630222336657E00E15FFF /* WebViewProvider.swift */; };
5177C21227B07C9E00643901 /* NewsFax.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = DFD6AACB27ADE80900463FAD /* NewsFax.nnwtheme */; };
5177C21327B07CFE00643901 /* NewsFax.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = DFD6AACB27ADE80900463FAD /* NewsFax.nnwtheme */; };
5177C21427B07D1E00643901 /* NewsFax.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = DFD6AACB27ADE80900463FAD /* NewsFax.nnwtheme */; };
517A745B2443665000B553B9 /* UIPageViewController-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 517A745A2443665000B553B9 /* UIPageViewController-Extensions.swift */; };
5183CCD0226E1E880010922C /* NonIntrinsicLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */; };
5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */; };
@@ -271,7 +277,6 @@
518C3193237B00D9004D740F /* DetailIconSchemeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5141E7552374A2890013FF27 /* DetailIconSchemeHandler.swift */; };
518C3194237B00DA004D740F /* DetailIconSchemeHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5141E7552374A2890013FF27 /* DetailIconSchemeHandler.swift */; };
518ED21D23D0F26000E0A862 /* UIViewController-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518ED21C23D0F26000E0A862 /* UIViewController-Extensions.swift */; };
51934CCB230F599B006127BE /* InteractiveNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CC1230F5963006127BE /* InteractiveNavigationController.swift */; };
51934CCE2310792F006127BE /* ActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CCD2310792F006127BE /* ActivityManager.swift */; };
51938DF2231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; };
51938DF3231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */; };
@@ -340,8 +345,6 @@
51BC4AFF247277E0000A6ED8 /* URL-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51BC4ADD247277DF000A6ED8 /* URL-Extensions.swift */; };
51BC4B00247277E0000A6ED8 /* URL-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51BC4ADD247277DF000A6ED8 /* URL-Extensions.swift */; };
51BC4B01247277E0000A6ED8 /* URL-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51BC4ADD247277DF000A6ED8 /* URL-Extensions.swift */; };
51C03081257D815A00609262 /* UnifiedWindow.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51C0307F257D815A00609262 /* UnifiedWindow.storyboard */; };
51C03082257D815A00609262 /* UnifiedWindow.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51C0307F257D815A00609262 /* UnifiedWindow.storyboard */; };
51C266EA238C334800F53014 /* ContextMenuPreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C266E9238C334800F53014 /* ContextMenuPreviewViewController.swift */; };
51C45258226508CF00C03939 /* AppAssets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C45254226507D200C03939 /* AppAssets.swift */; };
51C45259226508D300C03939 /* AppDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C45255226507D200C03939 /* AppDefaults.swift */; };
@@ -849,6 +852,7 @@
D5F4EDB720074D6500B9E363 /* WebFeed+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB620074D6500B9E363 /* WebFeed+Scriptability.swift */; };
D5F4EDB920074D7C00B9E363 /* Folder+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */; };
DD82AB0A231003F6002269DF /* SharingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD82AB09231003F6002269DF /* SharingTests.swift */; };
DFD6AACF27ADE86E00463FAD /* NewsFax.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = DFD6AACD27ADE86E00463FAD /* NewsFax.nnwtheme */; };
DFFB8FC2279B75E300AC21D7 /* Account in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 51BC2F4A24D343A500E90810 /* Account */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
DFFC199827A0D0D7004B7AEF /* NotificationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFFC199727A0D0D7004B7AEF /* NotificationsViewController.swift */; };
DFFC199A27A0D32A004B7AEF /* NotificationsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFFC199927A0D32A004B7AEF /* NotificationsTableViewCell.swift */; };
@@ -1165,6 +1169,7 @@
5103A9B324216A4200410853 /* blank.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = blank.html; sourceTree = "<group>"; };
5103A9DA242258C600410853 /* AccountsAddCloudKit.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AccountsAddCloudKit.xib; sourceTree = "<group>"; };
5103A9F624225E4C00410853 /* AccountsAddCloudKitWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsAddCloudKitWindowController.swift; sourceTree = "<group>"; };
51077C5727A86D16000C71DB /* Hyperlegible.nnwtheme */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Hyperlegible.nnwtheme; sourceTree = "<group>"; };
5108F6B52375E612001ABC45 /* CacheCleaner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheCleaner.swift; sourceTree = "<group>"; };
5108F6D12375EED2001ABC45 /* TimelineCustomizerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineCustomizerViewController.swift; sourceTree = "<group>"; };
5108F6D32375EEEF001ABC45 /* TimelinePreviewTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinePreviewTableViewController.swift; sourceTree = "<group>"; };
@@ -1272,7 +1277,6 @@
518B2ED22351B3DD00400001 /* NetNewsWire-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "NetNewsWire-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
518B2EE92351B4C200400001 /* NetNewsWire_iOSTests_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSTests_target.xcconfig; sourceTree = "<group>"; };
518ED21C23D0F26000E0A862 /* UIViewController-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController-Extensions.swift"; sourceTree = "<group>"; };
51934CC1230F5963006127BE /* InteractiveNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractiveNavigationController.swift; sourceTree = "<group>"; };
51934CCD2310792F006127BE /* ActivityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityManager.swift; sourceTree = "<group>"; };
51938DF1231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTimelineFeedDelegate.swift; sourceTree = "<group>"; };
5193CD57245E44A90092735E /* RedditFeedProvider-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RedditFeedProvider-Extensions.swift"; sourceTree = "<group>"; };
@@ -1308,7 +1312,6 @@
51BB7C302335ACDE008E8144 /* page.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = page.html; sourceTree = "<group>"; };
51BC4ADD247277DF000A6ED8 /* URL-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URL-Extensions.swift"; sourceTree = "<group>"; };
51BEB22C2451E8340066DEDD /* TwitterEnterDetailTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwitterEnterDetailTableViewController.swift; sourceTree = "<group>"; };
51C03080257D815A00609262 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Mac/Base.lproj/UnifiedWindow.storyboard; sourceTree = SOURCE_ROOT; };
51C266E9238C334800F53014 /* ContextMenuPreviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuPreviewViewController.swift; sourceTree = "<group>"; };
51C4524E226506F400C03939 /* UIStoryboard-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStoryboard-Extensions.swift"; sourceTree = "<group>"; };
51C45250226506F400C03939 /* String-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String-Extensions.swift"; sourceTree = "<group>"; };
@@ -1590,6 +1593,8 @@
D5F4EDB620074D6500B9E363 /* WebFeed+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WebFeed+Scriptability.swift"; sourceTree = "<group>"; };
D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Folder+Scriptability.swift"; sourceTree = "<group>"; };
DD82AB09231003F6002269DF /* SharingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharingTests.swift; sourceTree = "<group>"; };
DFD6AACB27ADE80900463FAD /* NewsFax.nnwtheme */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = NewsFax.nnwtheme; sourceTree = "<group>"; };
DFD6AACD27ADE86E00463FAD /* NewsFax.nnwtheme */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = NewsFax.nnwtheme; sourceTree = "<group>"; };
DFFC199727A0D0D7004B7AEF /* NotificationsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsViewController.swift; sourceTree = "<group>"; };
DFFC199927A0D32A004B7AEF /* NotificationsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsTableViewCell.swift; sourceTree = "<group>"; };
FF3ABF09232599450074C542 /* ArticleSorterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleSorterTests.swift; sourceTree = "<group>"; };
@@ -1850,7 +1855,9 @@
511D43CE231FA51100FB1562 /* Resources */ = {
isa = PBXGroup;
children = (
DFD6AACB27ADE80900463FAD /* NewsFax.nnwtheme */,
51DEE81126FB9233006DAA56 /* Appanoose.nnwtheme */,
51077C5727A86D16000C71DB /* Hyperlegible.nnwtheme */,
51DEE81726FBFF84006DAA56 /* Promenade.nnwtheme */,
5137C2E326F3F52D009EFEDB /* Sepia.nnwtheme */,
5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */,
@@ -1961,6 +1968,14 @@
path = Reddit;
sourceTree = "<group>";
};
5177C21027B07C8400643901 /* Recovered References */ = {
isa = PBXGroup;
children = (
DFD6AACD27ADE86E00463FAD /* NewsFax.nnwtheme */,
);
name = "Recovered References";
sourceTree = "<group>";
};
5183CCEA226F70350010922C /* Timer */ = {
isa = PBXGroup;
children = (
@@ -2036,7 +2051,6 @@
51627A92238A3836007B3B4B /* CroppingPreviewParameters.swift */,
512AF9C1236ED52C0066F8BE /* ImageHeaderView.swift */,
512AF9DC236F05230066F8BE /* InteractiveLabel.swift */,
51934CC1230F5963006127BE /* InteractiveNavigationController.swift */,
51A9A5F42380F6A60033AADF /* ModalNavigationController.swift */,
51EAED95231363EF00A9EEE3 /* NonIntrinsicButton.swift */,
5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */,
@@ -2245,7 +2259,6 @@
isa = PBXGroup;
children = (
8483630C2262A3FE00DA1D35 /* MainWindow.storyboard */,
51C0307F257D815A00609262 /* UnifiedWindow.storyboard */,
849A975D1ED9EB72007D329B /* MainWindowController.swift */,
519B8D322143397200FA689C /* SharingServiceDelegate.swift */,
849EE72020391F560082A1EA /* SharingServicePickerDelegate.swift */,
@@ -2494,6 +2507,7 @@
51CD32C324D2CD57009ABAEF /* ArticlesDatabase */,
51CD32C724D2E06C009ABAEF /* Secrets */,
51CD32A824D2CB25009ABAEF /* SyncDatabase */,
5177C21027B07C8400643901 /* Recovered References */,
);
sourceTree = "<group>";
usesTabs = 1;
@@ -2871,7 +2885,6 @@
176813F12564BB2C00D98635 /* Resources */,
1701E1BF25689B44009453D8 /* SwiftGen Localization */,
17EF6A1725C4E59D002C9F81 /* Embed Frameworks */,
84BB8F7F26224B5F00DB61F8 /* Delete Unnecessary Frameworks */,
);
buildRules = (
);
@@ -2915,7 +2928,6 @@
51314634235A7BBE00387FDC /* Frameworks */,
51314635235A7BBE00387FDC /* Resources */,
5102AE7724D17FB50050839C /* Embed Frameworks */,
513F328A2593EFCE0003048F /* Delete Unnecessary Frameworks */,
);
buildRules = (
);
@@ -2939,7 +2951,6 @@
513C5CE3232571C2003D4054 /* Frameworks */,
513C5CE4232571C2003D4054 /* Resources */,
5102AE7324D17FAA0050839C /* Embed Frameworks */,
513F328B2593F03F0003048F /* Delete Unnecessary Frameworks */,
);
buildRules = (
);
@@ -3077,6 +3088,7 @@
51C451DF2264C7F200C03939 /* Embed Frameworks */,
513C5CF1232571C2003D4054 /* Embed App Extensions */,
515D50802326D02600EE1167 /* Run Script: Verify No Build Settings */,
5170CA5A279E468000702605 /* Delete Unnecessary Frameworks */,
);
buildRules = (
);
@@ -3376,10 +3388,11 @@
5103A9F5242258C600410853 /* AccountsAddCloudKit.xib in Resources */,
65ED405E235DEF6C0081F399 /* DefaultFeeds.opml in Resources */,
51333D3C2468615D00EB5C91 /* AddRedditFeedSheet.xib in Resources */,
51C03082257D815A00609262 /* UnifiedWindow.storyboard in Resources */,
65ED405F235DEF6C0081F399 /* Preferences.storyboard in Resources */,
65ED4061235DEF6C0081F399 /* Assets.xcassets in Resources */,
65ED4063235DEF6C0081F399 /* RenameSheet.xib in Resources */,
DFD6AACF27ADE86E00463FAD /* NewsFax.nnwtheme in Resources */,
5177C21227B07C9E00643901 /* NewsFax.nnwtheme in Resources */,
65ED4064235DEF6C0081F399 /* AddFolderSheet.xib in Resources */,
65ED4065235DEF6C0081F399 /* AccountsFeedbin.xib in Resources */,
65ED4066235DEF6C0081F399 /* TimelineTableView.xib in Resources */,
@@ -3395,6 +3408,7 @@
65ED406C235DEF6C0081F399 /* Credits.rtf in Resources */,
65ED406D235DEF6C0081F399 /* Inspector.storyboard in Resources */,
65ED406E235DEF6C0081F399 /* AddWebFeedSheet.xib in Resources */,
51077C5927A86D16000C71DB /* Hyperlegible.nnwtheme in Resources */,
51DEE81326FB9233006DAA56 /* Appanoose.nnwtheme in Resources */,
B27EEBFA244D15F3000932E6 /* stylesheet.css in Resources */,
);
@@ -3426,6 +3440,7 @@
512392C324E3451400F11704 /* TwitterAdd.storyboard in Resources */,
516A093723609A3600EAE89B /* SettingsComboTableViewCell.xib in Resources */,
51F85BF32272531500C787DC /* Dedication.rtf in Resources */,
51077C5A27A86D16000C71DB /* Hyperlegible.nnwtheme in Resources */,
516A09422361248000EAE89B /* Inspector.storyboard in Resources */,
51DEE81A26FBFF84006DAA56 /* Promenade.nnwtheme in Resources */,
1768140B2564BB8300D98635 /* NetNewsWire_iOSwidgetextension_target.xcconfig in Resources */,
@@ -3445,6 +3460,7 @@
49F40DF92335B71000552BF4 /* newsfoot.js in Resources */,
512392C024E33A3C00F11704 /* RedditAdd.storyboard in Resources */,
51F85BEF2272520B00C787DC /* Thanks.rtf in Resources */,
5177C21327B07CFE00643901 /* NewsFax.nnwtheme in Resources */,
51CE1C0923621EDA005548FC /* RefreshProgressView.xib in Resources */,
84C9FC9D2262A1A900D921D6 /* Assets.xcassets in Resources */,
514219582353C28900E07E2C /* main_ios.js in Resources */,
@@ -3477,12 +3493,13 @@
5144EA3B227A379E00D19003 /* ImportOPMLSheet.xib in Resources */,
844B5B691FEA20DF00C7C76A /* SidebarKeyboardShortcuts.plist in Resources */,
5103A9F4242258C600410853 /* AccountsAddCloudKit.xib in Resources */,
51077C5827A86D16000C71DB /* Hyperlegible.nnwtheme in Resources */,
84A3EE5F223B667F00557320 /* DefaultFeeds.opml in Resources */,
51C03081257D815A00609262 /* UnifiedWindow.storyboard in Resources */,
849C78902362AAFC009A71E4 /* ExportOPMLSheet.xib in Resources */,
84C9FC8222629E4800D921D6 /* Preferences.storyboard in Resources */,
849C64681ED37A5D003D8FC0 /* Assets.xcassets in Resources */,
8483630B2262A3F000DA1D35 /* RenameSheet.xib in Resources */,
5177C21427B07D1E00643901 /* NewsFax.nnwtheme in Resources */,
848363052262A3CC00DA1D35 /* AddFolderSheet.xib in Resources */,
5144EA52227B8E4500D19003 /* AccountsFeedbin.xib in Resources */,
8405DDA222168920008CE1BF /* TimelineTableView.xib in Resources */,
@@ -3532,42 +3549,6 @@
shellPath = /bin/sh;
shellScript = "if ! command -v swiftgen &> /dev/null\nthen\n echo \"swiftgen could not be found\"\n exit\nfi\n\nswiftgen run strings -t structured-swift5 \"$PROJECT_DIR/Widget/Resources/en.lproj/Localizable.strings\" \"$PROJECT_DIR/Widget/Resources/Localizable.stringsdict\" --output \"$PROJECT_DIR/Widget/Resources/Localized.swift\";\n";
};
513F328A2593EFCE0003048F /* Delete Unnecessary Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Delete Unnecessary Frameworks";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Delete the framework that Xcode should have never included\n# https://forums.swift.org/t/is-this-an-xcode-bug-or-somehow-related-to-spm/33987\nrm -rf \"${TARGET_BUILD_DIR}/NetNewsWire iOS Intents Extension.appex/Frameworks\"\n";
};
513F328B2593F03F0003048F /* Delete Unnecessary Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Delete Unnecessary Frameworks";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Delete the framework that Xcode should have never included\n# https://forums.swift.org/t/is-this-an-xcode-bug-or-somehow-related-to-spm/33987\nrm -rf \"${TARGET_BUILD_DIR}/NetNewsWire iOS Share Extension.appex/Frameworks\"\n";
};
515D50802326D02600EE1167 /* Run Script: Verify No Build Settings */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 8;
@@ -3584,7 +3565,25 @@
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
shellScript = "xcrun -sdk macosx swiftc -target x86_64-macosx10.11 buildscripts/VerifyNoBuildSettings.swift -o $CONFIGURATION_TEMP_DIR/VerifyNoBS\n$CONFIGURATION_TEMP_DIR/VerifyNoBS ${PROJECT_NAME}.xcodeproj/project.pbxproj\n\n\nif [ $? -ne 0 ]\nthen\n echo \"error: Build Setting were found in the project.pbxproj file. Most likely you didn't intend to change this file and should revert it.\"\n exit 1\nfi\n";
shellScript = "xcrun -sdk macosx swiftc -target x86_64-macosx10.11 buildscripts/VerifyNoBS.swift -o $CONFIGURATION_TEMP_DIR/VerifyNoBS\n$CONFIGURATION_TEMP_DIR/VerifyNoBS ${PROJECT_NAME}.xcodeproj/project.pbxproj\n\n\nif [ $? -ne 0 ]\nthen\n echo \"error: Build Setting were found in the project.pbxproj file. Most likely you didn't intend to change this file and should revert it.\"\n exit 1\nfi\n";
};
5170CA5A279E468000702605 /* Delete Unnecessary Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Delete Unnecessary Frameworks";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "cd \"${CODESIGNING_FOLDER_PATH}/PlugIns/\"\n\nfor plugin in *; do\n if [ -d \"$plugin\" ]; then\n if [ -d \"${plugin}/Frameworks\" ]; then\n rm -rf \"${plugin}/Frameworks\"\n fi\n fi\ndone\n\n# codesign for Debugging on device\nif [ \"${CONFIGURATION}\" == \"Debug\" ] & [ \"${SDKROOT}\" != *Simulator* ] ; then\n\n echo \"Code signing frameworks...\"\n find \"${CODESIGNING_FOLDER_PATH}/Frameworks\" -maxdepth 1 -name '*.framework' -print0 | while read -d $'\\0' framework\n do\n # only sign frameworks without a signature\n if ! codesign -v \"${framework}\"; then\n codesign --force --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" --preserve-metadata=identifier,entitlements --timestamp=none \"${framework}\"\n echo \"Added missing signature to '${framework}'\"\n fi\n done\nfi\n";
};
652832CF2683DD0400E6F37C /* Run Script: Delete Unnecessary Frameworks For Share Extension */ = {
isa = PBXShellScriptBuildPhase;
@@ -3690,24 +3689,6 @@
shellPath = /bin/sh;
shellScript = "# Remove unused Sparkle components\nSPARKLE_DIR=\"${CODESIGNING_FOLDER_PATH}/Contents/Frameworks/Sparkle.framework\"\nfind \"${SPARKLE_DIR}\" -name Updater.app -execdir rm -rf {} \\;\nfind \"${SPARKLE_DIR}\" -name Autoupdate -execdir rm -rf {} \\;\n\nPLUGINS_DIR=\"${CODESIGNING_FOLDER_PATH}/Contents/PlugIns\"\nXPC_DIR=\"${CODESIGNING_FOLDER_PATH}/Contents/XPCServices\"\nfind \"${PLUGINS_DIR}\" -name Sparkle* -execdir rm -rf {} \\;\nfind \"${XPC_DIR}\" -name Sparkle* -execdir rm -rf {} \\;\n\n# Re-sign Sparkle after removing components\ncodesign --verbose --force -o runtime --preserve-metadata=entitlements --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" \"${CODESIGNING_FOLDER_PATH}/Contents/Frameworks/Sparkle.framework\"\n\n# Sign XPC Helpers and their internal binaries\ncodesign --verbose --force -o runtime --preserve-metadata=entitlements --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" \"${CODESIGNING_FOLDER_PATH}/Contents/XPCServices/org.sparkle-project.InstallerLauncher.xpc/Contents/MacOS/Updater.app\"\ncodesign --verbose --force -o runtime --preserve-metadata=entitlements --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" \"${CODESIGNING_FOLDER_PATH}/Contents/XPCServices/org.sparkle-project.InstallerLauncher.xpc/Contents/MacOS/Autoupdate\"\ncodesign --verbose --entitlements \"${PROJECT_DIR}/submodules/Sparkle/Downloader/org.sparkle-project.Downloader.entitlements\" --force -o runtime --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" \"${CODESIGNING_FOLDER_PATH}/Contents/XPCServices/org.sparkle-project.Downloader.xpc\"\ncodesign --verbose --force -o runtime --preserve-metadata=entitlements --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" \"${CODESIGNING_FOLDER_PATH}/Contents/XPCServices/org.sparkle-project.InstallerLauncher.xpc\"\ncodesign --verbose --force -o runtime --preserve-metadata=entitlements --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" \"${CODESIGNING_FOLDER_PATH}/Contents/XPCServices/org.sparkle-project.InstallerConnection.xpc\"\ncodesign --verbose --force -o runtime --preserve-metadata=entitlements --sign \"${EXPANDED_CODE_SIGN_IDENTITY}\" \"${CODESIGNING_FOLDER_PATH}/Contents/XPCServices/org.sparkle-project.InstallerStatus.xpc\"\n";
};
84BB8F7F26224B5F00DB61F8 /* Delete Unnecessary Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Delete Unnecessary Frameworks";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Delete the framework that Xcode should have never included\n# https://forums.swift.org/t/is-this-an-xcode-bug-or-somehow-related-to-spm/33987\nrm -rf \"${TARGET_BUILD_DIR}/NetNewsWire iOS Widget Extension.appex/Frameworks\"\n";
};
84C987A52000AC9E0066B150 /* Run Script: Automated build numbers */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@@ -4215,7 +4196,6 @@
51A1699D235E10D700EB091F /* SettingsViewController.swift in Sources */,
51C45293226509C800C03939 /* StarredFeedDelegate.swift in Sources */,
51D6A5BC23199C85001C27D8 /* MasterTimelineDataSource.swift in Sources */,
51934CCB230F599B006127BE /* InteractiveNavigationController.swift in Sources */,
769F2ED513DA03EE75B993A8 /* NewsBlurAccountViewController.swift in Sources */,
51BC4B01247277E0000A6ED8 /* URL-Extensions.swift in Sources */,
);
@@ -4536,14 +4516,6 @@
name = AddTwitterFeedSheet.xib;
sourceTree = "<group>";
};
51C0307F257D815A00609262 /* UnifiedWindow.storyboard */ = {
isa = PBXVariantGroup;
children = (
51C03080257D815A00609262 /* Base */,
);
name = UnifiedWindow.storyboard;
sourceTree = "<group>";
};
6581C73B20CED60100F4AD34 /* SafariExtensionViewController.xib */ = {
isa = PBXVariantGroup;
children = (

View File

@@ -26,6 +26,7 @@ struct ArticleTheme: Equatable {
let path: String?
let template: String?
let css: String?
let isAppTheme: Bool
var name: String {
guard let path = path else { return Self.defaultThemeName }
@@ -56,9 +57,11 @@ struct ArticleTheme: Equatable {
let templatePath = Bundle.main.path(forResource: "template", ofType: "html")!
template = Self.stringAtPath(templatePath)!
isAppTheme = true
}
init(path: String) throws {
init(path: String, isAppTheme: Bool) throws {
self.path = path
let infoPath = (path as NSString).appendingPathComponent("Info.plist")
@@ -75,6 +78,8 @@ struct ArticleTheme: Equatable {
let templatePath = (path as NSString).appendingPathComponent("template.html")
self.template = Self.stringAtPath(templatePath)
self.isAppTheme = isAppTheme
}
static func stringAtPath(_ f: String) -> String? {

View File

@@ -31,6 +31,7 @@ final class ArticleThemesManager: NSObject, NSFilePresenter {
set {
if newValue != currentThemeName {
AppDefaults.shared.currentThemeName = newValue
updateThemeNames()
updateCurrentTheme()
}
}
@@ -61,15 +62,6 @@ final class ArticleThemesManager: NSObject, NSFilePresenter {
abort()
}
let themeFilenames = Bundle.main.paths(forResourcesOfType: ArticleTheme.nnwThemeSuffix, inDirectory: nil)
let installedThemes = readInstalledThemes() ?? [String: Date]()
for themeFilename in themeFilenames {
let themeName = ArticleTheme.themeNameForPath(themeFilename)
if !installedThemes.keys.contains(themeName) {
try? importTheme(filename: themeFilename)
}
}
updateThemeNames()
updateCurrentTheme()
@@ -98,13 +90,34 @@ final class ArticleThemesManager: NSObject, NSFilePresenter {
}
try FileManager.default.copyItem(atPath: filename, toPath: toFilename)
let themeName = ArticleTheme.themeNameForPath(filename)
var installedThemes = readInstalledThemes() ?? [String: Date]()
installedThemes[themeName] = Date()
writeInstalledThemes(installedThemes)
}
func articleThemeWithThemeName(_ themeName: String) -> ArticleTheme? {
if themeName == AppDefaults.defaultThemeName {
return ArticleTheme.defaultTheme
}
let path: String
let isAppTheme: Bool
if let appThemePath = Bundle.main.url(forResource: themeName, withExtension: ArticleTheme.nnwThemeSuffix)?.path {
path = appThemePath
isAppTheme = true
} else if let installedPath = pathForThemeName(themeName, folder: folderPath) {
path = installedPath
isAppTheme = false
} else {
return nil
}
do {
return try ArticleTheme(path: path, isAppTheme: isAppTheme)
} catch {
NotificationCenter.default.post(name: .didFailToImportThemeWithError, object: nil, userInfo: ["error": error])
return nil
}
}
func deleteTheme(themeName: String) {
if let filename = pathForThemeName(themeName, folder: folderPath) {
try? FileManager.default.removeItem(atPath: filename)
@@ -118,30 +131,19 @@ final class ArticleThemesManager: NSObject, NSFilePresenter {
private extension ArticleThemesManager {
func updateThemeNames() {
let updatedThemeNames = allThemePaths(folderPath).map { ArticleTheme.themeNameForPath($0) }
let sortedThemeNames = updatedThemeNames.sorted(by: { $0.compare($1, options: .caseInsensitive) == .orderedAscending })
let appThemeFilenames = Bundle.main.paths(forResourcesOfType: ArticleTheme.nnwThemeSuffix, inDirectory: nil)
let appThemeNames = Set(appThemeFilenames.map { ArticleTheme.themeNameForPath($0) })
let installedThemeNames = Set(allThemePaths(folderPath).map { ArticleTheme.themeNameForPath($0) })
let allThemeNames = appThemeNames.union(installedThemeNames)
let sortedThemeNames = allThemeNames.sorted(by: { $0.compare($1, options: .caseInsensitive) == .orderedAscending })
if sortedThemeNames != themeNames {
themeNames = sortedThemeNames
}
}
func articleThemeWithThemeName(_ themeName: String) -> ArticleTheme? {
if themeName == AppDefaults.defaultThemeName {
return ArticleTheme.defaultTheme
}
guard let path = pathForThemeName(themeName, folder: folderPath) else {
return nil
}
do {
return try ArticleTheme(path: path)
} catch {
NotificationCenter.default.post(name: .didFailToImportThemeWithError, object: nil, userInfo: ["error": error])
return nil
}
}
func defaultArticleTheme() -> ArticleTheme {
return articleThemeWithThemeName(AppDefaults.defaultThemeName)!
}
@@ -178,14 +180,4 @@ private extension ArticleThemesManager {
return nil
}
func readInstalledThemes() -> [String: Date]? {
let filePath = (folderPath as NSString).appendingPathComponent("InstalledThemes.plist")
return NSDictionary(contentsOfFile: filePath) as? [String: Date]
}
func writeInstalledThemes(_ dict: [String: Date]) {
let filePath = (folderPath as NSString).appendingPathComponent("InstalledThemes.plist")
(dict as NSDictionary).write(toFile: filePath, atomically: true)
}
}

View File

@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>Name</key>
<string>Starter</string>
<string>Appanoose</string>
<key>ThemeIdentifier</key>
<string>com.netnewswire.themes.starter</string>
<key>CreatorHomePage</key>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Name</key>
<string>Hyperlegible</string>
<key>ThemeIdentifier</key>
<string>com.netnewswire.themes.hyperlegible</string>
<key>CreatorHomePage</key>
<string>http://netnewswire.com/</string>
<key>CreatorName</key>
<string>Ranchero Software</string>
<key>Version</key>
<integer>1</integer>
</dict>
</plist>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,47 @@
<!-- Template Variables
title: The title of the article
preferred_link: The best link to associate with the article for linking out.
external_link_label: A localized label for the external link.
external_link_stripped: The external link minus the scheme. Useful for displaying the external link.
external_link: The external link of the article if there is one provided by the author.
feed_link_title: The name of the feed associated with this article.
feed_link: The URL of the feed associated with this article.
byline: HTML that combines all the authors and links to them if available.
avatar_src: The image source URL for the feed icon / avatar.
dateline_style: Either "articleDateline" or "articleDatelineTitle" depending on if the title was populated or not.
datetime_long: Long version of a combined publish date and time.
datetime_medium: Medium length version of a combined publish date and time.
datetime_short: Short version of a combined publish date and time.
date_long: Long version of the publish date.
date_medium: Medium version of the publish date.
date_short: Long version of the publish date.
time_long: Long version of the publish time.
time_medium: Medium version of the publish time.
time_short: Long version of the publish time.
text_size_class: The size class that the user has selected in Preferences for article text.
body: The body of the article.
-->
<header class="headerContainer">
<table cellpadding=0 cellspacing=0 border=0 class="headerTable">
<tr>
<td class="header leftAlign"><a class="feedlink" href="[[feed_link]]">[[feed_link_title]]</a><br />[[byline]]</td>
<td class="header rightAlign avatar"><img id="nnwImageIcon" src="[[avatar_src]]" height=48 width=48 /></td>
</tr>
</table>
</header>
<article>
<div class="articleTitle"><h1><a href="[[preferred_link]]">[[title]]</a></h1></div>
<div class="[[dateline_style]]"><a href="[[preferred_link]]">[[datetime_medium]]</a></div>
<div class="externalLink">[[external_link_label]] <a href="[[external_link]]">[[external_link_stripped]]</a></div>
<div id="bodyContainer" class="articleBody [[text_size_class]]">[[body]]</div>
</article>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Name</key>
<string>NewsFax</string>
<key>ThemeIdentifier</key>
<string>com.mynameisstuart.themes.newsfax</string>
<key>CreatorHomePage</key>
<string>https://mynameisstuart.com/</string>
<key>CreatorName</key>
<string>Stuart Breckenridge</string>
<key>Version</key>
<integer>3</integer>
</dict>
</plist>

View File

@@ -0,0 +1,19 @@
The NewsFax themes uses the ModeSeven font throughout, which is available as Freeware.
Find out more [here](https://www.fontspace.com/modeseven-font-f2369).
ModeSeven is based on the bitmap font in Teletext televisions,
1980s-vintage Videotext terminals (such as the Prestel system used in
the UK), and the BBC Micro computer. (The name derives from the BBC
Micro screen mode which used the teletext character generator.)
This font looks "natural" at a size of 20 pixels, or any multiple thereof.
However, it has been hinted as to scale as well as an ex-bitmap font
can be expected to.
This font was created by hand with Fontographer 4.1.2 on a Macintosh.
The character definitions were worked out from a bitmap version of the
Teletext font created by James Fidell, and included in xbeeb (a BBC
Micro emulator for UNIX/X11). The spacing of the original has been
preserved, which is why many character shapes are aligned to the right
of their cells.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,90 @@
<!-- Template Variables
title: The title of the article
preferred_link: The best link to associate with the article for linking out.
external_link_label: A localized label for the external link.
external_link_stripped: The external link minus the scheme. Useful for displaying the external link.
external_link: The external link of the article if there is one provided by the author.
feed_link_title: The name of the feed associated with this article.
feed_link: The URL of the feed associated with this article.
byline: HTML that combines all the authors and links to them if available.
avatar_src: The image source URL for the feed icon / avatar.
dateline_style: Either "articleDateline" or "articleDatelineTitle" depending on if the title was populated or not.
datetime_long: Long version of a combined publish date and time.
datetime_medium: Medium length version of a combined publish date and time.
datetime_short: Short version of a combined publish date and time.
date_long: Long version of the publish date.
date_medium: Medium version of the publish date.
date_short: Long version of the publish date.
time_long: Long version of the publish time.
time_medium: Medium version of the publish time.
time_short: Long version of the publish time.
text_size_class: The size class that the user has selected in Preferences for article text.
body: The body of the article.
-->
<div class="feedHeader">
<table width="100%">
<tr>
<th class="newsfax" align="left">NEWSFAX</th>
<th class="newsfax-page" align="left"></th>
<th></th>
<th align="right">[[datetime_short]]</th>
</tr>
</table>
<div class="articleTitle">
<h1><a href="[[preferred_link]]">[[title]]</a></h1>
</div>
<div><a href="[[feed_link]]">[[feed_link_title]]</a></div>
<div>[[byline]]</div>
</div>
<hr />
<article>
<div id="bodyContainer" class="articleBody [[text_size_class]]">[[body]]</div>
<div class="externalLink"><a href="[[external_link]]">[[external_link]]</a></div>
<table class="newsfax-footer" width="100%">
<tr>
<th class="newsfax-footer-cell-red"><a href="https://duckduckgo.com/?q=news&t=h_&iar=news&ia=news">Headlines</a></th>
<th class="newsfax-footer-cell-green"><a href="https://duckduckgo.com/?q=sports+news&t=h_&ia=web">Sport</a></th>
<th class="newsfax-footer-cell-yellow"><a href="https://duckduckgo.com/?q=local+tv&t=h_&ia=places">Local TV<a></th>
<th class="newsfax-footer-cell-blue"><a href="[[feed_link]]">Website</a></th>
</tr>
</table>
</article>
<script type="text/javascript">
/* Generate a random Newsfax page number */
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1) + min); //The maximum is inclusive and the minimum is inclusive
}
let random = getRandomIntInclusive(100, 999);
let newsFaxElement = document.body.getElementsByClassName('newsfax-page')[0];
newsFaxElement.innerHTML = "P" + random;
/*
The arrow-circle-right SVG is provided by Font Awesome under the Creative Commons Attribution 4.0 International License.
For more details view the license here: https://fontawesome.com/license
*/
let externalLinkElement = document.body.getElementsByClassName('externalLink')[0].querySelectorAll('a')[0];
if (externalLinkElement.innerText != '') {
let host = externalLinkElement.hostname;
externalLinkElement.innerHTML = host + " " + '->';
}
</script>

View File

@@ -25,5 +25,6 @@ struct UserInfoKey {
static let selectedFeedsState = "selectedFeedsState"
static let isShowingExtractedArticle = "isShowingExtractedArticle"
static let articleWindowScrollY = "articleWindowScrollY"
static let isSidebarHidden = "isSidebarHidden"
}

View File

@@ -1,5 +1,19 @@
# iOS Release Notes
### 6.1 TestFlight build 6103 - 25 Jan 2022
Fixed regression with keyboard shortcuts.
Fixed crashing bug adding an account.
### 6.1 TestFlight build 6102 - 23 Jan 2022
Article themes. Several themes ship with the app, and you can create your own. You can change the theme in Preferences.
Copy URLs using repaired, rather than raw, feed links.
Disallow creation of iCloud account in the app if iCloud and iCloud Drive arent both enabled.
Fixed bug showing quote tweets that only included an image.
Video autoplay is now disallowed.
Article view now supports RTL layout.
### 6.0.1 TestFlight build 608 - 28 Aug 2021
Fixed our top crashing bug — it could happen when updating a table view

View File

@@ -257,6 +257,10 @@ struct AppAssets {
let image = UIImage(systemName: "star.fill")!
return IconImage(image, isSymbol: true, isBackgroundSupressed: true, preferredColor: AppAssets.starColor.cgColor)
}
static var themeImage: UIImage = {
return UIImage(systemName: "doc.richtext")!
}()
static var tickMarkColor: UIColor = {
return UIColor(named: "tickMarkColor")!

View File

@@ -28,7 +28,7 @@ enum UserInterfaceColorPalette: Int, CustomStringConvertible, CaseIterable {
final class AppDefaults {
static let defaultThemeName = "Defaults"
static let defaultThemeName = "Default"
static let shared = AppDefaults()
private init() {}
@@ -168,15 +168,6 @@ final class AppDefaults {
}
}
var articleFullscreenAvailable: Bool {
get {
return AppDefaults.bool(for: Key.articleFullscreenAvailable)
}
set {
AppDefaults.setBool(for: Key.articleFullscreenAvailable, newValue)
}
}
var articleFullscreenEnabled: Bool {
get {
return AppDefaults.bool(for: Key.articleFullscreenEnabled)

View File

@@ -12,19 +12,20 @@ import Account
import Articles
import SafariServices
class ArticleViewController: UIViewController {
class ArticleViewController: UIViewController, MainControllerIdentifiable {
typealias State = (extractedArticle: ExtractedArticle?,
isShowingExtractedArticle: Bool,
articleExtractorButtonState: ArticleExtractorButtonState,
windowScrollY: Int)
isShowingExtractedArticle: Bool,
articleExtractorButtonState: ArticleExtractorButtonState,
windowScrollY: Int)
@IBOutlet private weak var nextUnreadBarButtonItem: UIBarButtonItem!
@IBOutlet private weak var prevArticleBarButtonItem: UIBarButtonItem!
@IBOutlet private weak var nextArticleBarButtonItem: UIBarButtonItem!
@IBOutlet private weak var readBarButtonItem: UIBarButtonItem!
@IBOutlet private weak var starBarButtonItem: UIBarButtonItem!
@IBOutlet private weak var actionBarButtonItem: UIBarButtonItem!
@IBOutlet private weak var appearanceBarButtonItem: UIBarButtonItem!
@IBOutlet private var searchBar: ArticleSearchBar!
@IBOutlet private var searchBarBottomConstraint: NSLayoutConstraint!
@@ -43,8 +44,12 @@ class ArticleViewController: UIViewController {
return button
}()
var mainControllerIdentifer = MainControllerIdentifier.article
weak var coordinator: SceneCoordinator!
private let poppableDelegate = PoppableGestureRecognizerDelegate()
var article: Article? {
didSet {
if let controller = currentWebViewController, controller.article != article {
@@ -84,34 +89,33 @@ class ArticleViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
let fullScreenTapZone = UIView()
NSLayoutConstraint.activate([
fullScreenTapZone.widthAnchor.constraint(equalToConstant: 150),
fullScreenTapZone.heightAnchor.constraint(equalToConstant: 44)
])
fullScreenTapZone.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(didTapNavigationBar)))
navigationItem.titleView = fullScreenTapZone
NotificationCenter.default.addObserver(self, selector: #selector(reloadDueToThemeChange(_:)), name: .CurrentArticleThemeDidChangeNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(configureAppearanceMenu(_:)), name: .ArticleThemeNamesDidChangeNotification, object: nil)
articleExtractorButton.addTarget(self, action: #selector(toggleArticleExtractor(_:)), for: .touchUpInside)
toolbarItems?.insert(UIBarButtonItem(customView: articleExtractorButton), at: 6)
if let parentNavController = navigationController?.parent as? UINavigationController {
poppableDelegate.navigationController = parentNavController
parentNavController.interactivePopGestureRecognizer?.delegate = poppableDelegate
}
pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: [:])
pageViewController.delegate = self
pageViewController.dataSource = self
// This code is to disallow paging if we scroll from the left edge. If this code is removed
// PoppableGestureRecognizerDelegate will allow us to both navigate back and page back at the
// same time. That is really weird when it happens.
let panGestureRecognizer = UIPanGestureRecognizer()
panGestureRecognizer.delegate = self
pageViewController.scrollViewInsidePageControl?.addGestureRecognizer(panGestureRecognizer)
pageViewController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(pageViewController.view)
addChild(pageViewController!)
@@ -121,7 +125,7 @@ class ArticleViewController: UIViewController {
view.topAnchor.constraint(equalTo: pageViewController.view.topAnchor),
view.bottomAnchor.constraint(equalTo: pageViewController.view.bottomAnchor)
])
let controller: WebViewController
if let state = restoreState {
controller = createWebViewController(article, updateView: false)
@@ -136,13 +140,10 @@ class ArticleViewController: UIViewController {
if let rsp = restoreScrollPosition {
controller.setScrollPosition(isShowingExtractedArticle: rsp.isShowingExtractedArticle, articleWindowScrollY: rsp.articleWindowScrollY)
}
articleExtractorButton.buttonState = controller.articleExtractorButtonState
self.pageViewController.setViewControllers([controller], direction: .forward, animated: false, completion: nil)
if AppDefaults.shared.articleFullscreenEnabled {
controller.hideBars()
}
// Search bar
searchBar.translatesAutoresizingMaskIntoConstraints = false
@@ -152,15 +153,21 @@ class ArticleViewController: UIViewController {
searchBar.delegate = self
view.bringSubviewToFront(searchBar)
configureAppearanceMenu()
updateUI()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
coordinator.isArticleViewControllerPending = false
override func viewWillAppear(_ animated: Bool) {
navigationController?.isToolbarHidden = false
if AppDefaults.shared.articleFullscreenEnabled {
currentWebViewController?.hideBars()
}
super.viewWillAppear(animated)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if searchBar != nil && !searchBar.isHidden {
endFind()
}
@@ -181,14 +188,16 @@ class ArticleViewController: UIViewController {
readBarButtonItem.isEnabled = false
starBarButtonItem.isEnabled = false
actionBarButtonItem.isEnabled = false
appearanceBarButtonItem.isEnabled = false
return
}
nextUnreadBarButtonItem.isEnabled = coordinator.isAnyUnreadAvailable
prevArticleBarButtonItem.isEnabled = coordinator.isPrevArticleAvailable
nextArticleBarButtonItem.isEnabled = coordinator.isNextArticleAvailable
readBarButtonItem.isEnabled = true
starBarButtonItem.isEnabled = true
appearanceBarButtonItem.isEnabled = true
let permalinkPresent = article.preferredLink != nil
var isFeedProvider = false
@@ -218,6 +227,66 @@ class ArticleViewController: UIViewController {
}
override func contentScrollView(for edge: NSDirectionalRectEdge) -> UIScrollView? {
return currentWebViewController?.webView?.scrollView
}
@objc
func configureAppearanceMenu(_ sender: Any? = nil) {
var themeActions = [UIAction]()
for themeName in ArticleThemesManager.shared.themeNames {
let action = UIAction(title: themeName,
image: nil,
identifier: nil,
discoverabilityTitle: nil,
attributes: [],
state: ArticleThemesManager.shared.currentThemeName == themeName ? .on : .off,
handler: { action in
ArticleThemesManager.shared.currentThemeName = themeName
})
themeActions.append(action)
}
let defaultThemeAction = UIAction(title: NSLocalizedString("Default", comment: "Default"), image: nil, identifier: nil, discoverabilityTitle: nil, attributes: [], state: ArticleThemesManager.shared.currentThemeName == AppDefaults.defaultThemeName ? .on : .off) { _ in
ArticleThemesManager.shared.currentThemeName = AppDefaults.defaultThemeName
}
themeActions.append(defaultThemeAction)
let themeMenu = UIMenu(title: "Theme", image: AppAssets.themeImage, identifier: nil, options: .singleSelection, children: themeActions)
themeMenu.subtitle = NSLocalizedString("Change the look of articles.", comment: "Change theme")
var children: [UIMenuElement] = [themeMenu]
if let currentWebViewController = currentWebViewController {
if currentWebViewController.isFullScreenAvailable {
let fullScreenAction = UIAction(title: NSLocalizedString("Full Screen", comment: "Full Screen"),
image: UIImage(systemName: "arrow.up.backward.and.arrow.down.forward"),
identifier: nil,
discoverabilityTitle: nil,
attributes: [],
state: .off) { [weak self] _ in
self?.currentWebViewController?.hideBars()
}
fullScreenAction.subtitle = NSLocalizedString("Tap the top of the screen to exit Full Screen.", comment: "Exit criteria.")
children.append(fullScreenAction)
}
}
let appearanceMenu = UIMenu(title: NSLocalizedString("Article Appearance", comment: "Appearance"), image: UIImage(systemName: "textformat.size") , identifier: nil, options: .displayInline, children: children)
appearanceBarButtonItem.menu = appearanceMenu
}
@objc
func reloadDueToThemeChange(_ notification: Notification) {
currentWebViewController?.fullReload()
configureAppearanceMenu()
}
// MARK: Notifications
@objc dynamic func unreadCountDidChange(_ notification: Notification) {
@@ -235,7 +304,7 @@ class ArticleViewController: UIViewController {
updateUI()
}
}
@objc func contentSizeCategoryDidChange(_ note: Notification) {
currentWebViewController?.fullReload()
}
@@ -248,15 +317,11 @@ class ArticleViewController: UIViewController {
}
// MARK: Actions
@objc func didTapNavigationBar() {
currentWebViewController?.hideBars()
}
@objc func showBars(_ sender: Any) {
currentWebViewController?.showBars()
}
@IBAction func toggleArticleExtractor(_ sender: Any) {
currentWebViewController?.toggleArticleExtractor()
}
@@ -284,35 +349,35 @@ class ArticleViewController: UIViewController {
@IBAction func showActivityDialog(_ sender: Any) {
currentWebViewController?.showActivityDialog(popOverBarButtonItem: actionBarButtonItem)
}
@objc func toggleReaderView(_ sender: Any?) {
currentWebViewController?.toggleArticleExtractor()
}
// MARK: Keyboard Shortcuts
@objc func navigateToTimeline(_ sender: Any?) {
coordinator.navigateToTimeline()
}
// MARK: API
func focus() {
currentWebViewController?.focus()
}
func canScrollDown() -> Bool {
return currentWebViewController?.canScrollDown() ?? false
}
func canScrollUp() -> Bool {
return currentWebViewController?.canScrollUp() ?? false
}
func scrollPageDown() {
currentWebViewController?.scrollPageDown()
}
func scrollPageUp() {
currentWebViewController?.scrollPageUp()
}
@@ -320,7 +385,7 @@ class ArticleViewController: UIViewController {
func stopArticleExtractorIfProcessing() {
currentWebViewController?.stopArticleExtractorIfProcessing()
}
func openInAppBrowser() {
currentWebViewController?.openInAppBrowser()
}
@@ -387,9 +452,9 @@ extension ArticleViewController {
@objc func keyboardWillChangeFrame(_ notification: Notification) {
if !searchBar.isHidden,
let duration = notification.userInfo?[UIWindow.keyboardAnimationDurationUserInfoKey] as? Double,
let curveRaw = notification.userInfo?[UIWindow.keyboardAnimationCurveUserInfoKey] as? UInt,
let frame = notification.userInfo?[UIWindow.keyboardFrameEndUserInfoKey] as? CGRect {
let duration = notification.userInfo?[UIWindow.keyboardAnimationDurationUserInfoKey] as? Double,
let curveRaw = notification.userInfo?[UIWindow.keyboardAnimationCurveUserInfoKey] as? UInt,
let frame = notification.userInfo?[UIWindow.keyboardFrameEndUserInfoKey] as? CGRect {
let curve = UIView.AnimationOptions(rawValue: curveRaw)
let newHeight = view.safeAreaLayoutGuide.layoutFrame.maxY - frame.minY
@@ -422,19 +487,19 @@ extension ArticleViewController: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let webViewController = viewController as? WebViewController,
let currentArticle = webViewController.article,
let article = coordinator.findPrevArticle(currentArticle) else {
return nil
}
let currentArticle = webViewController.article,
let article = coordinator.findPrevArticle(currentArticle) else {
return nil
}
return createWebViewController(article)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let webViewController = viewController as? WebViewController,
let currentArticle = webViewController.article,
let article = coordinator.findNextArticle(currentArticle) else {
return nil
}
let currentArticle = webViewController.article,
let article = coordinator.findNextArticle(currentArticle) else {
return nil
}
return createWebViewController(article)
}
@@ -443,7 +508,7 @@ extension ArticleViewController: UIPageViewControllerDataSource {
// MARK: UIPageViewControllerDelegate
extension ArticleViewController: UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
guard finished, completed else { return }
guard let article = currentWebViewController?.article else { return }
@@ -460,17 +525,17 @@ extension ArticleViewController: UIPageViewControllerDelegate {
extension ArticleViewController: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
let point = gestureRecognizer.location(in: nil)
if point.x > 40 {
return true
}
return false
}
}
}

View File

@@ -19,8 +19,8 @@ class PreloadedWebView: WKWebView {
preferences.javaScriptCanOpenWindowsAutomatically = false
/// The defaults for `preferredContentMode` and `allowsContentJavaScript` are suitable
/// and don't need to be explicity set.
/// `allowsContentJavaScript` replaces `WKPreferences.javascriptEnbaled`.
/// and don't need to be explicitly set.
/// `allowsContentJavaScript` replaces `WKPreferences.javascriptEnabled`.
let webpagePreferences = WKWebpagePreferences()
let configuration = WKWebViewConfiguration()

View File

@@ -31,13 +31,13 @@ class WebViewController: UIViewController {
private var topShowBarsViewConstraint: NSLayoutConstraint!
private var bottomShowBarsViewConstraint: NSLayoutConstraint!
private var webView: PreloadedWebView? {
var webView: PreloadedWebView? {
return view.subviews[0] as? PreloadedWebView
}
private lazy var contextMenuInteraction = UIContextMenuInteraction(delegate: self)
private var isFullScreenAvailable: Bool {
return AppDefaults.shared.articleFullscreenAvailable && traitCollection.userInterfaceIdiom == .phone && coordinator.isRootSplitCollapsed
public var isFullScreenAvailable: Bool {
return traitCollection.userInterfaceIdiom == .phone && coordinator.isRootSplitCollapsed
}
private lazy var transition = ImageTransition(controller: self)
private var clickedImageCompletion: (() -> Void)?

View File

@@ -1,5 +1,5 @@
<?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">
<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="AJQ-jq-uMa">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
@@ -17,7 +17,7 @@
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="h1Q-FS-jlg" customClass="ArticleSearchBar" customModule="NetNewsWire" customModuleProvider="target">
<view hidden="YES" contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="h1Q-FS-jlg" customClass="ArticleSearchBar" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="0.0" y="782" width="414" height="31"/>
<color key="backgroundColor" name="barBackgroundColor"/>
</view>
@@ -90,12 +90,18 @@
<action selector="prevArticle:" destination="JEX-9P-axG" id="cMZ-tk-I4W"/>
</connections>
</barButtonItem>
<barButtonItem image="textformat.size" catalog="system" id="SoN-ax-tEE">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accLabelText" value="Appearance"/>
</userDefinedRuntimeAttributes>
</barButtonItem>
</rightBarButtonItems>
</navigationItem>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
<connections>
<outlet property="actionBarButtonItem" destination="9Ut-5B-JKP" id="9bO-kz-cTz"/>
<outlet property="appearanceBarButtonItem" destination="SoN-ax-tEE" id="UZr-ut-0fn"/>
<outlet property="nextArticleBarButtonItem" destination="2qz-M5-Yhk" id="IQd-jx-qEr"/>
<outlet property="nextUnreadBarButtonItem" destination="2w5-e9-C2V" id="Ekf-My-AHN"/>
<outlet property="prevArticleBarButtonItem" destination="v4j-fq-23N" id="Gny-Oh-cQa"/>
@@ -107,7 +113,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="FJe-Yq-33r" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2318.840579710145" y="-759.375"/>
<point key="canvasLocation" x="451" y="-431"/>
</scene>
<!--Timeline-->
<scene sceneID="fag-XH-avP">
@@ -153,12 +159,26 @@
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="nzm-Gf-Xce" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1620" y="-759"/>
<point key="canvasLocation" x="451" y="-1124"/>
</scene>
<!--Root Split View Controller-->
<scene sceneID="FfI-oe-67h">
<objects>
<splitViewController storyboardIdentifier="RootSplitViewController" allowDoubleColumnStyle="YES" preferredDisplayMode="twoBeside" id="AJQ-jq-uMa" customClass="RootSplitViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
<connections>
<segue destination="Kyk-vK-QRX" kind="relationship" relationship="supplementaryViewController" id="FW6-KM-3C4"/>
<segue destination="JEX-9P-axG" kind="relationship" relationship="detailViewController" id="JbU-kn-u7r"/>
<segue destination="7bK-jq-Zjz" kind="relationship" relationship="masterViewController" id="rFx-mT-r7a"/>
</connections>
</splitViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="9SW-km-PuE" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1320" y="-1123"/>
</scene>
<!--Feeds-->
<scene sceneID="smW-Zh-WAh">
<objects>
<tableViewController storyboardIdentifier="MasterFeedViewController" useStoryboardIdentifierAsRestorationIdentifier="YES" clearsSelectionOnViewWillAppear="NO" id="7bK-jq-Zjz" customClass="MasterFeedViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
<tableViewController storyboardIdentifier="MasterFeedViewController" extendedLayoutIncludesOpaqueBars="YES" useStoryboardIdentifierAsRestorationIdentifier="YES" clearsSelectionOnViewWillAppear="NO" id="7bK-jq-Zjz" customClass="MasterFeedViewController" customModule="NetNewsWire" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" sectionFooterHeight="18" id="r7i-6Z-zg0">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
@@ -216,7 +236,7 @@
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Rux-fX-hf1" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="900" y="-759"/>
<point key="canvasLocation" x="452" y="-1794"/>
</scene>
<!--Image View Controller-->
<scene sceneID="TT4-oA-DBw">
@@ -407,6 +427,7 @@
<image name="square.and.arrow.up" catalog="system" width="115" height="128"/>
<image name="square.and.arrow.up.fill" catalog="system" width="115" height="128"/>
<image name="star" catalog="system" width="128" height="116"/>
<image name="textformat.size" catalog="system" width="128" height="80"/>
<namedColor name="barBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</namedColor>

View File

@@ -47,7 +47,11 @@ class KeyboardManager {
static func createKeyCommand(title: String, action: String, input: String, modifiers: UIKeyModifierFlags) -> UIKeyCommand {
let selector = NSSelectorFromString(action)
return UIKeyCommand(title: title, image: nil, action: selector, input: input, modifierFlags: modifiers, propertyList: nil, alternates: [], discoverabilityTitle: nil, attributes: [], state: .on)
let keyCommand = UIKeyCommand(title: title, image: nil, action: selector, input: input, modifierFlags: modifiers, propertyList: nil, alternates: [], discoverabilityTitle: nil, attributes: [], state: .on)
if #available(iOS 15.0, *) {
keyCommand.wantsPriorityOverSystemBehavior = true
}
return keyCommand
}
}
@@ -62,7 +66,11 @@ private extension KeyboardManager {
if let title = keyEntry["title"] as? String {
return KeyboardManager.createKeyCommand(title: title, action: action, input: input, modifiers: modifiers)
} else {
return UIKeyCommand(input: input, modifierFlags: modifiers, action: NSSelectorFromString(action))
let keyCommand = UIKeyCommand(input: input, modifierFlags: modifiers, action: NSSelectorFromString(action))
if #available(iOS 15.0, *) {
keyCommand.wantsPriorityOverSystemBehavior = true
}
return keyCommand
}
}

View File

@@ -44,7 +44,7 @@ struct MasterFeedTableViewCellLayout {
var rDisclosure = CGRect.zero
if shouldShowDisclosure {
rDisclosure.size = MasterFeedTableViewCellLayout.disclosureButtonSize
rDisclosure.origin.x = bounds.origin.x
rDisclosure.origin.x = insets.left
}
// Favicon
@@ -73,7 +73,7 @@ struct MasterFeedTableViewCellLayout {
}
// Title
var rLabelx = MasterFeedTableViewCellLayout.disclosureButtonSize.width
var rLabelx = MasterFeedTableViewCellLayout.disclosureButtonSize.width + insets.left
if itemIsInFolder {
rLabelx += MasterFeedTableViewCellLayout.disclosureButtonSize.width - (rFavicon.width / 2)
}

View File

@@ -62,8 +62,6 @@ class MasterFeedTableViewSectionHeader: UITableViewHeaderFooterView {
return label
}()
private let unreadCountView = MasterFeedUnreadCountView(frame: CGRect.zero)
private lazy var disclosureButton: UIButton = {
let button = NonIntrinsicButton()
button.tintColor = AppAssets.secondaryAccentColor
@@ -97,7 +95,7 @@ class MasterFeedTableViewSectionHeader: UITableViewHeaderFooterView {
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
let layout = MasterFeedTableViewSectionHeaderLayout(cellWidth: size.width, insets: safeAreaInsets, label: titleView, unreadCountView: unreadCountView)
let layout = MasterFeedTableViewSectionHeaderLayout(cellWidth: size.width, insets: safeAreaInsets, label: titleView)
return CGSize(width: bounds.width, height: layout.height)
}
@@ -106,8 +104,7 @@ class MasterFeedTableViewSectionHeader: UITableViewHeaderFooterView {
super.layoutSubviews()
let layout = MasterFeedTableViewSectionHeaderLayout(cellWidth: contentView.bounds.size.width,
insets: contentView.safeAreaInsets,
label: titleView,
unreadCountView: unreadCountView)
label: titleView)
layoutWith(layout)
}
@@ -157,7 +154,6 @@ private extension MasterFeedTableViewSectionHeader {
func layoutWith(_ layout: MasterFeedTableViewSectionHeaderLayout) {
titleView.setFrameIfNotEqual(layout.titleRect)
unreadCountView.setFrameIfNotEqual(layout.unreadCountRect)
disclosureButton.setFrameIfNotEqual(layout.disclosureButtonRect)
let top = CGRect(x: safeAreaInsets.left, y: 0, width: frame.width - safeAreaInsets.right - safeAreaInsets.left, height: 0.33)

View File

@@ -12,19 +12,17 @@ import RSCore
struct MasterFeedTableViewSectionHeaderLayout {
private static let labelMarginRight = CGFloat(integerLiteral: 8)
private static let unreadCountMarginRight = CGFloat(integerLiteral: 0)
private static let disclosureButtonSize = CGSize(width: 44, height: 44)
private static let verticalPadding = CGFloat(integerLiteral: 11)
private static let minRowHeight = CGFloat(integerLiteral: 44)
let titleRect: CGRect
let unreadCountRect: CGRect
let disclosureButtonRect: CGRect
let height: CGFloat
init(cellWidth: CGFloat, insets: UIEdgeInsets, label: UILabel, unreadCountView: MasterFeedUnreadCountView) {
init(cellWidth: CGFloat, insets: UIEdgeInsets, label: UILabel) {
let bounds = CGRect(x: insets.left, y: 0.0, width: floor(cellWidth - insets.right), height: 0.0)
@@ -33,35 +31,20 @@ struct MasterFeedTableViewSectionHeaderLayout {
rDisclosure.size = MasterFeedTableViewSectionHeaderLayout.disclosureButtonSize
rDisclosure.origin.x = bounds.maxX - rDisclosure.size.width
// Unread Count
let unreadCountSize = unreadCountView.contentSize
let unreadCountIsHidden = unreadCountView.unreadCount < 1
var rUnread = CGRect.zero
if !unreadCountIsHidden {
rUnread.size = unreadCountSize
rUnread.origin.x = bounds.maxX - (MasterFeedTableViewSectionHeaderLayout.unreadCountMarginRight + unreadCountSize.width + rDisclosure.size.width)
}
// Max Unread Count
// We can't reload Section Headers so we don't let the title extend into the (probably) worse case Unread Count area.
let maxUnreadCountView = MasterFeedUnreadCountView(frame: CGRect.zero)
maxUnreadCountView.unreadCount = 888
let maxUnreadCountSize = maxUnreadCountView.contentSize
// Title
let rLabelx = 15.0
let rLabely = UIFontMetrics.default.scaledValue(for: MasterFeedTableViewSectionHeaderLayout.verticalPadding)
var labelWidth = CGFloat.zero
labelWidth = cellWidth - (rLabelx + MasterFeedTableViewSectionHeaderLayout.labelMarginRight + maxUnreadCountSize.width + MasterFeedTableViewSectionHeaderLayout.unreadCountMarginRight)
labelWidth = cellWidth - (rLabelx + MasterFeedTableViewSectionHeaderLayout.labelMarginRight)
let labelSizeInfo = MultilineUILabelSizer.size(for: label.text ?? "", font: label.font, numberOfLines: 0, width: Int(floor(labelWidth)))
var rLabel = CGRect(x: rLabelx, y: rLabely, width: labelWidth, height: labelSizeInfo.size.height)
// Determine cell height
let paddedLabelHeight = rLabel.maxY + UIFontMetrics.default.scaledValue(for: MasterFeedTableViewSectionHeaderLayout.verticalPadding)
let maxGraphicsHeight = [rUnread, rDisclosure].maxY()
let maxGraphicsHeight = [rDisclosure].maxY()
var cellHeight = max(paddedLabelHeight, maxGraphicsHeight)
if cellHeight < MasterFeedTableViewSectionHeaderLayout.minRowHeight {
cellHeight = MasterFeedTableViewSectionHeaderLayout.minRowHeight
@@ -69,9 +52,6 @@ struct MasterFeedTableViewSectionHeaderLayout {
// Center in Cell
let newBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.width, height: cellHeight)
if !unreadCountIsHidden {
rUnread = MasterFeedTableViewCellLayout.centerVertically(rUnread, newBounds)
}
rDisclosure = MasterFeedTableViewCellLayout.centerVertically(rDisclosure, newBounds)
// Small fonts need centered if we hit the minimum row height
@@ -81,7 +61,6 @@ struct MasterFeedTableViewSectionHeaderLayout {
// Assign the properties
self.height = cellHeight
self.unreadCountRect = rUnread
self.disclosureButtonRect = rDisclosure
self.titleRect = rLabel

View File

@@ -13,7 +13,7 @@ import RSCore
import RSTree
import SafariServices
class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
class MasterFeedViewController: UITableViewController, UndoableCommandRunner, MainControllerIdentifiable {
@IBOutlet weak var filterButton: UIBarButtonItem!
private var refreshProgressView: RefreshProgressView?
@@ -23,9 +23,11 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
}
}
var undoableCommands = [UndoableCommand]()
weak var coordinator: SceneCoordinator!
var mainControllerIdentifer = MainControllerIdentifier.masterFeed
weak var coordinator: SceneCoordinator!
var undoableCommands = [UndoableCommand]()
private let keyboardManager = KeyboardManager(type: .sidebar)
override var keyCommands: [UIKeyCommand]? {
@@ -78,6 +80,7 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
}
override func viewWillAppear(_ animated: Bool) {
navigationController?.isToolbarHidden = false
updateUI()
super.viewWillAppear(animated)
}

View File

@@ -27,8 +27,9 @@ struct MasterTimelineCellData {
let starred: Bool
let numberOfLines: Int
let iconSize: IconSize
init(article: Article, showFeedName: ShowFeedName, feedName: String?, byline: String?, iconImage: IconImage?, showIcon: Bool, featuredImage: UIImage?, numberOfLines: Int, iconSize: IconSize) {
let hideSeparator: Bool
init(article: Article, showFeedName: ShowFeedName, feedName: String?, byline: String?, iconImage: IconImage?, showIcon: Bool, featuredImage: UIImage?, numberOfLines: Int, iconSize: IconSize, hideSeparator: Bool) {
self.title = ArticleStringFormatter.truncatedTitle(article)
self.attributedTitle = ArticleStringFormatter.attributedTruncatedTitle(article)
@@ -65,6 +66,7 @@ struct MasterTimelineCellData {
self.starred = article.status.starred
self.numberOfLines = numberOfLines
self.iconSize = iconSize
self.hideSeparator = hideSeparator
}
@@ -83,6 +85,7 @@ struct MasterTimelineCellData {
self.starred = false
self.numberOfLines = 0
self.iconSize = .medium
self.hideSeparator = false
}
}

View File

@@ -82,7 +82,6 @@ class MasterTimelineTableViewCell: VibrantTableViewCell {
}
override func layoutSubviews() {
super.layoutSubviews()
let layout = updatedLayout(width: bounds.width)
@@ -94,8 +93,6 @@ class MasterTimelineTableViewCell: VibrantTableViewCell {
setFrame(for: summaryView, rect: layout.summaryRect)
feedNameView.setFrameIfNotEqual(layout.feedNameRect)
dateView.setFrameIfNotEqual(layout.dateRect)
separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
func setIconImage(_ image: IconImage) {
@@ -272,6 +269,14 @@ private extension MasterTimelineTableViewCell {
accessibilityLabel = label
}
func updateSeparator() {
if cellData?.hideSeparator ?? false {
separatorInset = UIEdgeInsets(top: 0, left: bounds.width + 1, bottom: 0, right: 0)
} else {
separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
}
func makeIconEmpty() {
if iconView.iconImage != nil {
iconView.iconImage = nil
@@ -305,6 +310,7 @@ private extension MasterTimelineTableViewCell {
updateStarView()
updateIconImage()
updateAccessiblityLabel()
updateSeparator()
}
}

View File

@@ -11,22 +11,25 @@ import RSCore
import Account
import Articles
class MasterTimelineViewController: UITableViewController, UndoableCommandRunner {
class MasterTimelineViewController: UITableViewController, UndoableCommandRunner, MainControllerIdentifiable {
private var numberOfTextLines = 0
private var iconSize = IconSize.medium
private lazy var feedTapGestureRecognizer = UITapGestureRecognizer(target: self, action:#selector(showFeedInspector(_:)))
private var refreshProgressView: RefreshProgressView?
private var filterButton: UIBarButtonItem!
@IBOutlet weak var markAllAsReadButton: UIBarButtonItem!
private var filterButton: UIBarButtonItem!
private var refreshProgressView: RefreshProgressView!
private var refreshProgressItemButton: UIBarButtonItem!
private var firstUnreadButton: UIBarButtonItem!
private lazy var dataSource = makeDataSource()
private let searchController = UISearchController(searchResultsController: nil)
var mainControllerIdentifer = MainControllerIdentifier.masterTimeline
weak var coordinator: SceneCoordinator!
var undoableCommands = [UndoableCommand]()
let scrollPositionQueue = CoalescingQueue(name: "Timeline Scroll Position", interval: 0.3, maxInterval: 1.0)
@@ -79,6 +82,9 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
// Configure the table
tableView.dataSource = dataSource
if #available(iOS 15.0, *) {
tableView.isPrefetchingEnabled = false
}
numberOfTextLines = AppDefaults.shared.timelineNumberOfLines
iconSize = AppDefaults.shared.timelineIconSize
resetEstimatedRowHeight()
@@ -89,8 +95,13 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
refreshControl = UIRefreshControl()
refreshControl!.addTarget(self, action: #selector(refreshAccounts(_:)), for: .valueChanged)
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
@@ -109,15 +120,18 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
}
override func viewWillAppear(_ animated: Bool) {
navigationController?.isToolbarHidden = false
// If the nav bar is hidden, fade it in to avoid it showing stuff as it is getting laid out
if navigationController?.navigationBar.isHidden ?? false {
navigationController?.navigationBar.alpha = 0
}
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
coordinator.isTimelineViewControllerPending = false
if navigationController?.navigationBar.alpha == 0 {
UIView.animate(withDuration: 0.5) {
@@ -436,7 +450,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
for article in visibleUpdatedArticles {
if let indexPath = dataSource.indexPath(for: article) {
if let cell = tableView.cellForRow(at: indexPath) as? MasterTimelineTableViewCell {
configure(cell, article: article)
configure(cell, article: article, indexPath: indexPath)
}
}
}
@@ -523,7 +537,8 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
}
@objc private func reloadAllVisibleCells() {
reconfigureCells(coordinator.articles)
let visibleArticles = tableView.indexPathsForVisibleRows!.compactMap { return dataSource.itemIdentifier(for: $0) }
reloadCells(visibleArticles)
}
private func reloadCells(_ articles: [Article]) {
@@ -534,15 +549,6 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
}
}
private func reconfigureCells(_ articles: [Article]) {
guard #available(iOS 15, *) else { return }
var snapshot = dataSource.snapshot()
snapshot.reconfigureItems(articles)
dataSource.apply(snapshot, animatingDifferences: false) { [weak self] in
self?.restoreSelectionIfNecessary(adjustScroll: false)
}
}
// MARK: Cell Configuring
private func resetEstimatedRowHeight() {
@@ -553,7 +559,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
let status = ArticleStatus(articleID: prototypeID, read: false, starred: false, dateArrived: Date())
let prototypeArticle = Article(accountID: prototypeID, articleID: prototypeID, webFeedID: prototypeID, uniqueID: prototypeID, title: longTitle, contentHTML: nil, contentText: nil, url: nil, externalURL: nil, summary: nil, imageURL: nil, datePublished: nil, dateModified: nil, authors: nil, status: status)
let prototypeCellData = MasterTimelineCellData(article: prototypeArticle, showFeedName: .feed, feedName: "Prototype Feed Name", byline: nil, iconImage: nil, showIcon: false, featuredImage: nil, numberOfLines: numberOfTextLines, iconSize: iconSize)
let prototypeCellData = MasterTimelineCellData(article: prototypeArticle, showFeedName: .feed, feedName: "Prototype Feed Name", byline: nil, iconImage: nil, showIcon: false, featuredImage: nil, numberOfLines: numberOfTextLines, iconSize: iconSize, hideSeparator: false)
if UIApplication.shared.preferredContentSizeCategory.isAccessibilityCategory {
let layout = MasterTimelineAccessibilityCellLayout(width: tableView.bounds.width, insets: tableView.safeAreaInsets, cellData: prototypeCellData)
@@ -603,9 +609,8 @@ extension MasterTimelineViewController: UISearchBarDelegate {
private extension MasterTimelineViewController {
func configureToolbar() {
guard !coordinator.isThreePanelMode else {
func configureToolbar() {
guard splitViewController?.isCollapsed ?? true else {
return
}
@@ -679,16 +684,9 @@ private extension MasterTimelineViewController {
firstUnreadButton.isEnabled = coordinator.isTimelineUnreadAvailable
if coordinator.isRootSplitCollapsed {
if let toolbarItems = toolbarItems, toolbarItems.last != firstUnreadButton {
var items = toolbarItems
items.append(firstUnreadButton)
setToolbarItems(items, animated: false)
}
setToolbarItems([markAllAsReadButton, .flexibleSpace(), refreshProgressItemButton, .flexibleSpace(), firstUnreadButton], animated: false)
} else {
if let toolbarItems = toolbarItems, toolbarItems.last == firstUnreadButton {
let items = Array(toolbarItems[0..<toolbarItems.count - 1])
setToolbarItems(items, animated: false)
}
setToolbarItems([markAllAsReadButton, .flexibleSpace()], animated: false)
}
}
@@ -719,22 +717,23 @@ private extension MasterTimelineViewController {
let dataSource: UITableViewDiffableDataSource<Int, Article> =
MasterTimelineDataSource(tableView: tableView, cellProvider: { [weak self] tableView, indexPath, article in
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MasterTimelineTableViewCell
self?.configure(cell, article: article)
self?.configure(cell, article: article, indexPath: indexPath)
return cell
})
dataSource.defaultRowAnimation = .middle
return dataSource
}
func configure(_ cell: MasterTimelineTableViewCell, article: Article) {
func configure(_ cell: MasterTimelineTableViewCell, article: Article, indexPath: IndexPath) {
let iconImage = iconImageFor(article)
let featuredImage = featuredImageFor(article)
let showFeedNames = coordinator.showFeedNames
let showIcon = coordinator.showIcons && iconImage != nil
cell.cellData = MasterTimelineCellData(article: article, showFeedName: showFeedNames, feedName: article.webFeed?.nameForDisplay, byline: article.byline(), iconImage: iconImage, showIcon: showIcon, featuredImage: featuredImage, numberOfLines: numberOfTextLines, iconSize: iconSize)
let hideSeparater = indexPath.row == coordinator.articles.count - 1
cell.cellData = MasterTimelineCellData(article: article, showFeedName: showFeedNames, feedName: article.webFeed?.nameForDisplay, byline: article.byline(), iconImage: iconImage, showIcon: showIcon, featuredImage: featuredImage, numberOfLines: numberOfTextLines, iconSize: iconSize, hideSeparator: hideSeparater)
}
func iconImageFor(_ article: Article) -> IconImage? {

View File

@@ -204,6 +204,8 @@
</array>
<key>CFBundleTypeName</key>
<string>NetNewsWire Theme</string>
<key>LSHandlerRank</key>
<string>Owner</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSItemContentTypes</key>

View File

@@ -25,11 +25,6 @@ class RootSplitViewController: UISplitViewController {
coordinator.resetFocus()
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
self.coordinator.configurePanelMode(for: size)
super.viewWillTransition(to: size, with: coordinator)
}
// MARK: Keyboard Shortcuts
@objc func scrollOrGoToNextUnread(_ sender: Any?) {

View File

@@ -14,10 +14,15 @@ import RSCore
import RSTree
import SafariServices
enum PanelMode {
case unset
case three
case standard
protocol MainControllerIdentifiable {
var mainControllerIdentifer: MainControllerIdentifier { get }
}
enum MainControllerIdentifier {
case none
case masterFeed
case masterTimeline
case article
}
enum SearchScope: Int {
@@ -54,34 +59,15 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
lazy var webViewProvider = WebViewProvider(coordinator: self)
private var panelMode: PanelMode = .unset
private var activityManager = ActivityManager()
private var rootSplitViewController: RootSplitViewController!
private var masterNavigationController: UINavigationController!
private var masterFeedViewController: MasterFeedViewController!
private var masterTimelineViewController: MasterTimelineViewController?
private var subSplitViewController: UISplitViewController?
private var articleViewController: ArticleViewController? {
if let detail = masterNavigationController.viewControllers.last as? ArticleViewController {
return detail
}
if let subSplit = subSplitViewController {
if let navController = subSplit.viewControllers.last as? UINavigationController {
return navController.topViewController as? ArticleViewController
}
} else {
if let navController = rootSplitViewController.viewControllers.last as? UINavigationController {
return navController.topViewController as? ArticleViewController
}
}
return nil
}
private var wasRootSplitViewControllerCollapsed = false
private var articleViewController: ArticleViewController?
private var lastMainControllerToAppear = MainControllerIdentifier.none
private let fetchAndMergeArticlesQueue = CoalescingQueue(name: "Fetch and Merge Articles", interval: 0.5)
private let rebuildBackingStoresQueue = CoalescingQueue(name: "Rebuild The Backing Stores", interval: 0.5)
private var fetchSerialNumber = 0
@@ -98,9 +84,6 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
private var savedSearchArticles: ArticleArray? = nil
private var savedSearchArticleIds: Set<String>? = nil
var isTimelineViewControllerPending = false
var isArticleViewControllerPending = false
private(set) var sortDirection = AppDefaults.shared.timelineSortDirection {
didSet {
if sortDirection != oldValue {
@@ -140,10 +123,6 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
return rootSplitViewController.isCollapsed
}
var isThreePanelMode: Bool {
return panelMode == .three
}
var isReadFeedsFiltered: Bool {
return treeControllerDelegate.isReadFiltered
}
@@ -294,11 +273,32 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
var timelineUnreadCount: Int = 0
override init() {
treeController = TreeController(delegate: treeControllerDelegate)
init(rootSplitViewController: RootSplitViewController) {
self.rootSplitViewController = rootSplitViewController
self.treeController = TreeController(delegate: treeControllerDelegate)
super.init()
self.masterFeedViewController = rootSplitViewController.viewController(for: .primary) as? MasterFeedViewController
self.masterFeedViewController.coordinator = self
if let navController = self.masterFeedViewController?.navigationController {
navController.delegate = self
configureNavigationController(navController)
}
self.masterTimelineViewController = rootSplitViewController.viewController(for: .supplementary) as? MasterTimelineViewController
self.masterTimelineViewController?.coordinator = 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]()))
@@ -321,30 +321,6 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
NotificationCenter.default.addObserver(self, selector: #selector(themeDownloadDidFail(_:)), name: .didFailToImportThemeWithError, object: nil)
}
func start(for size: CGSize) -> UIViewController {
rootSplitViewController = RootSplitViewController()
rootSplitViewController.coordinator = self
rootSplitViewController.preferredDisplayMode = .oneBesideSecondary
rootSplitViewController.viewControllers = [InteractiveNavigationController.template()]
rootSplitViewController.delegate = self
masterNavigationController = (rootSplitViewController.viewControllers.first as! UINavigationController)
masterNavigationController.delegate = self
masterFeedViewController = UIStoryboard.main.instantiateController(ofType: MasterFeedViewController.self)
masterFeedViewController.coordinator = self
masterNavigationController.pushViewController(masterFeedViewController, animated: false)
let articleViewController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self)
articleViewController.coordinator = self
let detailNavigationController = addNavControllerIfNecessary(articleViewController, showButton: true)
rootSplitViewController.showDetailViewController(detailNavigationController, sender: self)
configurePanelMode(for: size)
return rootSplitViewController
}
func restoreWindowState(_ activity: NSUserActivity?) {
if let activity = activity, let windowState = activity.userInfo?[UserInfoKey.windowState] as? [AnyHashable: Any] {
@@ -399,26 +375,6 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
handleReadArticle(userInfo)
}
func configurePanelMode(for size: CGSize) {
guard rootSplitViewController.traitCollection.userInterfaceIdiom == .pad else {
return
}
if (size.width / size.height) > 1.2 {
if panelMode == .unset || panelMode == .standard {
panelMode = .three
configureThreePanelMode()
}
} else {
if panelMode == .unset || panelMode == .three {
panelMode = .standard
configureStandardPanelMode()
}
}
wasRootSplitViewControllerCollapsed = rootSplitViewController.isCollapsed
}
func resetFocus() {
if currentArticle != nil {
masterTimelineViewController?.focus()
@@ -438,7 +394,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
func showSearch() {
selectFeed(indexPath: nil) {
self.installTimelineControllerIfNecessary(animated: false)
self.rootSplitViewController.show(.supplementary)
DispatchQueue.main.asyncAfter(deadline: .now()) {
self.masterTimelineViewController!.showSearchAll()
}
@@ -793,7 +749,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
if let ip = indexPath, let node = nodeFor(ip), let feed = node.representedObject as? Feed {
self.activityManager.selecting(feed: feed)
self.installTimelineControllerIfNecessary(animated: animations.contains(.navigation))
self.rootSplitViewController.show(.supplementary)
setTimelineFeed(feed, animated: false) {
if self.isReadFeedsFiltered {
self.rebuildBackingStores()
@@ -808,9 +764,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
self.rebuildBackingStores()
}
self.activityManager.invalidateSelecting()
if self.rootSplitViewController.isCollapsed && self.navControllerForTimeline().viewControllers.last is MasterTimelineViewController {
self.navControllerForTimeline().popViewController(animated: animations.contains(.navigation))
}
self.rootSplitViewController.show(.primary)
completion?()
}
@@ -858,31 +812,21 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
activityManager.reading(feed: timelineFeed, article: article)
if article == nil {
if rootSplitViewController.isCollapsed {
if masterNavigationController.children.last is ArticleViewController {
masterNavigationController.popViewController(animated: animations.contains(.navigation))
}
} else {
articleViewController?.article = nil
}
rootSplitViewController.show(.supplementary)
masterTimelineViewController?.updateArticleSelection(animations: animations)
articleViewController?.article = nil
return
}
let currentArticleViewController: ArticleViewController
if articleViewController == nil {
currentArticleViewController = installArticleController(animated: animations.contains(.navigation))
} else {
currentArticleViewController = articleViewController!
}
rootSplitViewController.show(.secondary)
// Mark article as read before navigating to it, so the read status does not flash unread/read on display
markArticles(Set([article!]), statusKey: .read, flag: true)
masterTimelineViewController?.updateArticleSelection(animations: animations)
currentArticleViewController.article = article
articleViewController?.article = article
if let isShowingExtractedArticle = isShowingExtractedArticle, let articleWindowScrollY = articleWindowScrollY {
currentArticleViewController.restoreScrollPosition = (isShowingExtractedArticle, articleWindowScrollY)
articleViewController?.restoreScrollPosition = (isShowingExtractedArticle, articleWindowScrollY)
}
}
@@ -1029,7 +973,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
func markAllAsReadInTimeline(completion: (() -> Void)? = nil) {
markAllAsRead(articles) {
self.masterNavigationController.popViewController(animated: true)
self.rootSplitViewController.show(.primary)
completion?()
}
}
@@ -1339,45 +1283,28 @@ class SceneCoordinator: NSObject, UndoableCommandRunner {
// MARK: UISplitViewControllerDelegate
extension SceneCoordinator: UISplitViewControllerDelegate {
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
masterTimelineViewController?.updateUI()
guard !isThreePanelMode else {
return true
}
if let articleViewController = (secondaryViewController as? UINavigationController)?.topViewController as? ArticleViewController {
if currentArticle != nil {
masterNavigationController.pushViewController(articleViewController, animated: false)
}
}
return true
}
func splitViewController(_ splitViewController: UISplitViewController, separateSecondaryFrom primaryViewController: UIViewController) -> UIViewController? {
masterTimelineViewController?.updateUI()
guard !isThreePanelMode else {
return subSplitViewController
func splitViewController(_ svc: UISplitViewController, topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column) -> UISplitViewController.Column {
switch proposedTopColumn {
case .supplementary:
if currentFeedIndexPath != nil {
return .supplementary
} else {
return .primary
}
case .secondary:
if currentArticle != nil {
return .secondary
} else {
if currentFeedIndexPath != nil {
return .supplementary
} else {
return .primary
}
}
default:
return .primary
}
if let articleViewController = masterNavigationController.viewControllers.last as? ArticleViewController {
articleViewController.showBars(self)
masterNavigationController.popViewController(animated: false)
let controller = addNavControllerIfNecessary(articleViewController, showButton: true)
return controller
}
if currentArticle == nil {
let articleViewController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self)
articleViewController.coordinator = self
let controller = addNavControllerIfNecessary(articleViewController, showButton: true)
return controller
}
return nil
}
}
@@ -1387,13 +1314,24 @@ extension SceneCoordinator: UISplitViewControllerDelegate {
extension SceneCoordinator: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
guard UIApplication.shared.applicationState != .background else {
return
}
if UIApplication.shared.applicationState == .background {
guard rootSplitViewController.isCollapsed else {
return
}
defer {
if let mainController = viewController as? MainControllerIdentifiable {
lastMainControllerToAppear = mainController.mainControllerIdentifer
} else if let mainController = (viewController as? UINavigationController)?.topViewController as? MainControllerIdentifiable {
lastMainControllerToAppear = mainController.mainControllerIdentifer
}
}
// If we are showing the Feeds and only the feeds start clearing stuff
if viewController === masterFeedViewController && !isThreePanelMode && !isTimelineViewControllerPending {
if viewController === masterFeedViewController && lastMainControllerToAppear == .masterTimeline {
activityManager.invalidateCurrentActivities()
selectFeed(nil, animations: [.scroll, .select, .navigation])
return
@@ -1403,25 +1341,51 @@ extension SceneCoordinator: UINavigationControllerDelegate {
// Don't clear it if we have pushed an ArticleViewController, but don't yet see it on the navigation stack.
// This happens when we are going to the next unread and we need to grab another timeline to continue. The
// ArticleViewController will be pushed, but we will briefly show the Timeline. Don't clear things out when that happens.
if viewController === masterTimelineViewController && !isThreePanelMode && rootSplitViewController.isCollapsed && !isArticleViewControllerPending {
currentArticle = nil
masterTimelineViewController?.updateArticleSelection(animations: [.scroll, .select, .navigation])
activityManager.invalidateReading()
if viewController === masterTimelineViewController && lastMainControllerToAppear == .article {
selectArticle(nil)
// Restore any bars hidden by the article controller
showStatusBar()
navigationController.setNavigationBarHidden(false, animated: true)
// We delay the showing of the navigation bars because it freaks out on iOS 15 with the new split view controller
// if it is trying to show at the same time as the show timeline animation
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
navigationController.setNavigationBarHidden(false, animated: true)
}
navigationController.setToolbarHidden(false, animated: true)
return
}
}
}
// MARK: Private
private extension SceneCoordinator {
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.tintColor = AppAssets.primaryAccentColor
}
func markArticlesWithUndo(_ articles: [Article], statusKey: ArticleStatus.Key, flag: Bool, completion: (() -> Void)? = nil) {
guard let undoManager = undoManager,
@@ -2077,134 +2041,6 @@ private extension SceneCoordinator {
}
// MARK: Three Panel Mode
func installTimelineControllerIfNecessary(animated: Bool) {
if navControllerForTimeline().viewControllers.filter({ $0 is MasterTimelineViewController }).count < 1 {
isTimelineViewControllerPending = true
masterTimelineViewController = UIStoryboard.main.instantiateController(ofType: MasterTimelineViewController.self)
masterTimelineViewController!.coordinator = self
navControllerForTimeline().pushViewController(masterTimelineViewController!, animated: animated)
}
}
@discardableResult
func installArticleController(state: ArticleViewController.State? = nil, animated: Bool) -> ArticleViewController {
isArticleViewControllerPending = true
let articleController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self)
articleController.coordinator = self
articleController.article = currentArticle
articleController.restoreState = state
if let subSplit = subSplitViewController {
let controller = addNavControllerIfNecessary(articleController, showButton: false)
subSplit.showDetailViewController(controller, sender: self)
} else if rootSplitViewController.isCollapsed || wasRootSplitViewControllerCollapsed {
masterNavigationController.pushViewController(articleController, animated: animated)
} else {
let controller = addNavControllerIfNecessary(articleController, showButton: true)
rootSplitViewController.showDetailViewController(controller, sender: self)
}
return articleController
}
func addNavControllerIfNecessary(_ controller: UIViewController, showButton: Bool) -> UIViewController {
// You will sometimes get a compact horizontal size class while in three panel mode. Dunno why it lies.
if rootSplitViewController.traitCollection.horizontalSizeClass == .compact && !isThreePanelMode {
return controller
} else {
let navController = InteractiveNavigationController.template(rootViewController: controller)
navController.isToolbarHidden = false
if showButton {
controller.navigationItem.leftBarButtonItem = rootSplitViewController.displayModeButtonItem
controller.navigationItem.leftItemsSupplementBackButton = true
} else {
controller.navigationItem.leftBarButtonItem = nil
controller.navigationItem.leftItemsSupplementBackButton = false
}
return navController
}
}
func installSubSplit() {
rootSplitViewController.preferredPrimaryColumnWidthFraction = 0.30
subSplitViewController = UISplitViewController()
subSplitViewController!.preferredDisplayMode = .oneBesideSecondary
subSplitViewController!.viewControllers = [InteractiveNavigationController.template()]
subSplitViewController!.preferredPrimaryColumnWidthFraction = 0.4285
rootSplitViewController.showDetailViewController(subSplitViewController!, sender: self)
rootSplitViewController.setOverrideTraitCollection(UITraitCollection(horizontalSizeClass: .regular), forChild: subSplitViewController!)
}
func navControllerForTimeline() -> UINavigationController {
if let subSplit = subSplitViewController {
return subSplit.viewControllers.first as! UINavigationController
} else {
return masterNavigationController
}
}
func configureThreePanelMode() {
articleViewController?.stopArticleExtractorIfProcessing()
let articleViewControllerState = articleViewController?.currentState
defer {
masterNavigationController.viewControllers = [masterFeedViewController]
}
if rootSplitViewController.viewControllers.last is InteractiveNavigationController {
_ = rootSplitViewController.viewControllers.popLast()
}
installSubSplit()
installTimelineControllerIfNecessary(animated: false)
masterTimelineViewController?.navigationItem.leftBarButtonItem = rootSplitViewController.displayModeButtonItem
masterTimelineViewController?.navigationItem.leftItemsSupplementBackButton = true
installArticleController(state: articleViewControllerState, animated: false)
masterFeedViewController.restoreSelectionIfNecessary(adjustScroll: true)
masterTimelineViewController!.restoreSelectionIfNecessary(adjustScroll: false)
}
func configureStandardPanelMode() {
articleViewController?.stopArticleExtractorIfProcessing()
let articleViewControllerState = articleViewController?.currentState
rootSplitViewController.preferredPrimaryColumnWidthFraction = UISplitViewController.automaticDimension
// Set the is Pending flags early to prevent the navigation controller delegate from thinking that we
// swiping around in the user interface
isTimelineViewControllerPending = true
isArticleViewControllerPending = true
masterNavigationController.viewControllers = [masterFeedViewController]
if rootSplitViewController.viewControllers.last is UISplitViewController {
subSplitViewController = nil
_ = rootSplitViewController.viewControllers.popLast()
}
if currentFeedIndexPath != nil {
masterTimelineViewController = UIStoryboard.main.instantiateController(ofType: MasterTimelineViewController.self)
masterTimelineViewController!.coordinator = self
masterNavigationController.pushViewController(masterTimelineViewController!, animated: false)
}
installArticleController(state: articleViewControllerState, animated: false)
}
// MARK: NSUserActivity
func windowState() -> [AnyHashable: Any] {

View File

@@ -14,35 +14,35 @@ import Zip
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
var coordinator = SceneCoordinator()
var coordinator: SceneCoordinator!
// UIWindowScene delegate
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
window = UIWindow(windowScene: scene as! UIWindowScene)
window!.tintColor = AppAssets.primaryAccentColor
updateUserInterfaceStyle()
window!.rootViewController = coordinator.start(for: window!.frame.size)
let rootViewController = window!.rootViewController as! RootSplitViewController
coordinator = SceneCoordinator(rootSplitViewController: rootViewController)
rootViewController.coordinator = coordinator
rootViewController.delegate = coordinator
coordinator.restoreWindowState(session.stateRestorationActivity)
NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange), name: UserDefaults.didChangeNotification, object: nil)
if let _ = connectionOptions.urlContexts.first?.url {
window?.makeKeyAndVisible()
self.scene(scene, openURLContexts: connectionOptions.urlContexts)
return
}
if let shortcutItem = connectionOptions.shortcutItem {
window!.makeKeyAndVisible()
handleShortcutItem(shortcutItem)
return
}
if let notificationResponse = connectionOptions.notificationResponse {
window!.makeKeyAndVisible()
coordinator.handle(notificationResponse)
return
}
@@ -50,8 +50,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
if let userActivity = connectionOptions.userActivities.first ?? session.stateRestorationActivity {
coordinator.handle(userActivity)
}
window!.makeKeyAndVisible()
}
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
@@ -74,7 +73,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func sceneWillEnterForeground(_ scene: UIScene) {
appDelegate.resumeDatabaseProcessingIfNecessary()
appDelegate.prepareAccountsForForeground()
coordinator.configurePanelMode(for: window!.frame.size)
coordinator.resetFocus()
}

View File

@@ -11,12 +11,12 @@ import UIKit
struct ArticleThemeImporter {
static func importTheme(controller: UIViewController, filename: String) throws {
let theme = try ArticleTheme(path: filename)
let theme = try ArticleTheme(path: filename, isAppTheme: false)
let localizedTitleText = NSLocalizedString("Install theme “%@” by %@?", comment: "Theme message text")
let title = NSString.localizedStringWithFormat(localizedTitleText as NSString, theme.name, theme.creatorName) as String
let localizedMessageText = NSLocalizedString("Author's Website:\n%@", comment: "Authors website")
let localizedMessageText = NSLocalizedString("Authors website:\n%@", comment: "Authors website")
let message = NSString.localizedStringWithFormat(localizedMessageText as NSString, theme.creatorHomePage) as String
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)

View File

@@ -71,9 +71,10 @@ class ArticleThemesTableViewController: UITableViewController {
}
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
guard indexPath.row != 0,
let cell = tableView.cellForRow(at: indexPath),
let themeName = cell.textLabel?.text else { return nil }
guard let cell = tableView.cellForRow(at: indexPath),
let themeName = cell.textLabel?.text,
let theme = 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

View File

@@ -20,14 +20,14 @@
<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="20" y="49.5" width="374" height="43.5"/>
<rect key="frame" x="20" y="49.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="43.5"/>
<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="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="43.5"/>
<rect key="frame" x="20" y="0.0" width="334" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
@@ -37,10 +37,10 @@
</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" width="374" height="43.5"/>
<rect key="frame" x="20" y="93.5" width="374" height="44"/>
<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="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="345.5" height="44"/>
<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">
@@ -58,14 +58,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="186.5" width="374" height="43.5"/>
<rect key="frame" x="20" y="187.5" width="374" height="44"/>
<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="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="345.5" height="44"/>
<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="43.5"/>
<rect key="frame" x="20" y="0.0" width="317.5" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
@@ -79,7 +79,7 @@
<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="280" width="374" height="43.5"/>
<rect key="frame" x="20" y="281.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="6QJ-fX-278" id="PDs-8c-XUa">
<rect key="frame" x="0.0" y="0.0" width="345.5" height="43.5"/>
@@ -100,7 +100,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="373.5" width="374" height="43.5"/>
<rect key="frame" x="20" y="375" 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 +117,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="417" width="374" height="43.5"/>
<rect key="frame" x="20" y="418.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="qke-Ha-PXl" id="pZi-ck-RV5">
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
@@ -134,7 +134,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="460.5" width="374" height="43.5"/>
<rect key="frame" x="20" y="462" 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,7 +155,7 @@
<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="554" width="374" height="43.5"/>
<rect key="frame" x="20" y="555.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="MpA-w1-Wwh" id="GhU-ib-Mz8">
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
@@ -188,7 +188,7 @@
</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="597.5" width="374" height="43.5"/>
<rect key="frame" x="20" y="599" 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"/>
@@ -221,7 +221,7 @@
</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="641" width="374" height="43.5"/>
<rect key="frame" x="20" y="642.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="5wo-fM-0l6" id="XAn-lK-LoN">
<rect key="frame" x="0.0" y="0.0" width="374" height="43.5"/>
@@ -254,7 +254,7 @@
</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="684.5" width="374" height="43.5"/>
<rect key="frame" x="20" y="686" 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"/>
@@ -281,7 +281,7 @@
<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="778" width="374" height="43.5"/>
<rect key="frame" x="20" y="779.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="WFP-zj-Pve" id="DCX-wc-LSo">
<rect key="frame" x="0.0" y="0.0" width="345.5" height="43.5"/>
@@ -313,14 +313,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="821.5" width="374" height="44"/>
<rect key="frame" x="20" y="823" 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="44"/>
<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="22"/>
<rect key="frame" x="20" y="11" width="163" height="21.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@@ -346,20 +346,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="865.5" width="374" height="44"/>
<rect key="frame" x="20" y="866.5" width="374" height="44.5"/>
<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"/>
<rect key="frame" x="0.0" y="0.0" width="374" height="44.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" 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="319" height="17.5"/>
<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"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dhR-L2-PX3" userLabel="Open Links in NetNewsWire">
<rect key="frame" x="347" y="7" width="51" height="31"/>
<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"/>
<color key="onTintColor" name="primaryAccentColor"/>
<connections>
<action selector="switchBrowserPreference:" destination="a0p-rk-skQ" eventType="valueChanged" id="hLC-cV-Wjj"/>
@@ -379,65 +379,24 @@
<outlet property="label" destination="Wm4-Y1-7nX" id="R62-za-yVz"/>
</connections>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="WR6-xo-ty2" customClass="VibrantTableViewCell" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="20" y="909.5" width="374" height="80.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="WR6-xo-ty2" id="zX8-l2-bVH">
<rect key="frame" x="0.0" y="0.0" width="374" height="80.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" verticalCompressionResistancePriority="751" ambiguous="YES" text="Enable Full Screen Articles" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="79e-5s-vd0">
<rect key="frame" x="20" y="11" width="172" height="15.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="2Md-2E-7Z4">
<rect key="frame" x="347" y="6" width="51" height="31"/>
<color key="onTintColor" name="primaryAccentColor"/>
<connections>
<action selector="switchFullscreenArticles:" destination="a0p-rk-skQ" eventType="valueChanged" id="5fa-Ad-e0j"/>
</connections>
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="749" ambiguous="YES" text="Tap the article top bar to enter Full Screen. Tap the top or bottom to exit." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="a30-nc-ZS4">
<rect key="frame" x="20" y="33" width="313" height="0.0"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="2Md-2E-7Z4" firstAttribute="centerY" secondItem="79e-5s-vd0" secondAttribute="centerY" id="3KV-rT-Dfb"/>
<constraint firstItem="a30-nc-ZS4" firstAttribute="leading" secondItem="zX8-l2-bVH" secondAttribute="leadingMargin" id="52y-SY-gbp"/>
<constraint firstItem="79e-5s-vd0" firstAttribute="top" secondItem="zX8-l2-bVH" secondAttribute="topMargin" id="9bF-Q1-sYE"/>
<constraint firstItem="2Md-2E-7Z4" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="a30-nc-ZS4" secondAttribute="trailing" constant="8" id="E9l-8S-WBL"/>
<constraint firstAttribute="trailing" secondItem="2Md-2E-7Z4" secondAttribute="trailing" constant="18" id="ELH-06-H2j"/>
<constraint firstItem="2Md-2E-7Z4" firstAttribute="top" relation="greaterThanOrEqual" secondItem="zX8-l2-bVH" secondAttribute="top" constant="6" id="aBe-aC-mva"/>
<constraint firstItem="a30-nc-ZS4" firstAttribute="bottom" secondItem="zX8-l2-bVH" secondAttribute="bottomMargin" id="b3g-at-rjh"/>
<constraint firstItem="2Md-2E-7Z4" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="79e-5s-vd0" secondAttribute="trailing" constant="8" id="lUn-8D-X20"/>
<constraint firstItem="79e-5s-vd0" firstAttribute="leading" secondItem="zX8-l2-bVH" secondAttribute="leadingMargin" id="tdZ-30-ACC"/>
<constraint firstItem="a30-nc-ZS4" firstAttribute="top" secondItem="79e-5s-vd0" secondAttribute="bottom" constant="6.5" id="wuJ-LG-d6p"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
<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="1040" width="374" height="43.5"/>
<rect key="frame" x="20" y="961" 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="357.5" height="43.5"/>
<rect key="frame" x="0.0" y="0.0" width="345.5" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<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">
<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">
<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" ambiguous="YES" 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" 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"/>
@@ -461,13 +420,13 @@
<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="1133.5" width="374" height="43.5"/>
<rect key="frame" x="20" y="1054.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="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" ambiguous="YES" insetsLayoutMarginsFromSafeArea="NO" text="NetNewsWire Help" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" id="uGk-2d-oFc">
<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"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
@@ -478,13 +437,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="1177" width="374" height="43.5"/>
<rect key="frame" x="20" y="1098" 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" ambiguous="YES" 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" 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"/>
@@ -495,13 +454,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="1220.5" width="374" height="43.5"/>
<rect key="frame" x="20" y="1141.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" ambiguous="YES" 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" 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"/>
@@ -512,7 +471,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="1264" width="374" height="43.5"/>
<rect key="frame" x="20" y="1185" 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"/>
@@ -529,7 +488,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="1307.5" width="374" height="43.5"/>
<rect key="frame" x="20" y="1228.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"/>
@@ -546,7 +505,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="1351" width="374" height="43.5"/>
<rect key="frame" x="20" y="1272" 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"/>
@@ -563,7 +522,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="1394.5" width="374" height="43.5"/>
<rect key="frame" x="20" y="1315.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"/>
@@ -580,7 +539,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="1438" width="374" height="43.5"/>
<rect key="frame" x="20" y="1359" 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"/>
@@ -597,7 +556,7 @@
</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="1481.5" width="374" height="43.5"/>
<rect key="frame" x="20" y="1402.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"/>
@@ -635,7 +594,6 @@
<outlet property="groupByFeedSwitch" destination="JNi-Wz-RbU" id="TwH-Kd-o6N"/>
<outlet property="openLinksInNetNewsWire" destination="dhR-L2-PX3" id="z1b-pX-bwG"/>
<outlet property="refreshClearsReadArticlesSwitch" destination="duV-CN-JmH" id="xTd-jF-Ei1"/>
<outlet property="showFullscreenArticlesSwitch" destination="2Md-2E-7Z4" id="lEN-VP-wEO"/>
<outlet property="timelineSortOrderSwitch" destination="Keq-Np-l9O" id="Zm7-HG-r5h"/>
</connections>
</tableViewController>

View File

@@ -81,12 +81,6 @@ class SettingsViewController: UITableViewController {
} else {
confirmMarkAllAsReadSwitch.isOn = false
}
if AppDefaults.shared.articleFullscreenAvailable {
showFullscreenArticlesSwitch.isOn = true
} else {
showFullscreenArticlesSwitch.isOn = false
}
colorPaletteDetailLabel.text = String(describing: AppDefaults.userInterfaceColorPalette)
openLinksInNetNewsWire.isOn = !AppDefaults.shared.useSystemBrowser
@@ -144,7 +138,7 @@ class SettingsViewController: UITableViewController {
}
return defaultNumberOfRows
case 5:
return traitCollection.userInterfaceIdiom == .phone ? 4 : 3
return 3
default:
return super.tableView(tableView, numberOfRowsInSection: section)
}
@@ -264,7 +258,7 @@ class SettingsViewController: UITableViewController {
case 7:
switch indexPath.row {
case 0:
openURL("https://netnewswire.com/help/ios/6.0/en/")
openURL("https://netnewswire.com/help/ios/6.1/en/")
tableView.selectRow(at: nil, animated: true, scrollPosition: .none)
case 1:
openURL("https://netnewswire.com/")
@@ -356,14 +350,6 @@ class SettingsViewController: UITableViewController {
}
}
@IBAction func switchFullscreenArticles(_ sender: Any) {
if showFullscreenArticlesSwitch.isOn {
AppDefaults.shared.articleFullscreenAvailable = true
} else {
AppDefaults.shared.articleFullscreenAvailable = false
}
}
@IBAction func switchBrowserPreference(_ sender: Any) {
if openLinksInNetNewsWire.isOn {
AppDefaults.shared.useSystemBrowser = false

View File

@@ -71,7 +71,7 @@ private extension TimelinePreviewTableViewController {
let iconImage = IconImage(AppAssets.faviconTemplateImage.withTintColor(AppAssets.secondaryAccentColor))
return MasterTimelineCellData(article: prototypeArticle, showFeedName: .feed, feedName: "Feed Name", byline: nil, iconImage: iconImage, showIcon: true, featuredImage: nil, numberOfLines: AppDefaults.shared.timelineNumberOfLines, iconSize: AppDefaults.shared.timelineIconSize)
return MasterTimelineCellData(article: prototypeArticle, showFeedName: .feed, feedName: "Feed Name", byline: nil, iconImage: iconImage, showIcon: true, featuredImage: nil, numberOfLines: AppDefaults.shared.timelineNumberOfLines, iconSize: AppDefaults.shared.timelineIconSize, hideSeparator: false)
}
}

View File

@@ -1,72 +0,0 @@
//
// InteractiveNavigationController.swift
// NetNewsWire
//
// Created by Maurice Parker on 8/22/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import UIKit
class InteractiveNavigationController: UINavigationController {
private let poppableDelegate = PoppableGestureRecognizerDelegate()
static func template() -> UINavigationController {
let navController = InteractiveNavigationController()
navController.configure()
return navController
}
static func template(rootViewController: UIViewController) -> UINavigationController {
let navController = InteractiveNavigationController(rootViewController: rootViewController)
navController.configure()
return navController
}
override func viewDidLoad() {
super.viewDidLoad()
poppableDelegate.navigationController = self
interactivePopGestureRecognizer?.delegate = poppableDelegate
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.userInterfaceStyle != previousTraitCollection?.userInterfaceStyle {
configure()
}
}
}
// MARK: Private
private extension InteractiveNavigationController {
func configure() {
isToolbarHidden = false
// Standard appearance with system background
let standardAppearance = UINavigationBarAppearance()
standardAppearance.backgroundColor = .clear
standardAppearance.shadowColor = nil
let scrollEdgeAppearance = UINavigationBarAppearance()
scrollEdgeAppearance.backgroundColor = .systemBackground
scrollEdgeAppearance.shadowColor = nil
navigationBar.standardAppearance = standardAppearance
navigationBar.scrollEdgeAppearance = scrollEdgeAppearance
navigationBar.compactAppearance = standardAppearance
navigationBar.compactScrollEdgeAppearance = scrollEdgeAppearance
let toolbarAppearance = UIToolbarAppearance()
toolbarAppearance.shadowColor = nil
toolbar.standardAppearance = toolbarAppearance
toolbar.compactAppearance = nil
toolbar.scrollEdgeAppearance = nil
toolbar.tintColor = AppAssets.primaryAccentColor
}
}

View File

@@ -1,7 +1,7 @@
// High Level Settings common to both the iOS application and any extensions we bundle with it
MARKETING_VERSION = 6.0.2
CURRENT_PROJECT_VERSION = 609
MARKETING_VERSION = 6.1
CURRENT_PROJECT_VERSION = 6103
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon