6 Commits

Author SHA1 Message Date
relikd
4c9362b42e Fix text color in About tab 2019-10-25 19:48:01 +02:00
relikd
9af191834e Fix menu flickering on macOS 10.15 2019-10-25 15:57:24 +02:00
relikd
8d2e4e4383 Fix preferences on macOS 10.15 2019-10-24 12:40:12 +02:00
relikd
473d4b6057 Update changelog 2019-10-04 12:52:22 +02:00
relikd
cee3780f71 Fix crash on macOS 10.14 2019-10-04 01:50:56 +02:00
relikd
58d7660b87 Deprecation warnings in macOS 10.14 2019-10-04 01:20:39 +02:00
15 changed files with 127 additions and 94 deletions

View File

@@ -7,6 +7,19 @@ and this project does adhere to [Semantic Versioning](https://semver.org/spec/v2
## [Unreleased]
## [1.0.2] - 2019-10-25
### Fixed
- *Status Bar Menu*: Preferences could not be opened on macOS 10.15
- *Status Bar Menu*: Menu flickering resulting in a hang on macOS 10.15
- *UI*: Text color in `About` tab
## [1.0.1] - 2019-10-04
### Fixed
- Crash on macOS 10.14 due to a `CGColorRef` null pointer
## [1.0.0] - 2019-10-03
### Added
- App Signing
@@ -115,7 +128,9 @@ and this project does adhere to [Semantic Versioning](https://semver.org/spec/v2
Initial release
[Unreleased]: https://github.com/relikd/baRSS/compare/v1.0.0...HEAD
[Unreleased]: https://github.com/relikd/baRSS/compare/v1.0.2...HEAD
[1.0.2]: https://github.com/relikd/baRSS/compare/v1.0.1...v1.0.2
[1.0.1]: https://github.com/relikd/baRSS/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/relikd/baRSS/compare/v0.9.4...v1.0.0
[0.9.4]: https://github.com/relikd/baRSS/compare/v0.9.3...v0.9.4
[0.9.3]: https://github.com/relikd/baRSS/compare/v0.9.2...v0.9.3

View File

@@ -31,39 +31,6 @@ But it will reuse `ETag` and `Last-Modified` headers to avoid unnecessary transm
Further, tuning the update frequently will decrease the traffic even more.
### Why create something that already existed?
First, open source is awesome!
Secondly, RSS Menu made some design decisions I didn't like.
For example, the new integrated browser window.
One thing I liked most, was the fact that feeds were opened in the default browser.
Not like 99% of the other feed readers on the market that show a separate HTML viewer window.
No rendering issues, no broken links, no content that is different from the actual news article.
I know, the whole purpose of RSS is to deliver content without the need of opening a webpage.
But for me RSS is more about being informed whenever a blog or news feed has some updated content.
E.g, subscribing to video channels without having to have an account.
### Why is this project not written in Swift?!
Actually, I started this project with Swift.
Even without adding much functionality, the app was exceeding the 10 Mb file size.
The working alpha version, written in Objective-C, had only 500 Kb.
The reason being that Swift frameworks are always packed into the final application.
Sadly, this was before Swift 5 and ABI stability.
Had I only started the project a year later…
But on the other hand, now it is macOS 10.12 compatible.
### 3rd Party Libraries
This project uses a modified version of Brent Simmons [RSXML](https://github.com/brentsimmons/RSXML) for feed parsing.
RSXML is licensed under a MIT license (same as this project).
Download & Install
------------------
@@ -72,18 +39,18 @@ Requires macOS Sierra (10.12) or higher.
### Easy way
Go to [releases](https://github.com/relikd/baRSS/releases) and downloaded the latest version.
Searching for the App Store release? Read this [notice](#app-store-notice).
### Build from source
You'll need Xcode and [Carthage](https://github.com/Carthage/Carthage#installing-carthage).
The latter is optional, you can build the [RSXML2](https://github.com/relikd/RSXML2) library from source instead.
The latter is optional, you can build the [RSXML2] library from source instead.
Carthage just makes it more convenient.
Download and unzip this project, navigate to the root folder and run `carthage bootstrap --platform macOS`.
Next, you need to clone [QLOPML](https://github.com/relikd/QLOPML) in the same folder where this project is.
Alternatively, you can simply delete the `QLOPML` project reference without much harm.
`QLOPML` is a Quick Look plugin for `.opml` files.
It will display the file contents whenever you hit space.
It will display the file contents whenever you hit spacebar.
That's it.
Open Xcode and build the project.
@@ -160,9 +127,61 @@ I may postpone some until demand increases …
FAQ / Q&A
---------
### App Store Notice
In the last couple of months I prepared baRSS to be released on the App Store.
With sandboxing enabled and hardened runtime environment, etc.
But, for the time being, I decided to not publish this app for political reasons.
I was not happy about some decisions made in the last weeks.
Decisions that were evaluated on monetary aspects and not on ethical considerations.
I won't support this conduct with my own money.
If you find this app somewhere on the App Store, you can be sure that it is a counterfeit.
As long as you can read this very notice, I am not responsible for the publication.
Further, I can't guarantee the App Store version wasn't modified by a malicious actor to spy on you.
### Why create something that already existed?
First, open source is awesome!
Secondly, RSS Menu made some design decisions I didn't like.
For example, the new integrated browser window.
One thing I liked most, was the fact that feeds were opened in the default browser.
Not like 99% of the other feed readers on the market that show a separate HTML viewer window.
No rendering issues, no broken links, no content that is different from the actual news article.
I know, the whole purpose of RSS is to deliver content without the need of opening a webpage.
But for me RSS is more about being informed whenever a blog or news feed has some updated content.
E.g, subscribing to video channels without having to have an account.
### Why is this project not written in Swift?!
Actually, I started this project with Swift.
Even without adding much functionality, the app was exceeding the 10 Mb file size.
The working alpha version, written in Objective-C, had only 500 Kb.
The reason being that Swift frameworks are always packed into the final application.
Sadly, this was before Swift 5 and ABI stability.
Had I only started the project a year later…
But on the other hand, now it is macOS 10.12 compatible.
### 3rd Party Libraries
This project uses a modified version of Brent Simmons' [RSXML](https://github.com/brentsimmons/RSXML) for feed parsing.
[RSXML2] is licensed under a MIT license (same as this project).
##### Trivia
- Start of project: __July 19, 2018__
- Estimated development time: __1940h+__
- Estimated development time: __1953h+__
- First prototype used __feedparser python__ library
[RSXML2]: https://github.com/relikd/RSXML2

View File

@@ -702,6 +702,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;

View File

@@ -80,5 +80,10 @@
return [NSString stringWithFormat:@"http://i.ytimg.com/vi/%@/hqdefault.jpg", videoid];
}
/// @return @c http://i.ytimg.com/vi/<videoid>/maxresdefault.jpg
+ (NSString*)videoImage4k:(NSString*)videoid {
return [NSString stringWithFormat:@"http://i.ytimg.com/vi/%@/maxresdefault.jpg", videoid];
}
@end

View File

@@ -312,17 +312,14 @@ static void Register(CGFloat size, NSImageName name, NSString *description, BOOL
/// Register all icons that require custom drawing in @c ImageNamed cache
void RegisterImageViewNames(void) {
const CGColorRef black = [NSColor controlTextColor].CGColor;
NSColor* const orange = [NSColor colorWithCalibratedRed:251/255.f green:163/255.f blue:58/255.f alpha:1.f]; // #FBA33A
Register(16, RSSImageDefaultRSSIcon, NSLocalizedString(@"RSS icon", nil), ^(NSRect r) { DrawRSSGradientIcon(r, orange); return YES; });
Register(16, RSSImageSettingsGlobal, NSLocalizedString(@"Global settings", nil), ^(NSRect r) { DrawGlobalIcon(r, black, NO); return YES; });
Register(16, RSSImageSettingsGroup, NSLocalizedString(@"Group settings", nil), ^(NSRect r) { DrawGroupIcon(r, black, NO); return YES; });
Register(16, RSSImageSettingsFeed, NSLocalizedString(@"Feed settings", nil), ^(NSRect r) { DrawRSSIcon(r, black, NO, YES); return YES; });
NSColor *orange = [NSColor colorWithCalibratedRed:251/255.f green:163/255.f blue:58/255.f alpha:1.f]; // #FBA33A
NSColor *c1 = UserPrefsColor(Pref_colorStatusIconTint, orange);
NSColor *c2 = UserPrefsColor(Pref_colorUnreadIndicator, [NSColor systemBlueColor]);
Register(16, RSSImageDefaultRSSIcon, NSLocalizedString(@"RSS icon", nil), ^(NSRect r) { DrawRSSGradientIcon(r, orange); return YES; });
Register(16, RSSImageSettingsGlobal, NSLocalizedString(@"Global settings", nil), ^(NSRect r) { DrawGlobalIcon(r, [NSColor controlTextColor].CGColor, NO); return YES; });
Register(16, RSSImageSettingsGroup, NSLocalizedString(@"Group settings", nil), ^(NSRect r) { DrawGroupIcon(r, [NSColor controlTextColor].CGColor, NO); return YES; });
Register(16, RSSImageSettingsFeed, NSLocalizedString(@"Feed settings", nil), ^(NSRect r) { DrawRSSIcon(r, [NSColor controlTextColor].CGColor, NO, YES); return YES; });
Register(16, RSSImageMenuBarIconActive, NSLocalizedString(@"RSS menu bar icon", nil), ^(NSRect r) { DrawRSSIcon(r, c1.CGColor, YES, YES); return YES; });
Register(16, RSSImageMenuBarIconPaused, NSLocalizedString(@"RSS menu bar icon, paused", nil), ^(NSRect r) { DrawRSSIcon(r, c1.CGColor, YES, NO); return YES; });
Register(14, RSSImageMenuItemUnread, NSLocalizedString(@"Unread icon", nil), ^(NSRect r) { DrawUnreadIcon(r, c2); return YES; });

View File

@@ -45,7 +45,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<string>1.0.2</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
@@ -70,7 +70,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>14360</string>
<string>14471</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.news</string>
<key>LSMinimumSystemVersion</key>

View File

@@ -142,7 +142,7 @@
NSProgressIndicator *spin = [[NSProgressIndicator alloc] initWithFrame: NSMakeRect(0, 0, HEIGHT_SPINNER, HEIGHT_SPINNER)];
spin.indeterminate = YES;
spin.displayedWhenStopped = NO;
spin.style = NSProgressIndicatorSpinningStyle;
spin.style = NSProgressIndicatorStyleSpinning;
spin.controlSize = NSControlSizeSmall;
return spin;
}

View File

@@ -74,7 +74,8 @@
/// Helper method to insert attributed (bold) text
- (void)str:(NSMutableAttributedString*)parent add:(NSString*)text bold:(BOOL)flag {
NSFont *font = [NSFont systemFontOfSize:NSFont.systemFontSize weight:(flag ? NSFontWeightMedium : NSFontWeightLight)];
[parent appendAttributedString:[[NSAttributedString alloc] initWithString:NonLocalized(text) attributes:@{ NSFontAttributeName : font }]];
NSDictionary *style = @{ NSFontAttributeName: font, NSForegroundColorAttributeName: [NSColor controlTextColor] };
[parent appendAttributedString:[[NSAttributedString alloc] initWithString:NonLocalized(text) attributes:style]];
}
/// Helper method to insert attributed hyperlink text

View File

@@ -24,20 +24,20 @@
@class ModalFeedEdit;
@interface ModalFeedEditView : NSView
@property (weak) IBOutlet NSTextField *url;
@property (weak) IBOutlet NSProgressIndicator *spinnerURL;
@property (weak) IBOutlet NSImageView *favicon;
@property (strong) IBOutlet NSTextField *url;
@property (strong) IBOutlet NSProgressIndicator *spinnerURL;
@property (strong) IBOutlet NSImageView *favicon;
@property (weak) IBOutlet NSTextField *name;
@property (weak) IBOutlet NSProgressIndicator *spinnerName;
@property (strong) IBOutlet NSTextField *name;
@property (strong) IBOutlet NSProgressIndicator *spinnerName;
@property (weak) IBOutlet NSTextField *refreshNum;
@property (weak) IBOutlet NSPopUpButton *refreshUnit;
@property (strong) IBOutlet NSTextField *refreshNum;
@property (strong) IBOutlet NSPopUpButton *refreshUnit;
@property (weak) IBOutlet NSButton *warningButton;
@property (strong) IBOutlet NSButton *warningButton;
@property NSPopover *warningPopover;
@property (weak) IBOutlet NSTextField *warningText;
@property (weak) IBOutlet NSButton *warningReload;
@property (strong) IBOutlet NSTextField *warningText;
@property (strong) IBOutlet NSButton *warningReload;
- (instancetype)initWithController:(ModalFeedEdit*)controller NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithFrame:(NSRect)frameRect NS_UNAVAILABLE;

View File

@@ -24,9 +24,9 @@
@class SettingsFeeds;
@interface SettingsFeedsView : NSView
@property (weak) IBOutlet NSOutlineView *outline;
@property (weak) IBOutlet NSTextField *status;
@property (weak) IBOutlet NSProgressIndicator *spinner;
@property (strong) IBOutlet NSOutlineView *outline;
@property (strong) IBOutlet NSTextField *status;
@property (strong) IBOutlet NSProgressIndicator *spinner;
- (instancetype)initWithController:(SettingsFeeds*)delegate NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithFrame:(NSRect)frameRect NS_UNAVAILABLE;

View File

@@ -24,8 +24,8 @@
@class SettingsGeneral;
@interface SettingsGeneralView : NSView
@property (weak) IBOutlet NSPopUpButton* popupHttpApplication;
@property (weak) IBOutlet NSTextField *defaultReader;
@property (strong) IBOutlet NSPopUpButton* popupHttpApplication;
@property (strong) IBOutlet NSTextField *defaultReader;
- (instancetype)initWithController:(SettingsGeneral*)controller NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithFrame:(NSRect)frameRect NS_UNAVAILABLE;

View File

@@ -82,11 +82,6 @@
}
}
/// Get rid of everything that is not needed.
- (void)menuDidClose:(NSMenu*)menu {
[menu cleanup];
}
/// Generate items for @c FeedGroup menu.
- (void)setFeedGroups:(NSArray<FeedGroup*>*)sortedList forMenu:(NSMenu*)menu {
[menu insertDefaultHeader];
@@ -125,17 +120,21 @@
Fetch @c Feed from core data and find deepest visible @c NSMenuItem.
@warning @c item and @c feed will often mismatch.
*/
- (void)updateFeedMenuItem:(NSManagedObjectID*)oid withBlock:(void(^)(Feed *feed, NSMenuItem *item))block {
Feed *feed = [[StoreCoordinator getMainContext] objectWithID:oid];
if ([feed isKindOfClass:[Feed class]]) {
NSMenuItem *item = [self.statusItem.mainMenu deepestItemWithPath:feed.indexPath];
if (item) block(feed, item);
}
- (BOOL)findDeepest:(NSManagedObjectID*)oid feed:(Feed*__autoreleasing*)feed menuItem:(NSMenuItem*__autoreleasing*)item {
Feed *f = [[StoreCoordinator getMainContext] objectWithID:oid];
if (![f isKindOfClass:[Feed class]]) return NO;
NSMenuItem *mi = [self.statusItem.mainMenu deepestItemWithPath:f.indexPath];
if (!mi) return NO;
*feed = f;
*item = mi;
return YES;
}
/// Callback method fired when feed has been updated in the background.
- (void)articlesUpdated:(NSNotification*)notify {
[self updateFeedMenuItem:notify.object withBlock:^(Feed *feed, NSMenuItem *item) {
Feed *feed;
NSMenuItem *item;
if ([self findDeepest:notify.object feed:&feed menuItem:&item]) {
// 1. update in-memory unread count
UnreadTotal *updated = [UnreadTotal new];
updated.total = feed.articles.count;
@@ -160,15 +159,17 @@
[item setTitleCount:uct.unread];
item = item.parentItem;
}
}];
}
}
/// Callback method fired when feed icon has changed.
- (void)feedIconUpdated:(NSNotification*)notify {
[self updateFeedMenuItem:notify.object withBlock:^(Feed *feed, NSMenuItem *item) {
Feed *feed;
NSMenuItem *item;
if ([self findDeepest:notify.object feed:&feed menuItem:&item]) {
if (item.submenu.isFeedMenu)
item.image = [feed iconImage16];
}];
}
}
@end

View File

@@ -44,10 +44,9 @@
self = [super init];
// Show icon & prefetch unread count
self.statusItem = [NSStatusBar.systemStatusBar statusItemWithLength:NSVariableStatusItemLength];
self.statusItem.highlightMode = YES;
self.unreadCountTotal = 0;
self.statusItem.image = [NSImage imageNamed:RSSImageMenuBarIconActive];
self.statusItem.image.template = YES;
self.statusItem.button.image = [NSImage imageNamed:RSSImageMenuBarIconActive];
self.statusItem.button.image.template = YES;
// Add empty menu (will be populated once opened)
self.statusItem.menu = [[NSMenu alloc] initWithTitle:@"M"];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mainMenuWillOpen) name:NSMenuDidBeginTrackingNotification object:self.statusItem.menu];
@@ -119,11 +118,13 @@
dispatch_async(dispatch_get_main_queue(), ^{
BOOL hasNet = [UpdateScheduler allowNetworkConnection];
BOOL tint = (self.unreadCountTotal > 0 && hasNet && UserPrefsBool(Pref_globalTintMenuIcon));
self.statusItem.image = [NSImage imageNamed:(hasNet ? RSSImageMenuBarIconActive : RSSImageMenuBarIconPaused)];
self.statusItem.image.template = !tint;
self.statusItem.button.image = [NSImage imageNamed:(hasNet ? RSSImageMenuBarIconActive : RSSImageMenuBarIconPaused)];
self.statusItem.button.image.template = !tint;
// TODO: use macOS 10.14 contentTintColor, if (@available(macOS 10.14, *)) {} else {}
BOOL showCount = (self.unreadCountTotal > 0 && UserPrefsBool(Pref_globalUnreadCount));
self.statusItem.title = (showCount ? [NSString stringWithFormat:@"%ld", self.unreadCountTotal] : @"");
self.statusItem.button.title = (showCount ? [NSString stringWithFormat:@"%ld", self.unreadCountTotal] : @"");
self.statusItem.button.imagePosition = (showCount ? NSImageLeft : NSImageOnly);
});
}

View File

@@ -33,7 +33,6 @@
- (NSMenuItem*)insertFeedGroupItem:(FeedGroup*)fg;
- (void)insertDefaultHeader;
// Update menu
- (void)cleanup;
- (void)setHeaderHasUnread:(BOOL)hasUnread hasRead:(BOOL)hasRead;
- (NSMenuItem*)deepestItemWithPath:(nonnull NSString*)path;
@end

View File

@@ -104,12 +104,6 @@ typedef NS_ENUM(NSInteger, MenuItemTag) {
#pragma mark - Update Menu
/// Replace this menu with a clean @c NSMenu. Copy old @c title and @c delegate to new menu. @b Won't work without supermenu!
- (void)cleanup {
NSMenu *m = [[NSMenu alloc] initWithTitle:self.title];
m.delegate = self.delegate;
self.parentItem.submenu = m;
}
/// Loop over default header and enable 'OpenAllUnread' and 'TagMarkAllRead' based on unread count.
- (void)setHeaderHasUnread:(BOOL)hasUnread hasRead:(BOOL)hasRead {