Refactoring UserPrefs
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user