Refactoring UserPrefs
This commit is contained in:
@@ -123,7 +123,7 @@ defaults write de.relikd.baRSS articlesInMenuLimit -int 40
|
||||
5. You can change the appearance of colors throughout the application. E.g., The tint color of the menu bar icon and the color of the blue dot of unread articles.
|
||||
```
|
||||
defaults write de.relikd.baRSS colorStatusIconTint -string "#37F"
|
||||
defaults write de.relikd.baRSS colorUnreadTickMark -string "#FBA33A"
|
||||
defaults write de.relikd.baRSS colorUnreadIndicator -string "#FBA33A"
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -407,10 +407,10 @@
|
||||
54E9CF2F225913850023696F /* Helper */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
54209E922117325100F3B5EF /* DrawImage.h */,
|
||||
54209E932117325100F3B5EF /* DrawImage.m */,
|
||||
5496B50F214D6275003ED4ED /* UserPrefs.h */,
|
||||
5496B510214D6275003ED4ED /* UserPrefs.m */,
|
||||
54209E922117325100F3B5EF /* DrawImage.h */,
|
||||
54209E932117325100F3B5EF /* DrawImage.m */,
|
||||
54910065233A4D4000858AE2 /* URLScheme.h */,
|
||||
54910066233A4D4000858AE2 /* URLScheme.m */,
|
||||
);
|
||||
@@ -655,10 +655,7 @@
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
@@ -750,6 +747,10 @@
|
||||
"$(PROJECT_DIR)",
|
||||
"$(PROJECT_DIR)/Carthage/Build/Mac",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"APP_NAME=\"\\@\\\"$(PRODUCT_NAME)\\\"\"",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||
@@ -801,6 +802,10 @@
|
||||
"$(PROJECT_DIR)",
|
||||
"$(PROJECT_DIR)/Carthage/Build/Mac",
|
||||
);
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"APP_NAME=\"\\@\\\"$(PRODUCT_NAME)\\\"\"",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
}
|
||||
|
||||
- (void)applicationWillFinishLaunching:(NSNotification *)notification {
|
||||
UserPrefsInit();
|
||||
RegisterImageViewNames();
|
||||
_statusItem = [BarStatusItem new];
|
||||
NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
|
||||
@@ -70,11 +71,10 @@
|
||||
[UpdateScheduler unregisterNetworkChangeNotification];
|
||||
}
|
||||
|
||||
/// Called during application start. Perform any version dependent updates here
|
||||
/// Called during application start. Perform any version migration updates here.
|
||||
- (void)migrateVersionUpdate {
|
||||
// Currently unused, but you'll be thankful to know the previous version number in the future
|
||||
[UserPrefs dbUpdateFileVersion];
|
||||
[UserPrefs dbUpdateAppVersion];
|
||||
// Currently unused, but you'll be thankful in the future for a previously saved version number
|
||||
[StoreCoordinator setOption:@"app-version" value: UserPrefsAppVersion()];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ static NSImageName const RSSImageMenuItemUnread = @"RSSImageMenuItemUnread";
|
||||
|
||||
/// Helper method calls @c (defaultCenter)postNotification:
|
||||
static inline void PostNotification(NSNotificationName name, id obj) { [[NSNotificationCenter defaultCenter] postNotificationName:name object:obj]; }
|
||||
/// Helper method calls @c (defaultCenter)addObserver:
|
||||
static inline void RegisterNotification(NSNotificationName name, SEL action, id observer) { [[NSNotificationCenter defaultCenter] addObserver:observer selector:action name:name object:nil]; }
|
||||
/**
|
||||
@c notification.object is @c NSNumber of type @c NSUInteger.
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
+ (void)didClickOnMenuItem:(NSMenuItem*)sender {
|
||||
NSString *url = [StoreCoordinator urlForFeedWithIndexPath:sender.representedObject];
|
||||
if (url && url.length > 0)
|
||||
[UserPrefs openURLsWithPreferredBrowser:@[[NSURL URLWithString:url]]];
|
||||
UserPrefsOpenURL(url);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -52,20 +52,20 @@
|
||||
NSString *title = self.title;
|
||||
if (!title) return @"";
|
||||
// TODO: It should be enough to get user prefs once per menu build
|
||||
if ([UserPrefs defaultNO:@"feedShortNames"]) {
|
||||
NSUInteger limit = [UserPrefs shortArticleNamesLimit];
|
||||
if (UserPrefsBool(Pref_feedTruncateTitle)) {
|
||||
NSUInteger limit = UserPrefsUInt(Pref_shortArticleNamesLimit);
|
||||
if (title.length > limit)
|
||||
title = [NSString stringWithFormat:@"%@…", [title substringToIndex:limit-1]];
|
||||
title = [[title substringToIndex:limit] stringByAppendingString:@"…"];
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
/// @return Fully initialized @c NSMenuItem with @c title, @c tooltip, @c tickmark, and @c action.
|
||||
/// @return Fully initialized @c NSMenuItem with @c title, @c tooltip, @c unread-indicator, and @c action.
|
||||
- (NSMenuItem*)newMenuItem {
|
||||
NSMenuItem *item = [NSMenuItem new];
|
||||
item.title = [self shortArticleName];
|
||||
item.enabled = (self.link.length > 0);
|
||||
item.state = (self.unread && [UserPrefs defaultYES:@"feedTickMark"] ? NSControlStateValueOn : NSControlStateValueOff);
|
||||
item.state = (self.unread && UserPrefsBool(Pref_feedUnreadIndicator) ? NSControlStateValueOn : NSControlStateValueOff);
|
||||
item.onStateImage = [NSImage imageNamed:RSSImageMenuItemUnread];
|
||||
item.accessibilityLabel = (self.unread ? NSLocalizedString(@"article: unread", @"accessibility label, feed menu item") : NSLocalizedString(@"article: read", @"accessibility label, feed menu item"));
|
||||
item.toolTip = (self.abstract ? self.abstract : self.body); // fall back to body (html)
|
||||
@@ -83,7 +83,7 @@
|
||||
NSString *url = fa.link;
|
||||
BOOL success = NO;
|
||||
if (url && url.length > 0 && !flipUnread) // flipUnread == change unread state
|
||||
success = [UserPrefs openURLsWithPreferredBrowser:@[[NSURL URLWithString:url]]];
|
||||
success = UserPrefsOpenURL(url);
|
||||
if (flipUnread || (success && fa.unread)) {
|
||||
fa.unread = !fa.unread;
|
||||
[StoreCoordinator saveContext:moc andParent:YES];
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
@import Cocoa;
|
||||
#import "DBv1+CoreDataModel.h"
|
||||
|
||||
static int const dbFileVersion = 1; // update in case database structure changes
|
||||
|
||||
@interface StoreCoordinator : NSObject
|
||||
// Managing contexts
|
||||
+ (NSManagedObjectContext*)getMainContext;
|
||||
|
||||
@@ -320,8 +320,8 @@ void RegisterImageViewNames(void) {
|
||||
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 *c1 = [UserPrefs defaultColor:orange forKey:@"colorStatusIconTint"];
|
||||
NSColor *c2 = [UserPrefs defaultColor:[NSColor systemBlueColor] forKey:@"colorUnreadTickMark"];
|
||||
NSColor *c1 = UserPrefsColor(Pref_colorStatusIconTint, orange);
|
||||
NSColor *c2 = UserPrefsColor(Pref_colorUnreadIndicator, [NSColor systemBlueColor]);
|
||||
|
||||
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; });
|
||||
|
||||
@@ -20,33 +20,91 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#ifndef UserPrefs_h
|
||||
#define UserPrefs_h
|
||||
|
||||
@import Cocoa;
|
||||
|
||||
@interface UserPrefs : NSObject
|
||||
// User Preferences Plist
|
||||
+ (BOOL)defaultYES:(NSString*)key;
|
||||
+ (BOOL)defaultNO:(NSString*)key;
|
||||
+ (NSUInteger)defaultUInt:(NSUInteger)defaultInt forKey:(NSString*)key;
|
||||
// ---------------------------------------------------------------
|
||||
// | MARK: Constants
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
+ (NSString*)getHttpApplication;
|
||||
+ (void)setHttpApplication:(NSString*)bundleID;
|
||||
+ (BOOL)openURLsWithPreferredBrowser:(NSArray<NSURL*>*)urls;
|
||||
// ------ Preferences window ------
|
||||
/** default: @c 1 */ static NSString* const Pref_prefSelectedTab = @"prefSelectedTab";
|
||||
/** default: @c nil */ static NSString* const Pref_prefWindowFrame = @"prefWindowFrame";
|
||||
/** default: @c nil */ static NSString* const Pref_modalSheetWidth = @"modalSheetWidth";
|
||||
// ------ General settings ------ (Preferences > General Tab) ------
|
||||
/** default: @c nil */ static NSString* const Pref_defaultHttpApplication = @"defaultHttpApplication";
|
||||
// ------ Appearance matrix ------ (Preferences > Appearance Tab) ------
|
||||
/** default: @c YES */ static NSString* const Pref_globalTintMenuIcon = @"globalTintMenuBarIcon";
|
||||
/** default: @c YES */ static NSString* const Pref_globalUpdateAll = @"globalUpdateAll";
|
||||
/** default: @c YES */ static NSString* const Pref_globalOpenUnread = @"globalOpenUnread";
|
||||
/** default: @c YES */ static NSString* const Pref_globalMarkRead = @"globalMarkRead";
|
||||
/** default: @c YES */ static NSString* const Pref_globalMarkUnread = @"globalMarkUnread";
|
||||
/** default: @c YES */ static NSString* const Pref_globalUnreadCount = @"globalUnreadCount";
|
||||
/** default: @c YES */ static NSString* const Pref_groupOpenUnread = @"groupOpenUnread";
|
||||
/** default: @c YES */ static NSString* const Pref_groupMarkRead = @"groupMarkRead";
|
||||
/** default: @c YES */ static NSString* const Pref_groupMarkUnread = @"groupMarkUnread";
|
||||
/** default: @c YES */ static NSString* const Pref_groupUnreadCount = @"groupUnreadCount";
|
||||
/** default: @c YES */ static NSString* const Pref_feedOpenUnread = @"feedOpenUnread";
|
||||
/** default: @c YES */ static NSString* const Pref_feedMarkRead = @"feedMarkRead";
|
||||
/** default: @c YES */ static NSString* const Pref_feedMarkUnread = @"feedMarkUnread";
|
||||
/** default: @c YES */ static NSString* const Pref_feedUnreadCount = @"feedUnreadCount";
|
||||
/** default: @c YES */ static NSString* const Pref_feedUnreadIndicator = @"feedUnreadIndicator";
|
||||
/** default: @c NO */ static NSString* const Pref_feedTruncateTitle = @"feedTruncateTitle";
|
||||
/** default: @c NO */ static NSString* const Pref_feedLimitArticles = @"feedLimitArticles";
|
||||
// ------ Hidden preferences ------ only modifiable via `defaults write de.relikd.baRSS {KEY}` ------
|
||||
/** default: @c 10 */ static NSString* const Pref_openFewLinksLimit = @"openFewLinksLimit";
|
||||
/** default: @c 60 */ static NSString* const Pref_shortArticleNamesLimit = @"shortArticleNamesLimit";
|
||||
/** default: @c 40 */ static NSString* const Pref_articlesInMenuLimit = @"articlesInMenuLimit";
|
||||
/** default: @c nil */ static NSString* const Pref_colorStatusIconTint = @"colorStatusIconTint";
|
||||
/** default: @c nil */ static NSString* const Pref_colorUnreadIndicator = @"colorUnreadIndicator";
|
||||
|
||||
// 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
|
||||
+ (NSColor*)defaultColor:(NSColor*)defaultColor forKey:(NSString*)key; // Change with: defaults write de.relikd.baRSS {KEY} -string "#FBA33A"
|
||||
|
||||
// Application Info Plist
|
||||
+ (NSString*)appName;
|
||||
+ (NSString*)appVersion;
|
||||
+ (NSString*)appVersionWithBuildNo;
|
||||
// ---------------------------------------------------------------
|
||||
// | MARK: - NSUserDefaults
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
// Core Data Properties
|
||||
+ (BOOL)dbIsUnusedInitalState;
|
||||
+ (BOOL)dbIsCurrentFileVersion;
|
||||
+ (BOOL)dbIsCurrentAppVersion;
|
||||
+ (void)dbUpdateFileVersion;
|
||||
+ (void)dbUpdateAppVersion;
|
||||
@end
|
||||
void UserPrefsInit(void);
|
||||
NSColor* UserPrefsColor(NSString *key, NSColor *defaultColor); // Change with: defaults write de.relikd.baRSS {KEY} -string "#FBA33A"
|
||||
// ------ Getter ------
|
||||
/// Helper method calls @c (standardUserDefaults)boolForKey:
|
||||
static inline BOOL UserPrefsBool(NSString* const key) { return [[NSUserDefaults standardUserDefaults] boolForKey:key]; }
|
||||
/// Helper method calls @c (standardUserDefaults)integerForKey:
|
||||
static inline NSInteger UserPrefsInt(NSString* const key) { return [[NSUserDefaults standardUserDefaults] integerForKey:key]; }
|
||||
/// Helper method calls @c (standardUserDefaults)integerForKey: @return @c (NSUInteger)result
|
||||
static inline NSUInteger UserPrefsUInt(NSString* const key) { return (NSUInteger)[[NSUserDefaults standardUserDefaults] integerForKey:key]; }
|
||||
/// Helper method calls @c (standardUserDefaults)stringForKey:
|
||||
static inline NSString* UserPrefsString(NSString* const key) { return [[NSUserDefaults standardUserDefaults] stringForKey:key]; }
|
||||
// ------ Setter ------
|
||||
/// Helper method calls @c (standardUserDefaults)setObject:forKey:
|
||||
static inline void UserPrefsSet(NSString* const key, id value) { [[NSUserDefaults standardUserDefaults] setObject:value forKey:key]; }
|
||||
/// Helper method calls @c (standardUserDefaults)setInteger:forKey:
|
||||
static inline void UserPrefsSetInt(NSString* const key, NSInteger value) { [[NSUserDefaults standardUserDefaults] setInteger:value forKey:key]; }
|
||||
/// Helper method calls @c (standardUserDefaults)setBool:forKey:
|
||||
static inline void UserPrefsSetBool(NSString* const key, BOOL value) { [[NSUserDefaults standardUserDefaults] setBool:value forKey:key]; }
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// | MARK: - NSBundle
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/// Helper method calls @c (mainBundle)CFBundleShortVersionString
|
||||
static inline NSString* UserPrefsAppVersion() { return [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"]; }
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// | MARK: - Open URLs
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
Open web links in default browser or a browser the user selected in the preferences.
|
||||
|
||||
@param urls A list of @c NSURL objects that will be opened immediatelly in bulk.
|
||||
@return @c YES if @c urls are opened successfully. @c NO on error.
|
||||
*/
|
||||
static inline BOOL UserPrefsOpenURLs(NSArray<NSURL*> *urls) {
|
||||
return [[NSWorkspace sharedWorkspace] openURLs:urls withAppBundleIdentifier:UserPrefsString(Pref_defaultHttpApplication) options:NSWorkspaceLaunchDefault additionalEventParamDescriptor:nil launchIdentifiers:nil];
|
||||
}
|
||||
/// Call @c UserPrefsOpenURLs() with single item array and convert string to @c NSURL
|
||||
static inline BOOL UserPrefsOpenURL(NSString *url) { return UserPrefsOpenURLs(@[[NSURL URLWithString:url]]); }
|
||||
|
||||
#endif /* UserPrefs_h */
|
||||
|
||||
@@ -21,72 +21,36 @@
|
||||
// SOFTWARE.
|
||||
|
||||
#import "UserPrefs.h"
|
||||
#import "StoreCoordinator.h"
|
||||
#import "NSString+Ext.h"
|
||||
#import "NSString+Ext.h" // hexColor
|
||||
|
||||
@implementation UserPrefs
|
||||
|
||||
#pragma mark - User Preferences Plist
|
||||
|
||||
/// @return @c YES if key is not set. Otherwise, return user defaults property from plist.
|
||||
+ (BOOL)defaultYES:(NSString*)key {
|
||||
if ([[NSUserDefaults standardUserDefaults] objectForKey:key] == NULL) {
|
||||
return YES;
|
||||
}
|
||||
return [[NSUserDefaults standardUserDefaults] boolForKey:key];
|
||||
/// Helper method for @c UserPrefsInit()
|
||||
static inline void defaultsAppend(NSMutableDictionary *defs, id value, NSArray<NSString*>* keys) {
|
||||
for (NSString *key in keys)
|
||||
[defs setObject:value forKey:key];
|
||||
}
|
||||
|
||||
/// @return @c NO if key is not set. Otherwise, return user defaults property from plist.
|
||||
+ (BOOL)defaultNO:(NSString*)key {
|
||||
return [[NSUserDefaults standardUserDefaults] boolForKey:key];
|
||||
/// Helper method calls @c (standardUserDefaults)registerDefaults:
|
||||
void UserPrefsInit(void) {
|
||||
NSMutableDictionary *defs = [NSMutableDictionary dictionary];
|
||||
defaultsAppend(defs, @YES, @[Pref_globalTintMenuIcon,
|
||||
Pref_globalUpdateAll,
|
||||
Pref_globalOpenUnread, Pref_groupOpenUnread, Pref_feedOpenUnread,
|
||||
Pref_globalMarkRead, Pref_groupMarkRead, Pref_feedMarkRead,
|
||||
Pref_globalMarkUnread, Pref_groupMarkUnread, Pref_feedMarkUnread,
|
||||
Pref_globalUnreadCount, Pref_groupUnreadCount, Pref_feedUnreadCount,
|
||||
Pref_feedUnreadIndicator]);
|
||||
defaultsAppend(defs, @NO, @[Pref_feedTruncateTitle,
|
||||
Pref_feedLimitArticles]);
|
||||
// Display limits & truncation ( defaults write de.relikd.baRSS {KEY} -int 10 )
|
||||
[defs setObject:[NSNumber numberWithUnsignedInteger:10] forKey:Pref_openFewLinksLimit];
|
||||
[defs setObject:[NSNumber numberWithUnsignedInteger:60] forKey:Pref_shortArticleNamesLimit];
|
||||
[defs setObject:[NSNumber numberWithUnsignedInteger:40] forKey:Pref_articlesInMenuLimit];
|
||||
[defs setObject:[NSNumber numberWithUnsignedInteger:1] forKey:Pref_prefSelectedTab]; // feed tab
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:defs];
|
||||
}
|
||||
|
||||
/// @return Return @c defaultInt if key is not set. Otherwise, return user defaults property from plist.
|
||||
+ (NSUInteger)defaultUInt:(NSUInteger)defaultInt forKey:(NSString*)key {
|
||||
NSInteger ret = [[NSUserDefaults standardUserDefaults] integerForKey:key];
|
||||
if (ret > 0) return (NSUInteger)ret;
|
||||
return defaultInt;
|
||||
}
|
||||
|
||||
/// @return User configured custom browser. Or @c nil if not set yet. (which will fallback to default browser)
|
||||
+ (NSString*)getHttpApplication {
|
||||
return [[NSUserDefaults standardUserDefaults] stringForKey:@"defaultHttpApplication"];
|
||||
}
|
||||
|
||||
/// Store custom browser bundle id to user defaults.
|
||||
+ (void)setHttpApplication:(NSString*)bundleID {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:bundleID forKey:@"defaultHttpApplication"];
|
||||
}
|
||||
|
||||
/**
|
||||
Open web links in default browser or a browser the user selected in the preferences.
|
||||
|
||||
@param urls A list of @c NSURL objects that will be opened immediatelly in bulk.
|
||||
@return @c YES if @c urls are opened successfully. @c NO on error.
|
||||
*/
|
||||
+ (BOOL)openURLsWithPreferredBrowser:(NSArray<NSURL*>*)urls {
|
||||
if (urls.count == 0) return NO;
|
||||
return [[NSWorkspace sharedWorkspace] openURLs:urls withAppBundleIdentifier:[self getHttpApplication] options:NSWorkspaceLaunchDefault additionalEventParamDescriptor:nil launchIdentifiers:nil];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Hidden Plist Properties -
|
||||
|
||||
|
||||
/// @return The limit on how many links should be opened at the same time, if user holds the option key.
|
||||
/// Default: @c 10
|
||||
+ (NSUInteger)openFewLinksLimit { return [self defaultUInt:10 forKey:@"openFewLinksLimit"]; }
|
||||
|
||||
/// @return The limit on when to truncate article titles (Short names setting must be active).
|
||||
/// Default: @c 60
|
||||
+ (NSUInteger)shortArticleNamesLimit { return [self defaultUInt:60 forKey:@"shortArticleNamesLimit"]; }
|
||||
|
||||
/// @return The maximum number of articles displayed per feed (Limit articles setting must be active).
|
||||
/// 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 {
|
||||
/// @return User set value. If it wasn't modified or couldn't be parsed return @c defaultColor
|
||||
NSColor* UserPrefsColor(NSString *key, NSColor *defaultColor) {
|
||||
NSString *colorStr = [[NSUserDefaults standardUserDefaults] stringForKey:key];
|
||||
if (colorStr) {
|
||||
NSColor *color = [colorStr hexColor];
|
||||
@@ -96,62 +60,3 @@
|
||||
}
|
||||
return defaultColor;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Application Info Plist
|
||||
|
||||
|
||||
/// @return The application name, e.g., 'baRSS' or 'baRSS Beta'
|
||||
+ (NSString*)appName {
|
||||
return [[NSBundle mainBundle] infoDictionary][(NSString*)kCFBundleNameKey];
|
||||
}
|
||||
|
||||
/// @return The application version number, e.g., '0.9.4'
|
||||
+ (NSString*)appVersion {
|
||||
return [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"];
|
||||
}
|
||||
|
||||
/// @return The application version number including build number, e.g., '0.9.4 (9906)'
|
||||
+ (NSString*)appVersionWithBuildNo {
|
||||
NSString *buildNo = [[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"];
|
||||
return [[self appVersion] stringByAppendingFormat:@" (%@)", buildNo];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Core Data Properties -
|
||||
|
||||
|
||||
/// Helper method that retrieves and transforms option value to int
|
||||
+ (int)dbIntForKey:(NSString*)key defaultsTo:(int)otherwise {
|
||||
NSString *str = [StoreCoordinator optionForKey:key];
|
||||
if (!str) return otherwise;
|
||||
int num = [NSDecimalNumber decimalNumberWithString:str].intValue;
|
||||
return isnan(num) ? otherwise : num;
|
||||
}
|
||||
|
||||
/// Check whether the database was just initialized (first install)
|
||||
+ (BOOL)dbIsUnusedInitalState {
|
||||
return [StoreCoordinator optionForKey:@"db-version"] == nil;
|
||||
}
|
||||
|
||||
/// Check whether the stored database version is up to date
|
||||
+ (BOOL)dbIsCurrentFileVersion {
|
||||
return [self dbIntForKey:@"db-version" defaultsTo:-1] == dbFileVersion;
|
||||
}
|
||||
|
||||
/// Write current database version to core data
|
||||
+ (void)dbUpdateFileVersion {
|
||||
[StoreCoordinator setOption:@"db-version" value:[NSString stringWithFormat:@"%d", dbFileVersion]];
|
||||
}
|
||||
|
||||
/// Check whether the stored application version is up to date
|
||||
+ (BOOL)dbIsCurrentAppVersion {
|
||||
return [[StoreCoordinator optionForKey:@"app-version"] isEqualToString:[self appVersion]];
|
||||
}
|
||||
|
||||
/// Write current application version to core data
|
||||
+ (void)dbUpdateAppVersion {
|
||||
[StoreCoordinator setOption:@"app-version" value:[self appVersion]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>13931</string>
|
||||
<string>14336</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.news</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
// SOFTWARE.
|
||||
|
||||
#import "NSURL+Ext.h"
|
||||
#import "UserPrefs.h" // appName in +faviconsCacheURL
|
||||
#import "NSError+Ext.h"
|
||||
|
||||
@implementation NSURL (Ext)
|
||||
@@ -36,7 +35,7 @@
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
path = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
|
||||
path = [path URLByAppendingPathComponent:[UserPrefs appName] isDirectory:YES];
|
||||
path = [path URLByAppendingPathComponent:APP_NAME isDirectory:YES];
|
||||
});
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -22,25 +22,21 @@
|
||||
|
||||
#import "SettingsAboutView.h"
|
||||
#import "NSView+Ext.h"
|
||||
#import "UserPrefs.h"
|
||||
|
||||
@implementation SettingsAboutView
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super initWithFrame: NSZeroRect];
|
||||
NSString *name = [UserPrefs appName];
|
||||
NSString *version = [NSString stringWithFormat:NSLocalizedString(@"Version %@", nil),
|
||||
#if DEBUG
|
||||
[UserPrefs appVersionWithBuildNo]
|
||||
#else
|
||||
[UserPrefs appVersion]
|
||||
NSDictionary *info = [[NSBundle mainBundle] infoDictionary];
|
||||
NSString *version = [NSString stringWithFormat:NSLocalizedString(@"Version %@", nil), info[@"CFBundleShortVersionString"]];
|
||||
#if DEBUG // append build number, e.g., '0.9.4 (9906)'
|
||||
version = [version stringByAppendingFormat:@" (%@)", info[@"CFBundleVersion"]];
|
||||
#endif
|
||||
];
|
||||
|
||||
// Application icon image (top-centered)
|
||||
NSImageView *logo = [[NSView imageView:NSImageNameApplicationIcon size:64] placeIn:self x:CENTER yTop:PAD_M];
|
||||
// Add app name
|
||||
NSTextField *lblN = [[[[NSView label:name] large] bold] placeIn:self x:CENTER yTop: YFromTop(logo) + PAD_M];
|
||||
NSTextField *lblN = [[[[NSView label:APP_NAME] large] bold] placeIn:self x:CENTER yTop: YFromTop(logo) + PAD_M];
|
||||
// Add version info
|
||||
NSTextField *lblV = [[[[NSView label:version] small] selectable] placeIn:self x:CENTER yTop: YFromTop(lblN) + PAD_S];
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#import "SettingsAppearanceView.h"
|
||||
#import "AppHook.h"
|
||||
#import "BarStatusItem.h"
|
||||
#import "UserPrefs.h"
|
||||
|
||||
@implementation SettingsAppearance
|
||||
|
||||
@@ -41,10 +42,9 @@
|
||||
|
||||
/// Sync new value with UserDefaults and update status bar icon
|
||||
- (void)didSelectCheckbox:(NSButton*)sender {
|
||||
BOOL state = (sender.state == NSControlStateValueOn);
|
||||
[[NSUserDefaults standardUserDefaults] setBool:state forKey:sender.identifier];
|
||||
if ([sender.identifier isEqualToString:@"globalUnreadCount"] ||
|
||||
[sender.identifier isEqualToString:@"globalTintMenuBarIcon"]) {
|
||||
NSString *pref = sender.identifier;
|
||||
UserPrefsSetBool(pref, (sender.state == NSControlStateValueOn));
|
||||
if (pref == Pref_globalUnreadCount || pref == Pref_globalTintMenuIcon) { // == because static string
|
||||
[[(AppHook*)NSApp statusItem] updateBarIcon];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,67 +22,64 @@
|
||||
|
||||
#import "SettingsAppearanceView.h"
|
||||
#import "NSView+Ext.h"
|
||||
#import "Constants.h"
|
||||
#import "UserPrefs.h"
|
||||
#import "Constants.h" // column icons
|
||||
#import "UserPrefs.h" // preference constants & UserPrefsBool()
|
||||
|
||||
@interface SettingsAppearanceView()
|
||||
@property (assign) NSUInteger row;
|
||||
@property (assign) CGFloat y;
|
||||
@end
|
||||
|
||||
|
||||
/***/ static CGFloat const IconSize = 18;
|
||||
/***/ static CGFloat const colWidth = (IconSize + PAD_M); // checkbox column width
|
||||
|
||||
/***/ static CGFloat const X__ = PAD_WIN + 0 * colWidth;
|
||||
/***/ static CGFloat const _X_ = PAD_WIN + 1 * colWidth;
|
||||
/***/ static CGFloat const __X = PAD_WIN + 2 * colWidth;
|
||||
|
||||
@implementation SettingsAppearanceView
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super initWithFrame: NSZeroRect];
|
||||
self.row = 0;
|
||||
// Insert matrix header (the three icons)
|
||||
[self head:0 img:RSSImageSettingsGlobal tooltip:NSLocalizedString(@"Show in menu bar", nil)];
|
||||
[self head:1 img:RSSImageSettingsGroup tooltip:NSLocalizedString(@"Show in group menu", nil)];
|
||||
[self head:2 img:RSSImageSettingsFeed tooltip:NSLocalizedString(@"Show in feed menu", nil)];
|
||||
// Generate checkbox matrix (checkbox state, X: default ON, O: default OFF, blank: hidden)
|
||||
[self entry:"X " label:NSLocalizedString(@"Tint menu bar icon on unread", nil)];
|
||||
[self entry:"X " label:NSLocalizedString(@"Update all feeds", nil)];
|
||||
[self entry:"XXX" label:NSLocalizedString(@"Open all unread", nil)];
|
||||
[self entry:"XXX" label:NSLocalizedString(@"Mark all read", nil)];
|
||||
[self entry:"XXX" label:NSLocalizedString(@"Mark all unread", nil)];
|
||||
[self entry:"XXX" label:NSLocalizedString(@"Number of unread items", nil)];
|
||||
[self entry:" X" label:NSLocalizedString(@"Tick mark unread items", nil)];
|
||||
[[self entry:" O" label:NSLocalizedString(@"Short article names", nil)] tooltip:NSLocalizedString(@"Truncate article title after 60 characters", nil)];
|
||||
[[self entry:" O" label:NSLocalizedString(@"Limit number of articles", nil)] tooltip:NSLocalizedString(@"Display at most 40 articles in feed menu", nil)];
|
||||
// Insert matrix header (icons above checkbox matrix)
|
||||
ColumnIcon(self, X__, RSSImageSettingsGlobal, NSLocalizedString(@"Show in menu bar", nil));
|
||||
ColumnIcon(self, _X_, RSSImageSettingsGroup, NSLocalizedString(@"Show in group menu", nil));
|
||||
ColumnIcon(self, __X, RSSImageSettingsFeed, NSLocalizedString(@"Show in feed menu", nil));
|
||||
// Generate checkbox matrix
|
||||
self.y = PAD_WIN + IconSize + PAD_S;
|
||||
[self entry:NSLocalizedString(@"Tint menu bar icon on unread", nil) c1:Pref_globalTintMenuIcon c2:nil c3:nil];
|
||||
[self entry:NSLocalizedString(@"Update all feeds", nil) c1:Pref_globalUpdateAll c2:nil c3:nil];
|
||||
[self entry:NSLocalizedString(@"Open all unread", nil) c1:Pref_globalOpenUnread c2:Pref_groupOpenUnread c3:Pref_feedOpenUnread];
|
||||
[self entry:NSLocalizedString(@"Mark all read", nil) c1:Pref_globalMarkRead c2:Pref_groupMarkRead c3:Pref_feedMarkRead];
|
||||
[self entry:NSLocalizedString(@"Mark all unread", nil) c1:Pref_globalMarkUnread c2:Pref_groupMarkUnread c3:Pref_feedMarkUnread];
|
||||
[self entry:NSLocalizedString(@"Number of unread articles", nil) c1:Pref_globalUnreadCount c2:Pref_groupUnreadCount c3:Pref_feedUnreadCount];
|
||||
[self entry:NSLocalizedString(@"Indicator for unread articles", nil) c1:nil c2:nil c3:Pref_feedUnreadIndicator];
|
||||
[[self entry:NSLocalizedString(@"Truncate article title", nil) c1:nil c2:nil c3:Pref_feedTruncateTitle]
|
||||
tooltip:NSLocalizedString(@"Truncate article title after 60 characters", nil)];
|
||||
[[self entry:NSLocalizedString(@"Limit number of articles", nil) c1:nil c2:nil c3:Pref_feedLimitArticles]
|
||||
tooltip:NSLocalizedString(@"Display at most 40 articles in feed menu", nil)];
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Helper method for matrix table header icons
|
||||
- (void)head:(int)x img:(NSImageName)img tooltip:(NSString*)ttip {
|
||||
[[[NSView imageView:img size:IconSize] tooltip:ttip] placeIn:self x:PAD_WIN + x * colWidth yTop:PAD_WIN];
|
||||
static inline void ColumnIcon(id this, CGFloat x, const NSImageName img, NSString *ttip) {
|
||||
[[[NSView imageView:img size:IconSize] placeIn:this x:x yTop:PAD_WIN] tooltip:ttip];
|
||||
}
|
||||
|
||||
/// Helper method for generating a checkbox
|
||||
static inline NSButton* Checkbox(id this, CGFloat x, CGFloat y, NSString *key) {
|
||||
NSButton *check = [[NSView checkbox: UserPrefsBool(key)] placeIn:this x:x yTop:y];
|
||||
check.identifier = key;
|
||||
return check;
|
||||
}
|
||||
|
||||
/// Create new entry with 1-3 checkboxes and a descriptive label
|
||||
- (NSTextField*)entry:(char*)m label:(NSString*)text {
|
||||
static char* const scope[] = { "global", "group", "feed" };
|
||||
static char* const ident[] = { "TintMenuBarIcon", "UpdateAll", "OpenUnread", "MarkRead", "MarkUnread", "UnreadCount", "TickMark", "ShortNames", "LimitArticles" };
|
||||
CGFloat y = PAD_WIN + IconSize + PAD_S + self.row * (PAD_S + HEIGHT_LABEL);
|
||||
|
||||
// Add checkboxes: row 0 - 8, col 0 - 2
|
||||
for (NSUInteger col = 0; col < 3; col++) {
|
||||
NSString *key = [NSString stringWithFormat:@"%s%s", scope[col], ident[self.row]];
|
||||
BOOL state;
|
||||
switch (m[col]) {
|
||||
case 'X': state = [UserPrefs defaultYES:key]; break;
|
||||
case 'O': state = [UserPrefs defaultNO: key]; break;
|
||||
default: continue; // ignore blanks
|
||||
}
|
||||
NSButton *check = [[NSView checkbox:state] placeIn:self x:PAD_WIN + col * colWidth + 2 yTop:y + 2]; // 2px checkbox offset
|
||||
check.identifier = key;
|
||||
check.accessibilityLabel = [text stringByAppendingFormat:@" (%s)", scope[col]]; // TODO: localize: global, group, feed
|
||||
}
|
||||
self.row += 1;
|
||||
// Add label
|
||||
return [[[NSView label:text] placeIn:self x:PAD_WIN + 3 * colWidth yTop:y] sizeToRight:PAD_WIN];
|
||||
- (NSTextField*)entry:(NSString*)label c1:(NSString*)pref1 c2:(NSString*)pref2 c3:(NSString*)pref3 {
|
||||
CGFloat y = self.y;
|
||||
self.y += (PAD_S + HEIGHT_LABEL);
|
||||
// TODO: localize: global, group, feed
|
||||
if (pref1) Checkbox(self, X__ + 2, y + 2, pref1).accessibilityLabel = [label stringByAppendingString:@" (global)"];
|
||||
if (pref2) Checkbox(self, _X_ + 2, y + 2, pref2).accessibilityLabel = [label stringByAppendingString:@" (group)"];
|
||||
if (pref3) Checkbox(self, __X + 2, y + 2, pref3).accessibilityLabel = [label stringByAppendingString:@" (feed)"];
|
||||
return [[[NSView label:label] placeIn:self x:PAD_WIN + 3 * colWidth yTop:y] sizeToRight:PAD_WIN];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
[pop addItemWithTitle: [self applicationNameForBundleId:bundleID]];
|
||||
pop.lastItem.representedObject = bundleID;
|
||||
}
|
||||
[pop selectItemAtIndex:[pop indexOfItemWithRepresentedObject:[UserPrefs getHttpApplication]]];
|
||||
[pop selectItemAtIndex:[pop indexOfItemWithRepresentedObject:UserPrefsString(Pref_defaultHttpApplication)]];
|
||||
// Default RSS Reader application
|
||||
NSString *feedBundleId = CFBridgingRelease(LSCopyDefaultHandlerForURLScheme(CFSTR("feed")));
|
||||
self.view.defaultReader.objectValue = [self applicationNameForBundleId:feedBundleId];
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
// Callback method fired when user selects a different item from popup list
|
||||
- (void)changeHttpApplication:(NSPopUpButton *)sender {
|
||||
[UserPrefs setHttpApplication:sender.selectedItem.representedObject];
|
||||
UserPrefsSet(Pref_defaultHttpApplication, sender.selectedItem.representedObject);
|
||||
}
|
||||
|
||||
// Callback method from round help button right of default feed reader text
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
// SOFTWARE.
|
||||
|
||||
#import "ModalSheet.h"
|
||||
#import "UserPrefs.h"
|
||||
#import "NSView+Ext.h"
|
||||
|
||||
@interface ModalSheet()
|
||||
@@ -35,7 +36,7 @@
|
||||
static NSInteger const maxWidth = 1200;
|
||||
static CGFloat const contentOffsetY = PAD_WIN + HEIGHT_BUTTON + PAD_L;
|
||||
|
||||
NSInteger w = [[NSUserDefaults standardUserDefaults] integerForKey:@"modalSheetWidth"];
|
||||
NSInteger w = UserPrefsInt(Pref_modalSheetWidth);
|
||||
if (w < minWidth) w = minWidth;
|
||||
else if (w > maxWidth) w = maxWidth;
|
||||
|
||||
@@ -90,8 +91,9 @@
|
||||
return;
|
||||
}
|
||||
// Save modal view width for next time
|
||||
CGFloat w = NSWidth(self.contentView.frame) - 2 * PAD_WIN;
|
||||
[[NSUserDefaults standardUserDefaults] setInteger:(NSInteger)w forKey:@"modalSheetWidth"];
|
||||
NSInteger width = (NSInteger)(NSWidth(self.contentView.frame) - 2 * PAD_WIN);
|
||||
if (UserPrefsInt(Pref_modalSheetWidth) != width)
|
||||
UserPrefsSetInt(Pref_modalSheetWidth, width);
|
||||
// Remove subviews to avoid _NSKeyboardFocusClipView issues
|
||||
[self.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
[self.sheetParent endSheet:self returnCode:(successful ? NSModalResponseOK : NSModalResponseCancel)];
|
||||
|
||||
@@ -49,13 +49,13 @@
|
||||
flexibleWidth,
|
||||
TabItem(NSImageNameInfo, NSLocalizedString(@"About", nil), [SettingsAbout class]),
|
||||
];
|
||||
[self switchToTab:[UserPrefs defaultUInt:0 forKey:@"preferencesTab"]];
|
||||
[self switchToTab: UserPrefsUInt(Pref_prefSelectedTab)];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Helper method to generate tab item with image, label, and controller.
|
||||
static NSTabViewItem* TabItem(NSImageName imageName, NSString *text, Class class) {
|
||||
static inline NSTabViewItem* TabItem(NSImageName imageName, NSString *text, Class class) {
|
||||
NSTabViewItem *item = [NSTabViewItem tabViewItemWithViewController: [class new]];
|
||||
item.image = [NSImage imageNamed:imageName];
|
||||
item.label = text;
|
||||
@@ -76,10 +76,9 @@ static NSTabViewItem* TabItem(NSImageName imageName, NSString *text, Class class
|
||||
/// Delegate method, store last selected tab to user preferences
|
||||
- (void)tabView:(NSTabView*)tabView didSelectTabViewItem:(nullable NSTabViewItem*)tabViewItem {
|
||||
[super tabView:tabView didSelectTabViewItem:tabViewItem];
|
||||
NSInteger prevIndex = [[NSUserDefaults standardUserDefaults] integerForKey:@"preferencesTab"];
|
||||
NSInteger newIndex = self.selectedTabViewItemIndex;
|
||||
if (prevIndex != newIndex)
|
||||
[[NSUserDefaults standardUserDefaults] setInteger:newIndex forKey:@"preferencesTab"];
|
||||
if (UserPrefsInt(Pref_prefSelectedTab) != newIndex)
|
||||
UserPrefsSetInt(Pref_prefSelectedTab, newIndex);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -95,7 +94,7 @@ static NSTabViewItem* TabItem(NSImageName imageName, NSString *text, Class class
|
||||
w.title = [NSString stringWithFormat:NSLocalizedString(@"%@ Preferences", nil), NSProcessInfo.processInfo.processName];
|
||||
w.contentViewController = [PrefTabs new];
|
||||
w.delegate = w;
|
||||
NSWindowPersistableFrameDescriptor prevFrame = [[NSUserDefaults standardUserDefaults] stringForKey:@"prefWindow"];
|
||||
NSWindowPersistableFrameDescriptor prevFrame = UserPrefsString(Pref_prefWindowFrame);
|
||||
if (!prevFrame) {
|
||||
[w setContentSize:NSMakeSize(320, 327)];
|
||||
[w center];
|
||||
@@ -111,7 +110,7 @@ static NSTabViewItem* TabItem(NSImageName imageName, NSString *text, Class class
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification *)notification {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:self.stringWithSavedFrame forKey:@"prefWindow"];
|
||||
UserPrefsSet(Pref_prefWindowFrame, self.stringWithSavedFrame);
|
||||
}
|
||||
|
||||
/// Do not respond to Cmd-Z and Cmd-Shift-Z. Will be handled in subview controllers.
|
||||
|
||||
@@ -105,14 +105,14 @@
|
||||
/// Generate items for @c FeedArticles menu.
|
||||
- (void)setArticles:(NSArray<FeedArticle*>*)sortedList forMenu:(NSMenu*)menu {
|
||||
[menu insertDefaultHeader];
|
||||
NSUInteger mc = 0;
|
||||
if ([UserPrefs defaultNO:@"feedLimitArticles"]) {
|
||||
mc = [UserPrefs articlesInMenuLimit];
|
||||
}
|
||||
NSInteger mc = NSIntegerMax;
|
||||
if (UserPrefsBool(Pref_feedLimitArticles))
|
||||
mc = UserPrefsInt(Pref_articlesInMenuLimit);
|
||||
|
||||
for (FeedArticle *fa in sortedList) {
|
||||
[menu addItem:[fa newMenuItem]];
|
||||
if (--mc == 0) // if mc==0 then unsigned int will underflow and turn into INT_MAX
|
||||
if (--mc < 0) // mc == 0 will first decrement to -1, then evaluate
|
||||
break;
|
||||
[menu addItem:[fa newMenuItem]];
|
||||
}
|
||||
UnreadTotal *uct = self.unreadMap[menu.titleIndexPath];
|
||||
[menu setHeaderHasUnread:(uct.unread > 0) hasRead:(uct.unread < uct.total)];
|
||||
|
||||
@@ -118,18 +118,18 @@
|
||||
- (void)updateBarIcon {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
BOOL hasNet = [UpdateScheduler allowNetworkConnection];
|
||||
BOOL tint = (self.unreadCountTotal > 0 && hasNet && [UserPrefs defaultYES:@"globalTintMenuBarIcon"]);
|
||||
BOOL tint = (self.unreadCountTotal > 0 && hasNet && UserPrefsBool(Pref_globalTintMenuIcon));
|
||||
self.statusItem.image = [NSImage imageNamed:(hasNet ? RSSImageMenuBarIconActive : RSSImageMenuBarIconPaused)];
|
||||
self.statusItem.image.template = !tint;
|
||||
|
||||
BOOL showCount = (self.unreadCountTotal > 0 && [UserPrefs defaultYES:@"globalUnreadCount"]);
|
||||
BOOL showCount = (self.unreadCountTotal > 0 && UserPrefsBool(Pref_globalUnreadCount));
|
||||
self.statusItem.title = (showCount ? [NSString stringWithFormat:@"%ld", self.unreadCountTotal] : @"");
|
||||
});
|
||||
}
|
||||
|
||||
/// Show popover with a brief notice that baRSS is running in the menu bar
|
||||
- (void)showWelcomeMessage {
|
||||
NSString *title = [NSString stringWithFormat:NSLocalizedString(@"Welcome to %@", nil), [UserPrefs appName]];
|
||||
NSString *title = [NSString stringWithFormat:NSLocalizedString(@"Welcome to %@", nil), APP_NAME];
|
||||
NSString *message = NSLocalizedString(@"There's no application window.\nEverything is up there.", nil);
|
||||
NSTextField *head = [[NSView label:title] bold];
|
||||
NSTextField *body = [[NSView label:message] small];
|
||||
@@ -172,7 +172,7 @@
|
||||
if ([UpdateScheduler isPaused])
|
||||
pause.title = NSLocalizedString(@"Resume Updates", nil);
|
||||
// 'Update all feeds' item
|
||||
if ([UserPrefs defaultYES:@"globalUpdateAll"]) {
|
||||
if (UserPrefsBool(Pref_globalUpdateAll)) {
|
||||
NSMenuItem *updateAll = [menu addItemWithTitle:NSLocalizedString(@"Update all feeds", nil) action:@selector(updateAllFeeds) keyEquivalent:@""];
|
||||
updateAll.target = self;
|
||||
updateAll.enabled = [UpdateScheduler allowNetworkConnection];
|
||||
|
||||
@@ -88,7 +88,8 @@ typedef NS_ENUM(NSInteger, MenuItemTag) {
|
||||
self.autoenablesItems = NO;
|
||||
NSMenuItem *itm = [self addItemIfAllowed:TagOpenAllUnread title:NSLocalizedString(@"Open all unread", nil)];
|
||||
if (itm) {
|
||||
[self addItem:[itm alternateWithTitle:[NSString stringWithFormat:NSLocalizedString(@"Open a few unread (%lu)", nil), [UserPrefs openFewLinksLimit]]]];
|
||||
NSString *altTitle = [NSString stringWithFormat:NSLocalizedString(@"Open a few unread (%lu)", nil), UserPrefsUInt(Pref_openFewLinksLimit)];
|
||||
[self addItem:[itm alternateWithTitle:altTitle]];
|
||||
}
|
||||
[self addItemIfAllowed:TagMarkAllRead title:NSLocalizedString(@"Mark all read", nil)];
|
||||
[self addItemIfAllowed:TagMarkAllUnread title:NSLocalizedString(@"Mark all unread", nil)];
|
||||
@@ -151,10 +152,16 @@ typedef NS_ENUM(NSInteger, MenuItemTag) {
|
||||
|
||||
/// Check user preferences for preferred display style.
|
||||
- (BOOL)allowDisplayOfHeaderItem:(MenuItemTag)tag {
|
||||
static char* const A[] = {"", "global", "feed", "group"};
|
||||
static char* const B[] = {"", "MarkRead", "MarkUnread", "OpenUnread"};
|
||||
int idx = (self.isMainMenu ? 1 : (self.isFeedMenu ? 2 : 3));
|
||||
return [UserPrefs defaultYES:[NSString stringWithFormat:@"%s%s", A[idx], B[tag & 3]]]; // first 2 bits
|
||||
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};
|
||||
int i = (self.isMainMenu ? 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]);
|
||||
default: return NO;
|
||||
}
|
||||
}
|
||||
|
||||
/// Check user preferences if item should be displayed in menu. If so, add it to the menu and set callback to @c self.
|
||||
@@ -176,7 +183,7 @@ typedef NS_ENUM(NSInteger, MenuItemTag) {
|
||||
NSUInteger limit = 0;
|
||||
if (sender.tag == TagOpenAllUnread) {
|
||||
if (sender.isAlternate)
|
||||
limit = [UserPrefs openFewLinksLimit];
|
||||
limit = UserPrefsUInt(Pref_openFewLinksLimit);
|
||||
openLinks = YES;
|
||||
} else if (sender.tag != TagMarkAllRead && sender.tag != TagMarkAllUnread) {
|
||||
return; // other menu item clicked. abort and return.
|
||||
@@ -200,7 +207,8 @@ typedef NS_ENUM(NSInteger, MenuItemTag) {
|
||||
if (fa.link.length > 0)
|
||||
[urls addObject:[NSURL URLWithString:fa.link]];
|
||||
}
|
||||
success = [UserPrefs openURLsWithPreferredBrowser:urls];
|
||||
if (urls.count > 0)
|
||||
success = UserPrefsOpenURLs(urls);
|
||||
}
|
||||
// if success == NO, do not modify unread state
|
||||
if (!openLinks || success) {
|
||||
@@ -242,7 +250,7 @@ typedef NS_ENUM(NSInteger, MenuItemTag) {
|
||||
if (loc != NSNotFound)
|
||||
self.title = [self.title substringToIndex:loc];
|
||||
}
|
||||
if (count > 0 && [UserPrefs defaultYES:(self.submenu.isFeedMenu ? @"feedUnreadCount" : @"groupUnreadCount")]) {
|
||||
if (count > 0 && UserPrefsBool(self.submenu.isFeedMenu ? Pref_feedUnreadCount : Pref_groupUnreadCount)) {
|
||||
self.tag = TagTitleCountVisible; // apply new mask
|
||||
self.title = [self.title stringByAppendingFormat:@" (%ld)", count];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user