Format message statuses with date if possible.
// FREEBIE
This commit is contained in:
parent
0b535ae811
commit
d557817bb4
@ -4,11 +4,13 @@
|
||||
|
||||
#import "AppSettingsViewController.h"
|
||||
#import "AttachmentSharing.h"
|
||||
#import "DateUtil.h"
|
||||
#import "DebugUIPage.h"
|
||||
#import "Environment.h"
|
||||
#import "FLAnimatedImage.h"
|
||||
#import "FingerprintViewController.h"
|
||||
#import "HomeViewController.h"
|
||||
#import "NSAttributedString+OWS.h"
|
||||
#import "NotificationsManager.h"
|
||||
#import "OWSAnyTouchGestureRecognizer.h"
|
||||
#import "OWSAudioAttachmentPlayer.h"
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#import "BlockListUIUtils.h"
|
||||
#import "BlockListViewController.h"
|
||||
#import "ContactsViewHelper.h"
|
||||
#import "DateUtil.h"
|
||||
#import "DebugUITableViewController.h"
|
||||
#import "Environment.h"
|
||||
#import "FingerprintViewController.h"
|
||||
@ -2151,22 +2152,22 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
|
||||
return [[NSAttributedString alloc]
|
||||
initWithString:NSLocalizedString(@"MESSAGE_STATUS_FAILED", @"message footer for failed messages")];
|
||||
} else if (outgoingMessage.messageState == TSOutgoingMessageStateSentToService) {
|
||||
NSString *text = (outgoingMessage.wasDelivered
|
||||
? NSLocalizedString(@"MESSAGE_STATUS_DELIVERED", @"message footer for delivered messages")
|
||||
: NSLocalizedString(@"MESSAGE_STATUS_SENT", @"message footer for sent messages"));
|
||||
NSAttributedString *result = [[NSAttributedString alloc] initWithString:text];
|
||||
if ([OWSReadReceiptManager.sharedManager areReadReceiptsEnabled] && outgoingMessage.wasDelivered
|
||||
&& outgoingMessage.recipientReadMap.count > 0) {
|
||||
NSAttributedString *checkmark = [[NSAttributedString alloc]
|
||||
initWithString:@"\uf00c "
|
||||
attributes:@{
|
||||
NSFontAttributeName : [UIFont ows_fontAwesomeFont:10.f],
|
||||
NSForegroundColorAttributeName : [UIColor ows_materialBlueColor],
|
||||
}];
|
||||
NSAttributedString *spacing = [[NSAttributedString alloc] initWithString:@" "];
|
||||
result = [[checkmark rtlSafeAppend:spacing referenceView:self.view] rtlSafeAppend:result
|
||||
referenceView:self.view];
|
||||
NSString *text;
|
||||
if (outgoingMessage.wasDelivered) {
|
||||
NSNumber *_Nullable firstRecipientReadTimestamp = [outgoingMessage firstRecipientReadTimestamp];
|
||||
if ([OWSReadReceiptManager.sharedManager areReadReceiptsEnabled] && firstRecipientReadTimestamp) {
|
||||
text = NSLocalizedString(@"MESSAGE_STATUS_READ", @"message footer for read messages");
|
||||
text = [text rtlSafeAppend:@" " referenceView:self.view];
|
||||
text = [text rtlSafeAppend:[DateUtil formatPastTimestampRelativeToNow:firstRecipientReadTimestamp
|
||||
.unsignedLongLongValue]
|
||||
referenceView:self.view];
|
||||
} else {
|
||||
text = NSLocalizedString(@"MESSAGE_STATUS_DELIVERED", @"message footer for delivered messages");
|
||||
}
|
||||
} else {
|
||||
text = NSLocalizedString(@"MESSAGE_STATUS_SENT", @"message footer for sent messages");
|
||||
}
|
||||
NSAttributedString *result = [[NSAttributedString alloc] initWithString:text];
|
||||
|
||||
// Show when it's the last message in the thread
|
||||
if (indexPath.item == [self.collectionView numberOfItemsInSection:indexPath.section] - 1) {
|
||||
|
||||
@ -21,14 +21,6 @@ class MessageMetadataViewController: OWSViewController {
|
||||
var attachmentStream: TSAttachmentStream?
|
||||
var messageBody: String?
|
||||
|
||||
static let dateFormatter: DateFormatter = CreateDateFormatter()
|
||||
private class func CreateDateFormatter() -> DateFormatter {
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateStyle = .short
|
||||
dateFormatter.timeStyle = .long
|
||||
return dateFormatter
|
||||
}
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
@available(*, unavailable, message:"use message: constructor instead.")
|
||||
@ -127,16 +119,14 @@ class MessageMetadataViewController: OWSViewController {
|
||||
}
|
||||
}
|
||||
|
||||
let sentDate = NSDate.ows_date(withMillisecondsSince1970:message.timestamp)
|
||||
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:MessageMetadataViewController.dateFormatter.string(from:sentDate)))
|
||||
value:DateUtil.formatPastTimestampRelative(toNow:message.timestamp)))
|
||||
|
||||
if let _ = message as? TSIncomingMessage {
|
||||
let receivedDate = message.dateForSorting()
|
||||
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:MessageMetadataViewController.dateFormatter.string(from:receivedDate)))
|
||||
value:DateUtil.formatPastTimestampRelative(toNow:message.timestampForSorting())))
|
||||
}
|
||||
|
||||
// TODO: We could include the "disappearing messages" state here.
|
||||
@ -287,19 +277,18 @@ class MessageMetadataViewController: OWSViewController {
|
||||
let recipientReadMap = message.recipientReadMap
|
||||
if let readTimestamp = recipientReadMap[recipientId] {
|
||||
assert(message.messageState == .sentToService)
|
||||
let readDate = NSDate.ows_date(withMillisecondsSince1970:readTimestamp.uint64Value)
|
||||
return String(format:NSLocalizedString("MESSAGE_STATUS_READ_WITH_TIMESTAMP_FORMAT",
|
||||
comment: "message status for messages read by the recipient. Embeds: {{the date and time the message was read}}."),
|
||||
MessageMetadataViewController.dateFormatter.string(from:readDate))
|
||||
return NSLocalizedString("MESSAGE_STATUS_READ", comment:"message footer for read messages").rtlSafeAppend(" ", referenceView:self.view)
|
||||
.rtlSafeAppend(
|
||||
DateUtil.formatPastTimestampRelative(toNow:readTimestamp.uint64Value), referenceView:self.view)
|
||||
}
|
||||
|
||||
let recipientDeliveryMap = message.recipientDeliveryMap
|
||||
if let deliveryTimestamp = recipientDeliveryMap[recipientId] {
|
||||
assert(message.messageState == .sentToService)
|
||||
let deliveryDate = NSDate.ows_date(withMillisecondsSince1970:deliveryTimestamp.uint64Value)
|
||||
return String(format:NSLocalizedString("MESSAGE_STATUS_DELIVERED_WITH_TIMESTAMP_FORMAT",
|
||||
comment: "message status for messages delivered to the recipient. Embeds: {{the date and time the message was delivered}}."),
|
||||
MessageMetadataViewController.dateFormatter.string(from:deliveryDate))
|
||||
return NSLocalizedString("MESSAGE_STATUS_DELIVERED",
|
||||
comment:"message status for message delivered to their recipient.").rtlSafeAppend(" ", referenceView:self.view)
|
||||
.rtlSafeAppend(
|
||||
DateUtil.formatPastTimestampRelative(toNow:deliveryTimestamp.uint64Value), referenceView:self.view)
|
||||
}
|
||||
|
||||
if message.wasDelivered {
|
||||
|
||||
@ -5,10 +5,12 @@
|
||||
@interface DateUtil : NSObject
|
||||
|
||||
+ (NSDateFormatter *)dateFormatter;
|
||||
+ (NSDateFormatter *)weekdayFormatter;
|
||||
//+ (NSDateFormatter *)weekdayFormatter;
|
||||
+ (NSDateFormatter *)timeFormatter;
|
||||
+ (BOOL)dateIsOlderThanOneDay:(NSDate *)date;
|
||||
+ (BOOL)dateIsOlderThanOneWeek:(NSDate *)date;
|
||||
+ (BOOL)dateIsToday:(NSDate *)date;
|
||||
|
||||
+ (NSString *)formatPastTimestampRelativeToNow:(uint64_t)pastTimestamp;
|
||||
|
||||
@end
|
||||
|
||||
@ -53,4 +53,36 @@ static NSString *const DATE_FORMAT_WEEKDAY = @"EEEE";
|
||||
return [self date:[NSDate date] isEqualToDateIgnoringTime:date];
|
||||
}
|
||||
|
||||
+ (NSString *)formatPastTimestampRelativeToNow:(uint64_t)pastTimestamp
|
||||
{
|
||||
OWSCAssert(pastTimestamp > 0);
|
||||
|
||||
uint64_t nowTimestamp = [NSDate ows_millisecondTimeStamp];
|
||||
if (pastTimestamp >= nowTimestamp) {
|
||||
OWSCFail(@"%@ Unexpected timestamp", self.tag);
|
||||
return NSLocalizedString(@"TIME_NOW", @"Indicates that the event happened now.");
|
||||
}
|
||||
|
||||
NSDate *pastDate = [NSDate ows_dateWithMillisecondsSince1970:pastTimestamp];
|
||||
if ([self dateIsToday:pastDate]) {
|
||||
return [[self timeFormatter] stringFromDate:pastDate];
|
||||
} else if (![self dateIsOlderThanOneWeek:pastDate]) {
|
||||
return [[self weekdayFormatter] stringFromDate:pastDate];
|
||||
} else {
|
||||
return [[self dateFormatter] stringFromDate:pastDate];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Logging
|
||||
|
||||
+ (NSString *)tag
|
||||
{
|
||||
return [NSString stringWithFormat:@"[%@]", self.class];
|
||||
}
|
||||
|
||||
- (NSString *)tag
|
||||
{
|
||||
return self.class.tag;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -4,6 +4,12 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSString (OWS)
|
||||
|
||||
- (NSString *)rtlSafeAppend:(NSString *)string referenceView:(UIView *)referenceView;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSAttributedString (OWS)
|
||||
|
||||
- (NSAttributedString *)rtlSafeAppend:(NSAttributedString *)string referenceView:(UIView *)referenceView;
|
||||
|
||||
@ -7,6 +7,22 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation NSString (OWS)
|
||||
|
||||
- (NSString *)rtlSafeAppend:(NSString *)string referenceView:(UIView *)referenceView
|
||||
{
|
||||
OWSAssert(string);
|
||||
OWSAssert(referenceView);
|
||||
|
||||
if ([referenceView isRTL]) {
|
||||
return [string stringByAppendingString:self];
|
||||
} else {
|
||||
return [self stringByAppendingString:string];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSAttributedString (OWS)
|
||||
|
||||
- (NSAttributedString *)rtlSafeAppend:(NSAttributedString *)string referenceView:(UIView *)referenceView
|
||||
|
||||
@ -839,6 +839,9 @@
|
||||
/* message footer for failed messages */
|
||||
"MESSAGE_STATUS_FAILED" = "Sending failed. Tap for info.";
|
||||
|
||||
/* message footer for read messages */
|
||||
"MESSAGE_STATUS_READ" = "Read";
|
||||
|
||||
/* message status for messages read by the recipient. Embeds: {{the date and time the message was read}}. */
|
||||
"MESSAGE_STATUS_READ_WITH_TIMESTAMP_FORMAT" = "Read %@";
|
||||
|
||||
@ -1520,6 +1523,9 @@
|
||||
/* {{number of weeks}}, embedded in strings, e.g. 'Alice updated disappearing messages expiration to {{5 weeks}}'. See other *_TIME_AMOUNT strings */
|
||||
"TIME_AMOUNT_WEEKS" = "%@ weeks";
|
||||
|
||||
/* Indicates that the event happened now. */
|
||||
"TIME_NOW" = "Now";
|
||||
|
||||
/* Label for the cancel button in an alert or action sheet. */
|
||||
"TXT_CANCEL_TITLE" = "Cancel";
|
||||
|
||||
|
||||
@ -187,6 +187,7 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) {
|
||||
- (void)updateWithReadRecipientId:(NSString *)recipientId
|
||||
readTimestamp:(uint64_t)readTimestamp
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
- (nullable NSNumber *)firstRecipientReadTimestamp;
|
||||
|
||||
#pragma mark - Sent Recipients
|
||||
|
||||
|
||||
@ -435,6 +435,17 @@ NSString *const kTSOutgoingMessageSentRecipientAll = @"kTSOutgoingMessageSentRec
|
||||
}];
|
||||
}
|
||||
|
||||
- (nullable NSNumber *)firstRecipientReadTimestamp
|
||||
{
|
||||
NSNumber *result = nil;
|
||||
for (NSNumber *timestamp in self.recipientReadMap.allValues) {
|
||||
if (!result || (result.unsignedLongLongValue > timestamp.unsignedLongLongValue)) {
|
||||
result = timestamp;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (OWSSignalServiceProtosDataMessageBuilder *)dataMessageBuilder
|
||||
|
||||
@ -24,6 +24,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
+ (NSDate *)ows_dateWithMillisecondsSince1970:(uint64_t)milliseconds;
|
||||
+ (uint64_t)ows_millisecondsSince1970ForDate:(NSDate *)date;
|
||||
|
||||
+ (NSString *)formatPastTimestampRelativeToNow:(uint64_t)timestamp;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
Loading…
Reference in New Issue
Block a user