Update date header and message footer date formatting.

This commit is contained in:
Matthew Chen 2021-08-31 14:00:56 -03:00
parent 2b2686b267
commit 2005be536b
9 changed files with 173 additions and 209 deletions

View File

@ -145,6 +145,7 @@
344A761324B36C8C009D69A5 /* TestingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344A761224B36C8C009D69A5 /* TestingViewController.swift */; };
344DAEDF248A7526000AD4FA /* DebugUIStress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344DAEDE248A7526000AD4FA /* DebugUIStress.swift */; };
344F248D2007CCD600CFB4F4 /* DisplayableText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344F248C2007CCD600CFB4F4 /* DisplayableText.swift */; };
3452851B26DE890400824983 /* DateUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3452851A26DE890300824983 /* DateUtil.swift */; };
3452C15625348F1D00F69070 /* GroupsV2Migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3452C15525348F1D00F69070 /* GroupsV2Migration.swift */; };
34546F502649989D007C4958 /* ChatColorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34546F4F2649989C007C4958 /* ChatColorViewController.swift */; };
3456A73223D63EBE00947219 /* GroupsV2Protos.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3456A73123D63EBE00947219 /* GroupsV2Protos.swift */; };
@ -1221,6 +1222,7 @@
344A761224B36C8C009D69A5 /* TestingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestingViewController.swift; sourceTree = "<group>"; };
344DAEDE248A7526000AD4FA /* DebugUIStress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugUIStress.swift; sourceTree = "<group>"; };
344F248C2007CCD600CFB4F4 /* DisplayableText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayableText.swift; sourceTree = "<group>"; };
3452851A26DE890300824983 /* DateUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateUtil.swift; sourceTree = "<group>"; };
3452C15525348F1D00F69070 /* GroupsV2Migration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupsV2Migration.swift; sourceTree = "<group>"; };
34546F4F2649989C007C4958 /* ChatColorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatColorViewController.swift; sourceTree = "<group>"; };
3456A73123D63EBE00947219 /* GroupsV2Protos.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupsV2Protos.swift; sourceTree = "<group>"; };
@ -2543,9 +2545,11 @@
883A7FD0269F640D00841DF9 /* Avatars */,
343D3D991E9283F100165CA4 /* BlockListUIUtils.h */,
343D3D9A1E9283F100165CA4 /* BlockListUIUtils.m */,
88D7BA9D266809F50088D1C2 /* CallMessageRelay.swift */,
3466087120E550F300AFFE73 /* ConversationStyle.swift */,
3464451022B7F97100A957B1 /* DateUtil.h */,
3464450F22B7F97000A957B1 /* DateUtil.m */,
3452851A26DE890300824983 /* DateUtil.swift */,
34480B4D1FD0A7A300BC14EF /* DebugLogger.h */,
34480B4E1FD0A7A300BC14EF /* DebugLogger.m */,
348ECD8B25F278450083C47D /* DebugLogger.swift */,
@ -2579,7 +2583,6 @@
340872BE22393CF900CB25B0 /* UIGestureRecognizer+OWS.swift */,
B97940251832BD2400BD66CB /* UIUtil.h */,
B97940261832BD2400BD66CB /* UIUtil.m */,
88D7BA9D266809F50088D1C2 /* CallMessageRelay.swift */,
);
path = utils;
sourceTree = "<group>";
@ -5457,6 +5460,7 @@
889C8A8D248831AC00C3D3D8 /* BlurTooltip.swift in Sources */,
34BBC859220C7ADA00857249 /* ImageEditorStrokeItem.swift in Sources */,
451F8A351FD710DE005CB9DA /* Searcher.swift in Sources */,
3452851B26DE890400824983 /* DateUtil.swift in Sources */,
3464450D22B7F93600A957B1 /* OWSOrphanDataCleaner.m in Sources */,
348D8E72262DF67A0019CAA8 /* ConversationAvatarView.swift in Sources */,
3474C57226111605006723D2 /* PaymentsFormat.swift in Sources */,

View File

@ -130,7 +130,7 @@ public class CVComponentDateHeader: CVComponentBase, CVRootComponent {
static func buildState(interaction: TSInteraction) -> State {
let date = Date(millisecondsSince1970: interaction.timestamp)
let text = DateUtil.formatDate(forConversationDateBreaks: date)
let text = DateUtil.formatDateHeaderForCVC(date)
return State(text: text)
}

View File

@ -199,7 +199,8 @@ public class CVComponentFooter: CVComponentBase, CVComponent {
comment: "Label indicating that a message failed to send.")
}
} else {
return DateUtil.formatMessageTimestamp(interaction.timestamp, shouldUseLongFormat: shouldUseLongFormat)
return DateUtil.formatMessageTimestampForCVC(interaction.timestamp,
shouldUseLongFormat: shouldUseLongFormat)
}
}

View File

@ -2885,8 +2885,7 @@ typedef NS_CLOSED_ENUM(NSUInteger, MessageContentType) {
return [DebugUIMessagesSingleAction
actionWithLabel:[NSString stringWithFormat:@"Fake Back-Date Message (%@)", label]
unstaggeredActionBlock:^(NSUInteger index, SDSAnyWriteTransaction *transaction) {
NSString *messageBody =
[[@(index).stringValue stringByAppendingString:@" "] stringByAppendingString:self.randomText];
NSString *messageBody = [@[ @(index).stringValue, self.randomText, label ] componentsJoinedByString:@" "];
TSOutgoingMessage *message = [self createFakeOutgoingMessage:thread
messageBody:messageBody
fakeAssetLoader:nil
@ -2898,8 +2897,9 @@ typedef NS_CLOSED_ENUM(NSUInteger, MessageContentType) {
linkPreview:nil
messageSticker:nil
transaction:transaction];
[message replaceReceivedAtTimestamp:(uint64_t)((int64_t)[NSDate ows_millisecondTimeStamp] + dateOffset)
transaction:transaction];
uint64_t timestamp = (uint64_t)((int64_t)[NSDate ows_millisecondTimeStamp] + dateOffset);
[message replaceTimestamp:timestamp transaction:transaction];
[message replaceReceivedAtTimestamp:timestamp transaction:transaction];
}];
}
@ -2926,6 +2926,12 @@ typedef NS_CLOSED_ENUM(NSUInteger, MessageContentType) {
[actions addObject:[self fakeBackDatedMessageAction:thread
label:@"Ten Days Ago"
dateOffset:-(int64_t)kDayInMs * 10]];
[actions addObject:[self fakeBackDatedMessageAction:thread
label:@"5 Months Ago"
dateOffset:-(int64_t)kMonthInMs * 5]];
[actions addObject:[self fakeBackDatedMessageAction:thread
label:@"7 Months Ago"
dateOffset:-(int64_t)kMonthInMs * 7]];
[actions addObject:[self fakeBackDatedMessageAction:thread
label:@"400 Days Ago"
dateOffset:-(int64_t)kDayInMs * 400]];

View File

@ -7,7 +7,6 @@ NS_ASSUME_NONNULL_BEGIN
@interface DateUtil : NSObject
+ (NSDateFormatter *)dateFormatter;
+ (NSDateFormatter *)timeFormatter;
+ (NSDateFormatter *)monthAndDayFormatter;
+ (NSDateFormatter *)shortDayOfWeekFormatter;
@ -29,9 +28,6 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSString *)formatTimestampAsDate:(uint64_t)timestamp;
+ (NSString *)formatDateAsDate:(NSDate *)date;
+ (NSString *)formatMessageTimestamp:(uint64_t)timestamp
shouldUseLongFormat:(BOOL)shouldUseLongFormat;
+ (BOOL)isTimestampFromLastHour:(uint64_t)timestamp;
// These two "exemplary" values can be used by views to measure
@ -39,11 +35,11 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSString *)exemplaryNowTimeFormat;
+ (NSString *)exemplaryMinutesTimeFormat;
+ (NSString *)formatDateForConversationDateBreaks:(NSDate *)date;
+ (BOOL)isSameDayWithTimestamp:(uint64_t)timestamp1 timestamp:(uint64_t)timestamp2;
+ (BOOL)isSameDayWithDate:(NSDate *)date1 date:(NSDate *)date2;
+ (BOOL)dateIsOlderThanYesterday:(NSDate *)date;
@end
NS_ASSUME_NONNULL_END

View File

@ -26,64 +26,6 @@ static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE";
return formatter;
}
+ (NSDateFormatter *)dateBreakRelativeDateFormatter
{
static NSDateFormatter *formatter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [NSDateFormatter new];
formatter.locale = [NSLocale currentLocale];
formatter.dateStyle = NSDateFormatterShortStyle;
formatter.timeStyle = NSDateFormatterNoStyle;
formatter.doesRelativeDateFormatting = YES;
});
return formatter;
}
+ (NSDateFormatter *)dateBreakThisWeekDateFormatter
{
static NSDateFormatter *formatter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [NSDateFormatter new];
formatter.locale = [NSLocale currentLocale];
// "Monday", "Tuesday", etc.
formatter.dateFormat = @"EEEE";
});
return formatter;
}
+ (NSDateFormatter *)dateBreakThisYearDateFormatter
{
static NSDateFormatter *formatter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [NSDateFormatter new];
formatter.locale = [NSLocale currentLocale];
// Tue, Jun 6
[formatter setLocalizedDateFormatFromTemplate:@"EE, MMM d"];
});
return formatter;
}
+ (NSDateFormatter *)dateBreakOldDateFormatter
{
static NSDateFormatter *formatter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [NSDateFormatter new];
formatter.locale = [NSLocale currentLocale];
formatter.dateStyle = NSDateFormatterMediumStyle;
formatter.timeStyle = NSDateFormatterNoStyle;
formatter.doesRelativeDateFormatting = YES;
});
return formatter;
}
+ (NSDateFormatter *)weekdayFormatter
{
static NSDateFormatter *formatter;
@ -96,19 +38,6 @@ static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE";
return formatter;
}
+ (NSDateFormatter *)timeFormatter
{
static NSDateFormatter *formatter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
formatter = [NSDateFormatter new];
[formatter setLocale:[NSLocale currentLocale]];
[formatter setTimeStyle:NSDateFormatterShortStyle];
[formatter setDateStyle:NSDateFormatterNoStyle];
});
return formatter;
}
+ (NSDateFormatter *)monthAndDayFormatter
{
static NSDateFormatter *formatter;
@ -200,42 +129,6 @@ static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE";
return dayDifference == 1;
}
// Returns the difference in days, ignoring hours, minutes, seconds.
// If both dates are the same date, returns 0.
// If firstDate is a day before secondDate, returns 1.
//
// Note: Assumes both dates use the "current" calendar.
+ (NSInteger)daysFromFirstDate:(NSDate *)firstDate toSecondDate:(NSDate *)secondDate
{
NSCalendar *calendar = [NSCalendar currentCalendar];
NSCalendarUnit units = NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
NSDateComponents *comp1 = [calendar components:units fromDate:firstDate];
NSDateComponents *comp2 = [calendar components:units fromDate:secondDate];
[comp1 setHour:12];
[comp2 setHour:12];
NSDate *date1 = [calendar dateFromComponents:comp1];
NSDate *date2 = [calendar dateFromComponents:comp2];
return [[calendar components:NSCalendarUnitDay fromDate:date1 toDate:date2 options:0] day];
}
// Returns the difference in years, ignoring shorter units of time.
// If both dates fall in the same year, returns 0.
// If firstDate is from the year before secondDate, returns 1.
//
// Note: Assumes both dates use the "current" calendar.
+ (NSInteger)yearsFromFirstDate:(NSDate *)firstDate toSecondDate:(NSDate *)secondDate
{
NSCalendar *calendar = [NSCalendar currentCalendar];
NSCalendarUnit units = NSCalendarUnitEra | NSCalendarUnitYear;
NSDateComponents *comp1 = [calendar components:units fromDate:firstDate];
NSDateComponents *comp2 = [calendar components:units fromDate:secondDate];
[comp1 setHour:12];
[comp2 setHour:12];
NSDate *date1 = [calendar dateFromComponents:comp1];
NSDate *date2 = [calendar dateFromComponents:comp2];
return [[calendar components:NSCalendarUnitYear fromDate:date1 toDate:date2 options:0] year];
}
+ (NSString *)formatPastTimestampRelativeToNow:(uint64_t)pastTimestamp
{
OWSCAssertDebug(pastTimestamp > 0);
@ -284,25 +177,6 @@ static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE";
return dateTimeString;
}
+ (NSString *)formatDateForConversationDateBreaks:(NSDate *)date
{
OWSAssertDebug(date);
if (![self dateIsThisYear:date]) {
// last year formatter: Nov 11, 2017
return [self.dateBreakOldDateFormatter stringFromDate:date];
} else if ([self dateIsOlderThanOneWeek:date]) {
// this year formatter: Tue, Jun 23
return [self.dateBreakThisYearDateFormatter stringFromDate:date];
} else if ([self dateIsOlderThanYesterday:date]) {
// day of week formatter: Thursday
return [self.dateBreakThisWeekDateFormatter stringFromDate:date];
} else {
// relative format: Today / Yesterday
return [self.dateBreakRelativeDateFormatter stringFromDate:date];
}
}
+ (NSString *)formatTimestampAsTime:(uint64_t)timestamp
{
return [self formatDateAsTime:[NSDate ows_dateWithMillisecondsSince1970:timestamp]];
@ -385,76 +259,6 @@ static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE";
return formatter;
}
+ (NSString *)formatMessageTimestamp:(uint64_t)timestamp
shouldUseLongFormat:(BOOL)shouldUseLongFormat
{
NSDate *date = [NSDate ows_dateWithMillisecondsSince1970:timestamp];
uint64_t nowTimestamp = [NSDate ows_millisecondTimeStamp];
NSDate *nowDate = [NSDate ows_dateWithMillisecondsSince1970:nowTimestamp];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *relativeDiffComponents =
[calendar components:NSCalendarUnitMinute | NSCalendarUnitHour fromDate:date toDate:nowDate options:0];
// Note: we are careful to treat "future" dates as "now".
NSInteger yearsDiff = [self yearsFromFirstDate:date toSecondDate:nowDate];
NSInteger daysDiff = [self daysFromFirstDate:date toSecondDate:nowDate];
NSInteger hoursDiff = MAX(0, [relativeDiffComponents hour]);
NSInteger minutesDiff = MAX(0, [relativeDiffComponents minute]);
if (yearsDiff > 0) {
// "Long date" + locale-specific "short" time format.
NSString *dayOfWeek = [self.otherYearMessageFormatter stringFromDate:date];
NSString *formattedTime = [[self timeFormatter] stringFromDate:date];
return [[dayOfWeek stringByAppendingString:@" "] stringByAppendingString:formattedTime];
} else if (daysDiff >= 7) {
// "Short date" + locale-specific "short" time format.
NSString *dayOfWeek = [self.thisYearMessageFormatter stringFromDate:date];
NSString *formattedTime = [[self timeFormatter] stringFromDate:date];
return [[dayOfWeek stringByAppendingString:@" "] stringByAppendingString:formattedTime];
} else if (daysDiff > 0) {
// "Day of week" + locale-specific "short" time format.
NSDateFormatter *thisWeekMessageFormatter = (shouldUseLongFormat
? self.thisWeekMessageFormatterLong
: self.thisWeekMessageFormatterShort);
NSString *dayOfWeek = [thisWeekMessageFormatter stringFromDate:date];
NSString *formattedTime = [[self timeFormatter] stringFromDate:date];
return [[dayOfWeek stringByAppendingString:@" "] stringByAppendingString:formattedTime];
} else if (hoursDiff > 0) {
if (shouldUseLongFormat && hoursDiff == 1) {
// Long format has a distinction between singular and plural
return NSLocalizedString(@"DATE_ONE_HOUR_AGO_LONG", @"Full string for a relative time of one hour ago.");
}
NSString *shortFormat = NSLocalizedString(@"DATE_HOURS_AGO_FORMAT", @"Format string for a relative time, expressed as a certain number of hours in the past. Embeds {{The number of hours}}.");
NSString *longFormat = NSLocalizedString(@"DATE_HOURS_AGO_LONG_FORMAT", @"Full format string for a relative time, expressed as a certain number of hours in the past. Embeds {{The number of hours}}.");
NSString *formatString = shouldUseLongFormat ? longFormat : shortFormat;
NSString *hoursString = [OWSFormat formatInt:hoursDiff];
return [NSString stringWithFormat:formatString, hoursString];
} else if (minutesDiff > 0) {
if (shouldUseLongFormat && minutesDiff == 1) {
// Long format has a distinction between singular and plural
return NSLocalizedString(@"DATE_ONE_MINUTE_AGO_LONG", @"Full string for a relative time of one minute ago.");
}
NSString *shortFormat = NSLocalizedString(@"DATE_MINUTES_AGO_FORMAT", @"Format string for a relative time, expressed as a certain number of minutes in the past. Embeds {{The number of minutes}}.");
NSString *longFormat = NSLocalizedString(@"DATE_MINUTES_AGO_LONG_FORMAT", @"Full format string for a relative time, expressed as a certain number of minutes in the past. Embeds {{The number of minutes}}.");
NSString *formatString = shouldUseLongFormat ? longFormat : shortFormat;
NSString *minutesString = [OWSFormat formatInt:minutesDiff];
return [NSString stringWithFormat:formatString, minutesString];
} else {
return NSLocalizedString(@"DATE_NOW", @"The present; the current time.");
}
}
+ (BOOL)isTimestampFromLastHour:(uint64_t)timestamp
{
NSDate *date = [NSDate ows_dateWithMillisecondsSince1970:timestamp];

View File

@ -0,0 +1,145 @@
//
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
import Foundation
extension DateUtil {
@objc
public static let timeFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = .current
formatter.timeStyle = .short
formatter.dateStyle = .none
return formatter
}()
// Returns the difference in days, ignoring hours, minutes, seconds.
// If both dates are the same date, returns 0.
// If firstDate is a day before secondDate, returns 1.
//
// Note: Assumes both dates use the "current" calendar.
@objc
public static func daysFrom(firstDate: Date, toSecondDate secondDate: Date) -> Int {
let calendar = Calendar.current
let units: Set<Calendar.Component> = [.era, .year, .month, .day]
var components1 = calendar.dateComponents(units, from: firstDate)
var components2 = calendar.dateComponents(units, from: secondDate)
components1.hour = 12
components2.hour = 12
guard let date1 = calendar.date(from: components1),
let date2 = calendar.date(from: components2) else {
owsFailDebug("Invalid date.")
return 0
}
guard let result = calendar.dateComponents([.day], from: date1, to: date2).day else {
owsFailDebug("Missing result.")
return 0
}
return result
}
// Returns the difference in years, ignoring shorter units of time.
// If both dates fall in the same year, returns 0.
// If firstDate is from the year before secondDate, returns 1.
//
// Note: Assumes both dates use the "current" calendar.
@objc
public static func yearsFrom(firstDate: Date, toSecondDate secondDate: Date) -> Int {
let calendar = Calendar.current
let units: Set<Calendar.Component> = [.era, .year]
var components1 = calendar.dateComponents(units, from: firstDate)
var components2 = calendar.dateComponents(units, from: secondDate)
components1.hour = 12
components2.hour = 12
guard let date1 = calendar.date(from: components1),
let date2 = calendar.date(from: components2) else {
owsFailDebug("Invalid date.")
return 0
}
guard let result = calendar.dateComponents([.year], from: date1, to: date2).year else {
owsFailDebug("Missing result.")
return 0
}
return result
}
// We might receive a message "from the future" due to a bug or
// malicious sender or a sender whose device time is misconfigured,
// etc. Clamp message and date headers dates to the past & present.
private static func safeDateForCVC(_ date: Date) -> Date {
let nowDate = Date()
return date < nowDate ? date : nowDate
}
@objc
public static func formatMessageTimestampForCVC(_ timestamp: UInt64,
shouldUseLongFormat: Bool) -> String {
let date = safeDateForCVC(Date(millisecondsSince1970: timestamp))
let calendar = Calendar.current
let minutesDiff = calendar.dateComponents([.minute], from: date, to: Date()).minute ?? 0
if minutesDiff < 1 {
return NSLocalizedString("DATE_NOW",
comment: "The present the current time.")
} else if shouldUseLongFormat && minutesDiff == 1 {
// Long format has a distinction between singular and plural
return NSLocalizedString("DATE_ONE_MINUTE_AGO_LONG",
comment: "Full string for a relative time of one minute ago.")
} else if minutesDiff <= 60 {
let shortFormat = NSLocalizedString("DATE_MINUTES_AGO_FORMAT",
comment: "Format string for a relative time, expressed as a certain number of minutes in the past. Embeds {{The number of minutes}}.")
let longFormat = NSLocalizedString("DATE_MINUTES_AGO_LONG_FORMAT",
comment: "Full format string for a relative time, expressed as a certain number of minutes in the past. Embeds {{The number of minutes}}.")
let format = shouldUseLongFormat ? longFormat : shortFormat
let minutesString = OWSFormat.formatInt(minutesDiff)
return String(format: format, minutesString)
} else {
return timeFormatter.string(from: date)
}
}
@objc
public static func formatDateHeaderForCVC(_ date: Date) -> String {
let date = safeDateForCVC(date)
let calendar = Calendar.current
let monthsDiff = calendar.dateComponents([.month], from: date, to: Date()).month ?? 0
if monthsDiff >= 6 {
// Mar 8, 2017
return dateHeaderOldDateFormatter.string(from: date)
} else if dateIsOlderThanYesterday(date) {
// Wed, Mar 3
return dateHeaderRecentDateFormatter.string(from: date)
} else {
// Today / Yesterday
return dateHeaderRelativeDateFormatter.string(from: date)
}
}
private static let dateHeaderRecentDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = .current
// Tue, Jun 6
formatter.setLocalizedDateFormatFromTemplate("EE, MMM d")
return formatter
}()
private static let dateHeaderOldDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = .current
formatter.timeStyle = .none
// Mar 8, 2017
formatter.dateStyle = .medium
return formatter
}()
private static let dateHeaderRelativeDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = .current
formatter.timeStyle = .none
formatter.dateStyle = .short
// Today / Yesterday
formatter.doesRelativeDateFormatting = true
return formatter
}()
}

View File

@ -104,6 +104,7 @@ NS_DESIGNATED_INITIALIZER NS_SWIFT_NAME(init(grdbId:uniqueId:receivedAtTimestamp
- (void)replaceSortId:(uint64_t)sortId;
#if TESTABLE_BUILD
- (void)replaceTimestamp:(uint64_t)timestamp transaction:(SDSAnyWriteTransaction *)transaction;
- (void)replaceReceivedAtTimestamp:(uint64_t)receivedAtTimestamp NS_SWIFT_NAME(replaceReceivedAtTimestamp(_:));
- (void)replaceReceivedAtTimestamp:(uint64_t)receivedAtTimestamp transaction:(SDSAnyWriteTransaction *)transaction;
#endif

View File

@ -315,6 +315,13 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value)
}
#if TESTABLE_BUILD
- (void)replaceTimestamp:(uint64_t)timestamp transaction:(SDSAnyWriteTransaction *)transaction
{
[self anyUpdateWithTransaction:transaction
block:^(TSInteraction *interaction) { interaction.timestamp = timestamp; }];
}
- (void)replaceReceivedAtTimestamp:(uint64_t)receivedAtTimestamp
{
self.receivedAtTimestamp = receivedAtTimestamp;