Displaying items in the bar + FeedConfig type enum

This commit is contained in:
relikd
2018-08-15 19:41:52 +02:00
parent 4f688e36a5
commit c4110cd160
15 changed files with 342 additions and 122 deletions

View File

@@ -19,16 +19,18 @@
546FC44321189975007CC3A3 /* SettingsGeneral.m in Sources */ = {isa = PBXBuildFile; fileRef = 546FC44121189975007CC3A3 /* SettingsGeneral.m */; }; 546FC44321189975007CC3A3 /* SettingsGeneral.m in Sources */ = {isa = PBXBuildFile; fileRef = 546FC44121189975007CC3A3 /* SettingsGeneral.m */; };
546FC44421189975007CC3A3 /* SettingsGeneral.xib in Resources */ = {isa = PBXBuildFile; fileRef = 546FC44221189975007CC3A3 /* SettingsGeneral.xib */; }; 546FC44421189975007CC3A3 /* SettingsGeneral.xib in Resources */ = {isa = PBXBuildFile; fileRef = 546FC44221189975007CC3A3 /* SettingsGeneral.xib */; };
546FC4472118A8E6007CC3A3 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 546FC4462118A8E6007CC3A3 /* Preferences.xib */; }; 546FC4472118A8E6007CC3A3 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 546FC4462118A8E6007CC3A3 /* Preferences.xib */; };
5477D34E21233C62002BA27F /* FeedConfig+Ext.m in Sources */ = {isa = PBXBuildFile; fileRef = 5477D34D21233C62002BA27F /* FeedConfig+Ext.m */; };
54ACC28121061B3B0020715F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC28021061B3B0020715F /* AppDelegate.m */; }; 54ACC28121061B3B0020715F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC28021061B3B0020715F /* AppDelegate.m */; };
54ACC28621061B3C0020715F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 54ACC28521061B3C0020715F /* Assets.xcassets */; }; 54ACC28621061B3C0020715F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 54ACC28521061B3C0020715F /* Assets.xcassets */; };
54ACC28921061B3C0020715F /* Main.xib in Resources */ = {isa = PBXBuildFile; fileRef = 54ACC28721061B3C0020715F /* Main.xib */; }; 54ACC28921061B3C0020715F /* Main.xib in Resources */ = {isa = PBXBuildFile; fileRef = 54ACC28721061B3C0020715F /* Main.xib */; };
54ACC28C21061B3C0020715F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC28B21061B3C0020715F /* main.m */; }; 54ACC28C21061B3C0020715F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC28B21061B3C0020715F /* main.m */; };
54ACC29521061E270020715F /* NewsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC29421061E270020715F /* NewsController.m */; }; 54ACC29521061E270020715F /* FeedDownload.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC29421061E270020715F /* FeedDownload.m */; };
54ACC29821061FBA0020715F /* Preferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC29721061FBA0020715F /* Preferences.m */; }; 54ACC29821061FBA0020715F /* Preferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC29721061FBA0020715F /* Preferences.m */; };
54E88320211B509D00064188 /* ModalFeedEdit.m in Sources */ = {isa = PBXBuildFile; fileRef = 54E8831E211B509D00064188 /* ModalFeedEdit.m */; }; 54E88320211B509D00064188 /* ModalFeedEdit.m in Sources */ = {isa = PBXBuildFile; fileRef = 54E8831E211B509D00064188 /* ModalFeedEdit.m */; };
54E88321211B509D00064188 /* ModalFeedEdit.xib in Resources */ = {isa = PBXBuildFile; fileRef = 54E8831F211B509D00064188 /* ModalFeedEdit.xib */; }; 54E88321211B509D00064188 /* ModalFeedEdit.xib in Resources */ = {isa = PBXBuildFile; fileRef = 54E8831F211B509D00064188 /* ModalFeedEdit.xib */; };
54F39C2E210BE1F700AEE730 /* DBv1.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC28221061B3B0020715F /* DBv1.xcdatamodeld */; }; 54F39C2E210BE1F700AEE730 /* DBv1.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC28221061B3B0020715F /* DBv1.xcdatamodeld */; };
54FE73D021220DEC003EAC65 /* StoreCoordinator.m in Sources */ = {isa = PBXBuildFile; fileRef = 54FE73CF21220DEC003EAC65 /* StoreCoordinator.m */; }; 54FE73D021220DEC003EAC65 /* StoreCoordinator.m in Sources */ = {isa = PBXBuildFile; fileRef = 54FE73CF21220DEC003EAC65 /* StoreCoordinator.m */; };
54FE73D3212316CD003EAC65 /* BarMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 54FE73D2212316CD003EAC65 /* BarMenu.m */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@@ -50,6 +52,8 @@
546FC44121189975007CC3A3 /* SettingsGeneral.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsGeneral.m; sourceTree = "<group>"; }; 546FC44121189975007CC3A3 /* SettingsGeneral.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsGeneral.m; sourceTree = "<group>"; };
546FC44221189975007CC3A3 /* SettingsGeneral.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SettingsGeneral.xib; 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>"; }; 546FC4462118A8E6007CC3A3 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Preferences.xib; sourceTree = "<group>"; };
5477D34C21233C62002BA27F /* FeedConfig+Ext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FeedConfig+Ext.h"; sourceTree = "<group>"; };
5477D34D21233C62002BA27F /* FeedConfig+Ext.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "FeedConfig+Ext.m"; sourceTree = "<group>"; };
54ACC27C21061B3B0020715F /* baRSS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = baRSS.app; sourceTree = BUILT_PRODUCTS_DIR; }; 54ACC27C21061B3B0020715F /* baRSS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = baRSS.app; sourceTree = BUILT_PRODUCTS_DIR; };
54ACC27F21061B3B0020715F /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; 54ACC27F21061B3B0020715F /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
54ACC28021061B3B0020715F /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; 54ACC28021061B3B0020715F /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
@@ -58,16 +62,17 @@
54ACC28821061B3C0020715F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Main.xib; sourceTree = "<group>"; }; 54ACC28821061B3C0020715F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Main.xib; sourceTree = "<group>"; };
54ACC28A21061B3C0020715F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 54ACC28A21061B3C0020715F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
54ACC28B21061B3C0020715F /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; 54ACC28B21061B3C0020715F /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
54ACC29321061E270020715F /* NewsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewsController.h; sourceTree = "<group>"; }; 54ACC29321061E270020715F /* FeedDownload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FeedDownload.h; sourceTree = "<group>"; };
54ACC29421061E270020715F /* NewsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewsController.m; sourceTree = "<group>"; }; 54ACC29421061E270020715F /* FeedDownload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FeedDownload.m; sourceTree = "<group>"; };
54ACC29621061FBA0020715F /* Preferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Preferences.h; sourceTree = "<group>"; }; 54ACC29621061FBA0020715F /* Preferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Preferences.h; sourceTree = "<group>"; };
54ACC29721061FBA0020715F /* Preferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Preferences.m; sourceTree = "<group>"; }; 54ACC29721061FBA0020715F /* Preferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Preferences.m; sourceTree = "<group>"; };
54E8831D211B509D00064188 /* ModalFeedEdit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModalFeedEdit.h; sourceTree = "<group>"; }; 54E8831D211B509D00064188 /* ModalFeedEdit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModalFeedEdit.h; sourceTree = "<group>"; };
54E8831E211B509D00064188 /* ModalFeedEdit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModalFeedEdit.m; sourceTree = "<group>"; }; 54E8831E211B509D00064188 /* ModalFeedEdit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModalFeedEdit.m; sourceTree = "<group>"; };
54E8831F211B509D00064188 /* ModalFeedEdit.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ModalFeedEdit.xib; sourceTree = "<group>"; }; 54E8831F211B509D00064188 /* ModalFeedEdit.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ModalFeedEdit.xib; sourceTree = "<group>"; };
54EC3E1D211D03C100E314F4 /* FeedConfig+Print.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FeedConfig+Print.h"; sourceTree = "<group>"; };
54FE73CE21220DEC003EAC65 /* StoreCoordinator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StoreCoordinator.h; sourceTree = "<group>"; }; 54FE73CE21220DEC003EAC65 /* StoreCoordinator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StoreCoordinator.h; sourceTree = "<group>"; };
54FE73CF21220DEC003EAC65 /* StoreCoordinator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StoreCoordinator.m; sourceTree = "<group>"; }; 54FE73CF21220DEC003EAC65 /* StoreCoordinator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StoreCoordinator.m; sourceTree = "<group>"; };
54FE73D1212316CD003EAC65 /* BarMenu.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BarMenu.h; sourceTree = "<group>"; };
54FE73D2212316CD003EAC65 /* BarMenu.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BarMenu.m; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -103,7 +108,8 @@
546FC44D2118B357007CC3A3 /* Preferences */ = { 546FC44D2118B357007CC3A3 /* Preferences */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
54EC3E1D211D03C100E314F4 /* FeedConfig+Print.h */, 5477D34C21233C62002BA27F /* FeedConfig+Ext.h */,
5477D34D21233C62002BA27F /* FeedConfig+Ext.m */,
54ACC29621061FBA0020715F /* Preferences.h */, 54ACC29621061FBA0020715F /* Preferences.h */,
54ACC29721061FBA0020715F /* Preferences.m */, 54ACC29721061FBA0020715F /* Preferences.m */,
546FC4462118A8E6007CC3A3 /* Preferences.xib */, 546FC4462118A8E6007CC3A3 /* Preferences.xib */,
@@ -151,10 +157,12 @@
544B011C2114EE9100386E5C /* AppHook.m */, 544B011C2114EE9100386E5C /* AppHook.m */,
54ACC27F21061B3B0020715F /* AppDelegate.h */, 54ACC27F21061B3B0020715F /* AppDelegate.h */,
54ACC28021061B3B0020715F /* AppDelegate.m */, 54ACC28021061B3B0020715F /* AppDelegate.m */,
54FE73D1212316CD003EAC65 /* BarMenu.h */,
54FE73D2212316CD003EAC65 /* BarMenu.m */,
54FE73CE21220DEC003EAC65 /* StoreCoordinator.h */, 54FE73CE21220DEC003EAC65 /* StoreCoordinator.h */,
54FE73CF21220DEC003EAC65 /* StoreCoordinator.m */, 54FE73CF21220DEC003EAC65 /* StoreCoordinator.m */,
54ACC29321061E270020715F /* NewsController.h */, 54ACC29321061E270020715F /* FeedDownload.h */,
54ACC29421061E270020715F /* NewsController.m */, 54ACC29421061E270020715F /* FeedDownload.m */,
54209E922117325100F3B5EF /* DrawImage.h */, 54209E922117325100F3B5EF /* DrawImage.h */,
54209E932117325100F3B5EF /* DrawImage.m */, 54209E932117325100F3B5EF /* DrawImage.m */,
546FC44D2118B357007CC3A3 /* Preferences */, 546FC44D2118B357007CC3A3 /* Preferences */,
@@ -267,9 +275,11 @@
54F39C2E210BE1F700AEE730 /* DBv1.xcdatamodeld in Sources */, 54F39C2E210BE1F700AEE730 /* DBv1.xcdatamodeld in Sources */,
544B011D2114EE9100386E5C /* AppHook.m in Sources */, 544B011D2114EE9100386E5C /* AppHook.m in Sources */,
546FC44321189975007CC3A3 /* SettingsGeneral.m in Sources */, 546FC44321189975007CC3A3 /* SettingsGeneral.m in Sources */,
54ACC29521061E270020715F /* NewsController.m in Sources */, 54ACC29521061E270020715F /* FeedDownload.m in Sources */,
5477D34E21233C62002BA27F /* FeedConfig+Ext.m in Sources */,
54ACC28C21061B3C0020715F /* main.m in Sources */, 54ACC28C21061B3C0020715F /* main.m in Sources */,
54ACC28121061B3B0020715F /* AppDelegate.m in Sources */, 54ACC28121061B3B0020715F /* AppDelegate.m in Sources */,
54FE73D3212316CD003EAC65 /* BarMenu.m in Sources */,
544B011A2114B41200386E5C /* ModalSheet.m in Sources */, 544B011A2114B41200386E5C /* ModalSheet.m in Sources */,
54ACC29821061FBA0020715F /* Preferences.m in Sources */, 54ACC29821061FBA0020715F /* Preferences.m in Sources */,
546FC43D21188AD5007CC3A3 /* SettingsFeeds.m in Sources */, 546FC43D21188AD5007CC3A3 /* SettingsFeeds.m in Sources */,

View File

@@ -26,6 +26,5 @@
@interface AppDelegate : NSObject <NSApplicationDelegate> @interface AppDelegate : NSObject <NSApplicationDelegate>
@property (readonly, strong) NSPersistentContainer *persistentContainer; @property (readonly, strong) NSPersistentContainer *persistentContainer;
- (IBAction)saveAction:(id)sender; - (IBAction)saveAction:(id)sender;
- (void)preferencesClosed;
@end @end

View File

@@ -22,45 +22,24 @@
#import "AppDelegate.h" #import "AppDelegate.h"
#import "PyHandler.h" #import "PyHandler.h"
#import "DrawImage.h" #import "BarMenu.h"
#import "Preferences.h"
#import "StoreCoordinator.h"
@interface AppDelegate () @interface AppDelegate ()
@property (weak) IBOutlet NSMenu *statusMenu; @property (strong) BarMenu *barMenu;
@property (strong) NSStatusItem *statusItem;
@property (strong) Preferences *prefWindow;
@end @end
@implementation AppDelegate @implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.statusItem = [NSStatusBar.systemStatusBar statusItemWithLength:NSVariableStatusItemLength]; self.barMenu = [BarMenu new];
self.statusItem.title = @"me";
self.statusItem.menu = self.statusMenu;
self.statusItem.highlightMode = YES;
self.statusItem.image = [[RSSIcon templateIcon:16 tint:nil] image];
self.statusItem.image.template = YES;
[PyHandler prepare]; [PyHandler prepare];
printf("up and running\n"); printf("up and running\n");
// [StoreCoordinator deleteUnreferencedFeeds];
} }
- (void)applicationWillTerminate:(NSNotification *)aNotification { - (void)applicationWillTerminate:(NSNotification *)aNotification {
[PyHandler shutdown]; [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 #pragma mark - Core Data stack
@synthesize persistentContainer = _persistentContainer; @synthesize persistentContainer = _persistentContainer;

View File

@@ -22,6 +22,6 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
@interface NewsController : NSObject @interface BarMenu : NSObject <NSMenuDelegate>
+ (void)downloadFeed:(NSString*)url withBlock:(nullable void (^)(NSDictionary* result, NSError* error))block; //+ (instancetype)start;
@end @end

196
baRSS/BarMenu.m Normal file
View File

@@ -0,0 +1,196 @@
//
// 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 "BarMenu.h"
#import "StoreCoordinator.h"
#import "DrawImage.h"
#import "Preferences.h"
@interface BarMenu()
@property (strong) NSStatusItem *barItem;
@property (strong) Preferences *prefWindow;
@property (weak) NSMenu *mm;
@end
@implementation BarMenu
- (instancetype)init {
self = [super init];
self.barItem = [self statusItem];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(preferencesClosed) name:@"baRSSPreferencesClosed" object:nil];
// [self donothing];
return self;
}
- (void)donothing {
dispatch_async(dispatch_get_main_queue(), ^{
[self.mm itemAtIndex:4].title = [NSString stringWithFormat:@"%@", [NSDate date]];
});
sleep(1);
[self performSelectorInBackground:@selector(donothing) withObject:nil];
}
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (NSStatusItem*)statusItem {
NSStatusItem *item = [NSStatusBar.systemStatusBar statusItemWithLength:NSVariableStatusItemLength];
item.title = @"me";
item.menu = self.mainMenu;
item.highlightMode = YES;
item.image = [[RSSIcon templateIcon:16 tint:nil] image];
item.image.template = YES;
return item;
}
- (void)openPreferences {
if (!self.prefWindow)
self.prefWindow = [[Preferences alloc] initWithWindowNibName:@"Preferences"];
[NSApp activateIgnoringOtherApps:YES];
[self.prefWindow showWindow:nil];
}
- (void)preferencesClosed {
self.prefWindow = nil;
}
#pragma mark - Main Menu Item Actions
- (void)pauseUpdates {
NSLog(@"1pause");
}
- (void)updateAllFeeds {
NSLog(@"1update all");
}
- (void)openAllUnread {
NSLog(@"1all unread");
}
- (void)openFeedURL:(NSMenuItem*)sender {
id obj = [StoreCoordinator objectWithID:sender.representedObject];
NSString *url = nil;
if ([obj isKindOfClass:[FeedItem class]]) {
url = [(FeedItem*)obj link];
} else if ([obj isKindOfClass:[FeedConfig class]]) {
url = [[(FeedConfig*)obj feed] link];
}
if (!url || url.length == 0) return;
[[NSWorkspace sharedWorkspace] openURLs:@[[NSURL URLWithString:url]] withAppBundleIdentifier:@"com.apple.Safari" options:NSWorkspaceLaunchDefault additionalEventParamDescriptor:nil launchIdentifiers:nil];
}
#pragma mark - Menu Generator
- (NSMenu*)mainMenu {
NSMenu *menu = [NSMenu new];
menu.autoenablesItems = NO;
// self.mm = menu;
[self addTitle:@"Pause Updates" selector:@selector(pauseUpdates) key:@"" toMenu:menu];
[self addTitle:@"Update all feeds" selector:@selector(updateAllFeeds) key:@"" toMenu:menu];
[self addTitle:@"Open all unread" selector:@selector(openAllUnread) key:@"" toMenu:menu];
[menu addItem:[NSMenuItem separatorItem]];
NSArray<FeedConfig*> *items = [StoreCoordinator sortedFeedConfigItems];
for (FeedConfig *fc in items) {
[menu addItem:[self menuItemForFeedConfig:fc]];
}
[menu addItem:[NSMenuItem separatorItem]];
[self addTitle:@"Preferences" selector:@selector(openPreferences) key:@"," toMenu:menu];
[menu addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
return menu;
}
- (void)addTitle:(NSString*)title selector:(SEL)selector key:(NSString*)key toMenu:(NSMenu*)menu {
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:title action:selector keyEquivalent:key];
item.target = self;
[menu addItem:item];
}
- (NSMenuItem*)menuItemForFeedConfig:(FeedConfig*)fc {
NSMenuItem *item;
if (fc.typ == SEPARATOR) {
item = [NSMenuItem separatorItem];
} else {
item = [[NSMenuItem alloc] initWithTitle:fc.name action:nil keyEquivalent:@""];
if (fc.typ == FEED) {
item.submenu = [self menuForFeed:fc.feed];
item.action = @selector(openFeedURL:);
item.target = self;
item.toolTip = fc.feed.subtitle;
item.enabled = (fc.feed.link.length > 0);
static NSImage *defaultRSSIcon;
if (!defaultRSSIcon)
defaultRSSIcon = [[[RSSIcon iconWithSize:NSMakeSize(16, 16)] autoGradient] image];
item.image = defaultRSSIcon;
} else {
item.submenu = [self menuForFeedConfig:fc];
item.image = [NSImage imageNamed:NSImageNameFolder];
item.image.size = NSMakeSize(16, 16);
}
}
item.representedObject = fc.objectID;
return item;
}
- (NSMenu*)menuForFeedConfig:(FeedConfig*)parent {
NSMenu *menu = [NSMenu new];
menu.autoenablesItems = NO;
// TODO: open unread for groups ...
for (FeedConfig *fc in parent.sortedChildren) {
[menu addItem:[self menuItemForFeedConfig:fc]];
}
return menu;
}
- (NSMenu*)menuForFeed:(Feed*)feed {
NSMenu *menu = [NSMenu new];
menu.autoenablesItems = NO;
// TODO: open unread for feed only ...
for (FeedItem *entry in feed.items) {
[menu addItem:[self menuItemForFeedItem:entry]];
}
return menu;
}
- (NSMenuItem*)menuItemForFeedItem:(FeedItem*)item {
NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle:item.title action:@selector(openFeedURL:) keyEquivalent:@""];
mi.target = self;
mi.representedObject = item.objectID;
mi.toolTip = item.subtitle;
mi.enabled = (item.link.length > 0);
return mi;
}
//- (NSIndexPath*)indexPathForMenu:(NSMenu*)menu {
// NSMenu *parent = menu.supermenu;
// if (parent == nil) {
// return [NSIndexPath new];
// } else {
// return [[self indexPathForMenu:parent] indexPathByAddingIndex:(NSUInteger)[parent indexOfItemWithSubmenu:menu]];
// }
//}
@end

View File

@@ -12,46 +12,6 @@
</customObject> </customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/> <customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate"> <customObject id="Voe-Tx-rLC" customClass="AppDelegate"/>
<connections>
<outlet property="statusMenu" destination="tDc-nD-HS2" id="eHw-32-GGa"/>
</connections>
</customObject>
<menu id="tDc-nD-HS2">
<items>
<menuItem title="Pause Updates" id="D7r-Vb-9eO">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<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="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="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="openPreferences:" target="Voe-Tx-rLC" id="a8v-fo-Drx"/>
</connections>
</menuItem>
<menuItem title="Quit" keyEquivalent="q" id="Nb6-yK-a1A">
<connections>
<action selector="terminate:" target="-1" id="STj-gf-HrE"/>
</connections>
</menuItem>
</items>
<point key="canvasLocation" x="-47" y="485"/>
</menu>
<customObject id="gkw-5j-nxL" customClass="NewsController"/>
</objects> </objects>
</document> </document>

27
baRSS/FeedDownload.h Normal file
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 FeedDownload : NSObject
+ (void)getFeed:(NSString*)url withBlock:(nullable void (^)(NSDictionary* result, NSError* error))block;
@end

View File

@@ -20,27 +20,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.
#import "NewsController.h" #import "FeedDownload.h"
#import "PyHandler.h" #import "PyHandler.h"
@interface NewsController () @implementation FeedDownload
@end
@implementation NewsController + (void)getFeed:(NSString*)url withBlock:(nullable void (^)(NSDictionary* result, NSError* error))block {
- (IBAction)pauseUpdates:(NSMenuItem *)sender {
NSLog(@"pause");
}
- (IBAction)updateAllFeeds:(NSMenuItem *)sender {
NSLog(@"update all");
}
- (IBAction)openAllUnread:(NSMenuItem *)sender {
NSLog(@"all unread");
}
+ (void)downloadFeed:(NSString*)url withBlock:(nullable void (^)(NSDictionary* result, NSError* error))block {
[NSThread detachNewThreadWithBlock:^{ [NSThread detachNewThreadWithBlock:^{
NSDictionary *dict = [PyHandler getFeed:url withEtag:nil andModified:nil]; NSDictionary *dict = [PyHandler getFeed:url withEtag:nil andModified:nil];
NSError *err = nil; NSError *err = nil;

View File

@@ -0,0 +1,36 @@
//
// 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 "FeedConfig+CoreDataClass.h"
@interface FeedConfig (Ext)
typedef enum int16_t {
GROUP = 0,
FEED = 1,
SEPARATOR = 2
} FeedConfigType;
@property (getter=typ, setter=setTyp:) FeedConfigType typ;
@property (readonly) NSArray<FeedConfig*> *sortedChildren;
- (NSString*)readableRefreshString;
- (NSString*)readableDescription;
@end

View File

@@ -20,21 +20,35 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE. // SOFTWARE.
#ifndef FeedConfig_Print_h #import "FeedConfig+Ext.h"
#define FeedConfig_Print_h
@implementation FeedConfig (Ext)
- (FeedConfigType)typ {
return (FeedConfigType)self.type;
}
- (void)setTyp:(FeedConfigType)typ {
self.type = typ;
}
- (NSArray<FeedConfig *> *)sortedChildren {
if (self.children.count == 0)
return nil;
return [self.children sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"sortIndex" ascending:YES]]];
}
@implementation FeedConfig (Print)
- (NSString*)readableRefreshString { - (NSString*)readableRefreshString {
return [NSString stringWithFormat:@"%d%c", self.refreshNum, [@"smhdw" characterAtIndex:self.refreshUnit % 5]]; return [NSString stringWithFormat:@"%d%c", self.refreshNum, [@"smhdw" characterAtIndex:self.refreshUnit % 5]];
} }
- (NSString*)readableDescription { - (NSString*)readableDescription {
switch (self.type) { switch (self.typ) {
case 0: return [NSString stringWithFormat:@"%@", self.name]; // Group case SEPARATOR: return @"-------------";
case 2: return @"-------------"; // Separator case GROUP: return [NSString stringWithFormat:@"%@", self.name];
default: case FEED:
return [NSString stringWithFormat:@"%@ (%@) - %@", self.name, self.url, [self readableRefreshString]]; return [NSString stringWithFormat:@"%@ (%@) - %@", self.name, self.url, [self readableRefreshString]];
} }
} }
@end
#endif /* FeedConfig_Print_h */ @end

View File

@@ -21,9 +21,8 @@
// SOFTWARE. // SOFTWARE.
#import "ModalFeedEdit.h" #import "ModalFeedEdit.h"
#import "NewsController.h" #import "FeedDownload.h"
#import "StoreCoordinator.h" #import "StoreCoordinator.h"
#import "FeedConfig+CoreDataProperties.h"
@interface ModalFeedEdit() @interface ModalFeedEdit()
@property (weak) IBOutlet NSTextField *url; @property (weak) IBOutlet NSTextField *url;
@@ -140,7 +139,7 @@
self.feedError = nil; self.feedError = nil;
[self.spinnerURL startAnimation:nil]; [self.spinnerURL startAnimation:nil];
[self.spinnerName startAnimation:nil]; [self.spinnerName startAnimation:nil];
[NewsController downloadFeed:self.previousURL withBlock:^(NSDictionary *result, NSError *error) { [FeedDownload getFeed:self.previousURL withBlock:^(NSDictionary *result, NSError *error) {
self.feedResult = result; self.feedResult = result;
self.feedError = error; // warning indicator .hidden is bound to feedError self.feedError = error; // warning indicator .hidden is bound to feedError
// TODO: play error sound? // TODO: play error sound?

View File

@@ -22,8 +22,7 @@
#import "SettingsFeeds.h" #import "SettingsFeeds.h"
#import "AppDelegate.h" #import "AppDelegate.h"
#import "DBv1+CoreDataModel.h" #import "FeedConfig+Ext.h"
#import "FeedConfig+Print.h"
#import "ModalSheet.h" #import "ModalSheet.h"
#import "ModalFeedEdit.h" #import "ModalFeedEdit.h"
#import "DrawImage.h" #import "DrawImage.h"
@@ -62,7 +61,7 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
[self.undoManager beginUndoGrouping]; [self.undoManager beginUndoGrouping];
FeedConfig *sp = [self insertSortedItemAtSelection]; FeedConfig *sp = [self insertSortedItemAtSelection];
sp.name = @"---"; sp.name = @"---";
sp.type = 2; sp.typ = SEPARATOR;
[self.undoManager endUndoGrouping]; [self.undoManager endUndoGrouping];
} }
@@ -93,8 +92,8 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
- (void)showModalForFeedConfig:(FeedConfig*)obj isGroupEdit:(BOOL)group { - (void)showModalForFeedConfig:(FeedConfig*)obj isGroupEdit:(BOOL)group {
BOOL existingItem = [obj isKindOfClass:[FeedConfig class]]; BOOL existingItem = [obj isKindOfClass:[FeedConfig class]];
if (existingItem) { if (existingItem) {
if (obj.type == 2) return; // Separator if (obj.typ == SEPARATOR) return;
group = (obj.type == 0); group = (obj.typ == GROUP);
} }
self.modalController = (group ? [ModalGroupEdit new] : [ModalFeedEdit new]); self.modalController = (group ? [ModalGroupEdit new] : [ModalFeedEdit new]);
self.modalController.representedObject = obj; self.modalController.representedObject = obj;
@@ -104,7 +103,7 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
[self.undoManager beginUndoGrouping]; [self.undoManager beginUndoGrouping];
if (!existingItem) { // create new item if (!existingItem) { // create new item
FeedConfig *item = [self insertSortedItemAtSelection]; FeedConfig *item = [self insertSortedItemAtSelection];
item.type = (group ? 0 : 1); item.typ = (group ? GROUP : FEED);
self.modalController.representedObject = item; self.modalController.representedObject = item;
} }
[self.modalController updateRepresentedObject]; [self.modalController updateRepresentedObject];
@@ -120,7 +119,7 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
FeedConfig *selected = [[[self.dataStore arrangedObjects] descendantNodeAtIndexPath:selectedIndex] representedObject]; FeedConfig *selected = [[[self.dataStore arrangedObjects] descendantNodeAtIndexPath:selectedIndex] representedObject];
NSUInteger lastIndex = selected.children.count; NSUInteger lastIndex = selected.children.count;
BOOL groupSelected = (selected.type == 0); BOOL groupSelected = (selected.typ == GROUP);
if (!groupSelected) { if (!groupSelected) {
lastIndex = (NSUInteger)selected.sortIndex + 1; // insert after selection lastIndex = (NSUInteger)selected.sortIndex + 1; // insert after selection
@@ -217,7 +216,7 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index { - (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index {
FeedConfig *fc = [(NSTreeNode*)item representedObject]; FeedConfig *fc = [(NSTreeNode*)item representedObject];
if (index == -1 && fc.type != 0) { // if drag is on specific item and that item isnt a group if (index == -1 && fc.typ != GROUP) { // if drag is on specific item and that item isnt a group
return NSDragOperationNone; return NSDragOperationNone;
} }
@@ -238,8 +237,8 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item { - (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
FeedConfig *f = [(NSTreeNode*)item representedObject]; FeedConfig *f = [(NSTreeNode*)item representedObject];
BOOL isFeed = (f.type == 1); BOOL isFeed = (f.typ == FEED);
BOOL isSeperator = (f.type == 2); BOOL isSeperator = (f.typ == SEPARATOR);
BOOL isRefreshColumn = [tableColumn.identifier isEqualToString:@"RefreshColumn"]; BOOL isRefreshColumn = [tableColumn.identifier isEqualToString:@"RefreshColumn"];
NSString *cellIdent = (isRefreshColumn ? @"cellRefresh" : (isSeperator ? @"cellSeparator" : @"cellFeed")); NSString *cellIdent = (isRefreshColumn ? @"cellRefresh" : (isSeperator ? @"cellSeparator" : @"cellFeed"));
@@ -252,7 +251,7 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
return cellView; // the refresh cell is already skipped with the above if condition return cellView; // the refresh cell is already skipped with the above if condition
} else { } else {
cellView.textField.objectValue = f.name; cellView.textField.objectValue = f.name;
if (f.type == 0) { if (f.typ == GROUP) {
cellView.imageView.image = [NSImage imageNamed:NSImageNameFolder]; cellView.imageView.image = [NSImage imageNamed:NSImageNameFolder];
} else { } else {
// TODO: load icon // TODO: load icon
@@ -283,7 +282,7 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
if (aSelector == @selector(copy:)) if (aSelector == @selector(copy:))
return YES; return YES;
// can edit only if selection is not a separator // can edit only if selection is not a separator
return (((FeedConfig*)self.dataStore.selectedNodes.firstObject.representedObject).type != 2); return (((FeedConfig*)self.dataStore.selectedNodes.firstObject.representedObject).typ != SEPARATOR);
} }
return [super respondsToSelector:aSelector]; return [super respondsToSelector:aSelector];
} }

View File

@@ -23,7 +23,6 @@
#import "Preferences.h" #import "Preferences.h"
#import "SettingsFeeds.h" #import "SettingsFeeds.h"
#import "SettingsGeneral.h" #import "SettingsGeneral.h"
#import "AppDelegate.h"
@interface Preferences () @interface Preferences ()
@@ -58,7 +57,7 @@
} }
- (void)windowWillClose:(NSNotification *)notification { - (void)windowWillClose:(NSNotification *)notification {
[(AppDelegate*)[NSApp delegate] preferencesClosed]; [[NSNotificationCenter defaultCenter] postNotificationName:@"baRSSPreferencesClosed" object:nil];
} }
@end @end

View File

@@ -21,11 +21,14 @@
// SOFTWARE. // SOFTWARE.
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import "DBv1+CoreDataModel.h"
#import "FeedConfig+Ext.h"
@class Feed;
@interface StoreCoordinator : NSObject @interface StoreCoordinator : NSObject
+ (void)save; + (void)save;
+ (void)deleteUnreferencedFeeds; + (void)deleteUnreferencedFeeds;
+ (NSArray<FeedConfig*>*)sortedFeedConfigItems;
+ (id)objectWithID:(NSManagedObjectID*)objID;
+ (Feed*)createFeedFromDictionary:(NSDictionary*)obj; + (Feed*)createFeedFromDictionary:(NSDictionary*)obj;
@end @end

View File

@@ -22,7 +22,6 @@
#import "StoreCoordinator.h" #import "StoreCoordinator.h"
#import "AppDelegate.h" #import "AppDelegate.h"
#import "DBv1+CoreDataModel.h"
@implementation StoreCoordinator @implementation StoreCoordinator
@@ -44,6 +43,21 @@
if (err) NSLog(@"%@", err); if (err) NSLog(@"%@", err);
} }
+ (NSArray<FeedConfig*>*)sortedFeedConfigItems {
NSManagedObjectContext *moc = [self getContext];
NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName: FeedConfig.entity.name];
fr.predicate = [NSPredicate predicateWithFormat:@"parent = NULL"]; // %@", parent
fr.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"sortIndex" ascending:YES]];
NSError *err;
NSArray *result = [moc executeFetchRequest:fr error:&err];
if (err) NSLog(@"%@", err);
return result;
}
+ (id)objectWithID:(NSManagedObjectID*)objID {
return [[self getContext] objectWithID:objID];
}
+ (Feed*)createFeedFromDictionary:(NSDictionary*)obj { + (Feed*)createFeedFromDictionary:(NSDictionary*)obj {
NSManagedObjectContext *moc = [self getContext]; NSManagedObjectContext *moc = [self getContext];
Feed *a = [[Feed alloc] initWithEntity:Feed.entity insertIntoManagedObjectContext:moc]; Feed *a = [[Feed alloc] initWithEntity:Feed.entity insertIntoManagedObjectContext:moc];