Merge branch 'charlesmchen/messageDateTimes'

pull/1/head
Matthew Chen 7 years ago
commit f131c71d90

@ -232,6 +232,10 @@ NS_ASSUME_NONNULL_BEGIN
actionBlock:^{
[DebugUIMessages createSystemMessagesInThread:thread];
}],
[OWSTableItem itemWithTitle:@"Create messages with variety of timestamps"
actionBlock:^{
[DebugUIMessages createTimestampMessagesInThread:thread];
}],
[OWSTableItem itemWithTitle:@"Send 10 text and system messages"
actionBlock:^{
@ -1534,6 +1538,61 @@ NS_ASSUME_NONNULL_BEGIN
});
}
+ (void)createTimestampMessagesInThread:(TSThread *)thread
{
OWSAssert(thread);
uint64_t now = [NSDate ows_millisecondTimeStamp];
NSArray<NSNumber *> *timestamps = @[
@(now + 1 * kHourInMs),
@(now),
@(now - 1 * kHourInMs),
@(now - 12 * kHourInMs),
@(now - 1 * kDayInMs),
@(now - 2 * kDayInMs),
@(now - 3 * kDayInMs),
@(now - 6 * kDayInMs),
@(now - 7 * kDayInMs),
@(now - 8 * kDayInMs),
@(now - 2 * kWeekInMs),
@(now - 1 * kMonthInMs),
@(now - 2 * kMonthInMs),
];
NSMutableArray<NSString *> *recipientIds = [thread.recipientIdentifiers mutableCopy];
[recipientIds removeObject:[TSAccountManager localNumber]];
NSString *recipientId = (recipientIds.count > 0 ? recipientIds.firstObject : @"+19174054215");
[TSStorageManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
for (NSNumber *timestamp in timestamps) {
NSString *randomText = [self randomText];
{
TSIncomingMessage *message =
[[TSIncomingMessage alloc] initWithTimestamp:timestamp.unsignedLongLongValue
inThread:thread
authorId:recipientId
sourceDeviceId:0
messageBody:randomText];
[message markAsReadWithTransaction:transaction sendReadReceipt:NO updateExpiration:NO];
}
{
TSOutgoingMessage *message =
[[TSOutgoingMessage alloc] initWithTimestamp:timestamp.unsignedLongLongValue
inThread:thread
messageBody:randomText];
[message saveWithTransaction:transaction];
[message updateWithMessageState:TSOutgoingMessageStateSentToService transaction:transaction];
[message updateWithSentRecipient:recipientId transaction:transaction];
[message updateWithDeliveredToRecipientId:recipientId
deliveryTimestamp:timestamp
transaction:transaction];
[message updateWithReadRecipientId:recipientId
readTimestamp:timestamp.unsignedLongLongValue
transaction:transaction];
}
}
}];
}
@end
NS_ASSUME_NONNULL_END

@ -211,7 +211,7 @@ class MessageDetailViewController: OWSViewController, UIScrollViewDelegate, Medi
}
for recipientId in thread.recipientIdentifiers {
let (recipientStatus, statusMessage) = MessageRecipientStatusUtils.recipientStatusAndStatusMessage(outgoingMessage: outgoingMessage, recipientId: recipientId, referenceView: self.view)
let (recipientStatus, shortStatusMessage, longStatusMessage) = MessageRecipientStatusUtils.recipientStatusAndStatusMessage(outgoingMessage: outgoingMessage, recipientId: recipientId, referenceView: self.view)
guard recipientStatus == recipientStatusGroup else {
continue
@ -229,9 +229,11 @@ class MessageDetailViewController: OWSViewController, UIScrollViewDelegate, Medi
let cell = ContactTableViewCell()
cell.configure(withRecipientId: recipientId, contactsManager: self.contactsManager)
let statusLabel = UILabel()
statusLabel.text = statusMessage
// We use the "short" status message to avoid being redundant with the section title.
statusLabel.text = shortStatusMessage
statusLabel.textColor = UIColor.ows_darkGray
statusLabel.font = UIFont.ows_footnote()
statusLabel.adjustsFontSizeToFitWidth = true
statusLabel.sizeToFit()
cell.accessoryView = statusLabel
cell.autoSetDimension(.height, toSize: ContactTableViewCell.rowHeight())
@ -258,12 +260,14 @@ class MessageDetailViewController: OWSViewController, UIScrollViewDelegate, Medi
rows.append(valueRow(name: NSLocalizedString("MESSAGE_METADATA_VIEW_SENT_DATE_TIME",
comment: "Label for the 'sent date & time' field of the 'message metadata' view."),
value: DateUtil.formatPastTimestampRelativeToNow(message.timestamp)))
value: DateUtil.formatPastTimestampRelativeToNow(message.timestamp,
isRTL:self.view.isRTL())))
if message as? TSIncomingMessage != nil {
rows.append(valueRow(name: NSLocalizedString("MESSAGE_METADATA_VIEW_RECEIVED_DATE_TIME",
comment: "Label for the 'received date & time' field of the 'message metadata' view."),
value: DateUtil.formatPastTimestampRelativeToNow(message.timestampForSorting())))
value: DateUtil.formatPastTimestampRelativeToNow(message.timestampForSorting(),
isRTL:self.view.isRTL())))
}
rows += addAttachmentMetadataRows()

@ -1,5 +1,5 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
@ -56,7 +56,7 @@ class MessageRecipientStatusUtils: NSObject {
public class func recipientStatus(outgoingMessage: TSOutgoingMessage,
recipientId: String,
referenceView: UIView) -> MessageRecipientStatus {
let (messageRecipientStatus, _) = recipientStatusAndStatusMessage(outgoingMessage: outgoingMessage,
let (messageRecipientStatus, _, _) = recipientStatusAndStatusMessage(outgoingMessage: outgoingMessage,
recipientId: recipientId,
referenceView: referenceView)
return messageRecipientStatus
@ -64,20 +64,31 @@ class MessageRecipientStatusUtils: NSObject {
// This method is per-recipient and "biased towards success".
// See comments above.
public class func statusMessage(outgoingMessage: TSOutgoingMessage,
public class func shortStatusMessage(outgoingMessage: TSOutgoingMessage,
recipientId: String,
referenceView: UIView) -> String {
let (_, shortStatusMessage, _) = recipientStatusAndStatusMessage(outgoingMessage: outgoingMessage,
recipientId: recipientId,
referenceView: referenceView)
return shortStatusMessage
}
// This method is per-recipient and "biased towards success".
// See comments above.
public class func longStatusMessage(outgoingMessage: TSOutgoingMessage,
recipientId: String,
referenceView: UIView) -> String {
let (_, statusMessage) = recipientStatusAndStatusMessage(outgoingMessage: outgoingMessage,
let (_, _, longStatusMessage) = recipientStatusAndStatusMessage(outgoingMessage: outgoingMessage,
recipientId: recipientId,
referenceView: referenceView)
return statusMessage
return longStatusMessage
}
// This method is per-recipient and "biased towards success".
// See comments above.
public class func recipientStatusAndStatusMessage(outgoingMessage: TSOutgoingMessage,
recipientId: String,
referenceView: UIView) -> (MessageRecipientStatus, String) {
referenceView: UIView) -> (status: MessageRecipientStatus, shortStatusMessage: String, longStatusMessage: String) {
// Legacy messages don't have "recipient read" state or "per-recipient delivery" state,
// so we fall back to `TSOutgoingMessageState` which is not per-recipient and therefore
// might be misleading.
@ -85,49 +96,53 @@ class MessageRecipientStatusUtils: NSObject {
let recipientReadMap = outgoingMessage.recipientReadMap
if let readTimestamp = recipientReadMap[recipientId] {
assert(outgoingMessage.messageState == .sentToService)
let statusMessage = NSLocalizedString("MESSAGE_STATUS_READ", comment:"message footer for read messages").rtlSafeAppend(" ", referenceView:referenceView)
.rtlSafeAppend(
DateUtil.formatPastTimestampRelativeToNow(readTimestamp.uint64Value), referenceView:referenceView)
return (.read, statusMessage)
let timestampString = DateUtil.formatPastTimestampRelativeToNow(readTimestamp.uint64Value,
isRTL:referenceView.isRTL())
let shortStatusMessage = timestampString
let longStatusMessage = NSLocalizedString("MESSAGE_STATUS_READ", comment:"message footer for read messages").rtlSafeAppend(" ", referenceView:referenceView)
.rtlSafeAppend(timestampString, referenceView:referenceView)
return (status:.read, shortStatusMessage:shortStatusMessage, longStatusMessage:longStatusMessage)
}
let recipientDeliveryMap = outgoingMessage.recipientDeliveryMap
if let deliveryTimestamp = recipientDeliveryMap[recipientId] {
assert(outgoingMessage.messageState == .sentToService)
let statusMessage = NSLocalizedString("MESSAGE_STATUS_DELIVERED",
let timestampString = DateUtil.formatPastTimestampRelativeToNow(deliveryTimestamp.uint64Value,
isRTL:referenceView.isRTL())
let shortStatusMessage = timestampString
let longStatusMessage = NSLocalizedString("MESSAGE_STATUS_DELIVERED",
comment:"message status for message delivered to their recipient.").rtlSafeAppend(" ", referenceView:referenceView)
.rtlSafeAppend(
DateUtil.formatPastTimestampRelativeToNow(deliveryTimestamp.uint64Value), referenceView:referenceView)
return (.delivered, statusMessage)
.rtlSafeAppend(timestampString, referenceView:referenceView)
return (status:.delivered, shortStatusMessage:shortStatusMessage, longStatusMessage:longStatusMessage)
}
if outgoingMessage.wasDelivered {
let statusMessage = NSLocalizedString("MESSAGE_STATUS_DELIVERED",
comment:"message status for message delivered to their recipient.")
return (.delivered, statusMessage)
return (status:.delivered, shortStatusMessage:statusMessage, longStatusMessage:statusMessage)
}
if outgoingMessage.messageState == .unsent {
let statusMessage = NSLocalizedString("MESSAGE_STATUS_FAILED", comment:"message footer for failed messages")
return (.failed, statusMessage)
return (status:.failed, shortStatusMessage:statusMessage, longStatusMessage:statusMessage)
} else if outgoingMessage.messageState == .sentToService ||
outgoingMessage.wasSent(toRecipient:recipientId) {
let statusMessage =
NSLocalizedString("MESSAGE_STATUS_SENT",
comment:"message footer for sent messages")
return (.sent, statusMessage)
return (status:.sent, shortStatusMessage:statusMessage, longStatusMessage:statusMessage)
} else if outgoingMessage.hasAttachments() {
assert(outgoingMessage.messageState == .attemptingOut)
let statusMessage = NSLocalizedString("MESSAGE_STATUS_UPLOADING",
comment:"message footer while attachment is uploading")
return (.uploading, statusMessage)
return (status:.uploading, shortStatusMessage:statusMessage, longStatusMessage:statusMessage)
} else {
assert(outgoingMessage.messageState == .attemptingOut)
let statusMessage = NSLocalizedString("MESSAGE_STATUS_SENDING",
comment:"message status while message is sending.")
return (.sending, statusMessage)
return (status:.sending, shortStatusMessage:statusMessage, longStatusMessage:statusMessage)
}
}

@ -1,7 +1,9 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@interface DateUtil : NSObject
+ (NSDateFormatter *)dateFormatter;
@ -11,6 +13,8 @@
+ (BOOL)dateIsToday:(NSDate *)date;
+ (NSString *)formatPastTimestampRelativeToNow:(uint64_t)pastTimestamp
NS_SWIFT_NAME(formatPastTimestampRelativeToNow(_:));
isRTL:(BOOL)isRTL NS_SWIFT_NAME(formatPastTimestampRelativeToNow(_:isRTL:));
@end
NS_ASSUME_NONNULL_END

@ -1,10 +1,13 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "DateUtil.h"
#import <SignalMessaging/NSString+OWS.h>
#import <SignalServiceKit/NSDate+OWS.h>
NS_ASSUME_NONNULL_BEGIN
static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE";
@implementation DateUtil
@ -65,7 +68,13 @@ static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE";
return [self date:[NSDate date] isEqualToDateIgnoringTime:date];
}
+ (NSString *)formatPastTimestampRelativeToNow:(uint64_t)pastTimestamp
+ (BOOL)dateIsYesterday:(NSDate *)date
{
NSDate *yesterday = [NSDate ows_dateWithMillisecondsSince1970:[NSDate ows_millisecondTimeStamp] - kDayInMs];
return [self date:yesterday isEqualToDateIgnoringTime:date];
}
+ (NSString *)formatPastTimestampRelativeToNow:(uint64_t)pastTimestamp isRTL:(BOOL)isRTL
{
OWSCAssert(pastTimestamp > 0);
@ -73,13 +82,18 @@ static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE";
BOOL isFutureTimestamp = pastTimestamp >= nowTimestamp;
NSDate *pastDate = [NSDate ows_dateWithMillisecondsSince1970:pastTimestamp];
NSString *dateString;
if (isFutureTimestamp || [self dateIsToday:pastDate]) {
return [[self timeFormatter] stringFromDate:pastDate];
} else if (![self dateIsOlderThanOneWeek:pastDate]) {
return [[self weekdayFormatter] stringFromDate:pastDate];
dateString = NSLocalizedString(@"DATE_TODAY", @"The current day.");
} else if ([self dateIsYesterday:pastDate]) {
dateString = NSLocalizedString(@"DATE_YESTERDAY", @"The day before today.");
} else {
return [[self dateFormatter] stringFromDate:pastDate];
dateString = [[self dateFormatter] stringFromDate:pastDate];
}
return [[dateString rtlSafeAppend:@" " isRTL:isRTL] rtlSafeAppend:[[self timeFormatter] stringFromDate:pastDate]
isRTL:isRTL];
}
@end
NS_ASSUME_NONNULL_END

@ -493,6 +493,12 @@
/* Title shown while the app is updating its database. */
"DATABASE_VIEW_OVERLAY_TITLE" = "Updating Database";
/* The current day. */
"DATE_TODAY" = "Today";
/* The day before today. */
"DATE_YESTERDAY" = "Yesterday";
/* Message indicating that the debug log is being uploaded. */
"DEBUG_LOG_ACTIVITY_INDICATOR" = "Sending Debug Log...";

@ -1,5 +1,5 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN
- (NSString *)ows_stripped;
- (NSString *)rtlSafeAppend:(NSString *)string referenceView:(UIView *)referenceView;
- (NSString *)rtlSafeAppend:(NSString *)string isRTL:(BOOL)isRTL;
- (NSString *)digitsOnly;

@ -1,5 +1,5 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "NSString+OWS.h"
@ -19,7 +19,14 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert(string);
OWSAssert(referenceView);
if ([referenceView isRTL]) {
return [self rtlSafeAppend:string isRTL:referenceView.isRTL];
}
- (NSString *)rtlSafeAppend:(NSString *)string isRTL:(BOOL)isRTL
{
OWSAssert(string);
if (isRTL) {
return [string stringByAppendingString:self];
} else {
return [self stringByAppendingString:string];
@ -28,7 +35,8 @@ NS_ASSUME_NONNULL_BEGIN
- (NSString *)removeAllCharactersIn:(NSCharacterSet *)characterSet
{
OWSAssert(characterSet != nil);
OWSAssert(characterSet);
return [[self componentsSeparatedByCharactersInSet:characterSet] componentsJoinedByString:@""];
}

Loading…
Cancel
Save