Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31712dedf9 | ||
|
|
c310933623 | ||
|
|
25be1033aa | ||
|
|
c30d6b82ed |
@@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project does adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
|
||||
## [1.6.2] – 2026-01-11
|
||||
### Added
|
||||
- Restore macOS 10.13 compatibility (without Notification support)
|
||||
- *Status Bar Menu:* "Update feeds" for all menu levels
|
||||
- *Status Bar Menu:* "Pause updates" can be removed
|
||||
|
||||
|
||||
## [1.6.1] – 2026-01-11
|
||||
### Fixed
|
||||
- Reschedule update timer after changing the refresh interval of a feed
|
||||
@@ -267,6 +274,7 @@ and this project does adhere to [Semantic Versioning](https://semver.org/spec/v2
|
||||
Initial release
|
||||
|
||||
|
||||
[1.6.2]: https://github.com/relikd/baRSS/compare/v1.6.1...v1.6.2
|
||||
[1.6.1]: https://github.com/relikd/baRSS/compare/v1.6.0...v1.6.1
|
||||
[1.6.0]: https://github.com/relikd/baRSS/compare/v1.5.5...v1.6.0
|
||||
[1.5.5]: https://github.com/relikd/baRSS/compare/v1.5.4...v1.5.5
|
||||
|
||||
@@ -5,8 +5,8 @@ CODE_SIGN_STYLE = Manual
|
||||
CODE_SIGN_IDENTITY = Apple Development
|
||||
ENABLE_HARDENED_RUNTIME = YES
|
||||
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14
|
||||
MARKETING_VERSION = 1.6.1
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13
|
||||
MARKETING_VERSION = 1.6.2
|
||||
PRODUCT_NAME = baRSS
|
||||
PRODUCT_BUNDLE_IDENTIFIER = de.relikd.baRSS
|
||||
CURRENT_PROJECT_VERSION = 17772
|
||||
CURRENT_PROJECT_VERSION = 17804
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[](#download--install)
|
||||
[](#download--install)
|
||||
[](https://github.com/relikd/baRSS/releases)
|
||||
[](https://github.com/relikd/baRSS/releases)
|
||||
[](LICENSE)
|
||||
@@ -35,7 +35,7 @@ Further, tuning the update frequently will decrease the traffic even more.
|
||||
Download & Install
|
||||
------------------
|
||||
|
||||
Requires macOS Mojave (10.14) or higher.
|
||||
Requires macOS High Sierra (10.13) or higher.
|
||||
|
||||
### Easy way
|
||||
Go to [releases](https://github.com/relikd/baRSS/releases) and downloaded the latest version.
|
||||
|
||||
@@ -47,9 +47,11 @@
|
||||
if (initial) [UpdateScheduler updateAllFavicons];
|
||||
}
|
||||
|
||||
// Notifications are disabled by default so this wont trigger for first app launch.
|
||||
// Also, this will register the notification delegate and respond to click & open feed.
|
||||
[NotifyEndpoint activate];
|
||||
if (@available(macOS 10.14, *)) {
|
||||
// Notifications are disabled by default so this wont trigger for first app launch.
|
||||
// Also, this will register the notification delegate and respond to click & open feed.
|
||||
[NotifyEndpoint activate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification {
|
||||
|
||||
@@ -129,7 +129,9 @@
|
||||
if (deletingSet.count > 0) {
|
||||
[localSet minusSet:deletingSet];
|
||||
[self removeArticles:deletingSet];
|
||||
[NotifyEndpoint dismiss:dismissed];
|
||||
if (@available(macOS 10.14, *)) {
|
||||
[NotifyEndpoint dismiss:dismissed];
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,9 @@
|
||||
NSNumber *num = (fa.unread ? @+1 : @-1);
|
||||
PostNotification(kNotificationTotalUnreadCountChanged, num);
|
||||
|
||||
[NotifyEndpoint dismiss:fa.feed.countUnread > 0 ? @[fa.notificationID] : @[fa.notificationID, fa.feed.notificationID]];
|
||||
if (@available(macOS 10.14, *)) {
|
||||
[NotifyEndpoint dismiss:fa.feed.countUnread > 0 ? @[fa.notificationID] : @[fa.notificationID, fa.feed.notificationID]];
|
||||
}
|
||||
}
|
||||
[moc reset];
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// Feed update
|
||||
+ (NSDate*)nextScheduledUpdate;
|
||||
+ (NSArray<Feed*>*)listOfFeedsThatNeedUpdate:(BOOL)forceAll inContext:(nullable NSManagedObjectContext*)moc;
|
||||
+ (NSArray<Feed*>*)feedsThatNeedUpdate:(nullable NSManagedObjectContext*)moc;
|
||||
+ (NSArray<Feed*>*)feedsWithIndexPath:(nullable NSString*)path inContext:(nullable NSManagedObjectContext*)moc;
|
||||
|
||||
// Count elements
|
||||
+ (BOOL)isEmpty;
|
||||
|
||||
@@ -79,14 +79,24 @@
|
||||
/**
|
||||
List of @c Feed items that need to be updated. Scheduled time is now (or in past).
|
||||
|
||||
@param forceAll If @c YES get a list of all @c Feed regardless of schedules time.
|
||||
@param moc If @c nil perform requests on main context (ok for reading).
|
||||
*/
|
||||
+ (NSArray<Feed*>*)listOfFeedsThatNeedUpdate:(BOOL)forceAll inContext:(nullable NSManagedObjectContext*)moc {
|
||||
+ (NSArray<Feed*>*)feedsThatNeedUpdate:(nullable NSManagedObjectContext*)moc {
|
||||
NSFetchRequest *fr = [Feed fetchRequest];
|
||||
if (!forceAll) {
|
||||
// when fetching also get those feeds that would need update soon (now + 2s)
|
||||
[fr where:@"meta.scheduled <= %@", [NSDate dateWithTimeIntervalSinceNow:+2]];
|
||||
// when fetching also get those feeds that would need update soon (now + 2s)
|
||||
[fr where:@"meta.scheduled <= %@", [NSDate dateWithTimeIntervalSinceNow:+2]];
|
||||
return [fr fetchAllRows:moc ? moc : [self getMainContext]];
|
||||
}
|
||||
|
||||
/** List of @c Feed items that match @c Feed.indexPath either by direct match or some child thereof.
|
||||
|
||||
@param path If @c nil return all @c Feed items. May match either full string OR startswith string + "."
|
||||
@param moc If @c nil perform requests on main context (ok for reading).
|
||||
*/
|
||||
+ (NSArray<Feed*>*)feedsWithIndexPath:(nullable NSString*)path inContext:(nullable NSManagedObjectContext*)moc {
|
||||
NSFetchRequest *fr = [Feed fetchRequest];
|
||||
if (path && path.length > 0) {
|
||||
[fr where:@"indexPath = %@ OR indexPath BEGINSWITH %@", path, [path stringByAppendingString:@"."]];
|
||||
}
|
||||
return [fr fetchAllRows:moc ? moc : [self getMainContext]];
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
+ (NSString*)updatingXFeeds;
|
||||
// Scheduling
|
||||
+ (void)scheduleNextFeed;
|
||||
+ (void)forceUpdateAllFeeds;
|
||||
+ (void)forceUpdate:(NSString*)indexPath;
|
||||
+ (void)downloadList:(NSArray<Feed*>*)list userInitiated:(BOOL)flag notifications:(BOOL)notify finally:(nullable os_block_t)block;
|
||||
+ (void)updateAllFavicons;
|
||||
// Auto Download & Parse Feed URL
|
||||
|
||||
@@ -18,7 +18,6 @@ static NSTimer *_timer;
|
||||
static SCNetworkReachabilityRef _reachability = NULL;
|
||||
static BOOL _isReachable = YES;
|
||||
static BOOL _updatePaused = NO;
|
||||
static BOOL _nextUpdateIsForced = NO;
|
||||
static _Atomic(NSUInteger) _queueSize = 0;
|
||||
|
||||
@implementation UpdateScheduler
|
||||
@@ -90,14 +89,9 @@ static _Atomic(NSUInteger) _queueSize = 0;
|
||||
nextTime = [NSDate dateWithTimeIntervalSinceNow:1];
|
||||
}
|
||||
[self scheduleTimer:nextTime];
|
||||
}
|
||||
|
||||
/// Start download of all feeds (immediatelly) regardless of @c .scheduled property.
|
||||
+ (void)forceUpdateAllFeeds {
|
||||
if (![self allowNetworkConnection]) // timer will restart once connection exists
|
||||
return;
|
||||
_nextUpdateIsForced = YES;
|
||||
[self scheduleTimer:[NSDate dateWithTimeIntervalSinceNow:0.05]];
|
||||
#ifdef DEBUG
|
||||
NSLog(@"schedule next update: %@", nextTime);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,13 +110,9 @@ static _Atomic(NSUInteger) _queueSize = 0;
|
||||
if (!nextTime)
|
||||
nextTime = [NSDate distantFuture];
|
||||
int tolerance = (int)([nextTime timeIntervalSinceNow] * 0.15);
|
||||
tolerance = (tolerance < 1 ? 1 : tolerance > 600 ? 600 : tolerance); // at least 1 sec, upto 10 min
|
||||
_timer.tolerance = tolerance;
|
||||
_timer.tolerance = (tolerance < 1 ? 1 : tolerance > 600 ? 600 : tolerance); // at least 1 sec, upto 10 min
|
||||
_timer.fireDate = nextTime;
|
||||
PostNotification(kNotificationScheduleTimerChanged, nil);
|
||||
#ifdef DEBUG
|
||||
NSLog(@"schedule timer: %@ (+/- %d sec)", nextTime, tolerance);
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (void)didWakeAfterSleep {
|
||||
@@ -134,17 +124,26 @@ static _Atomic(NSUInteger) _queueSize = 0;
|
||||
|
||||
/// Called when schedule timer runs out (earliest @c .schedule date). Or if forced by user.
|
||||
+ (void)updateTimerCallback {
|
||||
#ifdef DEBUG
|
||||
NSLog(@"fired");
|
||||
#endif
|
||||
BOOL updateAll = _nextUpdateIsForced;
|
||||
_nextUpdateIsForced = NO;
|
||||
|
||||
NSManagedObjectContext *moc = [StoreCoordinator createChildContext];
|
||||
NSArray<Feed*> *list = [StoreCoordinator listOfFeedsThatNeedUpdate:updateAll inContext:moc];
|
||||
//NSAssert(list.count > 0, @"ERROR: Something went wrong, timer fired too early.");
|
||||
|
||||
[self downloadList:list userInitiated:updateAll notifications:YES finally:^{
|
||||
NSArray<Feed*> *list = [StoreCoordinator feedsThatNeedUpdate:moc];
|
||||
[self update:list userInitiated:NO context:moc];
|
||||
}
|
||||
|
||||
/// Start download of feeds immediatelly, regardless of @c .scheduled property.
|
||||
+ (void)forceUpdate:(NSString*)indexPath {
|
||||
if (![self allowNetworkConnection]) // menu item should be disabled anyway
|
||||
return;
|
||||
NSManagedObjectContext *moc = [StoreCoordinator createChildContext];
|
||||
NSArray<Feed*> *list = [StoreCoordinator feedsWithIndexPath:indexPath inContext:moc];
|
||||
[self update:list userInitiated:YES context:moc];
|
||||
}
|
||||
|
||||
/// Helper method for actual download
|
||||
+ (void)update:(NSArray<Feed*>*)list userInitiated:(BOOL)flag context:(NSManagedObjectContext*)moc {
|
||||
#ifdef DEBUG
|
||||
NSLog(@"updating feeds: %ld (%@)", list.count, flag ? @"forced" : @"scheduled");
|
||||
#endif
|
||||
[self downloadList:list userInitiated:flag notifications:YES finally:^{
|
||||
[StoreCoordinator saveContext:moc andParent:YES]; // save parents too ...
|
||||
[moc reset];
|
||||
[self scheduleNextFeed]; // always reset the timer
|
||||
@@ -157,7 +156,7 @@ static _Atomic(NSUInteger) _queueSize = 0;
|
||||
|
||||
/// Perform @c FaviconDownload on all core data @c Feed entries.
|
||||
+ (void)updateAllFavicons {
|
||||
for (Feed *f in [StoreCoordinator listOfFeedsThatNeedUpdate:YES inContext:nil])
|
||||
for (Feed *f in [StoreCoordinator feedsWithIndexPath:nil inContext:nil])
|
||||
[FaviconDownload updateFeed:f finally:nil];
|
||||
}
|
||||
|
||||
@@ -212,26 +211,28 @@ static inline void AlertDownloadError(NSError *err, NSString *url) {
|
||||
|
||||
// after save, update notifications
|
||||
// dismiss previously delivered notifications
|
||||
if (deleted) {
|
||||
NSMutableArray *ids = [NSMutableArray array];
|
||||
for (FeedArticle *article in deleted) { // will contain non-articles too
|
||||
if ([article isKindOfClass:[FeedArticle class]] || [article isKindOfClass:[Feed class]]) {
|
||||
[ids addObject:article.notificationID];
|
||||
if (@available(macOS 10.14, *)) {
|
||||
if (deleted) {
|
||||
NSMutableArray *ids = [NSMutableArray array];
|
||||
for (FeedArticle *article in deleted) { // will contain non-articles too
|
||||
if ([article isKindOfClass:[FeedArticle class]] || [article isKindOfClass:[Feed class]]) {
|
||||
[ids addObject:article.notificationID];
|
||||
}
|
||||
}
|
||||
[NotifyEndpoint dismiss:ids]; // no-op if empty
|
||||
}
|
||||
[NotifyEndpoint dismiss:ids]; // no-op if empty
|
||||
}
|
||||
// post new notification (if needed)
|
||||
if (notify && inserted) {
|
||||
BOOL didAddAny = NO;
|
||||
for (FeedArticle *article in inserted) { // will contain non-articles too
|
||||
if ([article isKindOfClass:[FeedArticle class]]) {
|
||||
[NotifyEndpoint postArticle:article];
|
||||
didAddAny = YES;
|
||||
// post new notification (if needed)
|
||||
if (notify && inserted) {
|
||||
BOOL didAddAny = NO;
|
||||
for (FeedArticle *article in inserted) { // will contain non-articles too
|
||||
if ([article isKindOfClass:[FeedArticle class]]) {
|
||||
[NotifyEndpoint postArticle:article];
|
||||
didAddAny = YES;
|
||||
}
|
||||
}
|
||||
if (didAddAny)
|
||||
[NotifyEndpoint postFeed:f];
|
||||
}
|
||||
if (didAddAny)
|
||||
[NotifyEndpoint postFeed:f];
|
||||
}
|
||||
|
||||
if (needsNotification)
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
/** default: @c nil */ static NSString* const Pref_notificationType = @"notificationType";
|
||||
// ------ Appearance matrix ------ (Preferences > Appearance Tab) ------
|
||||
// menu buttons
|
||||
/** default: @c YES */ static NSString* const Pref_globalPauseUpdates = @"globalPauseUpdates";
|
||||
/** default: @c NO */ static NSString* const Pref_globalToggleHidden = @"globalToggleHidden";
|
||||
/** default: @c YES */ static NSString* const Pref_globalUpdateAll = @"globalUpdateAll";
|
||||
/** default: @c YES */ static NSString* const Pref_groupUpdateAll = @"groupUpdateAll";
|
||||
/** default: @c YES */ static NSString* const Pref_feedUpdateAll = @"feedUpdateAll";
|
||||
/** default: @c YES */ static NSString* const Pref_globalOpenUnread = @"globalOpenUnread";
|
||||
/** default: @c YES */ static NSString* const Pref_groupOpenUnread = @"groupOpenUnread";
|
||||
/** default: @c YES */ static NSString* const Pref_feedOpenUnread = @"feedOpenUnread";
|
||||
|
||||
@@ -12,7 +12,8 @@ void UserPrefsInit(void) {
|
||||
NSMutableDictionary *defs = [NSMutableDictionary dictionary];
|
||||
defaultsAppend(defs, @YES, @[
|
||||
Pref_globalTintMenuIcon,
|
||||
Pref_globalUpdateAll,
|
||||
Pref_globalPauseUpdates,
|
||||
Pref_globalUpdateAll, Pref_groupUpdateAll, Pref_feedUpdateAll,
|
||||
Pref_globalOpenUnread, Pref_groupOpenUnread, Pref_feedOpenUnread,
|
||||
Pref_globalMarkRead, Pref_groupMarkRead, Pref_feedMarkRead,
|
||||
Pref_globalMarkUnread, Pref_groupMarkUnread, Pref_feedMarkUnread,
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
API_AVAILABLE(macos(10.14))
|
||||
@interface NotifyEndpoint : NSObject <UNUserNotificationCenterDelegate>
|
||||
+ (void)activate;
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ static NSString* const kActionOpenOnly = @"OPEN_ONLY_DONT_MARK_READ";
|
||||
|
||||
@implementation NotifyEndpoint
|
||||
|
||||
API_AVAILABLE(macos(10.14))
|
||||
static NotifyEndpoint *singleton = nil;
|
||||
static NotificationType notifyType;
|
||||
|
||||
|
||||
@@ -49,16 +49,16 @@
|
||||
RSSImageSettingsFeed, NSLocalizedString(@"Feed menu", nil),
|
||||
]];
|
||||
|
||||
[self entry:NSLocalizedString(@"“Pause updates”", nil)
|
||||
help:NSLocalizedString(@"Show button to temporarily disable feed updates. E.g., no distrations during focus hours.", nil)
|
||||
tip:nil
|
||||
c1:Pref_globalPauseUpdates c2:nil c3:nil c4:nil];
|
||||
|
||||
[self entry:NSLocalizedString(@"“Show hidden feeds”", nil)
|
||||
help:NSLocalizedString(@"Show button to quickly toggle whether hidden entries should be shown. See option “Show only unread”.", nil)
|
||||
tip:NSLocalizedString(@"You can hold down option-key before opening the main menu to temporarily show all hidden entries.", nil)
|
||||
c1:Pref_globalToggleHidden c2:nil c3:nil c4:nil];
|
||||
|
||||
[self entry:NSLocalizedString(@"“Update all feeds”", nil)
|
||||
help:NSLocalizedString(@"Show button to reload all feeds. This will force fetch new online content regardless of next-update timer.", nil)
|
||||
tip:nil
|
||||
c1:Pref_globalUpdateAll c2:nil c3:nil c4:nil];
|
||||
|
||||
[self entry:NSLocalizedString(@"“Open all unread”", nil)
|
||||
help:NSLocalizedString(@"Show button to open unread articles.", nil)
|
||||
tip:nil
|
||||
@@ -74,6 +74,11 @@
|
||||
tip:NSLocalizedString(@"Alternatively, you can hold down option-key and click on an article to toggle that item (un-)read.", nil)
|
||||
c1:Pref_globalMarkUnread c2:Pref_groupMarkUnread c3:Pref_feedMarkUnread c4:nil];
|
||||
|
||||
[self entry:NSLocalizedString(@"“Update feeds”", nil)
|
||||
help:NSLocalizedString(@"Show button to reload all feeds. This will force fetch new online content regardless of next-update timer.", nil)
|
||||
tip:nil
|
||||
c1:Pref_globalUpdateAll c2:Pref_groupUpdateAll c3:Pref_feedUpdateAll c4:nil];
|
||||
|
||||
// self.y += PAD_M;
|
||||
[self intInput:Pref_openFewLinksLimit
|
||||
unit:NSLocalizedString(@"%ld unread", nil)
|
||||
|
||||
@@ -86,7 +86,9 @@
|
||||
- (void)changeNotificationType:(NSPopUpButton *)sender {
|
||||
UserPrefsSet(Pref_notificationType, sender.selectedItem.representedObject);
|
||||
self.view.notificationHelp.stringValue = [self notificationHelpString:UserPrefsNotificationType()];
|
||||
[NotifyEndpoint activate];
|
||||
if (@available(macOS 10.14, *)) {
|
||||
[NotifyEndpoint activate];
|
||||
}
|
||||
}
|
||||
|
||||
/// Help string explaining the different notification settings (for the current configuration)
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
#import "NotifyEndpoint.h"
|
||||
#import "NSView+Ext.h"
|
||||
#import "NSColor+Ext.h"
|
||||
#import "NSMenu+Ext.h"
|
||||
|
||||
@interface BarStatusItem()
|
||||
@property (strong) BarMenu *barMenu;
|
||||
@property (strong) NSStatusItem *statusItem;
|
||||
@property (assign) NSInteger unreadCountTotal;
|
||||
@property (weak) NSMenuItem *updateAllItem;
|
||||
/// Set to `true` if user toggled the `"Show hidden feeds"` menu option.
|
||||
@property (assign) BOOL optShowHidden;
|
||||
/// Set to `true` if menu bar was opened while holding down option-key.
|
||||
@@ -49,8 +49,8 @@
|
||||
/// Fired when network conditions change.
|
||||
- (void)networkChanged:(NSNotification*)notify {
|
||||
BOOL available = [[notify object] boolValue];
|
||||
self.updateAllItem.enabled = available;
|
||||
[self updateBarIcon];
|
||||
[self.statusItem.menu recursiveSetNetworkAvailable:available];
|
||||
}
|
||||
|
||||
/// Fired when a single feed has been updated. Object contains relative unread count change.
|
||||
@@ -77,7 +77,9 @@
|
||||
NSInteger oldCount = _unreadCountTotal;
|
||||
_unreadCountTotal = count > 0 ? (NSInteger)count : 0;
|
||||
[self updateBarIcon];
|
||||
[NotifyEndpoint setGlobalCount:_unreadCountTotal previousCount:oldCount];
|
||||
if (@available(macOS 10.14, *)) {
|
||||
[NotifyEndpoint setGlobalCount:_unreadCountTotal previousCount:oldCount];
|
||||
}
|
||||
}
|
||||
|
||||
/// Assign new value by adding @c count to total unread count (may be negative).
|
||||
@@ -88,7 +90,9 @@
|
||||
_unreadCountTotal = 0;
|
||||
}
|
||||
[self updateBarIcon];
|
||||
[NotifyEndpoint setGlobalCount:_unreadCountTotal previousCount:oldCount];
|
||||
if (@available(macOS 10.14, *)) {
|
||||
[NotifyEndpoint setGlobalCount:_unreadCountTotal previousCount:oldCount];
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch new total unread count from core data and assign it as new value (dispatch async on main thread).
|
||||
@@ -179,10 +183,12 @@
|
||||
|
||||
- (void)insertMainMenuHeader:(NSMenu*)menu {
|
||||
// 'Pause Updates' item
|
||||
NSMenuItem *pause = [menu addItemWithTitle:NSLocalizedString(@"Pause updates", nil) action:@selector(pauseUpdates) keyEquivalent:@""];
|
||||
pause.target = self;
|
||||
if ([UpdateScheduler isPaused])
|
||||
pause.title = NSLocalizedString(@"Resume updates", nil);
|
||||
if (UserPrefsBool(Pref_globalPauseUpdates)) {
|
||||
NSMenuItem *pause = [menu addItemWithTitle:NSLocalizedString(@"Pause updates", nil) action:@selector(pauseUpdates) keyEquivalent:@""];
|
||||
pause.target = self;
|
||||
if ([UpdateScheduler isPaused])
|
||||
pause.title = NSLocalizedString(@"Resume updates", nil);
|
||||
}
|
||||
|
||||
// 'show hidden feeds' item
|
||||
if (UserPrefsBool(Pref_globalToggleHidden)) {
|
||||
@@ -197,15 +203,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 'Update all feeds' item
|
||||
if (UserPrefsBool(Pref_globalUpdateAll)) {
|
||||
NSMenuItem *updateAll = [menu addItemWithTitle:NSLocalizedString(@"Update all feeds", nil) action:@selector(updateAllFeeds) keyEquivalent:@""];
|
||||
updateAll.target = self;
|
||||
updateAll.enabled = [UpdateScheduler allowNetworkConnection];
|
||||
self.updateAllItem = updateAll;
|
||||
if (menu.numberOfItems > 0) {
|
||||
// Separator between main header and default header
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
}
|
||||
// Separator between main header and default header
|
||||
[menu addItem:[NSMenuItem separatorItem]];
|
||||
}
|
||||
|
||||
/// Called when user clicks on 'Pause Updates' (main menu only).
|
||||
@@ -220,10 +221,4 @@
|
||||
self.barMenu.showHidden = self.optShowHidden;
|
||||
}
|
||||
|
||||
/// Called when user clicks on `Update all feeds` (main menu only).
|
||||
- (void)updateAllFeeds {
|
||||
// [self asyncReloadUnreadCount]; // should not be necessary
|
||||
[UpdateScheduler forceUpdateAllFeeds];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)insertDefaultHeader;
|
||||
// Update menu
|
||||
- (void)setHeaderHasUnread:(UnreadTotal*)count;
|
||||
- (void)recursiveSetNetworkAvailable:(BOOL)flag;
|
||||
- (nullable NSMenuItem*)deepestItemWithPath:(nonnull NSString*)path;
|
||||
@end
|
||||
|
||||
|
||||
@@ -6,12 +6,14 @@
|
||||
#import "Constants.h"
|
||||
#import "MapUnreadTotal.h"
|
||||
#import "NotifyEndpoint.h"
|
||||
#import "UpdateScheduler.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, MenuItemTag) {
|
||||
/// Used in @c allowDisplayOfHeaderItem: to identify and enable items
|
||||
TagMarkAllRead = 1,
|
||||
TagMarkAllUnread = 2,
|
||||
TagOpenAllUnread = 3,
|
||||
TagUpdateFeeds = 4,
|
||||
/// Delimiter item between default header and core data items
|
||||
TagHeaderDelimiter = 8,
|
||||
/// Indicator whether unread count is currently shown in menu item title or not
|
||||
@@ -83,6 +85,9 @@ typedef NS_ENUM(NSInteger, MenuItemTag) {
|
||||
}
|
||||
[self addItemIfAllowed:TagMarkAllRead title:NSLocalizedString(@"Mark all read", nil)];
|
||||
[self addItemIfAllowed:TagMarkAllUnread title:NSLocalizedString(@"Mark all unread", nil)];
|
||||
[self addItemIfAllowed:TagUpdateFeeds title:self.isFeedMenu ? NSLocalizedString(@"Update feed", nil) : NSLocalizedString(@"Update feeds", nil)]
|
||||
.enabled = [UpdateScheduler allowNetworkConnection];
|
||||
|
||||
if (self.numberOfItems > 0) {
|
||||
// in case someone has disabled all header items. Else, during articles menu rebuild it will stay on top.
|
||||
NSMenuItem *sep = [NSMenuItem separatorItem];
|
||||
@@ -112,6 +117,16 @@ typedef NS_ENUM(NSInteger, MenuItemTag) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Call this method whenever network availability changes to mark "Update feeds" button en-/disabled.
|
||||
- (void)recursiveSetNetworkAvailable:(BOOL)flag {
|
||||
[self itemWithTag:TagUpdateFeeds].enabled = flag;
|
||||
for (NSMenuItem *item in self.itemArray) {
|
||||
if (item.hasSubmenu) {
|
||||
[item.submenu recursiveSetNetworkAvailable:flag];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Iterate over all menu items in @c self.itemArray and find the item where @c submenu.title matches
|
||||
the first @c sortIndex in @c path. Recursively repeat the process for the items of this submenu and so on.
|
||||
@@ -141,11 +156,13 @@ typedef NS_ENUM(NSInteger, MenuItemTag) {
|
||||
static NSString* const mr[] = {Pref_globalMarkRead, Pref_groupMarkRead, Pref_feedMarkRead};
|
||||
static NSString* const mu[] = {Pref_globalMarkUnread, Pref_groupMarkUnread, Pref_feedMarkUnread};
|
||||
static NSString* const ou[] = {Pref_globalOpenUnread, Pref_groupOpenUnread, Pref_feedOpenUnread};
|
||||
static NSString* const ua[] = {Pref_globalUpdateAll, Pref_groupUpdateAll, Pref_feedUpdateAll};
|
||||
int i = (self.supermenu == nil ? 0 : (self.isFeedMenu ? 2 : 1));
|
||||
switch (tag) {
|
||||
case TagMarkAllRead: return UserPrefsBool(mr[i]);
|
||||
case TagMarkAllUnread: return UserPrefsBool(mu[i]);
|
||||
case TagOpenAllUnread: return UserPrefsBool(ou[i]);
|
||||
case TagUpdateFeeds: return UserPrefsBool(ua[i]);
|
||||
default: return NO;
|
||||
}
|
||||
}
|
||||
@@ -165,6 +182,10 @@ typedef NS_ENUM(NSInteger, MenuItemTag) {
|
||||
|
||||
/// Prepare @c userInfo dictionary and send @c NSNotification. Callback for every default header menu item.
|
||||
+ (void)headerMenuItemCallback:(NSMenuItem*)sender {
|
||||
if (sender.tag == TagUpdateFeeds) {
|
||||
[UpdateScheduler forceUpdate:sender.menu.titleIndexPath];
|
||||
return;
|
||||
}
|
||||
BOOL openLinks = NO;
|
||||
NSUInteger limit = 0;
|
||||
if (sender.tag == TagOpenAllUnread) {
|
||||
@@ -185,8 +206,10 @@ typedef NS_ENUM(NSInteger, MenuItemTag) {
|
||||
}
|
||||
NSManagedObjectContext *moc = [StoreCoordinator createChildContext];
|
||||
NSArray<FeedArticle*> *list = [StoreCoordinator articlesAtPath:path isFeed:isFeedMenu sorted:openLinks unread:markRead inContext:moc limit:limit];
|
||||
[NotifyEndpoint dismiss:
|
||||
[StoreCoordinator updateArticles:list markRead:markRead andOpen:openLinks inContext:moc]];
|
||||
NSArray<NSString *> *notificationIds = [StoreCoordinator updateArticles:list markRead:markRead andOpen:openLinks inContext:moc];
|
||||
if (@available(macOS 10.14, *)) {
|
||||
[NotifyEndpoint dismiss:notificationIds];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user