diff --git a/README.md b/README.md index 2c656d8..c20a00a 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,24 @@ All basic functionality is there. What's missing? - Authenticated feeds - Online sync with other services -- Automatic feed detection (e.g., YouTube) - Text / UI localisation +- App icon & UI icons All in all, the software is in a usable state. The remaining features will be added in the coming weeks. +Hidden options +-------------- + +1) When holding down the option key, the menu will show an item to open only a few unread items at a time. This number can be changed with the following Terminal command (default: 10): + + defaults write de.relikd.baRSS openFewLinksLimit -int 10 + +2) In preferences you can choose to show 'Short article names'. This will limit the number of displayed characters to 60 (default). With this Terminal command you can customize this number: + + defaults write de.relikd.baRSS shortArticleNamesLimit -int 50 + + ToDo ---- diff --git a/baRSS.xcodeproj/project.pbxproj b/baRSS.xcodeproj/project.pbxproj index 1dd0d82..4a0b45c 100644 --- a/baRSS.xcodeproj/project.pbxproj +++ b/baRSS.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ 54ACC28C21061B3C0020715F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC28B21061B3C0020715F /* main.m */; }; 54ACC29521061E270020715F /* FeedDownload.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC29421061E270020715F /* FeedDownload.m */; }; 54ACC29821061FBA0020715F /* Preferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 54ACC29721061FBA0020715F /* Preferences.m */; }; + 54BB048921FD2AB500C303A5 /* NSDate+Ext.m in Sources */ = {isa = PBXBuildFile; fileRef = 54BB048821FD2AB500C303A5 /* NSDate+Ext.m */; }; 54CC04382162532A00A48795 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 54CC04372162532A00A48795 /* main.m */; }; 54CC043E2162566900A48795 /* baRSS-Helper.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 54CC042C2162532800A48795 /* baRSS-Helper.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 54E88320211B509D00064188 /* ModalFeedEdit.m in Sources */ = {isa = PBXBuildFile; fileRef = 54E8831E211B509D00064188 /* ModalFeedEdit.m */; }; @@ -115,6 +116,8 @@ 54ACC29421061E270020715F /* FeedDownload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FeedDownload.m; sourceTree = ""; }; 54ACC29621061FBA0020715F /* Preferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Preferences.h; sourceTree = ""; }; 54ACC29721061FBA0020715F /* Preferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Preferences.m; sourceTree = ""; }; + 54BB048721FD2AB500C303A5 /* NSDate+Ext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+Ext.h"; sourceTree = ""; }; + 54BB048821FD2AB500C303A5 /* NSDate+Ext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+Ext.m"; sourceTree = ""; }; 54CC042C2162532800A48795 /* baRSS-Helper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "baRSS-Helper.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 54CC04362162532A00A48795 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 54CC04372162532A00A48795 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; @@ -183,6 +186,8 @@ 54209E932117325100F3B5EF /* DrawImage.m */, 544936F921F1E66100DEE9AA /* Statistics.h */, 544936FA21F1E66100DEE9AA /* Statistics.m */, + 54BB048721FD2AB500C303A5 /* NSDate+Ext.h */, + 54BB048821FD2AB500C303A5 /* NSDate+Ext.m */, ); path = Helper; sourceTree = ""; @@ -411,6 +416,7 @@ 544B011D2114EE9100386E5C /* AppHook.m in Sources */, 546FC44321189975007CC3A3 /* SettingsGeneral.m in Sources */, 54ACC29521061E270020715F /* FeedDownload.m in Sources */, + 54BB048921FD2AB500C303A5 /* NSDate+Ext.m in Sources */, 5477D34E21233C62002BA27F /* FeedGroup+Ext.m in Sources */, 544936FB21F1E66100DEE9AA /* Statistics.m in Sources */, 540F704521B6C16C0022E69D /* FeedMeta+Ext.m in Sources */, diff --git a/baRSS/Categories/Feed+Ext.m b/baRSS/Categories/Feed+Ext.m index dc110a5..2ef1b82 100644 --- a/baRSS/Categories/Feed+Ext.m +++ b/baRSS/Categories/Feed+Ext.m @@ -29,7 +29,6 @@ #import "FeedArticle+CoreDataClass.h" #import "StoreCoordinator.h" -#import #import @implementation Feed (Ext) @@ -46,7 +45,7 @@ NSInteger lastIndex = [StoreCoordinator numberRootItemsInContext:moc]; FeedGroup *fg = [FeedGroup newGroup:FEED inContext:moc]; [fg setParent:nil andSortIndex:(int32_t)lastIndex]; - [fg.feed.meta setRefresh:30 unit:RefreshUnitMinutes]; + [fg.feed.meta setRefreshAndSchedule:kDefaultFeedRefreshInterval]; return fg.feed; } diff --git a/baRSS/Categories/FeedGroup+Ext.h b/baRSS/Categories/FeedGroup+Ext.h index bd27e9d..ae72665 100644 --- a/baRSS/Categories/FeedGroup+Ext.h +++ b/baRSS/Categories/FeedGroup+Ext.h @@ -44,4 +44,5 @@ typedef NS_ENUM(int16_t, FeedGroupType) { - (BOOL)iterateSorted:(BOOL)ordered overDescendantFeeds:(void(^)(Feed *feed, BOOL* cancel))block; // Printing - (NSString*)readableDescription; +- (nonnull NSString*)refreshString; @end diff --git a/baRSS/Categories/FeedGroup+Ext.m b/baRSS/Categories/FeedGroup+Ext.m index 7a98626..cd1171d 100644 --- a/baRSS/Categories/FeedGroup+Ext.m +++ b/baRSS/Categories/FeedGroup+Ext.m @@ -23,8 +23,7 @@ #import "FeedGroup+Ext.h" #import "FeedMeta+Ext.h" #import "Feed+Ext.h" - -#import +#import "NSDate+Ext.h" @implementation FeedGroup (Ext) @@ -118,8 +117,19 @@ case SEPARATOR: return @"-------------"; case GROUP: return [NSString stringWithFormat:@"%@", self.name]; case FEED: - return [NSString stringWithFormat:@"%@ (%@) - %@", self.name, self.feed.meta.url, self.refreshStr]; + return [NSString stringWithFormat:@"%@ (%@) - %@", self.name, self.feed.meta.url, [self refreshString]]; } } +/// @return Formatted string for update interval ( e.g., @c 30m or @c 12h ) +- (nonnull NSString*)refreshString { + if (self.type == FEED) { + int32_t refresh = self.feed.meta.refresh; + if (refresh <= 0) + return @"∞"; // ∞ ƒ Ø + return [NSDate stringForInterval:refresh rounded:NO]; + } + return @""; +} + @end diff --git a/baRSS/Categories/FeedMeta+Ext.h b/baRSS/Categories/FeedMeta+Ext.h index f8e9dcf..ae649cc 100644 --- a/baRSS/Categories/FeedMeta+Ext.h +++ b/baRSS/Categories/FeedMeta+Ext.h @@ -22,22 +22,14 @@ #import "FeedMeta+CoreDataClass.h" -/// Easy memorable @c int16_t enum for refresh unit index -typedef NS_ENUM(int16_t, RefreshUnitType) { - RefreshUnitSeconds = 0, RefreshUnitMinutes = 1, RefreshUnitHours = 2, RefreshUnitDays = 3, RefreshUnitWeeks = 4 -}; - +static const int32_t kDefaultFeedRefreshInterval = 30 * 60; @interface FeedMeta (Ext) -@property (readonly) BOOL refreshIntervalDisabled; // self.refreshNum <= 0 -@property (readonly) int32_t refreshInterval; // self.refreshNum * RefreshUnitValue - // HTTP response - (void)setErrorAndPostponeSchedule; - (void)setSucessfulWithResponse:(NSHTTPURLResponse*)response; // Setter - (void)setUrlIfChanged:(NSString*)url; - (void)setEtag:(NSString*)etag modified:(NSString*)modified; -- (BOOL)setRefresh:(int32_t)refresh unit:(RefreshUnitType)unit; -- (BOOL)setRefreshAndUnitFromInterval:(int32_t)interval; +- (BOOL)setRefreshAndSchedule:(int32_t)refresh; @end diff --git a/baRSS/Categories/FeedMeta+Ext.m b/baRSS/Categories/FeedMeta+Ext.m index 7fb1ecc..dde44e7 100644 --- a/baRSS/Categories/FeedMeta+Ext.m +++ b/baRSS/Categories/FeedMeta+Ext.m @@ -24,30 +24,8 @@ #import "Feed+Ext.h" #import "FeedGroup+Ext.h" -/// smhdw: [1, 60, 3600, 86400, 604800] -static const int32_t RefreshUnitValues[] = {1, 60, 3600, 86400, 604800}; // smhdw - @implementation FeedMeta (Ext) -#pragma mark - Getter - -/// Check whether update interval is disabled by user (refresh interval is 0). -- (BOOL)refreshIntervalDisabled { - return (self.refreshNum <= 0); -} - -/// @return Time interval respecting the selected unit. E.g., returns @c 180 for @c '3m' -- (int32_t)refreshInterval { - return self.refreshNum * RefreshUnitValues[self.refreshUnit % 5]; -} - -/// @return Formatted string for update interval ( e.g., @c 30m or @c 12h ) -- (NSString*)readableRefreshString { - if (self.refreshIntervalDisabled) - return @"∞"; // ∞ ƒ Ø - return [NSString stringWithFormat:@"%d%c", self.refreshNum, [@"smhdw" characterAtIndex:self.refreshUnit % 5]]; -} - #pragma mark - HTTP response /// Increment @c errorCount and set new @c scheduled date (2^N minutes, max. 5.7 days). @@ -68,7 +46,7 @@ static const int32_t RefreshUnitValues[] = {1, 60, 3600, 86400, 604800}; // smhd self.errorCount = 0; // reset counter NSDictionary *header = [response allHeaderFields]; [self setEtag:header[@"Etag"] modified:header[@"Date"]]; // @"Expires", @"Last-Modified" - [self scheduleNow:[self refreshInterval]]; + [self scheduleNow:self.refresh]; } #pragma mark - Setter @@ -85,44 +63,22 @@ static const int32_t RefreshUnitValues[] = {1, 60, 3600, 86400, 604800}; // smhd } /** - Set @c refresh and @c unit from popup button selection. Only values that differ will be updated. - Also, calculate and set new @c scheduled date and update FeedGroup @c refreshStr (if changed). + Set @c refresh and calculate new @c scheduled date. @return @c YES if refresh interval has changed */ -- (BOOL)setRefresh:(int32_t)refresh unit:(RefreshUnitType)unit { - BOOL intervalChanged = (self.refreshNum != refresh || self.refreshUnit != unit); - if (self.refreshNum != refresh) self.refreshNum = refresh; - if (self.refreshUnit != unit) self.refreshUnit = unit; - - if (intervalChanged) { - [self scheduleNow:[self refreshInterval]]; - NSString *str = [self readableRefreshString]; - if (![self.feed.group.refreshStr isEqualToString:str]) - self.feed.group.refreshStr = str; +- (BOOL)setRefreshAndSchedule:(int32_t)refresh { + if (self.refresh != refresh) { + self.refresh = refresh; + [self scheduleNow:self.refresh]; + return YES; } - return intervalChanged; + return NO; } -/** - Set properties @c refreshNum and @c refreshUnit to highest possible (integer-dividable-)unit. - Only values that differ will be updated. - Also, calculate and set new @c scheduled date and update FeedGroup @c refreshStr (if changed). - - @return @c YES if refresh interval has changed - */ -- (BOOL)setRefreshAndUnitFromInterval:(int32_t)interval { - for (RefreshUnitType i = 4; i >= 0; i--) { // start with weeks - if (interval % RefreshUnitValues[i] == 0) { // find first unit that is dividable - return [self setRefresh:abs(interval) / RefreshUnitValues[i] unit:i]; - } - } - return NO; // since loop didn't return, no value was changed -} - -/// Calculate date from @c refreshNum and @c refreshUnit and set as next scheduled feed update. +/// Set next scheduled feed update or @c nil if @c refresh @c <= @c 0. - (void)scheduleNow:(NSTimeInterval)future { - if (self.refreshIntervalDisabled) { // update deactivated; manually update with force update all + if (self.refresh <= 0) { // update deactivated; manually update with force update all if (self.scheduled != nil) // already nil? Avoid unnecessary core data edits self.scheduled = nil; } else { diff --git a/baRSS/Constants.h b/baRSS/Constants.h index 5e3b889..fb5a37b 100644 --- a/baRSS/Constants.h +++ b/baRSS/Constants.h @@ -26,8 +26,7 @@ // TODO: Add support for media player? image feed? // // TODO: Disable 'update all' menu item during update? -// TODO: List of hidden preferences for readme -// TODO: Do we need to search for favicon in places other than '../favicon.ico'? + /** @c notification.object is @c NSNumber of type @c NSUInteger. diff --git a/baRSS/DBv1.xcdatamodeld/DBv1.xcdatamodel/contents b/baRSS/DBv1.xcdatamodeld/DBv1.xcdatamodel/contents index 5243533..c336d83 100644 --- a/baRSS/DBv1.xcdatamodeld/DBv1.xcdatamodel/contents +++ b/baRSS/DBv1.xcdatamodeld/DBv1.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -25,7 +25,6 @@ - @@ -40,8 +39,7 @@ - - + @@ -49,8 +47,8 @@ - + - + \ No newline at end of file diff --git a/baRSS/Helper/NSDate+Ext.h b/baRSS/Helper/NSDate+Ext.h new file mode 100644 index 0000000..930d010 --- /dev/null +++ b/baRSS/Helper/NSDate+Ext.h @@ -0,0 +1,24 @@ + +#import +#import + +typedef int32_t Interval; +typedef NS_ENUM(int32_t, TimeUnitType) { + TimeUnitSeconds = 1, + TimeUnitMinutes = 60, + TimeUnitHours = 60 * 60, + TimeUnitDays = 24 * 60 * 60, + TimeUnitWeeks = 7 * 24 * 60 * 60, + TimeUnitYears = 365 * 24 * 60 * 60 +}; + +@interface NSDate (Ext) ++ (nonnull NSString*)stringForInterval:(Interval)intv rounded:(BOOL)flag; +@end + + +@interface NSDate (RefreshControlsUI) ++ (Interval)intervalForPopup:(NSPopUpButton*)unit andField:(NSTextField*)value; ++ (void)setInterval:(Interval)intv forPopup:(NSPopUpButton*)popup andField:(NSTextField*)field; ++ (void)populateUnitsMenu:(NSPopUpButton*)popup selected:(TimeUnitType)unit; +@end diff --git a/baRSS/Helper/NSDate+Ext.m b/baRSS/Helper/NSDate+Ext.m new file mode 100644 index 0000000..f542b5a --- /dev/null +++ b/baRSS/Helper/NSDate+Ext.m @@ -0,0 +1,101 @@ + +#import "NSDate+Ext.h" + +static const char _shortnames[] = {'y','w','d','h','m','s'}; +static const char *_names[] = {"Years", "Weeks", "Days", "Hours", "Minutes", "Seconds"}; +static const TimeUnitType _values[] = { + TimeUnitYears, + TimeUnitWeeks, + TimeUnitDays, + TimeUnitHours, + TimeUnitMinutes, + TimeUnitSeconds, +}; + + +@implementation NSDate (Ext) + ++ (nonnull NSString*)stringForInterval:(Interval)intv rounded:(BOOL)flag { + if (flag) { + unsigned short i = [self floatUnitIndexForInterval:abs(intv)]; + return [NSString stringWithFormat:@"%1.1f%c", intv / (float)_values[i], _shortnames[i]]; + } + unsigned short i = [self exactUnitIndexForInterval:abs(intv)]; + return [NSString stringWithFormat:@"%d%c", intv / _values[i], _shortnames[i]]; +} + +/// @return Highest non-zero unit ( @c flag=YES ). Or highest integer-dividable unit ( @c flag=NO ). ++ (TimeUnitType)unitForInterval:(Interval)intv rounded:(BOOL)flag { + if (flag) { + return _values[[self floatUnitIndexForInterval:abs(intv)]]; + } + return _values[[self exactUnitIndexForInterval:abs(intv)]]; +} + +/// @return Highest unit type that allows integer division. E.g., '61 minutes'. ++ (unsigned short)exactUnitIndexForInterval:(Interval)intv { + for (unsigned short i = 0; i < 5; i++) + if (intv % _values[i] == 0) return i; + return 5; // seconds +} + +/// @return Highest non-zero unit type. Can be used with fractions e.g., '1.1 hours'. ++ (unsigned short)floatUnitIndexForInterval:(Interval)intv { + for (unsigned short i = 0; i < 5; i++) + if (intv > _values[i]) return i; + return 5; // seconds +} +/* NOT USED +/// Convert any unit to the next smaller one. Unit does not have to be exact. ++ (TimeUnitType)smallerUnit:(TimeUnitType)unit { + if (unit <= TimeUnitHours) return TimeUnitSeconds; + if (unit <= TimeUnitDays) return TimeUnitMinutes; // > hours + if (unit <= TimeUnitWeeks) return TimeUnitHours; // > days + if (unit <= TimeUnitYears) return TimeUnitDays; // > weeks + return TimeUnitWeeks; // > years +} + +/// @return Formatted string from @c timeIntervalSinceNow. +- (nonnull NSString*)intervalStringWithDecimal:(BOOL)flag { + return [NSDate stringForInterval:(Interval)[self timeIntervalSinceNow] rounded:flag]; +} + +/// @return Highest non-zero unit ( @c flag=YES ). Or highest integer-dividable unit ( @c flag=NO ). +- (TimeUnitType)unitWithDecimal:(BOOL)flag { + Interval absIntv = abs((Interval)[self timeIntervalSinceNow]); + if (flag) { + return _values[ [NSDate floatUnitIndexForInterval:absIntv] ]; + } + return _values[ [NSDate exactUnitIndexForInterval:absIntv] ]; +} +*/ +@end + + +@implementation NSDate (RefreshControlsUI) + +/// @return Interval by multiplying the text field value with the currently selected popup unit. ++ (Interval)intervalForPopup:(NSPopUpButton*)unit andField:(NSTextField*)value { + return value.intValue * (Interval)unit.selectedTag; +} + +/// Configure both @c NSControl elements based on the provided interval @c intv. ++ (void)setInterval:(Interval)intv forPopup:(NSPopUpButton*)popup andField:(NSTextField*)field { + TimeUnitType unit = [self unitForInterval:intv rounded:NO]; + [popup selectItemWithTag:unit]; + field.intValue = (int)(intv / unit); +} + +/// Insert all @c TimeUnitType items into popup button. Save unit value into @c tag attribute. ++ (void)populateUnitsMenu:(NSPopUpButton*)popup selected:(TimeUnitType)unit { + [popup removeAllItems]; + for (NSUInteger i = 0; i < 6; i++) { + [popup addItemWithTitle:[NSString stringWithUTF8String:_names[i]]]; + NSMenuItem *item = popup.lastItem; + [item setKeyEquivalent:[[NSString stringWithFormat:@"%c", _shortnames[i]] uppercaseString]]; + item.tag = _values[i]; + } + [popup selectItemWithTag:unit]; +} + +@end diff --git a/baRSS/Preferences/Feeds Tab/ModalFeedEdit.m b/baRSS/Preferences/Feeds Tab/ModalFeedEdit.m index 11caa75..dcf9033 100644 --- a/baRSS/Preferences/Feeds Tab/ModalFeedEdit.m +++ b/baRSS/Preferences/Feeds Tab/ModalFeedEdit.m @@ -27,6 +27,8 @@ #import "FeedMeta+Ext.h" #import "FeedGroup+Ext.h" #import "Statistics.h" +#import "NSDate+Ext.h" + #import @@ -89,6 +91,7 @@ [super viewDidLoad]; self.previousURL = @""; self.refreshNum.intValue = 30; + [NSDate populateUnitsMenu:self.refreshUnit selected:TimeUnitMinutes]; self.warningIndicator.image = nil; [self.warningIndicator.cell setHighlightsBy:NSNoCellMask]; [self populateTextFields:self.feedGroup]; @@ -102,12 +105,8 @@ self.name.objectValue = fg.name; self.url.objectValue = fg.feed.meta.url; self.previousURL = self.url.stringValue; - self.refreshNum.intValue = fg.feed.meta.refreshNum; - NSInteger unit = (NSInteger)fg.feed.meta.refreshUnit; - if (unit < 0 || unit > self.refreshUnit.numberOfItems - 1) - unit = self.refreshUnit.numberOfItems - 1; - [self.refreshUnit selectItemAtIndex:unit]; self.warningIndicator.image = [fg.feed iconImage16]; + [NSDate setInterval:fg.feed.meta.refresh forPopup:self.refreshUnit andField:self.refreshNum]; [self statsForCoreDataObject]; } @@ -122,7 +121,8 @@ [self.feedGroup setNameIfChanged:self.name.stringValue]; FeedMeta *meta = feed.meta; [meta setUrlIfChanged:self.previousURL]; - [meta setRefresh:self.refreshNum.intValue unit:(int16_t)self.refreshUnit.indexOfSelectedItem]; // updateTimer will be scheduled once preferences is closed + [meta setRefreshAndSchedule:[NSDate intervalForPopup:self.refreshUnit andField:self.refreshNum]]; + // updateTimer will be scheduled once preferences is closed if (self.didDownloadFeed) { [meta setEtag:self.httpEtag modified:self.httpDate]; [feed updateWithRSS:self.feedResult postUnreadCountChange:YES]; diff --git a/baRSS/Preferences/Feeds Tab/ModalFeedEdit.xib b/baRSS/Preferences/Feeds Tab/ModalFeedEdit.xib index c4b6895..caea2dd 100644 --- a/baRSS/Preferences/Feeds Tab/ModalFeedEdit.xib +++ b/baRSS/Preferences/Feeds Tab/ModalFeedEdit.xib @@ -86,24 +86,12 @@ - + - - - - - - - - - - - - - + diff --git a/baRSS/Preferences/Feeds Tab/OpmlExport.m b/baRSS/Preferences/Feeds Tab/OpmlExport.m index 927c91d..cd4c8cc 100644 --- a/baRSS/Preferences/Feeds Tab/OpmlExport.m +++ b/baRSS/Preferences/Feeds Tab/OpmlExport.m @@ -170,9 +170,9 @@ meta.url = [item attributeForKey:OPMLXMLURLKey]; id refresh = [item attributeForKey:@"refreshInterval"]; // baRSS specific if (refresh) { - [meta setRefreshAndUnitFromInterval:(int32_t)[refresh integerValue]]; + [meta setRefreshAndSchedule:(int32_t)[refresh integerValue]]; } else { - [meta setRefresh:30 unit:RefreshUnitMinutes]; + [meta setRefreshAndSchedule:kDefaultFeedRefreshInterval]; // TODO: set -1, then auto } } [list addObject:newFeed.feed]; @@ -232,7 +232,7 @@ [outline addAttribute:[NSXMLNode attributeWithName:OPMLHMTLURLKey stringValue:item.feed.link]]; [outline addAttribute:[NSXMLNode attributeWithName:OPMLXMLURLKey stringValue:item.feed.meta.url]]; [outline addAttribute:[NSXMLNode attributeWithName:OPMLTypeKey stringValue:@"rss"]]; - NSString *intervalStr = [NSString stringWithFormat:@"%d", item.feed.meta.refreshInterval]; + NSString *intervalStr = [NSString stringWithFormat:@"%d", item.feed.meta.refresh]; [outline addAttribute:[NSXMLNode attributeWithName:@"refreshInterval" stringValue:intervalStr]]; // baRSS specific // TODO: option to export unread state? } diff --git a/baRSS/Preferences/Feeds Tab/SettingsFeeds.m b/baRSS/Preferences/Feeds Tab/SettingsFeeds.m index 4a89ef9..477a799 100644 --- a/baRSS/Preferences/Feeds Tab/SettingsFeeds.m +++ b/baRSS/Preferences/Feeds Tab/SettingsFeeds.m @@ -408,8 +408,9 @@ static NSString *dragNodeType = @"baRSS-feed-drag"; NSTableCellView *cellView = [self.outlineView makeViewWithIdentifier:cellIdent owner:nil]; if (isRefreshColumn) { - cellView.textField.objectValue = fg.refreshStr; - cellView.textField.textColor = (fg.refreshStr.length > 1 ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]); + NSString *str = [fg refreshString]; + cellView.textField.stringValue = str; + cellView.textField.textColor = (str.length > 1 ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]); } else if (isSeperator) { return cellView; // refresh cell already skipped with the above if condition } else {