split nib files and restructured with Window- and ViewControllers

This commit is contained in:
relikd
2018-08-08 15:31:36 +02:00
parent 3a79faaa65
commit 7d3c7d7da9
21 changed files with 1379 additions and 1131 deletions

View File

@@ -14,6 +14,11 @@
544FBD4521064AEB008A260C /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 544FBD4421064AEB008A260C /* Python.framework */; };
544FBD4721064B2F008A260C /* getFeed.py in Resources */ = {isa = PBXBuildFile; fileRef = 544FBD4621064B2F008A260C /* getFeed.py */; };
544FBD4921064DF0008A260C /* feedparser521.py in Resources */ = {isa = PBXBuildFile; fileRef = 544FBD4821064DF0008A260C /* feedparser521.py */; };
546FC43D21188AD5007CC3A3 /* SettingsFeeds.m in Sources */ = {isa = PBXBuildFile; fileRef = 546FC43C21188AD5007CC3A3 /* SettingsFeeds.m */; };
546FC43F21188C78007CC3A3 /* SettingsFeeds.xib in Resources */ = {isa = PBXBuildFile; fileRef = 546FC43E21188C78007CC3A3 /* SettingsFeeds.xib */; };
546FC44321189975007CC3A3 /* SettingsGeneral.m in Sources */ = {isa = PBXBuildFile; fileRef = 546FC44121189975007CC3A3 /* SettingsGeneral.m */; };
546FC44421189975007CC3A3 /* SettingsGeneral.xib in Resources */ = {isa = PBXBuildFile; fileRef = 546FC44221189975007CC3A3 /* SettingsGeneral.xib */; };
546FC4472118A8E6007CC3A3 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 546FC4462118A8E6007CC3A3 /* Preferences.xib */; };
54ACC28121061B3B0020715F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC28021061B3B0020715F /* AppDelegate.m */; };
54ACC28621061B3C0020715F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 54ACC28521061B3C0020715F /* Assets.xcassets */; };
54ACC28921061B3C0020715F /* Main.xib in Resources */ = {isa = PBXBuildFile; fileRef = 54ACC28721061B3C0020715F /* Main.xib */; };
@@ -35,6 +40,13 @@
544FBD4421064AEB008A260C /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Python.framework; path = System/Library/Frameworks/Python.framework; sourceTree = SDKROOT; };
544FBD4621064B2F008A260C /* getFeed.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = getFeed.py; sourceTree = "<group>"; usesTabs = 0; };
544FBD4821064DF0008A260C /* feedparser521.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = feedparser521.py; sourceTree = "<group>"; usesTabs = 0; };
546FC43B21188AD5007CC3A3 /* SettingsFeeds.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SettingsFeeds.h; sourceTree = "<group>"; };
546FC43C21188AD5007CC3A3 /* SettingsFeeds.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SettingsFeeds.m; sourceTree = "<group>"; };
546FC43E21188C78007CC3A3 /* SettingsFeeds.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SettingsFeeds.xib; sourceTree = "<group>"; };
546FC44021189975007CC3A3 /* SettingsGeneral.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SettingsGeneral.h; sourceTree = "<group>"; };
546FC44121189975007CC3A3 /* SettingsGeneral.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SettingsGeneral.m; sourceTree = "<group>"; };
546FC44221189975007CC3A3 /* SettingsGeneral.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SettingsGeneral.xib; sourceTree = "<group>"; };
546FC4462118A8E6007CC3A3 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Preferences.xib; sourceTree = "<group>"; };
54ACC27C21061B3B0020715F /* baRSS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = baRSS.app; sourceTree = BUILT_PRODUCTS_DIR; };
54ACC27F21061B3B0020715F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
54ACC28021061B3B0020715F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
@@ -69,6 +81,32 @@
name = Frameworks;
sourceTree = "<group>";
};
546FC44521189ADC007CC3A3 /* Settings Tabs */ = {
isa = PBXGroup;
children = (
546FC44021189975007CC3A3 /* SettingsGeneral.h */,
546FC44121189975007CC3A3 /* SettingsGeneral.m */,
546FC44221189975007CC3A3 /* SettingsGeneral.xib */,
546FC43B21188AD5007CC3A3 /* SettingsFeeds.h */,
546FC43C21188AD5007CC3A3 /* SettingsFeeds.m */,
546FC43E21188C78007CC3A3 /* SettingsFeeds.xib */,
);
path = "Settings Tabs";
sourceTree = "<group>";
};
546FC44D2118B357007CC3A3 /* Preferences */ = {
isa = PBXGroup;
children = (
54ACC29621061FBA0020715F /* Preferences.h */,
54ACC29721061FBA0020715F /* Preferences.m */,
546FC4462118A8E6007CC3A3 /* Preferences.xib */,
546FC44521189ADC007CC3A3 /* Settings Tabs */,
544B01182114B41200386E5C /* ModalSheet.h */,
544B01192114B41200386E5C /* ModalSheet.m */,
);
path = Preferences;
sourceTree = "<group>";
};
549369F421091E6D001AF895 /* python */ = {
isa = PBXGroup;
children = (
@@ -107,12 +145,9 @@
54ACC28021061B3B0020715F /* AppDelegate.m */,
54ACC29321061E270020715F /* NewsController.h */,
54ACC29421061E270020715F /* NewsController.m */,
54ACC29621061FBA0020715F /* Preferences.h */,
54ACC29721061FBA0020715F /* Preferences.m */,
544B01182114B41200386E5C /* ModalSheet.h */,
544B01192114B41200386E5C /* ModalSheet.m */,
54209E922117325100F3B5EF /* DrawImage.h */,
54209E932117325100F3B5EF /* DrawImage.m */,
546FC44D2118B357007CC3A3 /* Preferences */,
54ACC28521061B3C0020715F /* Assets.xcassets */,
54ACC28721061B3C0020715F /* Main.xib */,
54ACC28A21061B3C0020715F /* Info.plist */,
@@ -188,7 +223,10 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
546FC4472118A8E6007CC3A3 /* Preferences.xib in Resources */,
54ACC28621061B3C0020715F /* Assets.xcassets in Resources */,
546FC44421189975007CC3A3 /* SettingsGeneral.xib in Resources */,
546FC43F21188C78007CC3A3 /* SettingsFeeds.xib in Resources */,
544FBD4921064DF0008A260C /* feedparser521.py in Resources */,
544FBD4721064B2F008A260C /* getFeed.py in Resources */,
54ACC28921061B3C0020715F /* Main.xib in Resources */,
@@ -204,11 +242,13 @@
files = (
54F39C2E210BE1F700AEE730 /* DBv1.xcdatamodeld in Sources */,
544B011D2114EE9100386E5C /* AppHook.m in Sources */,
546FC44321189975007CC3A3 /* SettingsGeneral.m in Sources */,
54ACC29521061E270020715F /* NewsController.m in Sources */,
54ACC28C21061B3C0020715F /* main.m in Sources */,
54ACC28121061B3B0020715F /* AppDelegate.m in Sources */,
544B011A2114B41200386E5C /* ModalSheet.m in Sources */,
54ACC29821061FBA0020715F /* Preferences.m in Sources */,
546FC43D21188AD5007CC3A3 /* SettingsFeeds.m in Sources */,
1968E0AE14B8E8A90E194980 /* PyHandler.m in Sources */,
54209E942117325100F3B5EF /* DrawImage.m in Sources */,
);
@@ -232,6 +272,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@@ -279,7 +320,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MACOSX_DEPLOYMENT_TARGET = 10.12;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
@@ -290,6 +331,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
@@ -331,7 +373,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MACOSX_DEPLOYMENT_TARGET = 10.12;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
};

View File

@@ -25,5 +25,7 @@
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (readonly, strong) NSPersistentContainer *persistentContainer;
- (void)preferencesClosed;
@end

View File

@@ -23,10 +23,12 @@
#import "AppDelegate.h"
#import "PyHandler.h"
#import "DrawImage.h"
#import "Preferences.h"
@interface AppDelegate ()
@property (strong) NSStatusItem *statusItem;
@property (weak) IBOutlet NSMenu *statusMenu;
@property (strong) NSStatusItem *statusItem;
@property (strong) Preferences *prefWindow;
@end
@implementation AppDelegate
@@ -46,6 +48,17 @@
[PyHandler shutdown];
}
- (IBAction)openPreferences:(id)sender {
if (!self.prefWindow)
self.prefWindow = [[Preferences alloc] initWithWindowNibName:@"Preferences"];
[NSApp activateIgnoringOtherApps:YES];
[self.prefWindow showWindow:nil];
}
- (void)preferencesClosed {
self.prefWindow = nil;
}
#pragma mark - Core Data stack
@synthesize persistentContainer = _persistentContainer;

View File

@@ -27,30 +27,31 @@ static NSEventModifierFlags fnKeyFlags = NSEventModifierFlagShift | NSEventModif
@implementation AppHook
- (void) sendEvent:(NSEvent *)event {
if ([event type] == NSEventTypeKeyDown) {
if (!event.characters || event.characters.length == 0) {
[super sendEvent:event];
return;
}
NSEventModifierFlags flags = (event.modifierFlags & fnKeyFlags); // ignore caps lock, etc.
unichar key = [event.characters characterAtIndex:0]; // charactersIgnoringModifiers
if (flags == NSEventModifierFlagCommand) {
switch (key) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
case 'z': if ([self sendAction:@selector(undo:) to:nil from:self]) return; break;
#pragma clang diagnostic pop
case 'x': if ([self sendAction:@selector(cut:) to:nil from:self]) return; break;
case 'c': if ([self sendAction:@selector(copy:) to:nil from:self]) return; break;
case 'v': if ([self sendAction:@selector(paste:) to:nil from:self]) return; break;
case 'a': if ([self sendAction:@selector(selectAll:) to:nil from:self]) return; break;
case 'q': if ([self sendAction:@selector(terminate:) to:nil from:self]) return; break;
case 'w': if ([self sendAction:@selector(performClose:) to:nil from:self]) return; break;
}
} else if (flags == (NSEventModifierFlagCommand | NSEventModifierFlagShift)) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
case 'z': if ([self sendAction:@selector(undo:) to:nil from:self]) return; break;
}
} else if (flags == (NSEventModifierFlagCommand | NSEventModifierFlagShift)) {
if (key == 'z') {
if ([self sendAction:@selector(redo:) to:nil from:self])
return;
}
} else {
if (key == 13 || key == 3) { // Enter / Return key
if (key == NSEnterCharacter || key == NSCarriageReturnCharacter) {
if ([self sendAction:@selector(enterPressed:) to:nil from:self])
return;
}

View File

@@ -3,7 +3,6 @@
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@@ -23,26 +22,26 @@
<menuItem title="Pause Updates" id="D7r-Vb-9eO">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="pauseUpdates:" target="1oZ-Uo-mIu" id="WaC-Gv-Jlh"/>
<action selector="pauseUpdates:" target="gkw-5j-nxL" id="c8f-Vl-zzt"/>
</connections>
</menuItem>
<menuItem title="Update All Feeds" id="wgp-fa-8Wj">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="updateAllFeeds:" target="1oZ-Uo-mIu" id="5yX-Gc-9Qg"/>
<action selector="updateAllFeeds:" target="gkw-5j-nxL" id="eeM-ZQ-Aha"/>
</connections>
</menuItem>
<menuItem title="Open All Unread" id="Qqw-Xj-oA5">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="openAllUnread:" target="1oZ-Uo-mIu" id="dpt-U6-GPp"/>
<action selector="openAllUnread:" target="gkw-5j-nxL" id="r6A-ca-Dz4"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="ld2-b0-07a"/>
<menuItem isSeparatorItem="YES" id="1VS-wM-kTc"/>
<menuItem title="Preferences" keyEquivalent="," id="VFY-eR-2EA">
<connections>
<action selector="makeKeyAndOrderFront:" target="ai3-RW-O8g" id="qaE-j2-fux"/>
<action selector="openPreferences:" target="Voe-Tx-rLC" id="a8v-fo-Drx"/>
</connections>
</menuItem>
<menuItem title="Quit" keyEquivalent="q" id="Nb6-yK-a1A">
@@ -51,632 +50,8 @@
</connections>
</menuItem>
</items>
<point key="canvasLocation" x="277" y="419"/>
<point key="canvasLocation" x="-47" y="485"/>
</menu>
<treeController mode="entity" entityName="FeedConfig" fetchPredicateFormat="parent == nil" automaticallyPreparesContent="YES" childrenKeyPath="children" leafKeyPath="type" id="1oZ-Uo-mIu" customClass="NewsController">
<connections>
<binding destination="Voe-Tx-rLC" name="managedObjectContext" keyPath="self.persistentContainer.viewContext" id="Q1f-VN-9qq"/>
<outlet property="outlineView" destination="hKk-G1-1po" id="Z4y-uD-Zse"/>
<outlet property="preferencesWindow" destination="ai3-RW-O8g" id="cNF-TI-ups"/>
<outlet property="viewModalEditFeed" destination="QwK-my-u5w" id="gpw-6X-48E"/>
<outlet property="viewModalEditGroup" destination="cQF-4Y-gsL" id="NJF-jl-dhg"/>
</connections>
</treeController>
<window title="baRSS Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" frameAutosaveName="prefWindow" animationBehavior="default" tabbingMode="disallowed" id="ai3-RW-O8g" userLabel="Preferences" customClass="Preferences">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="948" y="431" width="320" height="327"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
<value key="minSize" type="size" width="320" height="327"/>
<view key="contentView" id="ct3-G7-3SQ">
<rect key="frame" x="0.0" y="0.0" width="320" height="327"/>
<autoresizingMask key="autoresizingMask"/>
</view>
<toolbar key="toolbar" implicitIdentifier="5B23E7E6-13E5-4910-875D-2E3EA566F38B" autosavesConfiguration="NO" allowsUserCustomization="NO" displayMode="iconAndLabel" sizeMode="regular" id="wLj-fD-HpE">
<allowedToolbarItems>
<toolbarItem implicitItemIdentifier="AF4483E3-0457-47B7-AE52-AC11B1545455" explicitItemIdentifier="tabGeneral" label="General" paletteLabel="General" tag="-1" image="NSPreferencesGeneral" selectable="YES" id="0qP-ah-ojT">
<connections>
<action selector="tabClicked:" target="ai3-RW-O8g" id="ebr-gX-OQB"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="E8527558-3D5F-4B79-99E4-675C1557D10B" explicitItemIdentifier="tabFeeds" label="Feeds" paletteLabel="Feeds" tag="-1" image="NSUserAccounts" selectable="YES" id="Av5-VA-zps">
<connections>
<action selector="tabClicked:" target="ai3-RW-O8g" id="hhx-TR-X5c"/>
</connections>
</toolbarItem>
</allowedToolbarItems>
<defaultToolbarItems>
<toolbarItem reference="0qP-ah-ojT"/>
<toolbarItem reference="Av5-VA-zps"/>
</defaultToolbarItems>
</toolbar>
<connections>
<outlet property="modalSheet" destination="oXi-oJ-x37" id="EWx-yQ-jsK"/>
<outlet property="newsController" destination="1oZ-Uo-mIu" id="1HA-Vz-PBK"/>
<outlet property="viewFeeds" destination="EwH-fT-yW8" id="aBH-fR-foa"/>
<outlet property="viewGeneral" destination="8H4-sI-Ub8" id="PS7-gG-GJs"/>
</connections>
<point key="canvasLocation" x="-20" y="521"/>
</window>
<customView id="8H4-sI-Ub8" userLabel="Preferences-General">
<rect key="frame" x="0.0" y="0.0" width="320" height="327"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8fg-Da-IP3">
<rect key="frame" x="18" y="291" width="284" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Start on login" bezelStyle="regularSquare" imagePosition="left" inset="2" id="FZH-Op-qbn">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="K8S-BW-Na6" name="value" keyPath="values.startOnLogin" id="pzI-fT-f6T">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="0"/>
</dictionary>
</binding>
</connections>
</button>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jeZ-Rk-wS6">
<rect key="frame" x="155" y="17" width="148" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Default" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="Yb2-0r-GxD" id="g3B-HQ-prd">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="UbA-VE-jT1">
<items>
<menuItem title="Default" state="on" id="Yb2-0r-GxD"/>
<menuItem title="Safari" id="ewS-Sd-pW6"/>
<menuItem title="other …" id="Hes-dQ-Wvu"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xcd-GA-o0T">
<rect key="frame" x="18" y="22" width="133" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Open URL in:" id="ne1-ti-s3Q">
<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>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fLb-n2-4Ao">
<rect key="frame" x="18" y="248" width="284" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Show number of unread items:" id="nWD-1j-TOY">
<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>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GUs-Oh-hZV">
<rect key="frame" x="28" y="204" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="in groups" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="f74-LA-5Jp">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="K8S-BW-Na6" name="value" keyPath="values.unreadCountInGroups" id="s02-VK-YK9">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4DT-ca-4Lc">
<rect key="frame" x="28" y="224" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="in menu bar" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="pdX-rq-cJn">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="K8S-BW-Na6" name="value" keyPath="values.unreadCountInMenuBar" id="5a2-tl-pbO">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hUj-05-l3n">
<rect key="frame" x="18" y="161" width="284" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Show in global menu:" id="diU-z3-ANf">
<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>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AC4-r5-7Bp">
<rect key="frame" x="28" y="137" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Open all unread" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="ZJe-uW-2ZH">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="K8S-BW-Na6" name="value" keyPath="values.globalOpenUnread" id="RL3-dW-r1i">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JUl-Yj-If7">
<rect key="frame" x="28" y="97" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Mark all read" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Nuu-c7-so1">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="K8S-BW-Na6" name="value" keyPath="values.globalMarkRead" id="F1p-mq-ioJ">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="IYk-kt-g6F">
<rect key="frame" x="28" y="77" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Mark all unread" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="J6a-Sa-Jln">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="K8S-BW-Na6" name="value" keyPath="values.globalMarkUnread" id="xrj-88-9Vx">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="IXp-K9-rmH">
<rect key="frame" x="28" y="117" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Update all feeds" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="QlO-jJ-wwY">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="K8S-BW-Na6" name="value" keyPath="values.globalUpdateAll" id="Z0d-uc-Zkk">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iSF-za-duw">
<rect key="frame" x="18" y="49" width="133" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Menu bar icon:" id="fA3-89-Vs4">
<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>
<imageView focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kF6-OS-VSu">
<rect key="frame" x="156" y="42" width="32" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" selectable="YES" editable="YES" focusRingType="none" alignment="left" imageScaling="proportionallyDown" imageFrameStyle="grayBezel" image="NSBookmarksTemplate" id="KDF-hq-a31"/>
</imageView>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OgL-gT-9RX">
<rect key="frame" x="28" y="184" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="in feeds" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Zg8-Xf-2Xh">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="K8S-BW-Na6" name="value" keyPath="values.unreadCountInFeeds" id="QNe-dP-6av">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Gv1-xI-QZh">
<rect key="frame" x="18" y="271" width="284" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Show tick mark for unread entries" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="wDf-M5-15o">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="K8S-BW-Na6" name="value" keyPath="values.markEntries" id="otO-lj-Y6D">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
</subviews>
<point key="canvasLocation" x="-20" y="903.5"/>
</customView>
<customView id="EwH-fT-yW8" userLabel="Preferences-Feeds">
<rect key="frame" x="0.0" y="0.0" width="320" height="327"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="20" horizontalPageScroll="10" verticalLineScroll="20" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jUM-kR-Dxs">
<rect key="frame" x="0.0" y="20" width="320" height="307"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<clipView key="contentView" ambiguous="YES" id="nZO-rz-NyQ">
<rect key="frame" x="1" y="0.0" width="318" height="306"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="firstColumnOnly" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" typeSelect="NO" autosaveName="" rowHeight="18" headerView="ne2-ld-l1b" viewBased="YES" indentationPerLevel="15" outlineTableColumn="Lb1-9n-wlc" id="hKk-G1-1po">
<rect key="frame" x="0.0" y="0.0" width="318" height="283"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="NameColumn" editable="NO" width="262" minWidth="40" maxWidth="10000" id="Lb1-9n-wlc">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Name">
<font key="font" metaFont="smallSystem"/>
<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="cH3-bR-o7w">
<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="cellFeed" id="xPj-mA-zCd" userLabel="Feed">
<rect key="frame" x="1" y="1" width="262" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZkQ-CQ-77k" userLabel="img">
<rect key="frame" x="1" y="1" width="16" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSActionTemplate" id="6xE-Sq-YVt"/>
</imageView>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="v0D-kY-dKT" userLabel="str">
<rect key="frame" x="23" y="0.0" width="241" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="AQH-6L-dw6">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="imageView" destination="ZkQ-CQ-77k" id="0A9-d2-BsO"/>
<outlet property="textField" destination="v0D-kY-dKT" id="gFH-Fi-20f"/>
</connections>
</tableCellView>
<tableCellView identifier="cellSeparator" id="IkM-wJ-Az7" userLabel="Separator">
<rect key="frame" x="1" y="21" width="262" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mlO-VE-655" userLabel="img" customClass="DrawSeparator">
<rect key="frame" x="0.0" y="0.0" width="262" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</customView>
</subviews>
</tableCellView>
</prototypeCellViews>
<connections>
<binding destination="1oZ-Uo-mIu" name="value" keyPath="arrangedObjects" id="aPh-ik-Vma">
<dictionary key="options">
<bool key="NSConditionallySetsEditable" value="YES"/>
<bool key="NSCreatesSortDescriptor" value="NO"/>
</dictionary>
</binding>
</connections>
</tableColumn>
<tableColumn identifier="RefreshColumn" editable="NO" width="50" minWidth="40" maxWidth="100" id="8st-OH-BXG">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Refresh">
<font key="font" metaFont="smallSystem"/>
<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="mMS-tN-b0C">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<prototypeCellViews>
<tableCellView identifier="cellRefresh" id="tSf-op-fUB" userLabel="cellView">
<rect key="frame" x="266" y="1" width="50" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RZ4-Kn-HYa" userLabel="str">
<rect key="frame" x="-2" y="0.0" width="54" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="right" title="21042s" id="pIo-Xo-bMN">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="RZ4-Kn-HYa" id="FHL-bL-MN2"/>
</connections>
</tableCellView>
</prototypeCellViews>
<connections>
<binding destination="1oZ-Uo-mIu" name="value" keyPath="arrangedObjects" id="qDC-Su-t66">
<dictionary key="options">
<bool key="NSConditionallySetsEditable" value="YES"/>
<bool key="NSCreatesSortDescriptor" value="NO"/>
</dictionary>
</binding>
</connections>
</tableColumn>
</tableColumns>
<connections>
<action trigger="doubleAction" selector="doubleClickOutlineView:" target="1oZ-Uo-mIu" id="v7z-dG-bmC"/>
<outlet property="dataSource" destination="1oZ-Uo-mIu" id="sch-o5-yEm"/>
<outlet property="delegate" destination="1oZ-Uo-mIu" id="Nye-dQ-vdy"/>
</connections>
</outlineView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="lc2-zx-cet">
<rect key="frame" x="1" y="7" width="0.0" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="mHR-Uh-oAd">
<rect key="frame" x="-15" y="23" width="16" height="0.0"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" id="ne2-ld-l1b">
<rect key="frame" x="0.0" y="0.0" width="318" height="23"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
<button toolTip="Create new feed item" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jBx-pE-TgX">
<rect key="frame" x="0.0" y="-1" width="25" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="smallSquare" alternateTitle="Add feed" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="WMA-eZ-pOl">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent">n</string>
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</buttonCell>
<connections>
<action selector="add:" target="1oZ-Uo-mIu" id="Lw4-zq-eUW"/>
<binding destination="1oZ-Uo-mIu" name="enabled" keyPath="canInsert" id="1xq-Nj-Acq"/>
</connections>
</button>
<button toolTip="Delete item" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kwZ-TS-nM7">
<rect key="frame" x="24" y="-1" width="25" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="smallSquare" alternateTitle="Remove Feed" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="d9M-ZD-oma">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
CA
</string>
</buttonCell>
<connections>
<action selector="remove:" target="1oZ-Uo-mIu" id="7nP-Sj-Hap"/>
<binding destination="1oZ-Uo-mIu" name="enabled" keyPath="canRemove" id="9oY-fm-uq0"/>
</connections>
</button>
<button toolTip="Add new line separator" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BRb-Je-jM4">
<rect key="frame" x="96" y="-1" width="25" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="smallSquare" title="---" alternateTitle="Add separator" bezelStyle="smallSquare" image="NSPathTemplate" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="eK7-zU-Qd2">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="addSeparator:" target="1oZ-Uo-mIu" id="bs4-Jk-EWD"/>
</connections>
</button>
<button toolTip="Add new grouping folder" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kQF-LC-quC">
<rect key="frame" x="72" y="-1" width="25" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="smallSquare" alternateTitle="Add group" bezelStyle="smallSquare" image="NSPathTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="9m2-U5-xE2">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent">g</string>
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</buttonCell>
<connections>
<action selector="addGroup:" target="1oZ-Uo-mIu" id="8MO-eQ-XcJ"/>
</connections>
</button>
<button hidden="YES" toolTip="Import or Export data" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XaQ-S9-guo">
<rect key="frame" x="295" y="-1" width="25" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="smallSquare" alternateTitle="Export" bezelStyle="smallSquare" image="NSShareTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="fhQ-ZO-ocb">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
<point key="canvasLocation" x="350" y="903.5"/>
</customView>
<userDefaultsController representsSharedInstance="YES" id="K8S-BW-Na6"/>
<window title="Modal Sheet" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" frameAutosaveName="modalSheet" animationBehavior="default" id="oXi-oJ-x37" customClass="ModalSheet">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="131" y="159" width="332" height="145"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
<view key="contentView" id="m8f-7v-xRV">
<rect key="frame" x="0.0" y="0.0" width="332" height="145"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lHM-1e-0h3">
<rect key="frame" x="164" y="13" width="82" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="DO7-Wp-Cq3">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
Gw
</string>
</buttonCell>
<connections>
<action selector="didTapCancelButton:" target="oXi-oJ-x37" id="anY-ux-Ie4"/>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xUx-US-sER">
<rect key="frame" x="246" y="13" width="72" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="push" title="Done" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="wdX-J6-h3E">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="didTapDoneButton:" target="oXi-oJ-x37" id="umh-ON-tK6"/>
</connections>
</button>
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ow4-Dc-KCa">
<rect key="frame" x="20" y="53" width="292" height="72"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</customView>
</subviews>
</view>
<connections>
<outlet property="content" destination="ow4-Dc-KCa" id="fom-bt-A3N"/>
</connections>
<point key="canvasLocation" x="-407" y="551.5"/>
</window>
<customView id="QwK-my-u5w" customClass="ModalFeedEdit">
<rect key="frame" x="0.0" y="0.0" width="323" height="79"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Td3-u0-pGV" userLabel="URL Label">
<rect key="frame" x="-2" y="60" width="103" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="URL" id="VB0-b9-Imn">
<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>
<textField verticalHuggingPriority="750" fixedFrame="YES" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eWg-Kh-Bvb">
<rect key="frame" x="107" y="58" width="216" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="https://example.org/feed.rss" drawsBackground="YES" usesSingleLineMode="YES" id="udH-RT-BoZ">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="H9R-jT-1k4" userLabel="Name Label">
<rect key="frame" x="-2" y="31" width="103" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Name" id="paa-p9-Gef">
<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>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XJj-pu-bly">
<rect key="frame" x="107" y="29" width="216" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="Example Title" drawsBackground="YES" usesSingleLineMode="YES" id="tu7-Bi-83I">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lVa-3A-b87" userLabel="Refresh Label">
<rect key="frame" x="-2" y="2" width="103" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Refresh" id="Sb5-pD-amO">
<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>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vXf-Zz-0rI">
<rect key="frame" x="107" y="0.0" width="86" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="30" drawsBackground="YES" usesSingleLineMode="YES" id="C8B-JP-s9v">
<customFormatter key="formatter" id="OLW-GD-byx" customClass="StrictUIntFormatter"/>
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gYP-CV-xZj" userLabel="TimeUnit">
<rect key="frame" x="199" y="-3" width="127" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Minutes" bezelStyle="rounded" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" autoenablesItems="NO" altersStateOfSelectedItem="NO" selectedItem="b1E-eP-OOD" id="XWW-TF-FD4">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" showsStateColumn="NO" autoenablesItems="NO" id="zrI-Up-teS">
<items>
<menuItem title="Seconds" keyEquivalent="s" id="NV5-6S-mc1">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Minutes" keyEquivalent="m" id="b1E-eP-OOD">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Hours" keyEquivalent="h" id="ZLd-ga-MiY">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Days" keyEquivalent="d" id="IGV-5p-cG7">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Weeks" keyEquivalent="w" id="PyN-Fp-lrI">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
</subviews>
<connections>
<outlet property="refreshNum" destination="vXf-Zz-0rI" id="rUP-Fl-ejj"/>
<outlet property="refreshUnit" destination="gYP-CV-xZj" id="ufL-Lt-ad0"/>
<outlet property="title" destination="XJj-pu-bly" id="csa-JH-2s8"/>
<outlet property="url" destination="eWg-Kh-Bvb" id="SKN-kr-avo"/>
</connections>
<point key="canvasLocation" x="-421.5" y="779.5"/>
</customView>
<customView id="cQF-4Y-gsL" customClass="ModalGroupEdit">
<rect key="frame" x="0.0" y="0.0" width="260" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Jb1-Bk-KcD">
<rect key="frame" x="0.0" y="0.0" width="260" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="Group Name" placeholderString="Group Name" drawsBackground="YES" usesSingleLineMode="YES" id="gDe-xz-pxK">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="title" destination="Jb1-Bk-KcD" id="aht-3z-H7U"/>
</connections>
<point key="canvasLocation" x="-407" y="891"/>
</customView>
<customObject id="gkw-5j-nxL" customClass="NewsController"/>
</objects>
<resources>
<image name="NSActionTemplate" width="14" height="14"/>
<image name="NSAddTemplate" width="11" height="11"/>
<image name="NSBookmarksTemplate" width="17" height="18"/>
<image name="NSPathTemplate" width="16" height="10"/>
<image name="NSPreferencesGeneral" width="32" height="32"/>
<image name="NSRemoveTemplate" width="11" height="11"/>
<image name="NSShareTemplate" width="11" height="16"/>
<image name="NSUserAccounts" width="32" height="32"/>
</resources>
</document>

View File

@@ -96,8 +96,9 @@
CGContextDrawLinearGradient(c, gradient, CGPointMake(0, s), CGPointMake(s, 0), 0);
CGGradientRelease(gradient);
CFRelease(colors);
}
} else {
CGContextFillPath(c);
}
CGContextSetFillColorWithColor(c, [self.barsColor CGColor]);
}
CGContextAddPath(c, bars);

View File

@@ -1,113 +0,0 @@
//
// The MIT License (MIT)
// Copyright (c) 2018 Oleg Geier
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import "ModalSheet.h"
#define BETWEEN(x,min,max) (x < min ? min : x > max ? max : x)
#pragma mark - ModalSheet
@interface ModalSheet()
@property (weak) IBOutlet NSView *content;
@end
@implementation ModalSheet
- (void)setFormContent:(NSView *)subcontent {
[self.content.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
CGFloat heightDiff = subcontent.frame.size.height - self.content.frame.size.height;
NSRect oldFrame = self.frame;
oldFrame.size.height += heightDiff;
[self setFrame:oldFrame display:NO];
[subcontent setFrameSize:NSMakeSize(self.content.frame.size.width, subcontent.frame.size.height)];
[self.content addSubview:subcontent];
[self recalculateKeyViewLoop];
self.minSize = NSMakeSize(323 + 40, self.frame.size.height);
self.maxSize = NSMakeSize(1200, self.frame.size.height);
}
- (IBAction)didTapDoneButton:(id)sender {
[self.sheetParent endSheet:self returnCode:NSModalResponseOK];
}
- (IBAction)didTapCancelButton:(id)sender {
[self.sheetParent endSheet:self returnCode:NSModalResponseAbort];
}
@end
#pragma mark - ModalFeedEdit
@implementation ModalFeedEdit
- (void)setDefaultValues {
self.url.stringValue = @"";
self.title.stringValue = @"";
self.refreshNum.intValue = 30;
[self.refreshUnit selectItemAtIndex:1];
}
- (void)setURL:(NSString*)url name:(NSString*)name refreshNum:(int32_t)num unit:(int16_t)unit {
self.url.objectValue = url;
self.title.objectValue = name;
self.refreshNum.intValue = num;
[self.refreshUnit selectItemAtIndex:BETWEEN(unit, 0, self.refreshUnit.numberOfItems - 1)];
}
+ (NSString*)stringForRefreshNum:(int32_t)num unit:(int16_t)unit {
return [NSString stringWithFormat:@"%d%c", num, [@"smhdw" characterAtIndex:(NSUInteger)BETWEEN(unit, 0, 4)]];
}
@end
#pragma mark - ModalGroupEdit
@implementation ModalGroupEdit
- (void)setDefaultValues {
self.title.stringValue = @"New Group";
}
- (void)setGroupName:(NSString*)name {
self.title.objectValue = name;
}
@end
#pragma mark - StrictUIntFormatter
@implementation StrictUIntFormatter
- (NSString *)stringForObjectValue:(id)obj {
return [NSString stringWithFormat:@"%d", [[NSString stringWithFormat:@"%@", obj] intValue]];
}
- (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)obj forString:(NSString *)string errorDescription:(out NSString *__autoreleasing _Nullable *)error {
*obj = [[NSNumber numberWithInt:[string intValue]] stringValue];
return YES;
}
- (BOOL)isPartialStringValid:(NSString *__autoreleasing _Nonnull *)partialStringPtr proposedSelectedRange:(NSRangePointer)proposedSelRangePtr originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString *__autoreleasing _Nullable *)error {
for (NSUInteger i = 0; i < [*partialStringPtr length]; i++) {
unichar c = [*partialStringPtr characterAtIndex:i];
if (c < '0' || c > '9')
return NO;
}
return YES;
}
@end

View File

@@ -22,11 +22,6 @@
#import <Cocoa/Cocoa.h>
@interface NewsController : NSTreeController <NSOutlineViewDataSource, NSOutlineViewDelegate>
- (IBAction)addFeed:(NSButton *)sender;
- (IBAction)addGroup:(NSButton *)sender;
- (IBAction)addSeparator:(NSButton *)sender;
@interface NewsController : NSObject
- (NSString*)copyDescriptionOfSelectedItems;
- (void)openModalForSelection;
@end

View File

@@ -22,67 +22,17 @@
#import "NewsController.h"
#import "PyHandler.h"
#import "Preferences.h"
#import "DBv1+CoreDataModel.h"
#import "ModalSheet.h"
#import "DrawImage.h"
@interface NewsController ()
@property (weak) IBOutlet Preferences *preferencesWindow;
@property (weak) IBOutlet ModalFeedEdit *viewModalEditFeed;
@property (weak) IBOutlet ModalGroupEdit *viewModalEditGroup;
@property (weak) IBOutlet NSOutlineView *outlineView;
@property (strong) NSArray<NSTreeNode*> *currentlyDraggedNodes;
@end
@implementation NewsController
// Declare a string constant for the drag type - to be used when writing and retrieving pasteboard data...
static NSString *dragNodeType = @"baRSS-feed-drag";
- (void)awakeFromNib {
[super awakeFromNib];
// Set the outline view to accept the custom drag type AbstractTreeNodeType...
[self.outlineView registerForDraggedTypes:[NSArray arrayWithObject:dragNodeType]];
[self setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"sortIndex" ascending:YES]]];
}
- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
FeedConfig *f = [(NSTreeNode*)item representedObject];
bool isFeed = (f.type == 1);
bool isSeperator = (f.type == 2);
bool isRefreshColumn = [tableColumn.identifier isEqualToString:@"RefreshColumn"];
NSString *cellIdent = (isRefreshColumn ? @"cellRefresh" : (isSeperator ? @"cellSeparator" : @"cellFeed"));
// owner is nil to prohibit repeated awakeFromNib calls
NSTableCellView *cellView = [self.outlineView makeViewWithIdentifier:cellIdent owner:nil];
if (isRefreshColumn) {
cellView.textField.stringValue = (!isFeed ? @"" : [ModalFeedEdit stringForRefreshNum:f.refreshNum unit:f.refreshUnit]);
} else if (isSeperator) {
return cellView; // the refresh cell is already skipped with the above if condition
} else {
cellView.textField.objectValue = f.name;
if (f.type == 0) {
cellView.imageView.image = [NSImage imageNamed:NSImageNameFolder];
} else {
// TODO: load icon
static NSImage *defaultRSSIcon;
if (!defaultRSSIcon)
defaultRSSIcon = [[[RSSIcon iconWithSize:cellView.imageView.frame.size] autoGradient] image];
cellView.imageView.image = defaultRSSIcon;
}
}
if (isFeed) // also for refresh column
cellView.textField.textColor = (f.refreshNum == 0 ? [NSColor disabledControlTextColor] : [NSColor controlTextColor]);
return cellView;
}
- (IBAction)pauseUpdates:(NSMenuItem *)sender {
NSLog(@"pause");
}
- (IBAction)updateAllFeeds:(NSMenuItem *)sender {
NSLog(@"update all");
NSDictionary * obj = [PyHandler getFeed:@"https://feeds.feedburner.com/simpledesktops" withEtag:nil andModified:nil];
@@ -120,216 +70,4 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
NSLog(@"all unread");
}
#pragma mark - Insert & Edit Feed Items
- (IBAction)addFeed:(id)sender {
[self showModalForFeedConfig:nil isGroupEdit:NO];
}
- (IBAction)addGroup:(id)sender {
[self showModalForFeedConfig:nil isGroupEdit:YES];
}
- (IBAction)addSeparator:(id)sender {
[self.managedObjectContext.undoManager beginUndoGrouping];
FeedConfig *sp = [self insertSortedItemAtSelection];
sp.name = @"---";
sp.type = 2;
[self.managedObjectContext.undoManager endUndoGrouping];
}
- (void)remove:(id)sender {
[self.managedObjectContext.undoManager beginUndoGrouping];
for (NSIndexPath *path in self.selectionIndexPaths)
[self incrementIndicesBy:-1 forSubsequentNodes:path];
[super remove:sender];
[self.managedObjectContext.undoManager endUndoGrouping];
}
- (IBAction)doubleClickOutlineView:(NSOutlineView*)sender {
if (sender.clickedRow == -1)
return; // ignore clicks on column headers and where no row was selected
FeedConfig *fc = [(NSTreeNode*)[sender itemAtRow:sender.clickedRow] representedObject];
[self showModalForFeedConfig:fc isGroupEdit:YES]; // yes will be overwritten anyway
}
- (void)openModalForSelection {
[self showModalForFeedConfig:self.selectedObjects.firstObject isGroupEdit:YES]; // yes will be overwritten anyway
}
- (void)showModalForFeedConfig:(FeedConfig*)obj isGroupEdit:(bool)group {
bool existingItem = [obj isKindOfClass:[FeedConfig class]];
if (existingItem) {
if (obj.type == 2) return; // Separator
group = (obj.type == 0);
if (group) [self.viewModalEditGroup setGroupName:obj.name];
else [self.viewModalEditFeed setURL:obj.url name:obj.name refreshNum:obj.refreshNum unit:obj.refreshUnit];
} else {
if (group) [self.viewModalEditGroup setDefaultValues];
else [self.viewModalEditFeed setDefaultValues];
}
NSView *content = (group ? self.viewModalEditGroup : self.viewModalEditFeed);
[self.preferencesWindow presentModal:content completion:^(NSModalResponse returnCode) {
if (returnCode == NSModalResponseOK) {
[self.managedObjectContext.undoManager beginUndoGrouping];
FeedConfig *item = obj;
if (!existingItem) { // create new item
item = [self insertSortedItemAtSelection];
item.type = (group ? 0 : 1);
}
if (group) {
item.name = self.viewModalEditGroup.title.stringValue;
} else {
item.name = self.viewModalEditFeed.title.stringValue;
item.url = self.viewModalEditFeed.url.stringValue;
item.refreshNum = self.viewModalEditFeed.refreshNum.intValue;
item.refreshUnit = (int16_t)self.viewModalEditFeed.refreshUnit.indexOfSelectedItem;
}
[self.managedObjectContext.undoManager endUndoGrouping];
[self rearrangeObjects];
}
}];
}
- (FeedConfig*)insertSortedItemAtSelection {
NSIndexPath *selectedIndex = [self selectionIndexPath];
NSIndexPath *insertIndex = selectedIndex;
FeedConfig *selected = [[[self arrangedObjects] descendantNodeAtIndexPath:selectedIndex] representedObject];
NSUInteger lastIndex = selected.children.count;
bool groupSelected = (selected.type == 0);
if (!groupSelected) {
lastIndex = (NSUInteger)selected.sortIndex + 1; // insert after selection
insertIndex = [insertIndex indexPathByRemovingLastIndex];
[self incrementIndicesBy:+1 forSubsequentNodes:selectedIndex];
--selected.sortIndex; // insert after selection
}
FeedConfig *newItem = [[FeedConfig alloc] initWithEntity:FeedConfig.entity insertIntoManagedObjectContext:self.managedObjectContext];
[self insertObject:newItem atArrangedObjectIndexPath:[insertIndex indexPathByAddingIndex:lastIndex]];
// First insert, then parent, else troubles
newItem.sortIndex = (int32_t)lastIndex;
newItem.parent = (groupSelected ? selected : selected.parent);
return newItem;
}
#pragma mark - Import & Export of Data
- (NSString*)copyDescriptionOfSelectedItems {
NSMutableString *str = [[NSMutableString alloc] init];
for (FeedConfig *item in self.selectedObjects) {
[self traverseChildren:item appendString:str indentation:0];
}
[[NSPasteboard generalPasteboard] clearContents];
[[NSPasteboard generalPasteboard] setString:str forType:NSPasteboardTypeString];
NSLog(@"%@", str);
return str;
}
- (void)traverseChildren:(FeedConfig*)obj appendString:(NSMutableString*)str indentation:(int)indent {
for (int i = indent; i > 0; i--) {
[str appendString:@" "];
}
switch (obj.type) {
case 0: [str appendFormat:@"%@:\n", obj.name]; break; // Group
case 2: [str appendString:@"-------------\n"]; break; // Separator
default: [str appendFormat:@"%@ (%@) - %@\n", obj.name, obj.url, [ModalFeedEdit stringForRefreshNum:obj.refreshNum unit:obj.refreshUnit]];
}
for (FeedConfig *child in obj.children) {
[self traverseChildren:child appendString:str indentation:indent + 1];
}
}
- (void)incrementIndicesBy:(int)val forSubsequentNodes:(NSIndexPath*)path {
NSIndexPath *parentPath = [path indexPathByRemovingLastIndex];
NSTreeNode *root = [self arrangedObjects];
if (parentPath.length > 0)
root = [root descendantNodeAtIndexPath:parentPath];
for (NSUInteger i = [path indexAtPosition:path.length - 1]; i < root.childNodes.count; i++) {
((FeedConfig*)[root.childNodes[i] representedObject]).sortIndex += val;
}
}
#pragma mark - Dragging Support, Data Source Delegate
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard {
[self.managedObjectContext.undoManager beginUndoGrouping];
[pboard declareTypes:[NSArray arrayWithObject:dragNodeType] owner:self];
[pboard setString:@"dragging" forType:dragNodeType];
self.currentlyDraggedNodes = items;
return YES;
}
- (void)outlineView:(NSOutlineView *)outlineView draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation {
self.currentlyDraggedNodes = nil;
[self.managedObjectContext.undoManager endUndoGrouping];
if ([self.managedObjectContext hasChanges]) {
NSError *err;
[self.managedObjectContext save:&err];
if (err) NSLog(@"Error: %@", err);
}
}
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index {
NSArray<NSTreeNode *> *dstChildren = [item childNodes];
if (!item || !dstChildren)
dstChildren = [self arrangedObjects].childNodes;
bool isFolderDrag = (index == -1);
NSUInteger insertIndex = (isFolderDrag ? dstChildren.count : (NSUInteger)index);
// index where the items will be moved to, but not final since items above can vanish
NSIndexPath *dest = [item indexPath];
if (!dest) dest = [NSIndexPath indexPathWithIndex:insertIndex];
else dest = [dest indexPathByAddingIndex:insertIndex];
// decrement index for every item that is dragged from the same location (above the destination)
NSUInteger updateIndex = insertIndex;
for (NSTreeNode *node in self.currentlyDraggedNodes) {
NSIndexPath *nodesPath = [node indexPath];
if ([[nodesPath indexPathByRemovingLastIndex] isEqualTo:[dest indexPathByRemovingLastIndex]] &&
insertIndex > [nodesPath indexAtPosition:nodesPath.length - 1])
{
--updateIndex;
}
}
// decrement sort indices at source
for (NSTreeNode *node in self.currentlyDraggedNodes)
[self incrementIndicesBy:-1 forSubsequentNodes:[node indexPath]];
// increment sort indices at destination
if (!isFolderDrag)
[self incrementIndicesBy:(int)self.currentlyDraggedNodes.count forSubsequentNodes:dest];
// move items
[self moveNodes:self.currentlyDraggedNodes toIndexPath:dest];
// set sort indices for dragged items
for (NSUInteger i = 0; i < self.currentlyDraggedNodes.count; i++) {
FeedConfig *fc = [self.currentlyDraggedNodes[i] representedObject];
fc.sortIndex = (int32_t)(updateIndex + i);
}
return YES;
}
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index {
FeedConfig *fc = [(NSTreeNode*)item representedObject];
if (index == -1 && fc.type != 0) { // if drag is on specific item and that item isnt a group
return NSDragOperationNone;
}
NSTreeNode *parent = item;
while (parent != nil) {
for (NSTreeNode *node in self.currentlyDraggedNodes) {
if (parent == node)
return NSDragOperationNone; // cannot move items into a child of its own
}
parent = [parent parentNode];
}
return NSDragOperationGeneric;
}
@end

View File

@@ -1,95 +0,0 @@
//
// The MIT License (MIT)
// Copyright (c) 2018 Oleg Geier
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import "Preferences.h"
#import "NewsController.h"
#import "ModalSheet.h"
@interface Preferences ()
@property (weak) IBOutlet NSView *viewGeneral;
@property (weak) IBOutlet NSView *viewFeeds;
@property (weak) IBOutlet NewsController *newsController;
@end
@implementation Preferences
- (void)awakeFromNib {
[super awakeFromNib];
NSUInteger idx = (NSUInteger)[[NSUserDefaults standardUserDefaults] integerForKey:@"preferencesTab"];
if (idx >= self.toolbar.items.count)
idx = 0;
[self tabClicked:self.toolbar.items[idx]];
}
- (IBAction)tabClicked:(NSToolbarItem *)sender {
self.contentView = nil;
if ([sender.itemIdentifier isEqualToString:@"tabGeneral"])
self.contentView = self.viewGeneral;
else if ([sender.itemIdentifier isEqualToString:@"tabFeeds"])
self.contentView = self.viewFeeds;
self.toolbar.selectedItemIdentifier = sender.itemIdentifier;
[self recalculateKeyViewLoop];
[self setInitialFirstResponder:self.contentView];
[[NSUserDefaults standardUserDefaults] setInteger:(NSInteger)[self.toolbar.items indexOfObject:sender]
forKey:@"preferencesTab"];
}
- (void)undo:(id)sender {
[self.newsController.managedObjectContext.undoManager undo];
[self.newsController rearrangeObjects]; // update ordering
}
- (void)redo:(id)sender {
[self.newsController.managedObjectContext.undoManager redo];
[self.newsController rearrangeObjects]; // update ordering
}
- (void)copy:(id)sender {
[self.newsController copyDescriptionOfSelectedItems];
}
- (void)enterPressed:(id)sender {
[self.newsController openModalForSelection];
}
- (BOOL)respondsToSelector:(SEL)aSelector {
bool isFeedView = (self.contentView == self.viewFeeds) && !self.attachedSheet;
// Only if 'Feeds' Tab is selected & no open modal sheet & NSOutlineView has focus
if (aSelector == @selector(enterPressed:) || aSelector == @selector(copy:)) {
bool outlineHasFocus = [[self firstResponder] isKindOfClass:[NSOutlineView class]];
return isFeedView && outlineHasFocus && (self.newsController.selectedNodes.count > 0);
} else if (aSelector == @selector(undo:)) {
return isFeedView && [self.newsController.managedObjectContext.undoManager canUndo];
} else if (aSelector == @selector(redo:)) {
return isFeedView && [self.newsController.managedObjectContext.undoManager canRedo];
}
return [super respondsToSelector:aSelector];
}
- (void)presentModal:(NSView*)view completion:(void (^ __nullable)(NSModalResponse returnCode))handler {
[self.modalSheet setFormContent:view];
[self beginSheet:self.modalSheet completionHandler:handler];
}
@end

View File

@@ -22,8 +22,8 @@
#import <Cocoa/Cocoa.h>
@interface ModalSheet : NSWindow
- (void)setFormContent:(NSView *)subcontent;
@interface ModalSheet : NSPanel
+ (instancetype)modalWithView:(NSView*)content;
@end

View File

@@ -0,0 +1,150 @@
//
// The MIT License (MIT)
// Copyright (c) 2018 Oleg Geier
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import "ModalSheet.h"
#define BETWEEN(x,min,max) (x < min ? min : x > max ? max : x)
#pragma mark - ModalSheet
@implementation ModalSheet
- (void)didTapDoneButton:(id)sender { [self closeWithResponse:NSModalResponseOK]; }
- (void)didTapCancelButton:(id)sender { [self closeWithResponse:NSModalResponseAbort]; }
- (void)closeWithResponse:(NSModalResponse)response {
// store modal view width and remove subviews to avoid _NSKeyboardFocusClipView issues
// first object is always the view of the modal dialog
CGFloat w = self.contentView.subviews.firstObject.frame.size.width;
[[NSUserDefaults standardUserDefaults] setInteger:(NSInteger)w forKey:@"modalSheetWidth"];
[self.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
[self.sheetParent endSheet:self returnCode:response];
}
+ (instancetype)modalWithView:(NSView*)content {
static const int padWindow = 20;
static const int padButtons = 12;
static const int minWidth = 320;
static const int maxWidth = 1200;
NSInteger prevWidth = [[NSUserDefaults standardUserDefaults] integerForKey:@"modalSheetWidth"];
NSRect cFrame = NSMakeRect(padWindow, padWindow, BETWEEN(prevWidth, minWidth, maxWidth), content.frame.size.height);
NSRect wFrame = CGRectInset(cFrame, -padWindow, -padWindow);
NSWindowStyleMask style = NSWindowStyleMaskTitled | NSWindowStyleMaskResizable | NSWindowStyleMaskFullSizeContentView;
ModalSheet *sheet = [[super alloc] initWithContentRect:wFrame styleMask:style backing:NSBackingStoreBuffered defer:NO];
// Respond buttons
NSButton *btnDone = [NSButton buttonWithTitle:NSLocalizedString(@"Done", nil) target:sheet action:@selector(didTapDoneButton:)];
btnDone.keyEquivalent = @"\r"; // Enter / Return
btnDone.autoresizingMask = NSViewMinXMargin | NSViewMaxYMargin;
NSButton *btnCancel = [NSButton buttonWithTitle:NSLocalizedString(@"Cancel", nil) target:sheet action:@selector(didTapCancelButton:)];
btnCancel.keyEquivalent = [NSString stringWithFormat:@"%c", 0x1b]; // ESC
btnCancel.autoresizingMask = NSViewMinXMargin | NSViewMaxYMargin;
NSRect align = [btnDone alignmentRectForFrame:btnDone.frame];
align.origin.x = wFrame.size.width - align.size.width - padWindow;
align.origin.y = padWindow;
[btnDone setFrameOrigin:[btnDone frameForAlignmentRect:align].origin];
align.origin.x -= [btnCancel alignmentRectForFrame:btnCancel.frame].size.width + padButtons;
[btnCancel setFrameOrigin:[btnCancel frameForAlignmentRect:align].origin];
// this is equivalent, however I'm not sure if these values will change in a future OS
// [btnDone setFrameOrigin:NSMakePoint(wFrame.size.width - btnDone.frame.size.width - 12, 13)]; // =20 with alignment
// [btnCancel setFrameOrigin:NSMakePoint(btnDone.frame.origin.x - btnCancel.frame.size.width, 13)];
// add all UI elements to the window view
content.frame = cFrame;
[sheet.contentView addSubview:content];
[sheet.contentView addSubview:btnDone];
[sheet.contentView addSubview:btnCancel];
// add respond buttons to the window height
wFrame.size.height += align.size.height + padButtons;
[sheet setContentSize:wFrame.size];
// constraints on resizing
sheet.minSize = NSMakeSize(minWidth + 2 * padWindow, wFrame.size.height);
sheet.maxSize = NSMakeSize(maxWidth, wFrame.size.height);
return sheet;
}
@end
#pragma mark - ModalFeedEdit
@implementation ModalFeedEdit
- (void)setDefaultValues {
self.url.stringValue = @"";
self.title.stringValue = @"";
self.refreshNum.intValue = 30;
[self.refreshUnit selectItemAtIndex:1];
}
- (void)setURL:(NSString*)url name:(NSString*)name refreshNum:(int32_t)num unit:(int16_t)unit {
self.url.objectValue = url;
self.title.objectValue = name;
self.refreshNum.intValue = num;
[self.refreshUnit selectItemAtIndex:BETWEEN(unit, 0, self.refreshUnit.numberOfItems - 1)];
}
+ (NSString*)stringForRefreshNum:(int32_t)num unit:(int16_t)unit {
return [NSString stringWithFormat:@"%d%c", num, [@"smhdw" characterAtIndex:(NSUInteger)BETWEEN(unit, 0, 4)]];
}
@end
#pragma mark - ModalGroupEdit
@implementation ModalGroupEdit
- (void)setDefaultValues {
self.title.stringValue = @"New Group";
}
- (void)setGroupName:(NSString*)name {
self.title.objectValue = name;
}
@end
#pragma mark - StrictUIntFormatter
@implementation StrictUIntFormatter
- (NSString *)stringForObjectValue:(id)obj {
return [NSString stringWithFormat:@"%d", [[NSString stringWithFormat:@"%@", obj] intValue]];
}
- (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)obj forString:(NSString *)string errorDescription:(out NSString *__autoreleasing _Nullable *)error {
*obj = [[NSNumber numberWithInt:[string intValue]] stringValue];
return YES;
}
- (BOOL)isPartialStringValid:(NSString *__autoreleasing _Nonnull *)partialStringPtr proposedSelectedRange:(NSRangePointer)proposedSelRangePtr originalString:(NSString *)origString originalSelectedRange:(NSRange)origSelRange errorDescription:(NSString *__autoreleasing _Nullable *)error {
for (NSUInteger i = 0; i < [*partialStringPtr length]; i++) {
unichar c = [*partialStringPtr characterAtIndex:i];
if (c < '0' || c > '9')
return NO;
}
return YES;
}
@end

View File

@@ -22,10 +22,5 @@
#import <Cocoa/Cocoa.h>
@class ModalSheet;
@interface Preferences : NSWindow
@property (weak) IBOutlet ModalSheet *modalSheet;
- (void)presentModal:(NSView*)view completion:(void (^ __nullable)(NSModalResponse returnCode))handler;
@interface Preferences : NSWindowController <NSWindowDelegate>
@end

View File

@@ -0,0 +1,82 @@
//
// The MIT License (MIT)
// Copyright (c) 2018 Oleg Geier
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import "Preferences.h"
#import "SettingsFeeds.h"
#import "SettingsGeneral.h"
#import "AppDelegate.h"
@interface Preferences ()
@property (weak) IBOutlet SettingsGeneral *settingsGeneral;
@property (weak) IBOutlet SettingsFeeds *settingsFeeds;
@end
@implementation Preferences
- (void)windowDidLoad {
[super windowDidLoad];
NSUInteger idx = (NSUInteger)[[NSUserDefaults standardUserDefaults] integerForKey:@"preferencesTab"];
if (idx >= self.window.toolbar.items.count)
idx = 0;
[self tabClicked:self.window.toolbar.items[idx]];
}
- (IBAction)tabClicked:(NSToolbarItem *)sender {
self.window.contentView = nil;
if ([sender.itemIdentifier isEqualToString:@"tabGeneral"]) {
self.window.contentView = self.settingsGeneral.view;
} else if ([sender.itemIdentifier isEqualToString:@"tabFeeds"]) {
self.window.contentView = self.settingsFeeds.view;
}
self.window.toolbar.selectedItemIdentifier = sender.itemIdentifier;
[self.window recalculateKeyViewLoop];
[self.window setInitialFirstResponder:self.window.contentView];
NSInteger selectedIndex = (NSInteger)[self.window.toolbar.items indexOfObject:sender];
[[NSUserDefaults standardUserDefaults] setInteger:selectedIndex forKey:@"preferencesTab"];
}
- (void)windowWillClose:(NSNotification *)notification {
[(AppDelegate*)[NSApp delegate] preferencesClosed];
}
@end
@interface NonRespondingWindow : NSWindow
@end
@implementation NonRespondingWindow
- (BOOL)respondsToSelector:(SEL)aSelector {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
if (aSelector == @selector(enterPressed:) || aSelector == @selector(copy:)
|| aSelector == @selector(undo:) || aSelector == @selector(redo:)) {
#pragma clang diagnostic pop
return NO;
}
return [super respondsToSelector:aSelector];
}
@end

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="Preferences">
<connections>
<outlet property="settingsFeeds" destination="IYm-V7-352" id="KdS-eY-jdj"/>
<outlet property="settingsGeneral" destination="iap-X4-1Ef" id="VYy-lR-Cba"/>
<outlet property="window" destination="XQ4-ia-CCO" id="rse-30-FqG"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<window title="baRSS Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" frameAutosaveName="prefWindow" animationBehavior="default" tabbingMode="disallowed" id="XQ4-ia-CCO" userLabel="Window" customClass="NonRespondingWindow">
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES"/>
<rect key="contentRect" x="948" y="431" width="320" height="327"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
<value key="minSize" type="size" width="320" height="327"/>
<view key="contentView" id="hcr-99-ABl">
<rect key="frame" x="0.0" y="0.0" width="320" height="327"/>
<autoresizingMask key="autoresizingMask"/>
</view>
<toolbar key="toolbar" implicitIdentifier="5B23E7E6-13E5-4910-875D-2E3EA566F38B" autosavesConfiguration="NO" allowsUserCustomization="NO" displayMode="iconAndLabel" sizeMode="regular" id="vwy-mG-3U7">
<allowedToolbarItems>
<toolbarItem implicitItemIdentifier="AF4483E3-0457-47B7-AE52-AC11B1545455" explicitItemIdentifier="tabGeneral" label="General" paletteLabel="General" tag="-1" image="NSPreferencesGeneral" selectable="YES" id="WDq-RJ-C3X">
<connections>
<action selector="tabClicked:" target="-2" id="P5A-7V-1JL"/>
</connections>
</toolbarItem>
<toolbarItem implicitItemIdentifier="E8527558-3D5F-4B79-99E4-675C1557D10B" explicitItemIdentifier="tabFeeds" label="Feeds" paletteLabel="Feeds" tag="-1" image="NSUserAccounts" selectable="YES" id="atT-AS-vmR">
<connections>
<action selector="tabClicked:" target="-2" id="MVF-hq-6H4"/>
</connections>
</toolbarItem>
</allowedToolbarItems>
<defaultToolbarItems>
<toolbarItem reference="WDq-RJ-C3X"/>
<toolbarItem reference="atT-AS-vmR"/>
</defaultToolbarItems>
</toolbar>
<connections>
<outlet property="delegate" destination="-2" id="QYC-U2-meR"/>
</connections>
<point key="canvasLocation" x="-96" y="741"/>
</window>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<viewController id="iap-X4-1Ef" customClass="SettingsGeneral"/>
<viewController id="IYm-V7-352" customClass="SettingsFeeds"/>
</objects>
<resources>
<image name="NSPreferencesGeneral" width="32" height="32"/>
<image name="NSUserAccounts" width="32" height="32"/>
</resources>
</document>

View File

@@ -0,0 +1,27 @@
//
// The MIT License (MIT)
// Copyright (c) 2018 Oleg Geier
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import <Cocoa/Cocoa.h>
@interface SettingsFeeds : NSViewController <NSOutlineViewDataSource, NSOutlineViewDelegate>
@end

View File

@@ -0,0 +1,344 @@
//
// The MIT License (MIT)
// Copyright (c) 2018 Oleg Geier
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import "SettingsFeeds.h"
#import "DBv1+CoreDataModel.h"
#import "ModalSheet.h"
#import "DrawImage.h"
#import "AppDelegate.h"
@interface SettingsFeeds ()
@property (weak) IBOutlet ModalFeedEdit *viewModalEditFeed;
@property (weak) IBOutlet ModalGroupEdit *viewModalEditGroup;
@property (weak) IBOutlet NSOutlineView *outlineView;
@property (weak) IBOutlet NSTreeController *dataStore;
@property (strong) NSArray<NSTreeNode*> *currentlyDraggedNodes;
@property (strong) NSUndoManager *undoManager;
@end
@implementation SettingsFeeds
// Declare a string constant for the drag type - to be used when writing and retrieving pasteboard data...
static NSString *dragNodeType = @"baRSS-feed-drag";
- (void)viewDidLoad {
[super viewDidLoad];
self.dataStore.managedObjectContext = [(AppDelegate*)[NSApp delegate] persistentContainer].viewContext;
self.undoManager = self.dataStore.managedObjectContext.undoManager;
[self.outlineView registerForDraggedTypes:[NSArray arrayWithObject:dragNodeType]];
[self.dataStore setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"sortIndex" ascending:YES]]];
}
- (IBAction)addFeed:(id)sender {
[self showModalForFeedConfig:nil isGroupEdit:NO];
}
- (IBAction)addGroup:(id)sender {
[self showModalForFeedConfig:nil isGroupEdit:YES];
}
- (IBAction)addSeparator:(id)sender {
[self.undoManager beginUndoGrouping];
FeedConfig *sp = [self insertSortedItemAtSelection];
sp.name = @"---";
sp.type = 2;
[self.undoManager endUndoGrouping];
}
- (IBAction)remove:(id)sender {
[self.undoManager beginUndoGrouping];
for (NSIndexPath *path in self.dataStore.selectionIndexPaths)
[self incrementIndicesBy:-1 forSubsequentNodes:path];
[self.dataStore remove:sender];
[self.undoManager endUndoGrouping];
}
- (IBAction)doubleClickOutlineView:(NSOutlineView*)sender {
if (sender.clickedRow == -1)
return; // ignore clicks on column headers and where no row was selected
FeedConfig *fc = [(NSTreeNode*)[sender itemAtRow:sender.clickedRow] representedObject];
[self showModalForFeedConfig:fc isGroupEdit:YES]; // yes will be overwritten anyway
}
#pragma mark - Insert & Edit Feed Items
- (void)openModalForSelection {
[self showModalForFeedConfig:self.dataStore.selectedObjects.firstObject isGroupEdit:YES]; // yes will be overwritten anyway
}
- (void)showModalForFeedConfig:(FeedConfig*)obj isGroupEdit:(bool)group {
bool existingItem = [obj isKindOfClass:[FeedConfig class]];
if (existingItem) {
if (obj.type == 2) return; // Separator
group = (obj.type == 0);
if (group) [self.viewModalEditGroup setGroupName:obj.name];
else [self.viewModalEditFeed setURL:obj.url name:obj.name refreshNum:obj.refreshNum unit:obj.refreshUnit];
} else {
if (group) [self.viewModalEditGroup setDefaultValues];
else [self.viewModalEditFeed setDefaultValues];
}
NSView *content = (group ? self.viewModalEditGroup : self.viewModalEditFeed);
[self.view.window beginSheet:[ModalSheet modalWithView:content] completionHandler:^(NSModalResponse returnCode) {
if (returnCode == NSModalResponseOK) {
FeedConfig *item = obj;
if (!existingItem) { // create new item
item = [self insertSortedItemAtSelection];
item.type = (group ? 0 : 1);
}
if (group) {
if (![item.name isEqualToString: self.viewModalEditGroup.title.stringValue])
item.name = self.viewModalEditGroup.title.stringValue;
} else {
if (![item.name isEqualToString: self.viewModalEditFeed.title.stringValue])
item.name = self.viewModalEditFeed.title.stringValue;
if (![item.url isEqualToString:self.viewModalEditFeed.url.stringValue])
item.url = self.viewModalEditFeed.url.stringValue;
if (item.refreshNum != self.viewModalEditFeed.refreshNum.intValue)
item.refreshNum = self.viewModalEditFeed.refreshNum.intValue;
if (item.refreshUnit != self.viewModalEditFeed.refreshUnit.indexOfSelectedItem)
item.refreshUnit = (int16_t)self.viewModalEditFeed.refreshUnit.indexOfSelectedItem;
}
[self.dataStore rearrangeObjects];
}
}];
}
- (FeedConfig*)insertSortedItemAtSelection {
NSIndexPath *selectedIndex = [self.dataStore selectionIndexPath];
NSIndexPath *insertIndex = selectedIndex;
FeedConfig *selected = [[[self.dataStore arrangedObjects] descendantNodeAtIndexPath:selectedIndex] representedObject];
NSUInteger lastIndex = selected.children.count;
bool groupSelected = (selected.type == 0);
if (!groupSelected) {
lastIndex = (NSUInteger)selected.sortIndex + 1; // insert after selection
insertIndex = [insertIndex indexPathByRemovingLastIndex];
[self incrementIndicesBy:+1 forSubsequentNodes:selectedIndex];
--selected.sortIndex; // insert after selection
}
FeedConfig *newItem = [[FeedConfig alloc] initWithEntity:FeedConfig.entity insertIntoManagedObjectContext:self.dataStore.managedObjectContext];
[self.dataStore insertObject:newItem atArrangedObjectIndexPath:[insertIndex indexPathByAddingIndex:lastIndex]];
// First insert, then parent, else troubles
newItem.sortIndex = (int32_t)lastIndex;
newItem.parent = (groupSelected ? selected : selected.parent);
return newItem;
}
#pragma mark - Import & Export of Data
- (void)incrementIndicesBy:(int)val forSubsequentNodes:(NSIndexPath*)path {
NSIndexPath *parentPath = [path indexPathByRemovingLastIndex];
NSTreeNode *root = [self.dataStore arrangedObjects];
if (parentPath.length > 0)
root = [root descendantNodeAtIndexPath:parentPath];
for (NSUInteger i = [path indexAtPosition:path.length - 1]; i < root.childNodes.count; i++) {
((FeedConfig*)[root.childNodes[i] representedObject]).sortIndex += val;
}
}
#pragma mark - Dragging Support, Data Source Delegate
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard {
[self.undoManager beginUndoGrouping];
[pboard declareTypes:[NSArray arrayWithObject:dragNodeType] owner:self];
[pboard setString:@"dragging" forType:dragNodeType];
self.currentlyDraggedNodes = items;
return YES;
}
- (void)outlineView:(NSOutlineView *)outlineView draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation {
self.currentlyDraggedNodes = nil;
[self.undoManager endUndoGrouping];
if ([self.dataStore.managedObjectContext hasChanges]) {
NSError *err;
[self.dataStore.managedObjectContext save:&err];
if (err) NSLog(@"Error: %@", err);
}
}
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index {
NSArray<NSTreeNode *> *dstChildren = [item childNodes];
if (!item || !dstChildren)
dstChildren = [self.dataStore arrangedObjects].childNodes;
bool isFolderDrag = (index == -1);
NSUInteger insertIndex = (isFolderDrag ? dstChildren.count : (NSUInteger)index);
// index where the items will be moved to, but not final since items above can vanish
NSIndexPath *dest = [item indexPath];
if (!dest) dest = [NSIndexPath indexPathWithIndex:insertIndex];
else dest = [dest indexPathByAddingIndex:insertIndex];
// decrement index for every item that is dragged from the same location (above the destination)
NSUInteger updateIndex = insertIndex;
for (NSTreeNode *node in self.currentlyDraggedNodes) {
NSIndexPath *nodesPath = [node indexPath];
if ([[nodesPath indexPathByRemovingLastIndex] isEqualTo:[dest indexPathByRemovingLastIndex]] &&
insertIndex > [nodesPath indexAtPosition:nodesPath.length - 1])
{
--updateIndex;
}
}
// decrement sort indices at source
for (NSTreeNode *node in self.currentlyDraggedNodes)
[self incrementIndicesBy:-1 forSubsequentNodes:[node indexPath]];
// increment sort indices at destination
if (!isFolderDrag)
[self incrementIndicesBy:(int)self.currentlyDraggedNodes.count forSubsequentNodes:dest];
// move items
[self.dataStore moveNodes:self.currentlyDraggedNodes toIndexPath:dest];
// set sort indices for dragged items
for (NSUInteger i = 0; i < self.currentlyDraggedNodes.count; i++) {
FeedConfig *fc = [self.currentlyDraggedNodes[i] representedObject];
fc.sortIndex = (int32_t)(updateIndex + i);
}
return YES;
}
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index {
FeedConfig *fc = [(NSTreeNode*)item representedObject];
if (index == -1 && fc.type != 0) { // if drag is on specific item and that item isnt a group
return NSDragOperationNone;
}
NSTreeNode *parent = item;
while (parent != nil) {
for (NSTreeNode *node in self.currentlyDraggedNodes) {
if (parent == node)
return NSDragOperationNone; // cannot move items into a child of its own
}
parent = [parent parentNode];
}
return NSDragOperationGeneric;
}
#pragma mark - Data Source Delegate
- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
FeedConfig *f = [(NSTreeNode*)item representedObject];
bool isFeed = (f.type == 1);
bool isSeperator = (f.type == 2);
bool isRefreshColumn = [tableColumn.identifier isEqualToString:@"RefreshColumn"];
NSString *cellIdent = (isRefreshColumn ? @"cellRefresh" : (isSeperator ? @"cellSeparator" : @"cellFeed"));
// owner is nil to prohibit repeated awakeFromNib calls
NSTableCellView *cellView = [self.outlineView makeViewWithIdentifier:cellIdent owner:nil];
if (isRefreshColumn) {
cellView.textField.stringValue = (!isFeed ? @"" : [ModalFeedEdit stringForRefreshNum:f.refreshNum unit:f.refreshUnit]);
} else if (isSeperator) {
return cellView; // the refresh cell is already skipped with the above if condition
} else {
cellView.textField.objectValue = f.name;
if (f.type == 0) {
cellView.imageView.image = [NSImage imageNamed:NSImageNameFolder];
} else {
// TODO: load icon
static NSImage *defaultRSSIcon;
if (!defaultRSSIcon)
defaultRSSIcon = [[[RSSIcon iconWithSize:cellView.imageView.frame.size] autoGradient] image];
cellView.imageView.image = defaultRSSIcon;
}
}
if (isFeed) // also for refresh column
cellView.textField.textColor = (f.refreshNum == 0 ? [NSColor disabledControlTextColor] : [NSColor controlTextColor]);
return cellView;
}
#pragma mark - Keyboard Commands: undo, redo, copy, enter
- (BOOL)respondsToSelector:(SEL)aSelector {
if (aSelector == @selector(enterPressed:) || aSelector == @selector(copy:)) {
bool outlineHasFocus = [[self.view.window firstResponder] isKindOfClass:[NSOutlineView class]];
return outlineHasFocus && (self.dataStore.selectedNodes.count > 0);
} else if (aSelector == @selector(undo:)) {
return [self.undoManager canUndo];
} else if (aSelector == @selector(redo:)) {
return [self.undoManager canRedo];
}
return [super respondsToSelector:aSelector];
}
- (void)undo:(id)sender {
[self.undoManager undo];
[self.dataStore rearrangeObjects]; // update ordering
}
- (void)redo:(id)sender {
[self.undoManager redo];
[self.dataStore rearrangeObjects]; // update ordering
}
- (void)enterPressed:(id)sender {
[self openModalForSelection];
}
- (void)copy:(id)sender {
NSMutableString *str = [[NSMutableString alloc] init];
NSMutableArray<FeedConfig*> *items = [NSMutableArray arrayWithArray:self.dataStore.selectedObjects];
while (items.count > 0) {
[self traverseChildren:items[0] appendString:str indentation:0 onSelection:items];
}
[[NSPasteboard generalPasteboard] clearContents];
[[NSPasteboard generalPasteboard] setString:str forType:NSPasteboardTypeString];
NSLog(@"%@", str);
}
- (void)traverseChildren:(FeedConfig*)obj appendString:(NSMutableString*)str indentation:(int)indent onSelection:(NSMutableArray*)arr {
for (NSUInteger i = 0; i < arr.count; i++) {
if (obj == arr[i]) {
[arr removeObjectAtIndex:i];
break;
}
}
for (int i = indent; i > 0; i--) {
[str appendString:@" "];
}
switch (obj.type) {
case 0: [str appendFormat:@"%@:\n", obj.name]; break; // Group
case 2: [str appendString:@"-------------\n"]; break; // Separator
default: [str appendFormat:@"%@ (%@) - %@\n", obj.name, obj.url, [ModalFeedEdit stringForRefreshNum:obj.refreshNum unit:obj.refreshUnit]];
}
for (FeedConfig *child in obj.children) {
[self traverseChildren:child appendString:str indentation:indent + 1 onSelection:arr];
}
}
@end

View File

@@ -0,0 +1,346 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="SettingsFeeds">
<connections>
<outlet property="dataStore" destination="JPf-gH-wxm" id="9qy-D6-L4R"/>
<outlet property="outlineView" destination="wP9-Vd-f79" id="nKf-fc-7Np"/>
<outlet property="view" destination="zfc-Ie-Sdx" id="65R-bK-FDI"/>
<outlet property="viewModalEditFeed" destination="0p5-Fv-ym4" id="C7K-zb-25M"/>
<outlet property="viewModalEditGroup" destination="ZZI-U3-ymX" id="G34-k8-YYo"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<treeController mode="entity" entityName="FeedConfig" fetchPredicateFormat="parent == nil" automaticallyPreparesContent="YES" childrenKeyPath="children" leafKeyPath="type" id="JPf-gH-wxm"/>
<customView id="zfc-Ie-Sdx" userLabel="View">
<rect key="frame" x="0.0" y="0.0" width="320" height="327"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="20" horizontalPageScroll="10" verticalLineScroll="20" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="f1F-Mv-bod">
<rect key="frame" x="0.0" y="20" width="320" height="307"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<clipView key="contentView" ambiguous="YES" id="oIL-kH-Krb">
<rect key="frame" x="1" y="0.0" width="318" height="306"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="firstColumnOnly" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="18" rowSizeStyle="automatic" headerView="uEa-oG-fr0" viewBased="YES" indentationPerLevel="15" outlineTableColumn="3Eq-bQ-AGJ" id="wP9-Vd-f79">
<rect key="frame" x="0.0" y="0.0" width="318" height="283"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="NameColumn" editable="NO" width="262" minWidth="40" maxWidth="10000" id="3Eq-bQ-AGJ">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Name">
<font key="font" metaFont="smallSystem"/>
<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="gLU-zA-WTf">
<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="cellFeed" id="066-5N-dID" userLabel="Feed">
<rect key="frame" x="1" y="1" width="262" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qHf-yW-Ks4" userLabel="img">
<rect key="frame" x="1" y="1" width="16" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSActionTemplate" id="NRq-gp-RJ5"/>
</imageView>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="n7N-Pk-80l" userLabel="str">
<rect key="frame" x="23" y="0.0" width="241" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="wHQ-uQ-pww">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="imageView" destination="qHf-yW-Ks4" id="LBQ-xL-3vr"/>
<outlet property="textField" destination="n7N-Pk-80l" id="ei3-ux-jga"/>
</connections>
</tableCellView>
<tableCellView identifier="cellSeparator" id="tjK-7n-uRz" userLabel="Separator">
<rect key="frame" x="1" y="21" width="262" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="G7f-uh-abm" userLabel="img" customClass="DrawSeparator">
<rect key="frame" x="0.0" y="0.0" width="262" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</customView>
</subviews>
</tableCellView>
</prototypeCellViews>
<connections>
<binding destination="JPf-gH-wxm" name="value" keyPath="arrangedObjects" id="HfC-oh-cnN">
<dictionary key="options">
<bool key="NSConditionallySetsEditable" value="YES"/>
<bool key="NSCreatesSortDescriptor" value="NO"/>
</dictionary>
</binding>
</connections>
</tableColumn>
<tableColumn identifier="RefreshColumn" editable="NO" width="50" minWidth="40" maxWidth="100" id="N3k-JC-Czy">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Refresh">
<font key="font" metaFont="smallSystem"/>
<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="bQw-cL-PQs">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<prototypeCellViews>
<tableCellView identifier="cellRefresh" id="Qyt-7v-t3G" userLabel="cellView">
<rect key="frame" x="266" y="1" width="50" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="17I-Oo-q9s" userLabel="str">
<rect key="frame" x="-1" y="0.0" width="52" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="right" title="21042s" id="ZlY-7o-ZTa">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="17I-Oo-q9s" id="i0p-KF-aE8"/>
</connections>
</tableCellView>
</prototypeCellViews>
<connections>
<binding destination="JPf-gH-wxm" name="value" keyPath="arrangedObjects" id="aq0-dy-F1G">
<dictionary key="options">
<bool key="NSConditionallySetsEditable" value="YES"/>
<bool key="NSCreatesSortDescriptor" value="NO"/>
</dictionary>
</binding>
</connections>
</tableColumn>
</tableColumns>
<connections>
<action trigger="doubleAction" selector="doubleClickOutlineView:" target="-2" id="nqp-9A-7ac"/>
<outlet property="dataSource" destination="-2" id="3Iv-Pa-dvh"/>
<outlet property="delegate" destination="-2" id="eCu-Hd-4Ct"/>
</connections>
</outlineView>
</subviews>
</clipView>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="xsa-8D-Emz">
<rect key="frame" x="1" y="7" width="0.0" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="p12-eT-ex6">
<rect key="frame" x="-15" y="23" width="16" height="0.0"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" id="uEa-oG-fr0">
<rect key="frame" x="0.0" y="0.0" width="318" height="23"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
<button toolTip="Create new feed item" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3dn-fo-MZT">
<rect key="frame" x="0.0" y="-1" width="25" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="smallSquare" alternateTitle="Add feed" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="mfH-K0-yNS">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent">n</string>
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</buttonCell>
<connections>
<action selector="addFeed:" target="-2" id="iWE-sh-KY1"/>
<binding destination="JPf-gH-wxm" name="enabled" keyPath="canInsert" id="TJb-gv-6gO"/>
</connections>
</button>
<button toolTip="Delete item" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Xxm-75-8K8">
<rect key="frame" x="24" y="-1" width="25" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="smallSquare" alternateTitle="Remove Feed" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="6iS-E4-jzq">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
CA
</string>
</buttonCell>
<connections>
<action selector="remove:" target="-2" id="JeR-iq-Gjb"/>
<binding destination="JPf-gH-wxm" name="enabled" keyPath="canRemove" id="XYY-gx-tiN"/>
</connections>
</button>
<button toolTip="Add new line separator" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kn9-pd-A47">
<rect key="frame" x="96" y="-1" width="25" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="smallSquare" title="---" alternateTitle="Add separator" bezelStyle="smallSquare" image="NSPathTemplate" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="r9B-nl-XkX">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="addSeparator:" target="-2" id="dVQ-ge-moI"/>
<binding destination="JPf-gH-wxm" name="enabled" keyPath="canInsert" id="2aK-XU-RUD"/>
</connections>
</button>
<button toolTip="Add new grouping folder" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jPg-sh-1Az">
<rect key="frame" x="72" y="-1" width="25" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="smallSquare" alternateTitle="Add group" bezelStyle="smallSquare" image="NSPathTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="rPk-c8-lMe">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent">g</string>
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</buttonCell>
<connections>
<action selector="addGroup:" target="-2" id="V3k-2H-4Kc"/>
<binding destination="JPf-gH-wxm" name="enabled" keyPath="canInsert" id="JCF-ey-YUL"/>
</connections>
</button>
<button hidden="YES" toolTip="Import or Export data" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6ul-3K-fOy">
<rect key="frame" x="295" y="-1" width="25" height="23"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="smallSquare" alternateTitle="Export" bezelStyle="smallSquare" image="NSShareTemplate" imagePosition="overlaps" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="nrA-7c-1sL">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</subviews>
<point key="canvasLocation" x="27" y="883"/>
</customView>
<customView id="0p5-Fv-ym4" userLabel="Modal Edit Feed" customClass="ModalFeedEdit">
<rect key="frame" x="0.0" y="0.0" width="320" height="79"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qGE-iP-bhd" userLabel="URL Label">
<rect key="frame" x="-2" y="60" width="103" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="URL" id="20W-UE-O54">
<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>
<textField verticalHuggingPriority="750" fixedFrame="YES" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dBf-Ic-aFx">
<rect key="frame" x="107" y="58" width="213" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="https://example.org/feed.rss" drawsBackground="YES" usesSingleLineMode="YES" id="9uG-PC-ydS">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Gwc-hR-gQU" userLabel="Name Label">
<rect key="frame" x="-2" y="31" width="103" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Name" id="ZZt-vJ-gqR">
<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>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Sif-B7-ReQ">
<rect key="frame" x="107" y="29" width="213" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="Example Title" drawsBackground="YES" usesSingleLineMode="YES" id="B6j-EO-17H">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OtU-zo-1Fb" userLabel="Refresh Label">
<rect key="frame" x="-2" y="2" width="103" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Refresh" id="XDh-kX-OcM">
<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>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kGm-Pt-t1H">
<rect key="frame" x="107" y="0.0" width="85" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="30" drawsBackground="YES" usesSingleLineMode="YES" id="rm9-UV-YhG">
<customFormatter key="formatter" id="Ubj-jG-b6k" customClass="StrictUIntFormatter"/>
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mB4-d4-lQz" userLabel="TimeUnit">
<rect key="frame" x="198" y="-3" width="125" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Seconds" bezelStyle="rounded" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" autoenablesItems="NO" altersStateOfSelectedItem="NO" selectedItem="KZL-Pi-rjI" id="0ux-Qa-zbq">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" showsStateColumn="NO" autoenablesItems="NO" id="Snb-Bo-1GG">
<items>
<menuItem title="Seconds" keyEquivalent="s" id="TnX-Hk-ZFr">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Minutes" keyEquivalent="m" id="KZL-Pi-rjI">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Hours" keyEquivalent="h" id="uwN-nk-aaQ">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Days" keyEquivalent="d" id="XCA-xq-97w">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="Weeks" keyEquivalent="w" id="r9d-8y-QrY">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
</subviews>
<connections>
<outlet property="refreshNum" destination="kGm-Pt-t1H" id="OJY-yn-Mye"/>
<outlet property="refreshUnit" destination="mB4-d4-lQz" id="xsk-oZ-up1"/>
<outlet property="title" destination="Sif-B7-ReQ" id="vdX-oR-Lvv"/>
<outlet property="url" destination="dBf-Ic-aFx" id="DqH-R5-Sfe"/>
</connections>
<point key="canvasLocation" x="27" y="1131"/>
</customView>
<customView id="ZZI-U3-ymX" userLabel="Modal Edit Group" customClass="ModalGroupEdit">
<rect key="frame" x="0.0" y="0.0" width="260" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zl1-tn-hla">
<rect key="frame" x="0.0" y="0.0" width="260" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="Group Name" placeholderString="Group Name" drawsBackground="YES" usesSingleLineMode="YES" id="afG-YW-7CW">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="title" destination="zl1-tn-hla" id="R4x-bv-CHB"/>
</connections>
<point key="canvasLocation" x="27" y="1229"/>
</customView>
</objects>
<resources>
<image name="NSActionTemplate" width="14" height="14"/>
<image name="NSAddTemplate" width="11" height="11"/>
<image name="NSPathTemplate" width="16" height="10"/>
<image name="NSRemoveTemplate" width="11" height="11"/>
<image name="NSShareTemplate" width="11" height="16"/>
</resources>
</document>

View File

@@ -0,0 +1,27 @@
//
// The MIT License (MIT)
// Copyright (c) 2018 Oleg Geier
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import <Cocoa/Cocoa.h>
@interface SettingsGeneral : NSViewController
@end

View File

@@ -0,0 +1,33 @@
//
// The MIT License (MIT)
// Copyright (c) 2018 Oleg Geier
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import "SettingsGeneral.h"
@implementation SettingsGeneral
- (void)viewDidLoad {
[super viewDidLoad];
}
// TODO: show list of installed browsers and make menu choosable
@end

View File

@@ -0,0 +1,228 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="SettingsGeneral">
<connections>
<outlet property="view" destination="mbb-wD-pDD" id="Syb-4w-ekh"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<userDefaultsController representsSharedInstance="YES" id="iU7-KA-nY5"/>
<customView id="mbb-wD-pDD" userLabel="View">
<rect key="frame" x="0.0" y="0.0" width="320" height="327"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XF4-m8-sya">
<rect key="frame" x="18" y="291" width="284" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Start on login" bezelStyle="regularSquare" imagePosition="left" inset="2" id="WwD-9B-kMx">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="iU7-KA-nY5" name="value" keyPath="values.startOnLogin" id="LnI-lN-nUf">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="0"/>
</dictionary>
</binding>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4Z4-ko-oj2">
<rect key="frame" x="18" y="271" width="284" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Show tick mark for unread entries" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="3cL-4f-90v">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="iU7-KA-nY5" name="value" keyPath="values.markEntries" id="44f-w7-faP">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="yAR-77-YL8">
<rect key="frame" x="18" y="248" width="284" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Show number of unread items:" id="3jA-g1-5aG">
<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>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="QYu-9A-RSx">
<rect key="frame" x="28" y="224" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="in menu bar" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="NHd-8Y-lgR">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="iU7-KA-nY5" name="value" keyPath="values.unreadCountInMenuBar" id="DJz-7q-FEI">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="iGf-ZI-o6t">
<rect key="frame" x="28" y="204" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="in groups" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="fhA-hO-eSv">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="iU7-KA-nY5" name="value" keyPath="values.unreadCountInGroups" id="8R1-go-abo">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ezY-pZ-WN7">
<rect key="frame" x="28" y="184" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="in feeds" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="PgG-Pm-s9M">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="iU7-KA-nY5" name="value" keyPath="values.unreadCountInFeeds" id="7bx-Th-0os">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5s3-gS-ufH">
<rect key="frame" x="18" y="161" width="284" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Show in global menu:" id="6rt-um-3x5">
<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>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Xbr-a8-v9X">
<rect key="frame" x="28" y="137" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Open all unread" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="FT6-me-ACu">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="iU7-KA-nY5" name="value" keyPath="values.globalOpenUnread" id="c20-0p-cPb">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Eyy-w7-79K">
<rect key="frame" x="28" y="117" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Update all feeds" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Z56-ik-iHk">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="iU7-KA-nY5" name="value" keyPath="values.globalUpdateAll" id="FrQ-u0-lFo">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="lAu-qx-vWl">
<rect key="frame" x="28" y="97" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Mark all read" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="8Ko-Cq-fCy">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="iU7-KA-nY5" name="value" keyPath="values.globalMarkRead" id="uiO-3M-xfT">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="eKg-IL-v85">
<rect key="frame" x="28" y="77" width="274" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Mark all unread" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="K4h-ul-R6b">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="iU7-KA-nY5" name="value" keyPath="values.globalMarkUnread" id="drp-87-kfY">
<dictionary key="options">
<bool key="NSAllowsEditingMultipleValuesSelection" value="NO"/>
<integer key="NSNullPlaceholder" value="1"/>
</dictionary>
</binding>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="36q-Dv-PLf">
<rect key="frame" x="18" y="49" width="133" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Menu bar icon:" id="Mkr-3d-gmN">
<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>
<imageView focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="usG-bX-431">
<rect key="frame" x="156" y="42" width="32" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" selectable="YES" editable="YES" focusRingType="none" alignment="left" imageScaling="proportionallyDown" imageFrameStyle="grayBezel" image="NSBookmarksTemplate" id="QxY-0c-aDo"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2sG-NO-OJz">
<rect key="frame" x="18" y="22" width="133" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Open URL in:" id="vNb-i3-dvE">
<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>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BcN-gW-jBg">
<rect key="frame" x="155" y="17" width="148" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Default" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="qW6-vv-pdE" id="R91-En-pHg">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="M0i-AE-1LS">
<items>
<menuItem title="Default" state="on" id="qW6-vv-pdE"/>
<menuItem title="Safari" id="RTt-ZJ-ZHv"/>
<menuItem title="other …" id="hSc-D3-fq8"/>
</items>
</menu>
</popUpButtonCell>
</popUpButton>
</subviews>
<point key="canvasLocation" x="-20" y="903.5"/>
</customView>
</objects>
<resources>
<image name="NSBookmarksTemplate" width="17" height="18"/>
</resources>
</document>