Storing of feed entries and fetched property bugfix
This commit is contained in:
@@ -28,43 +28,46 @@
|
|||||||
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 */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
1968E7919BAA36F042FCB717 /* PyHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyHandler.h; sourceTree = "<group>"; };
|
1968E7919BAA36F042FCB717 /* PyHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyHandler.h; sourceTree = "<group>"; };
|
||||||
1968EF7567E06D2A5BB3481A /* PyHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PyHandler.m; sourceTree = "<group>"; };
|
1968EF7567E06D2A5BB3481A /* PyHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PyHandler.m; sourceTree = "<group>"; };
|
||||||
54209E922117325100F3B5EF /* DrawImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DrawImage.h; sourceTree = "<group>"; };
|
54209E922117325100F3B5EF /* DrawImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DrawImage.h; sourceTree = "<group>"; };
|
||||||
54209E932117325100F3B5EF /* DrawImage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DrawImage.m; sourceTree = "<group>"; };
|
54209E932117325100F3B5EF /* DrawImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DrawImage.m; sourceTree = "<group>"; };
|
||||||
544B01182114B41200386E5C /* ModalSheet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ModalSheet.h; sourceTree = "<group>"; };
|
544B01182114B41200386E5C /* ModalSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModalSheet.h; sourceTree = "<group>"; };
|
||||||
544B01192114B41200386E5C /* ModalSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ModalSheet.m; sourceTree = "<group>"; };
|
544B01192114B41200386E5C /* ModalSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ModalSheet.m; sourceTree = "<group>"; };
|
||||||
544B011B2114EE9100386E5C /* AppHook.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppHook.h; sourceTree = "<group>"; };
|
544B011B2114EE9100386E5C /* AppHook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppHook.h; sourceTree = "<group>"; };
|
||||||
544B011C2114EE9100386E5C /* AppHook.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppHook.m; sourceTree = "<group>"; };
|
544B011C2114EE9100386E5C /* AppHook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppHook.m; sourceTree = "<group>"; };
|
||||||
544FBD4421064AEB008A260C /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Python.framework; path = System/Library/Frameworks/Python.framework; sourceTree = SDKROOT; };
|
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; };
|
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; };
|
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>"; };
|
546FC43B21188AD5007CC3A3 /* SettingsFeeds.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsFeeds.h; sourceTree = "<group>"; };
|
||||||
546FC43C21188AD5007CC3A3 /* SettingsFeeds.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SettingsFeeds.m; sourceTree = "<group>"; };
|
546FC43C21188AD5007CC3A3 /* SettingsFeeds.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsFeeds.m; sourceTree = "<group>"; };
|
||||||
546FC43E21188C78007CC3A3 /* SettingsFeeds.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SettingsFeeds.xib; 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>"; };
|
546FC44021189975007CC3A3 /* SettingsGeneral.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsGeneral.h; sourceTree = "<group>"; };
|
||||||
546FC44121189975007CC3A3 /* SettingsGeneral.m */ = {isa = PBXFileReference; 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>"; };
|
||||||
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; 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; 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>"; };
|
||||||
54ACC28321061B3B0020715F /* DBv1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = DBv1.xcdatamodel; sourceTree = "<group>"; };
|
54ACC28321061B3B0020715F /* DBv1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = DBv1.xcdatamodel; sourceTree = "<group>"; };
|
||||||
54ACC28521061B3C0020715F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
54ACC28521061B3C0020715F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
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; 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; lastKnownFileType = sourcecode.c.h; path = NewsController.h; sourceTree = "<group>"; };
|
54ACC29321061E270020715F /* NewsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewsController.h; sourceTree = "<group>"; };
|
||||||
54ACC29421061E270020715F /* NewsController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NewsController.m; sourceTree = "<group>"; };
|
54ACC29421061E270020715F /* NewsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewsController.m; sourceTree = "<group>"; };
|
||||||
54ACC29621061FBA0020715F /* Preferences.h */ = {isa = PBXFileReference; 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; 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; 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; 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; lastKnownFileType = sourcecode.c.h; path = "FeedConfig+Print.h"; 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>"; };
|
||||||
|
54FE73CF21220DEC003EAC65 /* StoreCoordinator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StoreCoordinator.m; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@@ -148,6 +151,8 @@
|
|||||||
544B011C2114EE9100386E5C /* AppHook.m */,
|
544B011C2114EE9100386E5C /* AppHook.m */,
|
||||||
54ACC27F21061B3B0020715F /* AppDelegate.h */,
|
54ACC27F21061B3B0020715F /* AppDelegate.h */,
|
||||||
54ACC28021061B3B0020715F /* AppDelegate.m */,
|
54ACC28021061B3B0020715F /* AppDelegate.m */,
|
||||||
|
54FE73CE21220DEC003EAC65 /* StoreCoordinator.h */,
|
||||||
|
54FE73CF21220DEC003EAC65 /* StoreCoordinator.m */,
|
||||||
54ACC29321061E270020715F /* NewsController.h */,
|
54ACC29321061E270020715F /* NewsController.h */,
|
||||||
54ACC29421061E270020715F /* NewsController.m */,
|
54ACC29421061E270020715F /* NewsController.m */,
|
||||||
54209E922117325100F3B5EF /* DrawImage.h */,
|
54209E922117325100F3B5EF /* DrawImage.h */,
|
||||||
@@ -271,6 +276,7 @@
|
|||||||
54E88320211B509D00064188 /* ModalFeedEdit.m in Sources */,
|
54E88320211B509D00064188 /* ModalFeedEdit.m in Sources */,
|
||||||
1968E0AE14B8E8A90E194980 /* PyHandler.m in Sources */,
|
1968E0AE14B8E8A90E194980 /* PyHandler.m in Sources */,
|
||||||
54209E942117325100F3B5EF /* DrawImage.m in Sources */,
|
54209E942117325100F3B5EF /* DrawImage.m in Sources */,
|
||||||
|
54FE73D021220DEC003EAC65 /* StoreCoordinator.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
||||||
@property (readonly, strong) NSPersistentContainer *persistentContainer;
|
@property (readonly, strong) NSPersistentContainer *persistentContainer;
|
||||||
|
- (IBAction)saveAction:(id)sender;
|
||||||
- (void)preferencesClosed;
|
- (void)preferencesClosed;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#import "PyHandler.h"
|
#import "PyHandler.h"
|
||||||
#import "DrawImage.h"
|
#import "DrawImage.h"
|
||||||
#import "Preferences.h"
|
#import "Preferences.h"
|
||||||
|
#import "StoreCoordinator.h"
|
||||||
|
|
||||||
@interface AppDelegate ()
|
@interface AppDelegate ()
|
||||||
@property (weak) IBOutlet NSMenu *statusMenu;
|
@property (weak) IBOutlet NSMenu *statusMenu;
|
||||||
@@ -42,6 +43,7 @@
|
|||||||
self.statusItem.image.template = YES;
|
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 {
|
||||||
@@ -75,6 +77,7 @@
|
|||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
NSUndoManager *um = [[NSUndoManager alloc] init];
|
NSUndoManager *um = [[NSUndoManager alloc] init];
|
||||||
|
um.groupsByEvent = NO;
|
||||||
um.levelsOfUndo = 30;
|
um.levelsOfUndo = 30;
|
||||||
_persistentContainer.viewContext.undoManager = um;
|
_persistentContainer.viewContext.undoManager = um;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,6 @@
|
|||||||
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
|
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
<relationship name="config" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="FeedConfig" inverseName="feed" inverseEntity="FeedConfig" syncable="YES"/>
|
<relationship name="config" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="FeedConfig" inverseName="feed" inverseEntity="FeedConfig" syncable="YES"/>
|
||||||
<relationship name="items" optional="YES" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="FeedItem" inverseName="feed" inverseEntity="FeedItem" syncable="YES"/>
|
<relationship name="items" optional="YES" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="FeedItem" inverseName="feed" inverseEntity="FeedItem" syncable="YES"/>
|
||||||
<fetchedProperty name="tags" optional="YES" syncable="YES">
|
|
||||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="Feed" predicateString="(SELF.tags.feedItem=$FETCH_SOURCE.items)"/>
|
|
||||||
</fetchedProperty>
|
|
||||||
</entity>
|
</entity>
|
||||||
<entity name="FeedConfig" representedClassName="FeedConfig" syncable="YES" codeGenerationType="class">
|
<entity name="FeedConfig" representedClassName="FeedConfig" syncable="YES" codeGenerationType="class">
|
||||||
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
@@ -42,7 +39,7 @@
|
|||||||
<relationship name="feedItem" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="FeedItem" inverseName="tags" inverseEntity="FeedItem" syncable="YES"/>
|
<relationship name="feedItem" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="FeedItem" inverseName="tags" inverseEntity="FeedItem" syncable="YES"/>
|
||||||
</entity>
|
</entity>
|
||||||
<elements>
|
<elements>
|
||||||
<element name="Feed" positionX="-209" positionY="-3" width="128" height="239"/>
|
<element name="Feed" positionX="-209" positionY="-3" width="128" height="210"/>
|
||||||
<element name="FeedConfig" positionX="-20" positionY="-126" width="128" height="180"/>
|
<element name="FeedConfig" positionX="-20" positionY="-126" width="128" height="180"/>
|
||||||
<element name="FeedItem" positionX="-20" positionY="81" width="128" height="165"/>
|
<element name="FeedItem" positionX="-20" positionY="81" width="128" height="165"/>
|
||||||
<element name="FeedTag" positionX="187" positionY="171" width="128" height="75"/>
|
<element name="FeedTag" positionX="187" positionY="171" width="128" height="75"/>
|
||||||
|
|||||||
@@ -23,6 +23,5 @@
|
|||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
@interface NewsController : NSObject
|
@interface NewsController : NSObject
|
||||||
|
|
||||||
+ (void)downloadFeed:(NSString*)url withBlock:(nullable void (^)(NSDictionary* result, NSError* error))block;
|
+ (void)downloadFeed:(NSString*)url withBlock:(nullable void (^)(NSDictionary* result, NSError* error))block;
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
#import "NewsController.h"
|
#import "NewsController.h"
|
||||||
#import "PyHandler.h"
|
#import "PyHandler.h"
|
||||||
#import "DBv1+CoreDataModel.h"
|
|
||||||
|
|
||||||
@interface NewsController ()
|
@interface NewsController ()
|
||||||
@end
|
@end
|
||||||
@@ -35,35 +34,6 @@
|
|||||||
|
|
||||||
- (IBAction)updateAllFeeds:(NSMenuItem *)sender {
|
- (IBAction)updateAllFeeds:(NSMenuItem *)sender {
|
||||||
NSLog(@"update all");
|
NSLog(@"update all");
|
||||||
NSDictionary * obj = [PyHandler getFeed:@"https://feeds.feedburner.com/simpledesktops" withEtag:nil andModified:nil];
|
|
||||||
NSLog(@"obj = %@", obj);
|
|
||||||
// TODO: check status code
|
|
||||||
/*
|
|
||||||
Feed *a = [[Feed alloc] initWithEntity:Feed.entity insertIntoManagedObjectContext:self.managedObjectContext];
|
|
||||||
a.title = obj[@"feed"][@"title"];
|
|
||||||
a.subtitle = obj[@"feed"][@"subtitle"];
|
|
||||||
a.author = obj[@"feed"][@"author"];
|
|
||||||
a.link = obj[@"feed"][@"link"];
|
|
||||||
a.published = obj[@"feed"][@"published"];
|
|
||||||
a.icon = obj[@"feed"][@"icon"];
|
|
||||||
a.etag = obj[@"header"][@"etag"];
|
|
||||||
a.date = obj[@"header"][@"date"];
|
|
||||||
a.modified = obj[@"header"][@"modified"];
|
|
||||||
for (NSDictionary *entry in obj[@"entries"]) {
|
|
||||||
FeedItem *b = [[FeedItem alloc] initWithEntity:FeedItem.entity insertIntoManagedObjectContext:self.managedObjectContext];
|
|
||||||
b.title = entry[@"title"];
|
|
||||||
b.subtitle = entry[@"subtitle"];
|
|
||||||
b.author = entry[@"author"];
|
|
||||||
b.link = entry[@"link"];
|
|
||||||
b.published = entry[@"published"];
|
|
||||||
b.summary = entry[@"summary"];
|
|
||||||
for (NSString *tag in entry[@"tags"]) {
|
|
||||||
FeedTag *c = [[FeedTag alloc] initWithEntity:FeedTag.entity insertIntoManagedObjectContext:self.managedObjectContext];
|
|
||||||
c.name = tag;
|
|
||||||
[b addTagsObject:c];
|
|
||||||
}
|
|
||||||
[a addItemsObject:b];
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)openAllUnread:(NSMenuItem *)sender {
|
- (IBAction)openAllUnread:(NSMenuItem *)sender {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
@protocol ModalFeedConfigEdit <NSObject>
|
@protocol ModalFeedConfigEdit <NSObject>
|
||||||
- (void)updateRepresentedObject; // must call [item.managedObjectContext refreshAllObjects]
|
- (void)updateRepresentedObject; // must call [item.managedObjectContext refreshObject:item mergeChanges:YES];
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#import "ModalFeedEdit.h"
|
#import "ModalFeedEdit.h"
|
||||||
#import "NewsController.h"
|
#import "NewsController.h"
|
||||||
|
#import "StoreCoordinator.h"
|
||||||
#import "FeedConfig+CoreDataProperties.h"
|
#import "FeedConfig+CoreDataProperties.h"
|
||||||
|
|
||||||
@interface ModalFeedEdit()
|
@interface ModalFeedEdit()
|
||||||
@@ -38,8 +39,9 @@
|
|||||||
@property (strong) NSError *feedError;
|
@property (strong) NSError *feedError;
|
||||||
@property (strong) NSDictionary *feedResult;
|
@property (strong) NSDictionary *feedResult;
|
||||||
|
|
||||||
@property (assign) BOOL shouldEvaluate;
|
@property (assign) BOOL shouldSaveObject;
|
||||||
@property (assign) BOOL lateEvaluation;
|
@property (assign) BOOL objectNeedsSaving;
|
||||||
|
@property (assign) BOOL objectIsModified;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ModalFeedEdit
|
@implementation ModalFeedEdit
|
||||||
@@ -48,7 +50,9 @@
|
|||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
self.previousURL = @"";
|
self.previousURL = @"";
|
||||||
self.refreshNum.intValue = 30;
|
self.refreshNum.intValue = 30;
|
||||||
self.shouldEvaluate = NO;
|
self.shouldSaveObject = NO;
|
||||||
|
self.objectNeedsSaving = NO;
|
||||||
|
self.objectIsModified = NO;
|
||||||
|
|
||||||
FeedConfig *fc = [self feedConfigOrNil];
|
FeedConfig *fc = [self feedConfigOrNil];
|
||||||
if (fc) {
|
if (fc) {
|
||||||
@@ -65,21 +69,30 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
FeedConfig *item = [self feedConfigOrNil];
|
if (self.shouldSaveObject) {
|
||||||
if (self.shouldEvaluate && self.lateEvaluation && item) {
|
if (self.objectNeedsSaving)
|
||||||
if (!item.name || [item.name isEqualToString:@""]) {
|
[self updateRepresentedObject];
|
||||||
[self setTitleFromFeed];
|
NSUndoManager *um = [self feedConfigOrNil].managedObjectContext.undoManager;
|
||||||
if (![item.name isEqualToString: self.name.stringValue]) // only if result isnt empty as well
|
[um endUndoGrouping];
|
||||||
item.name = self.name.stringValue;
|
if (!self.objectIsModified) {
|
||||||
[item.managedObjectContext refreshAllObjects];
|
[um disableUndoRegistration];
|
||||||
|
[um undoNestedGroup];
|
||||||
|
[um enableUndoRegistration];
|
||||||
|
} else {
|
||||||
|
[StoreCoordinator save];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateRepresentedObject {
|
- (void)updateRepresentedObject {
|
||||||
FeedConfig *item = [self feedConfigOrNil];
|
FeedConfig *item = [self feedConfigOrNil];
|
||||||
if (item) {
|
if (item) {
|
||||||
|
if (!self.shouldSaveObject) { // first call to this method
|
||||||
|
[item.managedObjectContext.undoManager beginUndoGrouping];
|
||||||
|
}
|
||||||
|
self.shouldSaveObject = YES;
|
||||||
|
self.objectNeedsSaving = NO; // after this method it is saved
|
||||||
|
|
||||||
// if's to prevent unnecessary undo groups if nothing has changed
|
// if's to prevent unnecessary undo groups if nothing has changed
|
||||||
if (![item.name isEqualToString: self.name.stringValue])
|
if (![item.name isEqualToString: self.name.stringValue])
|
||||||
item.name = self.name.stringValue;
|
item.name = self.name.stringValue;
|
||||||
@@ -90,11 +103,17 @@
|
|||||||
if (item.refreshUnit != self.refreshUnit.indexOfSelectedItem)
|
if (item.refreshUnit != self.refreshUnit.indexOfSelectedItem)
|
||||||
item.refreshUnit = (int16_t)self.refreshUnit.indexOfSelectedItem;
|
item.refreshUnit = (int16_t)self.refreshUnit.indexOfSelectedItem;
|
||||||
|
|
||||||
self.shouldEvaluate = YES;
|
|
||||||
self.lateEvaluation = NO;
|
if (self.feedResult) {
|
||||||
// TODO: append feed result
|
Feed *rss = [StoreCoordinator createFeedFromDictionary:self.feedResult];
|
||||||
NSLog(@"here i want to set it");
|
if (item.feed)
|
||||||
[item.managedObjectContext refreshAllObjects];
|
[item.managedObjectContext deleteObject:(NSManagedObject*)item.feed];
|
||||||
|
item.feed = rss;
|
||||||
|
}
|
||||||
|
if ([item.managedObjectContext hasChanges]) {
|
||||||
|
self.objectIsModified = YES;
|
||||||
|
[item.managedObjectContext refreshObject:item mergeChanges:YES];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,17 +137,15 @@
|
|||||||
if (obj.object == self.url && [self urlHasChanged]) {
|
if (obj.object == self.url && [self urlHasChanged]) {
|
||||||
self.previousURL = self.url.stringValue;
|
self.previousURL = self.url.stringValue;
|
||||||
self.feedResult = nil;
|
self.feedResult = nil;
|
||||||
NSLog(@"setting result to nil");
|
|
||||||
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) {
|
[NewsController downloadFeed:self.previousURL withBlock:^(NSDictionary *result, NSError *error) {
|
||||||
self.feedResult = result;
|
self.feedResult = result;
|
||||||
NSLog(@"got results back");
|
|
||||||
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?
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
self.lateEvaluation = YES; // stays YES if this block runs after updateRepresentedObject:
|
self.objectNeedsSaving = YES; // stays YES if this block runs after updateRepresentedObject:
|
||||||
[self setTitleFromFeed];
|
[self setTitleFromFeed];
|
||||||
[self.spinnerURL stopAnimation:nil];
|
[self.spinnerURL stopAnimation:nil];
|
||||||
[self.spinnerName stopAnimation:nil];
|
[self.spinnerName stopAnimation:nil];
|
||||||
@@ -186,7 +203,7 @@
|
|||||||
NSString *name = ((NSTextField*)self.view).stringValue;
|
NSString *name = ((NSTextField*)self.view).stringValue;
|
||||||
if (![item.name isEqualToString: name]) {
|
if (![item.name isEqualToString: name]) {
|
||||||
item.name = name;
|
item.name = name;
|
||||||
[item.managedObjectContext refreshAllObjects];
|
[item.managedObjectContext refreshObject:item mergeChanges:YES];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
/** Manages the NSOutlineView and Feed creation and editing */
|
||||||
@interface SettingsFeeds : NSViewController <NSOutlineViewDataSource, NSOutlineViewDelegate>
|
@interface SettingsFeeds : NSViewController <NSOutlineViewDataSource, NSOutlineViewDelegate>
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -101,12 +101,14 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
|
|||||||
|
|
||||||
[self.view.window beginSheet:[ModalSheet modalWithView:self.modalController.view] completionHandler:^(NSModalResponse returnCode) {
|
[self.view.window beginSheet:[ModalSheet modalWithView:self.modalController.view] completionHandler:^(NSModalResponse returnCode) {
|
||||||
if (returnCode == NSModalResponseOK) {
|
if (returnCode == NSModalResponseOK) {
|
||||||
|
[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.type = (group ? 0 : 1);
|
||||||
self.modalController.representedObject = item;
|
self.modalController.representedObject = item;
|
||||||
}
|
}
|
||||||
[self.modalController updateRepresentedObject];
|
[self.modalController updateRepresentedObject];
|
||||||
|
[self.undoManager endUndoGrouping];
|
||||||
}
|
}
|
||||||
self.modalController = nil;
|
self.modalController = nil;
|
||||||
}];
|
}];
|
||||||
@@ -328,6 +330,12 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
|
|||||||
NSLog(@"%@", str);
|
NSLog(@"%@", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Go through all children recursively and prepend the string with spaces as nesting
|
||||||
|
@param obj Root Node or parent Node
|
||||||
|
@param str An initialized @c NSMutableString to append to
|
||||||
|
@param prefix Should be @c @@"" for the first call
|
||||||
|
*/
|
||||||
- (void)traverseChildren:(NSTreeNode*)obj appendString:(NSMutableString*)str prefix:(NSString*)prefix {
|
- (void)traverseChildren:(NSTreeNode*)obj appendString:(NSMutableString*)str prefix:(NSString*)prefix {
|
||||||
[str appendFormat:@"%@%@\n", prefix, [obj.representedObject readableDescription]];
|
[str appendFormat:@"%@%@\n", prefix, [obj.representedObject readableDescription]];
|
||||||
prefix = [prefix stringByAppendingString:@" "];
|
prefix = [prefix stringByAppendingString:@" "];
|
||||||
|
|||||||
31
baRSS/StoreCoordinator.h
Normal file
31
baRSS/StoreCoordinator.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// 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 <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@class Feed;
|
||||||
|
|
||||||
|
@interface StoreCoordinator : NSObject
|
||||||
|
+ (void)save;
|
||||||
|
+ (void)deleteUnreferencedFeeds;
|
||||||
|
+ (Feed*)createFeedFromDictionary:(NSDictionary*)obj;
|
||||||
|
@end
|
||||||
77
baRSS/StoreCoordinator.m
Normal file
77
baRSS/StoreCoordinator.m
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
//
|
||||||
|
// 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 "StoreCoordinator.h"
|
||||||
|
#import "AppDelegate.h"
|
||||||
|
#import "DBv1+CoreDataModel.h"
|
||||||
|
|
||||||
|
@implementation StoreCoordinator
|
||||||
|
|
||||||
|
+ (NSManagedObjectContext*)getContext {
|
||||||
|
return [(AppDelegate*)[NSApp delegate] persistentContainer].viewContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)save {
|
||||||
|
[(AppDelegate*)[NSApp delegate] saveAction:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)deleteUnreferencedFeeds {
|
||||||
|
NSManagedObjectContext *moc = [self getContext];
|
||||||
|
NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:Feed.entity.name];
|
||||||
|
fr.predicate = [NSPredicate predicateWithFormat:@"config = NULL"];
|
||||||
|
NSBatchDeleteRequest *bdr = [[NSBatchDeleteRequest alloc] initWithFetchRequest:fr];
|
||||||
|
NSError *err;
|
||||||
|
[moc executeRequest:bdr error:&err];
|
||||||
|
if (err) NSLog(@"%@", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (Feed*)createFeedFromDictionary:(NSDictionary*)obj {
|
||||||
|
NSManagedObjectContext *moc = [self getContext];
|
||||||
|
Feed *a = [[Feed alloc] initWithEntity:Feed.entity insertIntoManagedObjectContext:moc];
|
||||||
|
a.title = obj[@"feed"][@"title"];
|
||||||
|
a.subtitle = obj[@"feed"][@"subtitle"];
|
||||||
|
a.author = obj[@"feed"][@"author"];
|
||||||
|
a.link = obj[@"feed"][@"link"];
|
||||||
|
a.published = obj[@"feed"][@"published"];
|
||||||
|
a.icon = obj[@"feed"][@"icon"];
|
||||||
|
a.etag = obj[@"header"][@"etag"];
|
||||||
|
a.date = obj[@"header"][@"date"];
|
||||||
|
a.modified = obj[@"header"][@"modified"];
|
||||||
|
for (NSDictionary *entry in obj[@"entries"]) {
|
||||||
|
FeedItem *b = [[FeedItem alloc] initWithEntity:FeedItem.entity insertIntoManagedObjectContext:moc];
|
||||||
|
b.title = entry[@"title"];
|
||||||
|
b.subtitle = entry[@"subtitle"];
|
||||||
|
b.author = entry[@"author"];
|
||||||
|
b.link = entry[@"link"];
|
||||||
|
b.published = entry[@"published"];
|
||||||
|
b.summary = entry[@"summary"];
|
||||||
|
for (NSString *tag in entry[@"tags"]) {
|
||||||
|
FeedTag *c = [[FeedTag alloc] initWithEntity:FeedTag.entity insertIntoManagedObjectContext:moc];
|
||||||
|
c.name = tag;
|
||||||
|
[b addTagsObject:c];
|
||||||
|
}
|
||||||
|
[a addItemsObject:b];
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
Reference in New Issue
Block a user