Menu - Preferences Sync. There is still a bug with unread count ...

This commit is contained in:
relikd
2018-08-19 04:04:36 +02:00
parent f2281b91c4
commit 733ce7af79
9 changed files with 126 additions and 87 deletions

View File

@@ -23,7 +23,9 @@
#import <Cocoa/Cocoa.h>
#import <CoreData/CoreData.h>
@class BarMenu;
@interface AppHook : NSApplication <NSApplicationDelegate>
@property (readonly, strong) BarMenu *barMenu;
@property (readonly, strong) NSPersistentContainer *persistentContainer;
- (IBAction)saveAction:(id)sender;
@end

View File

@@ -24,10 +24,6 @@
#import "PyHandler.h"
#import "BarMenu.h"
@interface AppHook()
@property (strong) BarMenu *barMenu;
@end
@implementation AppHook
- (instancetype)init {
@@ -37,7 +33,7 @@
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.barMenu = [BarMenu new];
_barMenu = [BarMenu new];
[PyHandler prepare];
printf("up and running\n");
}
@@ -46,10 +42,6 @@
[PyHandler shutdown];
}
- (IBAction)closePreferences:(id)sender {
NSLog(@"closing in %@", sender);
}
#pragma mark - Core Data stack
@@ -67,13 +59,8 @@
abort();
}
}];
NSUndoManager *um = [[NSUndoManager alloc] init];
um.groupsByEvent = NO;
um.levelsOfUndo = 30;
_persistentContainer.viewContext.undoManager = um;
}
}
return _persistentContainer;
}
@@ -81,26 +68,6 @@
#pragma mark - Core Data Saving and Undo support
- (IBAction)saveAction:(id)sender {
// Performs the save action for the application, which is to send the save: message to the application's managed object context. Any encountered errors are presented to the user.
NSManagedObjectContext *context = self.persistentContainer.viewContext;
if (![context commitEditing]) {
NSLog(@"%@:%@ unable to commit editing before saving", [self class], NSStringFromSelector(_cmd));
}
NSError *error = nil;
if (context.hasChanges && ![context save:&error]) {
// Customize this code block to include application-specific recovery steps.
[[NSApplication sharedApplication] presentError:error];
}
}
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window {
// Returns the NSUndoManager for the application. In this case, the manager returned is that of the managed object context for the application.
return self.persistentContainer.viewContext.undoManager;
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
// Save changes in the application's managed object context before the application terminates.
NSManagedObjectContext *context = self.persistentContainer.viewContext;

View File

@@ -22,7 +22,14 @@
#import <Cocoa/Cocoa.h>
@class FeedConfig;
@protocol ModalEditDelegate <NSObject>
- (void)modalDidUpdateFeedConfig:(FeedConfig*)config;
@end
@protocol ModalFeedConfigEdit <NSObject>
@property (weak) id<ModalEditDelegate> delegate;
- (void)updateRepresentedObject; // must call [item.managedObjectContext refreshObject:item mergeChanges:YES];
@end

View File

@@ -44,6 +44,7 @@
@end
@implementation ModalFeedEdit
@synthesize delegate;
- (void)viewDidLoad {
[super viewDidLoad];
@@ -71,48 +72,47 @@
if (self.shouldSaveObject) {
if (self.objectNeedsSaving)
[self updateRepresentedObject];
NSUndoManager *um = [self feedConfigOrNil].managedObjectContext.undoManager;
FeedConfig *item = [self feedConfigOrNil];
NSUndoManager *um = item.managedObjectContext.undoManager;
[um endUndoGrouping];
if (!self.objectIsModified) {
[um disableUndoRegistration];
[um undoNestedGroup];
[um enableUndoRegistration];
} else {
[StoreCoordinator save];
[self.delegate modalDidUpdateFeedConfig:item];
}
}
}
- (void)updateRepresentedObject {
FeedConfig *item = [self feedConfigOrNil];
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 (![item.name isEqualToString: self.name.stringValue])
item.name = self.name.stringValue;
if (![item.url isEqualToString:self.url.stringValue])
item.url = self.url.stringValue;
if (item.refreshNum != self.refreshNum.intValue)
item.refreshNum = self.refreshNum.intValue;
if (item.refreshUnit != self.refreshUnit.indexOfSelectedItem)
item.refreshUnit = (int16_t)self.refreshUnit.indexOfSelectedItem;
if (self.feedResult) {
Feed *rss = [StoreCoordinator createFeedFromDictionary:self.feedResult];
if (item.feed)
[item.managedObjectContext deleteObject:(NSManagedObject*)item.feed];
item.feed = rss;
}
if ([item.managedObjectContext hasChanges]) {
self.objectIsModified = YES;
[item.managedObjectContext refreshObject:item mergeChanges:YES];
}
if (!item)
return;
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 (![item.name isEqualToString: self.name.stringValue])
item.name = self.name.stringValue;
if (![item.url isEqualToString:self.url.stringValue])
item.url = self.url.stringValue;
if (item.refreshNum != self.refreshNum.intValue)
item.refreshNum = self.refreshNum.intValue;
if (item.refreshUnit != self.refreshUnit.indexOfSelectedItem)
item.refreshUnit = (int16_t)self.refreshUnit.indexOfSelectedItem;
if (self.feedResult) {
Feed *rss = [StoreCoordinator createFeedFromDictionary:self.feedResult inContext:item.managedObjectContext];
if (item.feed)
[item.managedObjectContext deleteObject:(NSManagedObject*)item.feed];
item.feed = rss;
}
if ([item.managedObjectContext hasChanges]) {
self.objectIsModified = YES;
[item.managedObjectContext refreshObject:item mergeChanges:YES];
}
}
@@ -151,7 +151,6 @@
});
}];
}
// http://feeds.feedburner.com/simpledesktops
}
- (void)setTitleFromFeed {
@@ -183,6 +182,7 @@
#pragma mark - ModalGroupEdit
@implementation ModalGroupEdit
@synthesize delegate;
- (void)viewDidLoad {
[super viewDidLoad];
if ([self.representedObject isKindOfClass:[FeedConfig class]]) {
@@ -203,6 +203,7 @@
if (![item.name isEqualToString: name]) {
item.name = name;
[item.managedObjectContext refreshObject:item mergeChanges:YES];
[self.delegate modalDidUpdateFeedConfig:item];
}
}
}

View File

@@ -22,12 +22,13 @@
#import "SettingsFeeds.h"
#import "AppHook.h"
#import "FeedConfig+Ext.h"
#import "BarMenu.h"
#import "ModalSheet.h"
#import "ModalFeedEdit.h"
#import "DrawImage.h"
#import "StoreCoordinator.h"
@interface SettingsFeeds ()
@interface SettingsFeeds () <ModalEditDelegate>
@property (weak) IBOutlet NSOutlineView *outlineView;
@property (weak) IBOutlet NSTreeController *dataStore;
@@ -43,10 +44,29 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
- (void)viewDidLoad {
[super viewDidLoad];
self.dataStore.managedObjectContext = [(AppHook*)NSApp persistentContainer].viewContext;
self.undoManager = self.dataStore.managedObjectContext.undoManager;
[self.outlineView registerForDraggedTypes:[NSArray arrayWithObject:dragNodeType]];
[self.dataStore setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"sortIndex" ascending:YES]]];
NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[childContext setParentContext:[(AppHook*)NSApp persistentContainer].viewContext];
// childContext.automaticallyMergesChangesFromParent = YES;
NSUndoManager *um = [[NSUndoManager alloc] init];
um.groupsByEvent = NO;
um.levelsOfUndo = 30;
childContext.undoManager = um;
self.dataStore.managedObjectContext = childContext;
self.undoManager = self.dataStore.managedObjectContext.undoManager;
}
- (void)dealloc {
[self saveAndRebuildMenu];
}
- (void)saveAndRebuildMenu {
[StoreCoordinator saveContext:self.dataStore.managedObjectContext];
[StoreCoordinator saveContext:self.dataStore.managedObjectContext.parentContext];
[[(AppHook*)NSApp barMenu] rebuildMenu]; // updating individual items was way to complicated ...
}
- (IBAction)addFeed:(id)sender {
@@ -63,6 +83,7 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
sp.name = @"---";
sp.typ = SEPARATOR;
[self.undoManager endUndoGrouping];
[self saveAndRebuildMenu];
}
- (IBAction)remove:(id)sender {
@@ -71,6 +92,7 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
[self incrementIndicesBy:-1 forSubsequentNodes:path];
[self.dataStore remove:sender];
[self.undoManager endUndoGrouping];
[self saveAndRebuildMenu];
}
- (IBAction)doubleClickOutlineView:(NSOutlineView*)sender {
@@ -97,22 +119,28 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
}
self.modalController = (group ? [ModalGroupEdit new] : [ModalFeedEdit new]);
self.modalController.representedObject = obj;
self.modalController.delegate = self;
[self.view.window beginSheet:[ModalSheet modalWithView:self.modalController.view] completionHandler:^(NSModalResponse returnCode) {
if (returnCode == NSModalResponseOK) {
[self.undoManager beginUndoGrouping];
if (!existingItem) { // create new item
[self.undoManager beginUndoGrouping];
FeedConfig *item = [self insertSortedItemAtSelection];
item.typ = (group ? GROUP : FEED);
self.modalController.representedObject = item;
}
[self.modalController updateRepresentedObject];
[self.undoManager endUndoGrouping];
if (!existingItem)
[self.undoManager endUndoGrouping];
}
self.modalController = nil;
}];
}
- (void)modalDidUpdateFeedConfig:(FeedConfig*)config {
[self saveAndRebuildMenu];
}
- (FeedConfig*)insertSortedItemAtSelection {
NSIndexPath *selectedIndex = [self.dataStore selectionIndexPath];
NSIndexPath *insertIndex = selectedIndex;
@@ -164,13 +192,15 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
}
- (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);
if (self.dataStore.managedObjectContext.hasChanges) {
[self saveAndRebuildMenu];
} else {
[self.undoManager disableUndoRegistration];
[self.undoManager undoNestedGroup];
[self.undoManager enableUndoRegistration];
}
self.currentlyDraggedNodes = nil;
}
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index {
@@ -290,11 +320,13 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
- (void)undo:(id)sender {
[self.undoManager undo];
[self.dataStore rearrangeObjects]; // update ordering
[self saveAndRebuildMenu];
}
- (void)redo:(id)sender {
[self.undoManager redo];
[self.dataStore rearrangeObjects]; // update ordering
[self saveAndRebuildMenu];
}
- (void)enterPressed:(id)sender {

View File

@@ -23,5 +23,5 @@
#import <Cocoa/Cocoa.h>
@interface BarMenu : NSObject <NSMenuDelegate>
//+ (instancetype)start;
- (void)rebuildMenu;
@end

View File

@@ -59,13 +59,16 @@ typedef NS_OPTIONS(NSInteger, MenuItemTag) {
- (instancetype)init {
self = [super init];
self.barItem = [NSStatusBar.systemStatusBar statusItemWithLength:NSVariableStatusItemLength];
self.barItem.menu = self.mainMenu;
self.barItem.highlightMode = YES;
[self updateBarIcon];
self.barItem.menu = [self generateMainMenu];
// [self donothing];
return self;
}
- (void)rebuildMenu {
self.barItem.menu = [self generateMainMenu];
}
- (void)donothing {
dispatch_async(dispatch_get_main_queue(), ^{
[self.mm itemAtIndex:4].title = [NSString stringWithFormat:@"%@", [NSDate date]];
@@ -74,6 +77,21 @@ typedef NS_OPTIONS(NSInteger, MenuItemTag) {
[self performSelectorInBackground:@selector(donothing) withObject:nil];
}
- (void)printUnreadRecurisve:(NSMenu*)menu str:(NSString*)prefix {
for (NSMenuItem *item in menu.itemArray) {
if (!item.hasUnread) continue;
MenuItemInfo *info = item.representedObject;
id obj = [StoreCoordinator objectWithID:info.objID];
if ([obj isKindOfClass:[FeedItem class]])
NSLog(@"%@ %@ (%d == %d)", prefix, item.title, item.unreadCount, [obj unread]);
else
NSLog(@"%@ %@ (%d)", prefix, item.title, item.unreadCount);
if (item.hasSubmenu) {
[self printUnreadRecurisve:item.submenu str:[NSString stringWithFormat:@" %@", prefix]];
}
}
}
/**
Update menu bar icon and text according to unread count and user preferences.
*/
@@ -87,6 +105,8 @@ typedef NS_OPTIONS(NSInteger, MenuItemTag) {
self.barItem.image = [[RSSIcon templateIcon:16 tint:nil] image];
self.barItem.image.template = YES;
}
NSLog(@"==> %d", self.unreadCountTotal);
[self printUnreadRecurisve:self.barItem.menu str:@""];
}
@@ -96,7 +116,7 @@ typedef NS_OPTIONS(NSInteger, MenuItemTag) {
/**
Builds main menu with items on the very first menu level. Including Preferences, Quit, etc.
*/
- (NSMenu*)mainMenu {
- (NSMenu*)generateMainMenu {
NSMenu *menu = [NSMenu new];
menu.autoenablesItems = NO;
[self addTitle:NSLocalizedString(@"Pause Updates", nil) selector:@selector(pauseUpdates:) toMenu:menu tag:TagPauseUpdates];
@@ -104,9 +124,11 @@ typedef NS_OPTIONS(NSInteger, MenuItemTag) {
[menu addItem:[NSMenuItem separatorItem]];
[self defaultHeaderForMenu:menu scope:ScopeGlobal];
self.unreadCountTotal = 0;
for (FeedConfig *fc in [StoreCoordinator sortedFeedConfigItems]) {
[menu addItem:[self menuItemForFeedConfig:fc unread:&_unreadCountTotal]];
}
[self updateBarIcon];
[menu addItem:[NSMenuItem separatorItem]];
[self addTitle:NSLocalizedString(@"Preferences", nil) selector:@selector(openPreferences) toMenu:menu tag:TagPreferences];

View File

@@ -26,9 +26,9 @@
@interface StoreCoordinator : NSObject
+ (void)save;
+ (void)saveContext:(NSManagedObjectContext*)context;
+ (void)deleteUnreferencedFeeds;
+ (NSArray<FeedConfig*>*)sortedFeedConfigItems;
+ (id)objectWithID:(NSManagedObjectID*)objID;
+ (Feed*)createFeedFromDictionary:(NSDictionary*)obj;
+ (Feed*)createFeedFromDictionary:(NSDictionary*)obj inContext:(NSManagedObjectContext*)context;
@end

View File

@@ -29,8 +29,16 @@
return [(AppHook*)NSApp persistentContainer].viewContext;
}
+ (void)save {
[(AppHook*)NSApp saveAction:nil];
+ (void)saveContext:(NSManagedObjectContext*)context {
// Performs the save action for the application, which is to send the save: message to the application's managed object context. Any encountered errors are presented to the user.
if (![context commitEditing]) {
NSLog(@"%@:%@ unable to commit editing before saving", [self class], NSStringFromSelector(_cmd));
}
NSError *error = nil;
if (context.hasChanges && ![context save:&error]) {
// Customize this code block to include application-specific recovery steps.
[[NSApplication sharedApplication] presentError:error];
}
}
+ (void)deleteUnreferencedFeeds {
@@ -58,8 +66,8 @@
return [[self getContext] objectWithID:objID];
}
+ (Feed*)createFeedFromDictionary:(NSDictionary*)obj {
NSManagedObjectContext *moc = [self getContext];
+ (Feed*)createFeedFromDictionary:(NSDictionary*)obj inContext:(NSManagedObjectContext*)moc {
// NSManagedObjectContext *moc = [self getContext];
Feed *a = [[Feed alloc] initWithEntity:Feed.entity insertIntoManagedObjectContext:moc];
a.title = obj[@"feed"][@"title"];
a.subtitle = obj[@"feed"][@"subtitle"];