diff --git a/Signal/src/ViewControllers/HomeView/HomeViewCell.m b/Signal/src/ViewControllers/HomeView/HomeViewCell.m index 2b3c06948..ce114e472 100644 --- a/Signal/src/ViewControllers/HomeView/HomeViewCell.m +++ b/Signal/src/ViewControllers/HomeView/HomeViewCell.m @@ -192,6 +192,9 @@ const NSUInteger kHomeViewAvatarHSpacing = 12; [self updateNameLabel]; [self updateAvatarView]; + // We update the fonts every time this cell is configured to ensure that + // changes to the dynamic type settings are reflected. + self.snippetLabel.font = [self snippetFont]; self.snippetLabel.attributedText = [self attributedSnippetForThread:thread blockedPhoneNumberSet:blockedPhoneNumberSet]; self.dateTimeLabel.attributedText = [self attributedStringForDate:thread.lastMessageDate]; @@ -204,6 +207,7 @@ const NSUInteger kHomeViewAvatarHSpacing = 12; NSUInteger unreadCount = [[OWSMessageUtils sharedManager] unreadMessagesInThread:thread]; if (unreadCount > 0) { self.unreadBadge.hidden = NO; + self.unreadLabel.font = [UIFont ows_dynamicTypeCaption1Font]; self.unreadLabel.text = [OWSFormat formatInt:MIN(99, (int)unreadCount)]; [self.viewConstraints addObjectsFromArray:@[ @@ -304,7 +308,7 @@ const NSUInteger kHomeViewAvatarHSpacing = 12; dateTimeString = [[DateUtil dateFormatter] stringFromDate:date]; } else if ([DateUtil dateIsOlderThanOneWeek:date]) { dateTimeString = [[DateUtil monthAndDayFormatter] stringFromDate:date]; - } else if ([DateUtil dateIsOlderThanOneDay:date]) { + } else if ([DateUtil dateIsOlderThanToday:date]) { dateTimeString = [[DateUtil shortDayOfWeekFormatter] stringFromDate:date]; } else { dateTimeString = [[DateUtil timeFormatter] stringFromDate:date]; @@ -382,6 +386,8 @@ const NSUInteger kHomeViewAvatarHSpacing = 12; { OWSAssertIsOnMainThread(); + self.nameLabel.font = self.nameFont; + TSThread *thread = self.thread; if (thread == nil) { OWSFail(@"%@ thread should not be nil", self.logTag); diff --git a/Signal/src/util/DateUtil.h b/Signal/src/util/DateUtil.h index 2ffeed30c..0ef6bf2d1 100644 --- a/Signal/src/util/DateUtil.h +++ b/Signal/src/util/DateUtil.h @@ -11,10 +11,11 @@ NS_ASSUME_NONNULL_BEGIN + (NSDateFormatter *)monthAndDayFormatter; + (NSDateFormatter *)shortDayOfWeekFormatter; -+ (BOOL)dateIsOlderThanOneDay:(NSDate *)date; ++ (BOOL)dateIsOlderThanToday:(NSDate *)date; + (BOOL)dateIsOlderThanOneWeek:(NSDate *)date; + (BOOL)dateIsToday:(NSDate *)date; + (BOOL)dateIsThisYear:(NSDate *)date; ++ (BOOL)dateIsYesterday:(NSDate *)date; + (NSString *)formatPastTimestampRelativeToNow:(uint64_t)pastTimestamp isRTL:(BOOL)isRTL NS_SWIFT_NAME(formatPastTimestampRelativeToNow(_:isRTL:)); diff --git a/Signal/src/util/DateUtil.m b/Signal/src/util/DateUtil.m index 696377915..d22255f41 100644 --- a/Signal/src/util/DateUtil.m +++ b/Signal/src/util/DateUtil.m @@ -71,8 +71,13 @@ static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE"; return formatter; } -+ (BOOL)dateIsOlderThanOneDay:(NSDate *)date { - NSDate *now = [NSDate date]; ++ (BOOL)dateIsOlderThanToday:(NSDate *)date +{ + return [self dateIsOlderThanToday:date now:[NSDate date]]; +} + ++ (BOOL)dateIsOlderThanToday:(NSDate *)date now:(NSDate *)now +{ NSCalendar *calendar = [NSCalendar currentCalendar]; NSUInteger dateDayOfEra = [calendar ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:date]; @@ -80,8 +85,13 @@ static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE"; return dateDayOfEra < nowDayOfEra; } -+ (BOOL)dateIsOlderThanOneWeek:(NSDate *)date { - NSDate *now = [NSDate date]; ++ (BOOL)dateIsOlderThanOneWeek:(NSDate *)date +{ + return [self dateIsOlderThanOneWeek:date now:[NSDate date]]; +} + ++ (BOOL)dateIsOlderThanOneWeek:(NSDate *)date now:(NSDate *)now +{ NSCalendar *calendar = [NSCalendar currentCalendar]; NSUInteger dateDayOfEra = [calendar ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:date]; @@ -89,17 +99,13 @@ static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE"; return dateDayOfEra < (nowDayOfEra - 6); } -+ (BOOL)date:(NSDate *)date isEqualToDateIgnoringTime:(NSDate *)anotherDate { - static const unsigned componentFlags = (NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay); - NSDateComponents *components1 = [[NSCalendar autoupdatingCurrentCalendar] components:componentFlags fromDate:date]; - NSDateComponents *components2 = - [[NSCalendar autoupdatingCurrentCalendar] components:componentFlags fromDate:anotherDate]; - return ((components1.year == components2.year) && (components1.month == components2.month) && - (components1.day == components2.day)); ++ (BOOL)dateIsToday:(NSDate *)date +{ + return [self dateIsToday:date now:[NSDate date]]; } -+ (BOOL)dateIsToday:(NSDate *)date { - NSDate *now = [NSDate date]; ++ (BOOL)dateIsToday:(NSDate *)date now:(NSDate *)now +{ NSCalendar *calendar = [NSCalendar currentCalendar]; return ([calendar ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:date] == [calendar ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:now]); @@ -107,7 +113,11 @@ static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE"; + (BOOL)dateIsThisYear:(NSDate *)date { - NSDate *now = [NSDate date]; + return [self dateIsThisYear:date now:[NSDate date]]; +} + ++ (BOOL)dateIsThisYear:(NSDate *)date now:(NSDate *)now +{ NSCalendar *calendar = [NSCalendar currentCalendar]; return ( [calendar component:NSCalendarUnitYear fromDate:date] == [calendar component:NSCalendarUnitYear fromDate:now]); @@ -115,8 +125,14 @@ static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE"; + (BOOL)dateIsYesterday:(NSDate *)date { - NSDate *yesterday = [NSDate ows_dateWithMillisecondsSince1970:[NSDate ows_millisecondTimeStamp] - kDayInMs]; - return [self date:yesterday isEqualToDateIgnoringTime:date]; + return [self dateIsYesterday:date now:[NSDate date]]; +} + ++ (BOOL)dateIsYesterday:(NSDate *)date now:(NSDate *)now +{ + NSCalendar *calendar = [NSCalendar currentCalendar]; + return ([calendar ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:date] == + [calendar ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitEra forDate:now] - 1); } + (NSString *)formatPastTimestampRelativeToNow:(uint64_t)pastTimestamp isRTL:(BOOL)isRTL diff --git a/Signal/test/util/UtilTest.m b/Signal/test/util/UtilTest.m index bb002afe2..4091725f9 100644 --- a/Signal/test/util/UtilTest.m +++ b/Signal/test/util/UtilTest.m @@ -10,6 +10,18 @@ #import #import +@interface DateUtil (Test) + ++ (BOOL)dateIsOlderThanToday:(NSDate *)date now:(NSDate *)now; ++ (BOOL)dateIsOlderThanOneWeek:(NSDate *)date now:(NSDate *)now; ++ (BOOL)dateIsToday:(NSDate *)date now:(NSDate *)now; ++ (BOOL)dateIsThisYear:(NSDate *)date now:(NSDate *)now; ++ (BOOL)dateIsYesterday:(NSDate *)date now:(NSDate *)now; + +@end + +#pragma mark - + @interface NSString (OWS_Test) - (NSString *)removeAllCharactersIn:(NSCharacterSet *)characterSet; @@ -79,7 +91,19 @@ - (void)testDateComparators { - NSDate *now = [NSDate new]; + // Use a specific reference date to make this test deterministic, + // and to avoid failing around midnight, new year's, etc. + NSDateComponents *nowDateComponents = [NSDateComponents new]; + nowDateComponents.year = 2015; + nowDateComponents.month = 8; + nowDateComponents.day = 31; + nowDateComponents.hour = 8; + NSDate *now = [[NSCalendar currentCalendar] dateFromComponents:nowDateComponents]; + + NSDateFormatter *formatter = [NSDateFormatter new]; + formatter.dateStyle = NSDateFormatterLongStyle; + formatter.timeStyle = NSDateFormatterLongStyle; + NSLog(@"now: %@", [formatter stringFromDate:now]); NSDate *oneSecondAgo = [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] - kSecondInterval]; @@ -111,73 +135,83 @@ NSDate *twoYearsAhead = [NSDate dateWithTimeIntervalSinceReferenceDate:[now timeIntervalSinceReferenceDate] + kYearInterval * 2]; - // These might fail around midnight. - XCTAssertTrue([DateUtil dateIsToday:oneSecondAgo]); - XCTAssertTrue([DateUtil dateIsToday:oneMinuteAgo]); - XCTAssertFalse([DateUtil dateIsToday:oneDayAgo]); - XCTAssertFalse([DateUtil dateIsToday:threeDaysAgo]); - XCTAssertFalse([DateUtil dateIsToday:tenDaysAgo]); - XCTAssertFalse([DateUtil dateIsToday:oneYearAgo]); - XCTAssertFalse([DateUtil dateIsToday:twoYearsAgo]); - - // These might fail around midnight. - XCTAssertTrue([DateUtil dateIsToday:oneSecondAhead]); - XCTAssertTrue([DateUtil dateIsToday:oneMinuteAhead]); - XCTAssertFalse([DateUtil dateIsToday:oneDayAhead]); - XCTAssertFalse([DateUtil dateIsToday:threeDaysAhead]); - XCTAssertFalse([DateUtil dateIsToday:tenDaysAhead]); - XCTAssertFalse([DateUtil dateIsToday:oneYearAhead]); - XCTAssertFalse([DateUtil dateIsToday:twoYearsAhead]); - - // These might fail around midnight. - XCTAssertFalse([DateUtil dateIsOlderThanOneDay:oneSecondAgo]); - XCTAssertFalse([DateUtil dateIsOlderThanOneDay:oneMinuteAgo]); - XCTAssertTrue([DateUtil dateIsOlderThanOneDay:oneDayAgo]); - XCTAssertTrue([DateUtil dateIsOlderThanOneDay:threeDaysAgo]); - XCTAssertTrue([DateUtil dateIsOlderThanOneDay:tenDaysAgo]); - XCTAssertTrue([DateUtil dateIsOlderThanOneDay:oneYearAgo]); - XCTAssertTrue([DateUtil dateIsOlderThanOneDay:twoYearsAgo]); - - // These might fail around midnight. - XCTAssertFalse([DateUtil dateIsOlderThanOneDay:oneSecondAhead]); - XCTAssertFalse([DateUtil dateIsOlderThanOneDay:oneMinuteAhead]); - XCTAssertFalse([DateUtil dateIsOlderThanOneDay:oneDayAhead]); - XCTAssertFalse([DateUtil dateIsOlderThanOneDay:threeDaysAhead]); - XCTAssertFalse([DateUtil dateIsOlderThanOneDay:tenDaysAhead]); - XCTAssertFalse([DateUtil dateIsOlderThanOneDay:oneYearAhead]); - XCTAssertFalse([DateUtil dateIsOlderThanOneDay:twoYearsAhead]); - - // These might fail around midnight. - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneSecondAgo]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneMinuteAgo]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneDayAgo]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:threeDaysAgo]); - XCTAssertTrue([DateUtil dateIsOlderThanOneWeek:tenDaysAgo]); - XCTAssertTrue([DateUtil dateIsOlderThanOneWeek:oneYearAgo]); - XCTAssertTrue([DateUtil dateIsOlderThanOneWeek:twoYearsAgo]); - - // These might fail around midnight. - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneSecondAhead]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneMinuteAhead]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneDayAhead]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:threeDaysAhead]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:tenDaysAhead]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneYearAhead]); - XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:twoYearsAhead]); - - // These might fail around new year's. - XCTAssertTrue([DateUtil dateIsThisYear:oneSecondAgo]); - XCTAssertTrue([DateUtil dateIsThisYear:oneMinuteAgo]); - XCTAssertTrue([DateUtil dateIsThisYear:oneDayAgo]); - XCTAssertFalse([DateUtil dateIsThisYear:oneYearAgo]); - XCTAssertFalse([DateUtil dateIsThisYear:twoYearsAgo]); - - // These might fail around new year's. - XCTAssertTrue([DateUtil dateIsThisYear:oneSecondAhead]); - XCTAssertTrue([DateUtil dateIsThisYear:oneMinuteAhead]); - XCTAssertTrue([DateUtil dateIsThisYear:oneDayAhead]); - XCTAssertFalse([DateUtil dateIsThisYear:oneYearAhead]); - XCTAssertFalse([DateUtil dateIsThisYear:twoYearsAhead]); + NSLog(@"oneSecondAgo: %@", [formatter stringFromDate:oneSecondAgo]); + + XCTAssertTrue([DateUtil dateIsToday:oneSecondAgo now:now]); + XCTAssertTrue([DateUtil dateIsToday:oneMinuteAgo now:now]); + XCTAssertFalse([DateUtil dateIsToday:oneDayAgo now:now]); + XCTAssertFalse([DateUtil dateIsToday:threeDaysAgo now:now]); + XCTAssertFalse([DateUtil dateIsToday:tenDaysAgo now:now]); + XCTAssertFalse([DateUtil dateIsToday:oneYearAgo now:now]); + XCTAssertFalse([DateUtil dateIsToday:twoYearsAgo now:now]); + + XCTAssertTrue([DateUtil dateIsToday:oneSecondAhead now:now]); + XCTAssertTrue([DateUtil dateIsToday:oneMinuteAhead now:now]); + XCTAssertFalse([DateUtil dateIsToday:oneDayAhead now:now]); + XCTAssertFalse([DateUtil dateIsToday:threeDaysAhead now:now]); + XCTAssertFalse([DateUtil dateIsToday:tenDaysAhead now:now]); + XCTAssertFalse([DateUtil dateIsToday:oneYearAhead now:now]); + XCTAssertFalse([DateUtil dateIsToday:twoYearsAhead now:now]); + + XCTAssertFalse([DateUtil dateIsYesterday:oneSecondAgo now:now]); + XCTAssertFalse([DateUtil dateIsYesterday:oneMinuteAgo now:now]); + XCTAssertTrue([DateUtil dateIsYesterday:oneDayAgo now:now]); + XCTAssertFalse([DateUtil dateIsYesterday:threeDaysAgo now:now]); + XCTAssertFalse([DateUtil dateIsYesterday:tenDaysAgo now:now]); + XCTAssertFalse([DateUtil dateIsYesterday:oneYearAgo now:now]); + XCTAssertFalse([DateUtil dateIsYesterday:twoYearsAgo now:now]); + + XCTAssertFalse([DateUtil dateIsYesterday:oneSecondAhead now:now]); + XCTAssertFalse([DateUtil dateIsYesterday:oneMinuteAhead now:now]); + XCTAssertFalse([DateUtil dateIsYesterday:oneDayAhead now:now]); + XCTAssertFalse([DateUtil dateIsYesterday:threeDaysAhead now:now]); + XCTAssertFalse([DateUtil dateIsYesterday:tenDaysAhead now:now]); + XCTAssertFalse([DateUtil dateIsYesterday:oneYearAhead now:now]); + XCTAssertFalse([DateUtil dateIsYesterday:twoYearsAhead now:now]); + + XCTAssertFalse([DateUtil dateIsOlderThanToday:oneSecondAgo now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanToday:oneMinuteAgo now:now]); + XCTAssertTrue([DateUtil dateIsOlderThanToday:oneDayAgo now:now]); + XCTAssertTrue([DateUtil dateIsOlderThanToday:threeDaysAgo now:now]); + XCTAssertTrue([DateUtil dateIsOlderThanToday:tenDaysAgo now:now]); + XCTAssertTrue([DateUtil dateIsOlderThanToday:oneYearAgo now:now]); + XCTAssertTrue([DateUtil dateIsOlderThanToday:twoYearsAgo now:now]); + + XCTAssertFalse([DateUtil dateIsOlderThanToday:oneSecondAhead now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanToday:oneMinuteAhead now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanToday:oneDayAhead now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanToday:threeDaysAhead now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanToday:tenDaysAhead now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanToday:oneYearAhead now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanToday:twoYearsAhead now:now]); + + XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneSecondAgo now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneMinuteAgo now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneDayAgo now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:threeDaysAgo now:now]); + XCTAssertTrue([DateUtil dateIsOlderThanOneWeek:tenDaysAgo now:now]); + XCTAssertTrue([DateUtil dateIsOlderThanOneWeek:oneYearAgo now:now]); + XCTAssertTrue([DateUtil dateIsOlderThanOneWeek:twoYearsAgo now:now]); + + XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneSecondAhead now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneMinuteAhead now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneDayAhead now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:threeDaysAhead now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:tenDaysAhead now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:oneYearAhead now:now]); + XCTAssertFalse([DateUtil dateIsOlderThanOneWeek:twoYearsAhead now:now]); + + XCTAssertTrue([DateUtil dateIsThisYear:oneSecondAgo now:now]); + XCTAssertTrue([DateUtil dateIsThisYear:oneMinuteAgo now:now]); + XCTAssertTrue([DateUtil dateIsThisYear:oneDayAgo now:now]); + XCTAssertFalse([DateUtil dateIsThisYear:oneYearAgo now:now]); + XCTAssertFalse([DateUtil dateIsThisYear:twoYearsAgo now:now]); + + XCTAssertTrue([DateUtil dateIsThisYear:oneSecondAhead now:now]); + XCTAssertTrue([DateUtil dateIsThisYear:oneMinuteAhead now:now]); + XCTAssertTrue([DateUtil dateIsThisYear:oneDayAhead now:now]); + XCTAssertFalse([DateUtil dateIsThisYear:oneYearAhead now:now]); + XCTAssertFalse([DateUtil dateIsThisYear:twoYearsAhead now:now]); } - (void)testObjectComparison