From a7444a21b55bc1a44ad2c13d2a8a0e80f80da5ba Mon Sep 17 00:00:00 2001 From: Mitchell Livingston Date: Fri, 17 Oct 2014 05:12:00 +0000 Subject: [PATCH] Yosemite: use NSDateComponentsFormatter instead of custom time string code --- macosx/InfoActivityViewController.m | 20 ++++++++++++++++++-- macosx/NSStringAdditions.h | 4 ++-- macosx/NSStringAdditions.m | 18 ++++++++++++++---- macosx/StatsWindowController.m | 20 ++++++++++++++++++-- macosx/Torrent.m | 25 ++++++++++++++++++++++--- macosx/TrackerNode.m | 24 ++++++++++++++++++++++-- 6 files changed, 96 insertions(+), 15 deletions(-) diff --git a/macosx/InfoActivityViewController.m b/macosx/InfoActivityViewController.m index b2f93c91e..1da72f9cb 100644 --- a/macosx/InfoActivityViewController.m +++ b/macosx/InfoActivityViewController.m @@ -23,6 +23,7 @@ *****************************************************************************/ #import "InfoActivityViewController.h" +#import "NSApplicationAdditions.h" #import "NSStringAdditions.h" #import "PiecesView.h" #import "Torrent.h" @@ -185,8 +186,23 @@ //uses a relative date, so can't be set once [fDateAddedField setObjectValue: [torrent dateAdded]]; - [fDownloadTimeField setStringValue: [NSString timeString: [torrent secondsDownloading] showSeconds: YES]]; - [fSeedTimeField setStringValue: [NSString timeString: [torrent secondsSeeding] showSeconds: YES]]; + if ([NSApp isOnYosemiteOrBetter]) { + static NSDateComponentsFormatter *timeFormatter; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + timeFormatter = [NSDateComponentsFormatter new]; + timeFormatter.unitsStyle = NSDateComponentsFormatterUnitsStyleShort; + timeFormatter.allowedUnits = NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; + timeFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorDropLeading; + }); + + [fDownloadTimeField setStringValue: [timeFormatter stringFromTimeInterval:[torrent secondsDownloading]]]; + [fSeedTimeField setStringValue: [timeFormatter stringFromTimeInterval:[torrent secondsSeeding]]]; + } + else { + [fDownloadTimeField setStringValue: [NSString timeString: [torrent secondsDownloading] includesTimeRemainingPhrase:NO showSeconds: YES]]; + [fSeedTimeField setStringValue: [NSString timeString: [torrent secondsSeeding] includesTimeRemainingPhrase:NO showSeconds: YES]]; + } [fPiecesView updateView]; } diff --git a/macosx/NSStringAdditions.h b/macosx/NSStringAdditions.h index 202a70502..d0f7eb41a 100644 --- a/macosx/NSStringAdditions.h +++ b/macosx/NSStringAdditions.h @@ -40,8 +40,8 @@ + (NSString *) percentString: (CGFloat) progress longDecimals: (BOOL) longDecimals; -+ (NSString *) timeString: (uint64_t) seconds showSeconds: (BOOL) showSeconds; -+ (NSString *) timeString: (uint64_t) seconds showSeconds: (BOOL) showSeconds maxFields: (NSUInteger) max; ++ (NSString *) timeString: (uint64_t) seconds includesTimeRemainingPhrase: (BOOL) includesTimeRemainingPhrase showSeconds: (BOOL) showSeconds; ++ (NSString *) timeString: (uint64_t) seconds includesTimeRemainingPhrase: (BOOL) includesTimeRemainingPhrase showSeconds: (BOOL) showSeconds maxFields: (NSUInteger) max; - (NSComparisonResult) compareNumeric: (NSString *) string; //simple compare method for strings with numbers (works for IP addresses) diff --git a/macosx/NSStringAdditions.m b/macosx/NSStringAdditions.m index b1cf62a80..51043e109 100644 --- a/macosx/NSStringAdditions.m +++ b/macosx/NSStringAdditions.m @@ -153,13 +153,17 @@ return [NSString localizedStringWithFormat: @"%.1f%%", tr_truncd(progress * 100.0, 1)]; } -+ (NSString *) timeString: (uint64_t) seconds showSeconds: (BOOL) showSeconds ++ (NSString *) timeString: (uint64_t) seconds includesTimeRemainingPhrase: (BOOL) includesTimeRemainingPhrase showSeconds: (BOOL) showSeconds { - return [NSString timeString: seconds showSeconds: showSeconds maxFields: NSUIntegerMax]; + return [NSString timeString: seconds + includesTimeRemainingPhrase: includesTimeRemainingPhrase + showSeconds: showSeconds + maxFields: NSUIntegerMax]; } -+ (NSString *) timeString: (uint64_t) seconds showSeconds: (BOOL) showSeconds maxFields: (NSUInteger) max ++ (NSString *) timeString: (uint64_t) seconds includesTimeRemainingPhrase: (BOOL) includesTimeRemainingPhrase showSeconds: (BOOL) showSeconds maxFields: (NSUInteger) max { + NSAssert(![NSApp isOnYosemiteOrBetter], @"you should be using NSDateComponentsFormatter on >= 10.10"); NSParameterAssert(max > 0); NSMutableArray * timeArray = [NSMutableArray arrayWithCapacity: MIN(max, 5)]; @@ -200,7 +204,13 @@ if (max > 0 && showSeconds) [timeArray addObject: [NSString stringWithFormat: NSLocalizedString(@"%u sec", "time string"), remaining]]; - return [timeArray componentsJoinedByString: @" "]; + NSString * timeString = [timeArray componentsJoinedByString: @" "]; + + if (includesTimeRemainingPhrase) { + timeString = [NSString stringWithFormat: NSLocalizedString(@"%@ remaining", "time remaining string"), timeString]; + } + + return timeString; } - (NSComparisonResult) compareNumeric: (NSString *) string diff --git a/macosx/StatsWindowController.m b/macosx/StatsWindowController.m index f8512879f..133616f5f 100644 --- a/macosx/StatsWindowController.m +++ b/macosx/StatsWindowController.m @@ -196,8 +196,24 @@ tr_session * fLib = NULL; : NSLocalizedString(@"Total N/A", "stats total"); [fRatioAllField setStringValue: totalRatioString]; - [fTimeField setStringValue: [NSString timeString: statsSession.secondsActive showSeconds: NO]]; - [fTimeAllField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@ total", "stats total"), [NSString timeString: statsAll.secondsActive showSeconds: NO]]]; + if ([NSApp isOnYosemiteOrBetter]) { + static NSDateComponentsFormatter *timeFormatter; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + timeFormatter = [NSDateComponentsFormatter new]; + timeFormatter.unitsStyle = NSDateComponentsFormatterUnitsStyleFull; + timeFormatter.maximumUnitCount = 3; + timeFormatter.allowedUnits = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitWeekOfMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute; + timeFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorDropLeading; + }); + + [fTimeField setStringValue: [timeFormatter stringFromTimeInterval:statsSession.secondsActive]]; + [fTimeAllField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@ total", "stats total"), [timeFormatter stringFromTimeInterval:statsAll.secondsActive]]]; + } + else { + [fTimeField setStringValue: [NSString timeString: statsSession.secondsActive includesTimeRemainingPhrase:NO showSeconds: NO]]; + [fTimeAllField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@ total", "stats total"), [NSString timeString: statsAll.secondsActive includesTimeRemainingPhrase:NO showSeconds: NO]]]; + } if (statsAll.sessionCount == 1) [fNumOpenedField setStringValue: NSLocalizedString(@"1 time", "stats window -> times opened")]; diff --git a/macosx/Torrent.m b/macosx/Torrent.m index f5b295234..f8c2e3a56 100644 --- a/macosx/Torrent.m +++ b/macosx/Torrent.m @@ -25,6 +25,7 @@ #import "Torrent.h" #import "GroupsController.h" #import "FileListNode.h" +#import "NSApplicationAdditions.h" #import "NSStringAdditions.h" #import "TrackerNode.h" @@ -1980,10 +1981,28 @@ int trashDataFile(const char * filename) else return NSLocalizedString(@"remaining time unknown", "Torrent -> eta string"); - NSString * idleString = [NSString stringWithFormat: NSLocalizedString(@"%@ remaining", "Torrent -> eta string"), - [NSString timeString: eta showSeconds: YES maxFields: 2]]; - if (fromIdle) + NSString * idleString; + + if ([NSApp isOnYosemiteOrBetter]) { + static NSDateComponentsFormatter *formatter; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + formatter = [NSDateComponentsFormatter new]; + formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleShort; + formatter.maximumUnitCount = 2; + formatter.collapsesLargestUnit = YES; + formatter.includesTimeRemainingPhrase = YES; + }); + + idleString = [formatter stringFromTimeInterval: eta]; + } + else { + idleString = [NSString timeString: eta includesTimeRemainingPhrase: YES showSeconds: YES maxFields: 2]; + } + + if (fromIdle) { idleString = [idleString stringByAppendingFormat: @" (%@)", NSLocalizedString(@"inactive", "Torrent -> eta string")]; + } return idleString; } diff --git a/macosx/TrackerNode.m b/macosx/TrackerNode.m index c2649fa1d..ecbff61ca 100644 --- a/macosx/TrackerNode.m +++ b/macosx/TrackerNode.m @@ -23,6 +23,7 @@ *****************************************************************************/ #import "TrackerNode.h" +#import "NSApplicationAdditions.h" #import "NSStringAdditions.h" @implementation TrackerNode @@ -156,9 +157,28 @@ return [NSLocalizedString(@"Announce in progress", "Tracker next announce") stringByAppendingEllipsis]; case TR_TRACKER_WAITING: + { + const NSTimeInterval nextAnnounceTimeLeft = fStat.nextAnnounceTime - [[NSDate date] timeIntervalSince1970]; + + NSString *timeString; + if ([NSApp isOnYosemiteOrBetter]) { + static NSDateComponentsFormatter *formatter; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + formatter = [NSDateComponentsFormatter new]; + formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleAbbreviated; + formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorDropLeading; + formatter.collapsesLargestUnit = YES; + }); + + timeString = [formatter stringFromTimeInterval: nextAnnounceTimeLeft]; + } + else { + timeString = [NSString timeString: nextAnnounceTimeLeft includesTimeRemainingPhrase: NO showSeconds: YES]; + } return [NSString stringWithFormat: NSLocalizedString(@"Next announce in %@", "Tracker next announce"), - [NSString timeString: fStat.nextAnnounceTime - [[NSDate date] timeIntervalSince1970] showSeconds: YES]]; - + timeString]; + } case TR_TRACKER_QUEUED: return [NSLocalizedString(@"Announce is queued", "Tracker next announce") stringByAppendingEllipsis]; -- 2.40.0