Custom colors via defaults plist

This commit is contained in:
relikd
2019-09-26 16:24:51 +02:00
parent 23b5bba794
commit b25565c74f
11 changed files with 126 additions and 56 deletions

View File

@@ -22,14 +22,6 @@
@import Cocoa;
@interface NSColor (RandomColor)
/// just for testing purposes
+ (NSColor*)randomColor;
/// RGB color with (251, 163, 58)
+ (NSColor*)rssOrange;
@end
/// Draw separator line in @c NSOutlineView
IB_DESIGNABLE
@interface DrawSeparator : NSView

View File

@@ -22,20 +22,7 @@
#import "DrawImage.h"
#import "Constants.h"
@implementation NSColor (RandomColor)
/// @return Color with random R, G, B values for testing purposes
+ (NSColor*)randomColor {
return [NSColor colorWithRed:(arc4random()%50+20)/100.0
green:(arc4random()%50+20)/100.0
blue:(arc4random()%50+20)/100.0
alpha:1];
}
/// @return Orange color that is typically used for RSS
+ (NSColor*)rssOrange {
return [NSColor colorWithCalibratedRed:251/255.0 green:163/255.0 blue:58/255.0 alpha:1.0];
}
@end
#import "UserPrefs.h"
@implementation DrawSeparator
@@ -278,14 +265,14 @@ static void DrawRSSIcon(CGRect r, CGColorRef color, BOOL background, BOOL connec
}
/// Draw RSS icon (with orange gradient, corner @c 0.4, white radio waves)
static void DrawRSSGradientIcon(CGRect r) {
static void DrawRSSGradientIcon(CGRect r, NSColor *color) {
const CGFloat size = ShorterSide(r.size);
CGContextRef c = NSGraphicsContext.currentContext.CGContext;
DrawRoundedFrame(c, r, NSColor.whiteColor.CGColor, YES, 0.4, 1.0, 0.7);
// Gradient
CGContextSaveGState(c);
CGContextClip(c);
DrawGradient(c, size, [NSColor rssOrange]);
DrawGradient(c, size, color);
CGContextRestoreGState(c);
// Bars
AddRSSIconPath(c, size, YES);
@@ -297,7 +284,8 @@ static void DrawUnreadIcon(CGRect r, NSColor *color) {
CGFloat size = ShorterSide(r.size) / 2.0;
CGContextRef c = NSGraphicsContext.currentContext.CGContext;
CGMutablePathRef path = CGPathCreateMutable();
SetContentScale(c, r.size, 0.8);
SetContentScale(c, r.size, 0.7);
CGContextTranslateCTM(c, 0, size * -0.15); // align with baseline of menu item text
CGContextSetFillColorWithColor(c, color.CGColor);
PathAddRing(path, size, size * 0.7);
@@ -325,12 +313,17 @@ 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;
Register(16, RSSImageDefaultRSSIcon, NSLocalizedString(@"RSS icon", nil), ^(NSRect r) { DrawRSSGradientIcon(r); return YES; });
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; });
Register(16, RSSImageMenuBarIconActive, NSLocalizedString(@"RSS menu bar icon", nil), ^(NSRect r) { DrawRSSIcon(r, [NSColor rssOrange].CGColor, YES, YES); return YES; });
Register(16, RSSImageMenuBarIconPaused, NSLocalizedString(@"RSS menu bar icon, paused", nil), ^(NSRect r) { DrawRSSIcon(r, [NSColor rssOrange].CGColor, YES, NO); return YES; });
Register(12, RSSImageMenuItemUnread, NSLocalizedString(@"Unread icon", nil), ^(NSRect r) { DrawUnreadIcon(r, [NSColor systemBlueColor]); return YES; });
// TODO: user selected color for rss bar icon & unread dot
NSColor *c1 = [UserPrefs defaultColor:orange forKey:@"colorStatusIconTint"];
NSColor *c2 = [UserPrefs defaultColor:[NSColor systemBlueColor] forKey:@"colorUnreadTickMark"];
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

@@ -33,9 +33,10 @@
+ (BOOL)openURLsWithPreferredBrowser:(NSArray<NSURL*>*)urls;
// Hidden Plist Properties
+ (NSUInteger)openFewLinksLimit; // Change with: 'defaults write de.relikd.baRSS openFewLinksLimit -int 10'
+ (NSUInteger)shortArticleNamesLimit; // Change with: 'defaults write de.relikd.baRSS shortArticleNamesLimit -int 50'
+ (NSUInteger)articlesInMenuLimit; // Change with: 'defaults write de.relikd.baRSS articlesInMenuLimit -int 40'
+ (NSUInteger)openFewLinksLimit; // Change with: defaults write de.relikd.baRSS openFewLinksLimit -int 10
+ (NSUInteger)shortArticleNamesLimit; // Change with: defaults write de.relikd.baRSS shortArticleNamesLimit -int 50
+ (NSUInteger)articlesInMenuLimit; // Change with: defaults write de.relikd.baRSS articlesInMenuLimit -int 40
+ (NSColor*)defaultColor:(NSColor*)defaultColor forKey:(NSString*)key; // Change with: defaults write de.relikd.baRSS {KEY} -string "#FBA33A"
// Application Info Plist
+ (NSString*)appName;

View File

@@ -22,6 +22,7 @@
#import "UserPrefs.h"
#import "StoreCoordinator.h"
#import "NSString+Ext.h"
@implementation UserPrefs
@@ -84,6 +85,18 @@
/// Default: @c 40
+ (NSUInteger)articlesInMenuLimit { return [self defaultUInt:40 forKey:@"articlesInMenuLimit"]; }
/// @return Returns @c defaultColor if defaults value couldn't be parsed or wasn't modified by user.
+ (NSColor*)defaultColor:(NSColor*)defaultColor forKey:(NSString*)key {
NSString *colorStr = [[NSUserDefaults standardUserDefaults] stringForKey:key];
if (colorStr) {
NSColor *color = [colorStr hexColor];
if (color) return color;
NSLog(@"Error reading defaults '%@'. Hex color '%@' is invalid. It should be of the form #RBG or #RRGGBB.", key, colorStr);
[[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
}
return defaultColor;
}
#pragma mark - Application Info Plist

View File

@@ -70,7 +70,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>13723</string>
<string>13931</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.news</string>
<key>LSMinimumSystemVersion</key>

View File

@@ -28,8 +28,9 @@
@interface NSError (Ext)
// Generators
+ (instancetype)statusCode:(NSInteger)code reason:(nullable NSString*)reason;
+ (instancetype)canceledByUser;
+ (instancetype)feedURLNotFound:(NSURL*)url;
+ (instancetype)canceledByUser;
//+ (instancetype)formattingError:(NSString*)description;
// User notification
- (BOOL)inCaseLog:(nullable const char*)title;
- (BOOL)inCasePresent:(NSApplication*)app;

View File

@@ -115,17 +115,23 @@ static const char* CodeDescription(NSInteger code) {
return [self errorWithDomain:NSURLErrorDomain code:errCode userInfo:info];
}
/// Generate @c NSError for user canceled operation. With title "Operation canceled.".
+ (instancetype)canceledByUser {
NSDictionary *info = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"Operation canceled.", nil) };
return [self errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:info];
}
/// Generate @c NSError for webpages that don't contain feed urls.
+ (instancetype)feedURLNotFound:(NSURL*)url {
return RSXMLMakeErrorWrongParser(RSXMLErrorExpectingFeed, RSXMLErrorExpectingHTML, url);
}
/// Generate @c NSError for user canceled operation. With title "Operation was canceled."
+ (instancetype)canceledByUser {
return [NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil];
}
/*// Generate @c NSError for invalid or malformed input. With title "The value is invalid."
+ (instancetype)formattingError:(NSString*)description {
NSDictionary *info = nil;
if (description) info = @{ NSLocalizedRecoverySuggestionErrorKey: description };
return [NSError errorWithDomain:NSCocoaErrorDomain code:NSFormattingError userInfo:info];
}*/
// ---------------------------------------------------------------
// | MARK: - User notification
// ---------------------------------------------------------------

View File

@@ -22,7 +22,11 @@
@import Cocoa;
@interface NSString (Ext)
@interface NSString (PlainHTML)
+ (NSString*)plainTextFromHTMLData:(NSData*)data;
- (nonnull NSString*)htmlToPlainText;
@end
@interface NSString (HexColor)
- (nullable NSColor*)hexColor;
@end

View File

@@ -22,7 +22,7 @@
#import "NSString+Ext.h"
@implementation NSString (Ext)
@implementation NSString (PlainHTML)
/// Init string with @c NSUTF8StringEncoding and call @c htmlToPlainText
+ (NSString*)plainTextFromHTMLData:(NSData*)data {
@@ -112,3 +112,51 @@ static inline BOOL CLOSE(NSString *tag, NSString *match) {
}
@end
@implementation NSString (HexColor)
/**
Color from hex string with format: @c #[0x|0X]([A]RGB|[AA]RRGGBB)
@return @c nil if string is not properly formatted.
*/
- (nullable NSColor*)hexColor {
if ([self characterAtIndex:0] != '#') // must start with '#'
return nil;
NSScanner *scanner = [NSScanner scannerWithString:self];
scanner.scanLocation = 1;
unsigned int value;
if (![scanner scanHexInt:&value])
return nil;
NSUInteger len = scanner.scanLocation - 1; // -'#'
if (len > 1 && ([self characterAtIndex:2] == 'x' || [self characterAtIndex:3] == 'X'))
len -= 2; // ignore '0x'RRGGBB
unsigned int r = 0, g = 0, b = 0, a = 255;
switch (len) {
case 4: // #ARGB
// ignore alpha for now
// a = (value >> 8) & 0xF0; a = a | (a >> 4);
case 3: // #RGB
r = (value >> 4) & 0xF0; r = r | (r >> 4);
g = (value) & 0xF0; g = g | (g >> 4);
b = (value) & 0x0F; b = b | (b << 4);
break;
case 8: // #AARRGGBB
// a = (value >> 24) & 0xFF;
case 6: // #RRGGBB
r = (value >> 16) & 0xFF;
g = (value >> 8) & 0xFF;
b = (value) & 0xFF;
break;
default:
return nil;
}
return [NSColor colorWithCalibratedRed:r/255.f green:g/255.f blue:b/255.f alpha:a/255.f];
}
@end