diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj
index c0888091c..3f418be51 100644
--- a/Signal.xcodeproj/project.pbxproj
+++ b/Signal.xcodeproj/project.pbxproj
@@ -50,7 +50,6 @@
 		34B3F8851E8DF1700035BE1A /* NewGroupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8551E8DF1700035BE1A /* NewGroupViewController.m */; };
 		34B3F8861E8DF1700035BE1A /* NotificationSettingsOptionsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8571E8DF1700035BE1A /* NotificationSettingsOptionsViewController.m */; };
 		34B3F8871E8DF1700035BE1A /* NotificationSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8591E8DF1700035BE1A /* NotificationSettingsViewController.m */; };
-		34B3F8881E8DF1700035BE1A /* OversizeTextMessageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F85A1E8DF1700035BE1A /* OversizeTextMessageViewController.swift */; };
 		34B3F8891E8DF1700035BE1A /* OWSConversationSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F85C1E8DF1700035BE1A /* OWSConversationSettingsViewController.m */; };
 		34B3F88A1E8DF1700035BE1A /* OWSLinkDeviceViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F85E1E8DF1700035BE1A /* OWSLinkDeviceViewController.m */; };
 		34B3F88B1E8DF1700035BE1A /* OWSLinkedDevicesTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8601E8DF1700035BE1A /* OWSLinkedDevicesTableViewController.m */; };
@@ -477,7 +476,6 @@
 		34B3F8571E8DF1700035BE1A /* NotificationSettingsOptionsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NotificationSettingsOptionsViewController.m; sourceTree = "<group>"; };
 		34B3F8581E8DF1700035BE1A /* NotificationSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotificationSettingsViewController.h; sourceTree = "<group>"; };
 		34B3F8591E8DF1700035BE1A /* NotificationSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NotificationSettingsViewController.m; sourceTree = "<group>"; };
-		34B3F85A1E8DF1700035BE1A /* OversizeTextMessageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OversizeTextMessageViewController.swift; sourceTree = "<group>"; };
 		34B3F85B1E8DF1700035BE1A /* OWSConversationSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSConversationSettingsViewController.h; sourceTree = "<group>"; };
 		34B3F85C1E8DF1700035BE1A /* OWSConversationSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSConversationSettingsViewController.m; sourceTree = "<group>"; };
 		34B3F85D1E8DF1700035BE1A /* OWSLinkDeviceViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSLinkDeviceViewController.h; sourceTree = "<group>"; };
@@ -1048,7 +1046,6 @@
 				34B3F8571E8DF1700035BE1A /* NotificationSettingsOptionsViewController.m */,
 				34B3F8581E8DF1700035BE1A /* NotificationSettingsViewController.h */,
 				34B3F8591E8DF1700035BE1A /* NotificationSettingsViewController.m */,
-				34B3F85A1E8DF1700035BE1A /* OversizeTextMessageViewController.swift */,
 				34CCAF391F0C2748004084F4 /* OWSAddToContactViewController.h */,
 				34CCAF3A1F0C2748004084F4 /* OWSAddToContactViewController.m */,
 				34533F161EA8D2070006114F /* OWSAudioAttachmentPlayer.h */,
@@ -2291,7 +2288,6 @@
 				34D1F0881F8678AA0066283D /* ConversationViewLayout.m in Sources */,
 				76EB068618170B34006006FC /* ContactTableViewCell.m in Sources */,
 				3497DBEF1ECE2E4700DB2605 /* DomainFrontingCountryViewController.m in Sources */,
-				34B3F8881E8DF1700035BE1A /* OversizeTextMessageViewController.swift in Sources */,
 				452314A01F7E9E18003A428C /* DirectionalPanGestureRecognizer.swift in Sources */,
 				34330AA31E79686200DF2FB9 /* OWSProgressView.m in Sources */,
 				34B3F8A21E8EA6040035BE1A /* ViewControllerUtils.m in Sources */,
diff --git a/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h b/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h
index a94f6b944..22b18ae08 100644
--- a/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h
+++ b/Signal/src/ViewControllers/ConversationView/Cells/ConversationViewCell.h
@@ -20,14 +20,14 @@ NS_ASSUME_NONNULL_BEGIN
                   imageView:(UIView *)imageView;
 - (void)didTapVideoViewItem:(ConversationViewItem *)viewItem attachmentStream:(TSAttachmentStream *)attachmentStream;
 - (void)didTapAudioViewItem:(ConversationViewItem *)viewItem attachmentStream:(TSAttachmentStream *)attachmentStream;
-- (void)didTapOversizeTextMessage:(NSString *)displayableText attachmentStream:(TSAttachmentStream *)attachmentStream;
+- (void)didTapTruncatedTextMessage:(ConversationViewItem *)conversationItem;
 - (void)didTapFailedIncomingAttachment:(ConversationViewItem *)viewItem
                      attachmentPointer:(TSAttachmentPointer *)attachmentPointer;
 - (void)didTapFailedOutgoingMessage:(TSOutgoingMessage *)message;
 - (void)didPanWithGestureRecognizer:(UIPanGestureRecognizer *)gestureRecognizer
                            viewItem:(ConversationViewItem *)conversationItem;
 
-- (void)showMetadataViewForMessage:(TSMessage *)message;
+- (void)showMetadataViewForViewItem:(ConversationViewItem *)conversationItem;
 
 #pragma mark - System Cell
 
diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m
index cbcec0aec..4901da5ec 100644
--- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m
+++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m
@@ -73,6 +73,7 @@ NS_ASSUME_NONNULL_BEGIN
 @property (nonatomic) BubbleMaskingView *payloadView;
 @property (nonatomic) UILabel *dateHeaderLabel;
 @property (nonatomic) UITextView *textView;
+@property (nonatomic, nullable) UILabel *tapForMoreLabel;
 @property (nonatomic, nullable) UIImageView *bubbleImageView;
 @property (nonatomic, nullable) AttachmentUploadView *attachmentUploadView;
 @property (nonatomic, nullable) UIImageView *stillImageView;
@@ -130,7 +131,6 @@ NS_ASSUME_NONNULL_BEGIN
     self.textView = [UITextView new];
     // Honor dynamic type in the message bodies.
     self.textView.font = [self textMessageFont];
-    self.textView.font = [UIFont ows_regularFontWithSize:16.f];
     self.textView.backgroundColor = [UIColor clearColor];
     self.textView.opaque = NO;
     self.textView.editable = NO;
@@ -183,17 +183,27 @@ NS_ASSUME_NONNULL_BEGIN
     return [UIFont ows_dynamicTypeBodyFont];
 }
 
+- (UIFont *)tapForMoreFont
+{
+    return [UIFont ows_regularFontWithSize:12.f];
+}
+
+- (CGFloat)tapForMoreHeight
+{
+    return (CGFloat)ceil([self tapForMoreFont].lineHeight * 1.25);
+}
+
 - (OWSMessageCellType)cellType
 {
     return self.viewItem.messageCellType;
 }
 
-- (nullable NSString *)textMessage
+- (nullable DisplayableText *)displayableText
 {
     // This should always be valid for the appropriate cell types.
-    OWSAssert(self.viewItem.textMessage);
+    OWSAssert(self.viewItem.displayableText);
 
-    return self.viewItem.textMessage;
+    return self.viewItem.displayableText;
 }
 
 - (nullable TSAttachmentStream *)attachmentStream
@@ -571,7 +581,7 @@ NS_ASSUME_NONNULL_BEGIN
 {
     self.bubbleImageView.hidden = NO;
     self.textView.hidden = NO;
-    self.textView.text = self.textMessage;
+    self.textView.text = self.displayableText.displayText;
     UIColor *textColor = [self textColor];
     self.textView.textColor = textColor;
     self.textView.font = [self textMessageFont];
@@ -592,12 +602,34 @@ NS_ASSUME_NONNULL_BEGIN
             = (UIDataDetectorTypeLink | UIDataDetectorTypeAddress | UIDataDetectorTypeCalendarEvent);
     }
 
-    self.contentConstraints = @[
-        [self.textView autoPinLeadingToSuperviewWithMargin:self.textLeadingMargin],
-        [self.textView autoPinTrailingToSuperviewWithMargin:self.textTrailingMargin],
-        [self.textView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:self.textVMargin],
-        [self.textView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:self.textVMargin],
-    ];
+    if (self.displayableText.isTextTruncated) {
+        self.tapForMoreLabel = [UILabel new];
+        self.tapForMoreLabel.text = NSLocalizedString(@"CONVERSATION_VIEW_OVERSIZE_TEXT_TAP_FOR_MORE",
+            @"Indicator on truncated text messages that they can be tapped to see the entire text message.");
+        self.tapForMoreLabel.font = [self tapForMoreFont];
+        self.tapForMoreLabel.textColor = [textColor colorWithAlphaComponent:0.85];
+        self.tapForMoreLabel.textAlignment = [self.tapForMoreLabel textAlignmentUnnatural];
+        [self.bubbleImageView addSubview:self.tapForMoreLabel];
+
+        self.contentConstraints = @[
+            [self.textView autoPinLeadingToSuperviewWithMargin:self.textLeadingMargin],
+            [self.textView autoPinTrailingToSuperviewWithMargin:self.textTrailingMargin],
+            [self.textView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:self.textVMargin],
+
+            [self.tapForMoreLabel autoPinLeadingToSuperviewWithMargin:self.textLeadingMargin],
+            [self.tapForMoreLabel autoPinTrailingToSuperviewWithMargin:self.textTrailingMargin],
+            [self.tapForMoreLabel autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.textView],
+            [self.tapForMoreLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:self.textVMargin],
+            [self.tapForMoreLabel autoSetDimension:ALDimensionHeight toSize:self.tapForMoreHeight],
+        ];
+    } else {
+        self.contentConstraints = @[
+            [self.textView autoPinLeadingToSuperviewWithMargin:self.textLeadingMargin],
+            [self.textView autoPinTrailingToSuperviewWithMargin:self.textTrailingMargin],
+            [self.textView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:self.textVMargin],
+            [self.textView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:self.textVMargin],
+        ];
+    }
 }
 
 - (void)loadForStillImageDisplay
@@ -772,11 +804,12 @@ NS_ASSUME_NONNULL_BEGIN
             CGFloat textVMargin = self.textVMargin;
             const int maxTextWidth = (int)floor(maxMessageWidth - (leftMargin + rightMargin));
 
-            self.textView.text = self.textMessage;
+            self.textView.text = self.displayableText.displayText;
             self.textView.font = [self textMessageFont];
             CGSize textSize = [self.textView sizeThatFits:CGSizeMake(maxTextWidth, CGFLOAT_MAX)];
+            CGFloat tapForMoreHeight = (self.displayableText.isTextTruncated ? [self tapForMoreHeight] : 0.f);
             cellSize = CGSizeMake((CGFloat)ceil(textSize.width + leftMargin + rightMargin),
-                (CGFloat)ceil(textSize.height + textVMargin * 2));
+                (CGFloat)ceil(textSize.height + textVMargin * 2 + tapForMoreHeight));
             break;
         }
         case OWSMessageCellType_StillImage:
@@ -907,6 +940,8 @@ NS_ASSUME_NONNULL_BEGIN
     self.textView.text = nil;
     self.textView.hidden = YES;
     self.textView.dataDetectorTypes = UIDataDetectorTypeNone;
+    [self.tapForMoreLabel removeFromSuperview];
+    self.tapForMoreLabel = nil;
     self.footerLabel.text = nil;
     self.footerLabel.hidden = YES;
     self.bubbleImageView.image = nil;
@@ -990,9 +1025,11 @@ NS_ASSUME_NONNULL_BEGIN
 
         switch (self.cellType) {
             case OWSMessageCellType_TextMessage:
-                break;
             case OWSMessageCellType_OversizeTextMessage:
-                [self.delegate didTapOversizeTextMessage:self.textMessage attachmentStream:self.attachmentStream];
+                if (self.displayableText.isTextTruncated) {
+                    [self.delegate didTapTruncatedTextMessage:self.viewItem];
+                    return;
+                }
                 break;
             case OWSMessageCellType_StillImage:
                 [self.delegate didTapImageViewItem:self.viewItem
@@ -1093,7 +1130,7 @@ NS_ASSUME_NONNULL_BEGIN
 {
     OWSAssert([self.viewItem.interaction isKindOfClass:[TSMessage class]]);
 
-    [self.delegate showMetadataViewForMessage:self.message];
+    [self.delegate showMetadataViewForViewItem:self.viewItem];
 }
 
 - (BOOL)canBecomeFirstResponder
diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m
index c73c92901..0d9a8a5c3 100644
--- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m
+++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m
@@ -2040,18 +2040,17 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
     [self.audioAttachmentPlayer play];
 }
 
-- (void)didTapOversizeTextMessage:(NSString *)displayableText attachmentStream:(TSAttachmentStream *)attachmentStream
+- (void)didTapTruncatedTextMessage:(ConversationViewItem *)conversationItem
 {
     OWSAssert([NSThread isMainThread]);
-    OWSAssert(displayableText);
-    OWSAssert(attachmentStream);
+    OWSAssert(conversationItem);
 
-    // Tapping on incoming and outgoing "oversize text messages" should show the
-    // "oversize text message" view.
-    OversizeTextMessageViewController *messageVC =
-        [[OversizeTextMessageViewController alloc] initWithDisplayableText:displayableText
-                                                          attachmentStream:attachmentStream];
-    [self.navigationController pushViewController:messageVC animated:YES];
+    TSMessage *message = (TSMessage *)conversationItem.interaction;
+    MessageMetadataViewController *view =
+        [[MessageMetadataViewController alloc] initWithViewItem:conversationItem
+                                                        message:message
+                                                           mode:MessageMetadataViewModeFocusOnMessage];
+    [self.navigationController pushViewController:view animated:YES];
 }
 
 - (void)didTapFailedIncomingAttachment:(ConversationViewItem *)viewItem
@@ -2074,12 +2073,16 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
     [self handleUnsentMessageTap:message];
 }
 
-- (void)showMetadataViewForMessage:(TSMessage *)message
+- (void)showMetadataViewForViewItem:(ConversationViewItem *)conversationItem
 {
     OWSAssert([NSThread isMainThread]);
-    OWSAssert(message);
+    OWSAssert(conversationItem);
 
-    MessageMetadataViewController *view = [[MessageMetadataViewController alloc] initWithMessage:message];
+    TSMessage *message = (TSMessage *)conversationItem.interaction;
+    MessageMetadataViewController *view =
+        [[MessageMetadataViewController alloc] initWithViewItem:conversationItem
+                                                        message:message
+                                                           mode:MessageMetadataViewModeFocusOnMetadata];
     [self.navigationController pushViewController:view animated:YES];
 }
 
@@ -4085,7 +4088,10 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
                 // want to inadvertently clobber it here.
                 OWSAssert(self.navigationController.delegate == nil) self.navigationController.delegate = self;
                 TSMessage *message = (TSMessage *)interaction;
-                MessageMetadataViewController *view = [[MessageMetadataViewController alloc] initWithMessage:message];
+                MessageMetadataViewController *view =
+                    [[MessageMetadataViewController alloc] initWithViewItem:conversationItem
+                                                                    message:message
+                                                                       mode:MessageMetadataViewModeFocusOnMetadata];
                 [self.navigationController pushViewController:view animated:YES];
             } else {
                 OWSFail(@"%@ Can't show message metadata for message of type: %@", self.tag, [interaction class]);
diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h
index b8bcd6352..45ed5c93d 100644
--- a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h
+++ b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.h
@@ -22,6 +22,20 @@ typedef NS_ENUM(NSInteger, OWSMessageCellType) {
 
 NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
 
+#pragma mark -
+
+@interface DisplayableText : NSObject
+
+@property (nonatomic) NSString *fullText;
+
+@property (nonatomic) NSString *displayText;
+
+@property (nonatomic) BOOL isTextTruncated;
+
+@end
+
+#pragma mark -
+
 @class ConversationViewCell;
 @class OWSAudioMessageView;
 @class TSAttachmentPointer;
@@ -72,19 +86,11 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
 
 - (CGFloat)audioProgressSeconds;
 
-#pragma mark - Expiration
-
-// TODO:
-//@property (nonatomic, readonly) BOOL isExpiringMessage;
-//@property (nonatomic, readonly) BOOL shouldStartExpireTimer;
-//@property (nonatomic, readonly) double expiresAtSeconds;
-//@property (nonatomic, readonly) uint32_t expiresInSeconds;
-
 #pragma mark - View State Caching
 
 // These methods only apply to text & attachment messages.
 - (OWSMessageCellType)messageCellType;
-- (nullable NSString *)textMessage;
+- (nullable DisplayableText *)displayableText;
 - (nullable TSAttachmentStream *)attachmentStream;
 - (nullable TSAttachmentPointer *)attachmentPointer;
 - (CGSize)contentSize;
@@ -93,13 +99,6 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType);
 // if a load has previously failed.
 @property (nonatomic) BOOL didCellMediaFailToLoad;
 
-// TODO:
-//// Cells will request that this adapter clear its cached media views,
-//// but the adapter should only honor requests from the last cell to
-//// use its views.
-//- (void)setLastPresentingCell:(nullable id)cell;
-//- (void)clearCachedMediaViewsIfLastPresentingCell:(id)cell;
-
 #pragma mark - UIMenuController
 
 - (NSArray<UIMenuItem *> *)menuControllerItems;
diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m
index 14753c245..58a5a385a 100644
--- a/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m
+++ b/Signal/src/ViewControllers/ConversationView/ConversationViewItem.m
@@ -37,6 +37,14 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
     }
 }
 
+#pragma mark -
+
+@implementation DisplayableText
+
+@end
+
+#pragma mark -
+
 @interface ConversationViewItem ()
 
 @property (nonatomic, nullable) NSValue *cachedCellSize;
@@ -50,7 +58,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
 
 @property (nonatomic) BOOL hasViewState;
 @property (nonatomic) OWSMessageCellType messageCellType;
-@property (nonatomic, nullable) NSString *textMessage;
+@property (nonatomic, nullable) DisplayableText *displayableText;
 @property (nonatomic, nullable) TSAttachmentStream *attachmentStream;
 @property (nonatomic, nullable) TSAttachmentPointer *attachmentPointer;
 @property (nonatomic) CGSize contentSize;
@@ -85,7 +93,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
 
     self.hasViewState = NO;
     self.messageCellType = OWSMessageCellType_Unknown;
-    self.textMessage = nil;
+    self.displayableText = nil;
     self.attachmentStream = nil;
     self.attachmentPointer = nil;
     self.contentSize = CGSizeZero;
@@ -266,49 +274,71 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
     return cache;
 }
 
-- (NSString *)displayableTextForText:(NSString *)text interactionId:(NSString *)interactionId
+- (DisplayableText *)displayableTextForText:(NSString *)text interactionId:(NSString *)interactionId
 {
     OWSAssert(text);
     OWSAssert(interactionId.length > 0);
 
-    NSString *_Nullable displayableText = [[self displayableTextCache] objectForKey:interactionId];
+    return [self displayableTextForInteractionId:interactionId
+                                       textBlock:^{
+                                           return text;
+                                       }];
+}
+
+- (DisplayableText *)displayableTextForAttachmentStream:(TSAttachmentStream *)attachmentStream
+                                          interactionId:(NSString *)interactionId
+{
+    OWSAssert(attachmentStream);
+    OWSAssert(interactionId.length > 0);
+
+    return [self displayableTextForInteractionId:interactionId
+                                       textBlock:^{
+                                           NSData *textData = [NSData dataWithContentsOfURL:attachmentStream.mediaURL];
+                                           NSString *text =
+                                               [[NSString alloc] initWithData:textData encoding:NSUTF8StringEncoding];
+                                           return text;
+                                       }];
+}
+
+- (DisplayableText *)displayableTextForInteractionId:(NSString *)interactionId
+                                           textBlock:(NSString * (^_Nonnull)())textBlock
+{
+    OWSAssert(interactionId.length > 0);
+
+    DisplayableText *_Nullable displayableText = [[self displayableTextCache] objectForKey:interactionId];
     if (!displayableText) {
+        NSString *text = textBlock();
+
         // Only show up to 2kb of text.
         const NSUInteger kMaxTextDisplayLength = 2 * 1024;
         text = [text ows_stripped];
-        displayableText = [[DisplayableTextFilter new] displayableText:text];
-        if (displayableText.length > kMaxTextDisplayLength) {
+        NSString *fullText = [[[DisplayableTextFilter new] displayableText:text] ows_stripped];
+        displayableText = [DisplayableText new];
+        if (!fullText) {
+            displayableText.fullText = @"";
+        } else {
+            displayableText.fullText = fullText;
+        }
+        NSString *displayText = fullText;
+        if (displayText.length > kMaxTextDisplayLength) {
             // Trim whitespace before _AND_ after slicing the snipper from the string.
-            NSString *snippet = [
-                [[displayableText ows_stripped] substringWithRange:NSMakeRange(0, kMaxTextDisplayLength)] ows_stripped];
-            displayableText = [NSString stringWithFormat:NSLocalizedString(@"OVERSIZE_TEXT_DISPLAY_FORMAT",
-                                                             @"A display format for oversize text messages."),
-                                        snippet];
+            NSString *snippet = [[displayText substringWithRange:NSMakeRange(0, kMaxTextDisplayLength)] ows_stripped];
+            displayText = [NSString stringWithFormat:NSLocalizedString(@"OVERSIZE_TEXT_DISPLAY_FORMAT",
+                                                         @"A display format for oversize text messages."),
+                                    snippet];
+            displayableText.isTextTruncated = YES;
         }
-        if (!displayableText) {
-            displayableText = @"";
+        if (!displayText) {
+            displayableText.displayText = @"";
+        } else {
+            displayableText.displayText = displayText;
         }
+
         [[self displayableTextCache] setObject:displayableText forKey:interactionId];
     }
     return displayableText;
 }
 
-- (NSString *)displayableTextForAttachmentStream:(TSAttachmentStream *)attachmentStream
-                                   interactionId:(NSString *)interactionId
-{
-    OWSAssert(attachmentStream);
-    OWSAssert(interactionId.length > 0);
-
-    NSString *_Nullable displayableText = [[self displayableTextCache] objectForKey:interactionId];
-    if (displayableText) {
-        return displayableText;
-    }
-
-    NSData *textData = [NSData dataWithContentsOfURL:attachmentStream.mediaURL];
-    NSString *text = [[NSString alloc] initWithData:textData encoding:NSUTF8StringEncoding];
-    return [self displayableTextForText:text interactionId:interactionId];
-}
-
 - (void)ensureViewState
 {
     OWSAssert([self.interaction isKindOfClass:[TSMessage class]]);
@@ -321,7 +351,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
     TSMessage *interaction = (TSMessage *)self.interaction;
     if (interaction.body != nil) {
         self.messageCellType = OWSMessageCellType_TextMessage;
-        self.textMessage = [self displayableTextForText:interaction.body interactionId:interaction.uniqueId];
+        self.displayableText = [self displayableTextForText:interaction.body interactionId:interaction.uniqueId];
         return;
     } else {
         NSString *_Nullable attachmentId = interaction.attachmentIds.firstObject;
@@ -332,8 +362,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
 
                 if ([attachment.contentType isEqualToString:OWSMimeTypeOversizeTextMessage]) {
                     self.messageCellType = OWSMessageCellType_OversizeTextMessage;
-                    self.textMessage = [self displayableTextForAttachmentStream:self.attachmentStream
-                                                                  interactionId:interaction.uniqueId];
+                    self.displayableText = [self displayableTextForAttachmentStream:self.attachmentStream
+                                                                      interactionId:interaction.uniqueId];
                     return;
                 } else if ([self.attachmentStream isAnimated] || [self.attachmentStream isImage] ||
                     [self.attachmentStream isVideo]) {
@@ -387,13 +417,17 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
     return _messageCellType;
 }
 
-- (nullable NSString *)textMessage
+- (nullable DisplayableText *)displayableText
 {
     OWSAssert([NSThread isMainThread]);
 
     [self ensureViewState];
 
-    return _textMessage;
+    OWSAssert(_displayableText);
+    OWSAssert(_displayableText.displayText);
+    OWSAssert(_displayableText.fullText);
+
+    return _displayableText;
 }
 
 - (nullable TSAttachmentStream *)attachmentStream
@@ -495,7 +529,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
     switch (self.messageCellType) {
         case OWSMessageCellType_TextMessage:
         case OWSMessageCellType_OversizeTextMessage:
-            [UIPasteboard.generalPasteboard setString:self.textMessage];
+            OWSAssert(self.displayableText);
+            [UIPasteboard.generalPasteboard setString:self.displayableText.fullText];
             break;
         case OWSMessageCellType_StillImage:
         case OWSMessageCellType_AnimatedImage:
@@ -527,7 +562,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
     switch (self.messageCellType) {
         case OWSMessageCellType_TextMessage:
         case OWSMessageCellType_OversizeTextMessage:
-            [AttachmentSharing showShareUIForText:self.textMessage];
+            OWSAssert(self.displayableText);
+            [AttachmentSharing showShareUIForText:self.displayableText.fullText];
             break;
         case OWSMessageCellType_StillImage:
         case OWSMessageCellType_AnimatedImage:
@@ -618,7 +654,8 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
     switch (self.messageCellType) {
         case OWSMessageCellType_TextMessage:
         case OWSMessageCellType_OversizeTextMessage:
-            return self.textMessage.length > 0;
+            OWSAssert(self.displayableText);
+            return self.displayableText.fullText.length > 0;
         case OWSMessageCellType_StillImage:
         case OWSMessageCellType_AnimatedImage:
         case OWSMessageCellType_Audio:
diff --git a/Signal/src/ViewControllers/CropScaleImageViewController.swift b/Signal/src/ViewControllers/CropScaleImageViewController.swift
index 09c0d0166..db19bf440 100644
--- a/Signal/src/ViewControllers/CropScaleImageViewController.swift
+++ b/Signal/src/ViewControllers/CropScaleImageViewController.swift
@@ -101,15 +101,9 @@ class CropScaleImageViewController: OWSViewController {
 
     // MARK: Initializers
 
-    @available(*, unavailable, message:"use srcImage:successCompletion: constructor instead.")
+    @available(*, unavailable, message:"use other constructor instead.")
     required init?(coder aDecoder: NSCoder) {
-        self.srcImage = UIImage(named:"fail")!
-        self.successCompletion = { _ in
-        }
-        super.init(coder: aDecoder)
-        owsFail("\(self.TAG) invalid constructor")
-
-        configureCropAndScale()
+        fatalError("\(#function) is unimplemented.")
     }
 
     required init(srcImage: UIImage, successCompletion : @escaping (UIImage) -> Void) {
diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m
index 891392d4b..3553f924c 100644
--- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m
+++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m
@@ -627,7 +627,7 @@ NS_ASSUME_NONNULL_BEGIN
                               @"pulvinar a, rhoncus vitae nisl. Sed mi nunc, tempus at varius in, malesuada vitae "
                               @"dui. Vivamus efficitur pulvinar erat vitae congue. Proin vehicula turpis non felis "
                               @"congue facilisis. Nullam aliquet dapibus ligula ac mollis. Etiam sit amet posuere "
-                              @"lorem, in rhoncus nisi."];
+                              @"lorem, in rhoncus nisi.\n\n"];
     }
 
     DataSource *_Nullable dataSource = [DataSourceValue dataSourceWithOversizeText:message];
diff --git a/Signal/src/ViewControllers/GifPicker/GifPickerLayout.swift b/Signal/src/ViewControllers/GifPicker/GifPickerLayout.swift
index bebfbe5ec..585df8de6 100644
--- a/Signal/src/ViewControllers/GifPicker/GifPickerLayout.swift
+++ b/Signal/src/ViewControllers/GifPicker/GifPickerLayout.swift
@@ -22,8 +22,7 @@ class GifPickerLayout: UICollectionViewLayout {
 
     @available(*, unavailable, message:"use other constructor instead.")
     required init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-        owsFail("\(self.TAG) invalid constructor")
+        fatalError("\(#function) is unimplemented.")
     }
 
     override init() {
diff --git a/Signal/src/ViewControllers/MessageMetadataViewController.swift b/Signal/src/ViewControllers/MessageMetadataViewController.swift
index ac52c911f..fd9334ae5 100644
--- a/Signal/src/ViewControllers/MessageMetadataViewController.swift
+++ b/Signal/src/ViewControllers/MessageMetadataViewController.swift
@@ -4,6 +4,12 @@
 
 import Foundation
 
+@objc
+enum MessageMetadataViewMode: UInt {
+    case focusOnMessage
+    case focusOnMetadata
+}
+
 class MessageMetadataViewController: OWSViewController {
 
     static let TAG = "[MessageMetadataViewController]"
@@ -18,6 +24,8 @@ class MessageMetadataViewController: OWSViewController {
     let bubbleFactory = OWSMessagesBubbleImageFactory()
     var bubbleView: UIView?
 
+    let mode: MessageMetadataViewMode
+    let viewItem: ConversationViewItem
     var message: TSMessage
 
     var mediaMessageView: MediaMessageView?
@@ -32,18 +40,16 @@ class MessageMetadataViewController: OWSViewController {
 
     // MARK: Initializers
 
-    @available(*, unavailable, message:"use message: constructor instead.")
+    @available(*, unavailable, message:"use other constructor instead.")
     required init?(coder aDecoder: NSCoder) {
-        self.contactsManager = Environment.getCurrent().contactsManager
-        self.message = TSMessage()
-        self.databaseConnection = TSStorageManager.shared().newDatabaseConnection()!
-        super.init(coder: aDecoder)
-        owsFail("\(self.TAG) invalid constructor")
+        fatalError("\(#function) is unimplemented.")
     }
 
-    required init(message: TSMessage) {
+    required init(viewItem: ConversationViewItem, message: TSMessage, mode: MessageMetadataViewMode) {
         self.contactsManager = Environment.getCurrent().contactsManager
+        self.viewItem = viewItem
         self.message = message
+        self.mode = mode
         self.databaseConnection = TSStorageManager.shared().newDatabaseConnection()!
         super.init(nibName: nil, bundle: nil)
     }
@@ -62,12 +68,15 @@ class MessageMetadataViewController: OWSViewController {
         createViews()
 
         self.view.layoutIfNeeded()
-        if let bubbleView = self.bubbleView {
-            let showAtLeast: CGFloat = 50
-            let middleCenter = CGPoint(x: bubbleView.frame.origin.x + bubbleView.frame.width / 2,
-                                       y: bubbleView.frame.origin.y + bubbleView.frame.height - showAtLeast)
-            let offset = bubbleView.superview!.convert(middleCenter, to: scrollView)
-            self.scrollView!.setContentOffset(offset, animated: false)
+
+        if mode == .focusOnMetadata {
+            if let bubbleView = self.bubbleView {
+                let showAtLeast: CGFloat = 50
+                let middleCenter = CGPoint(x: bubbleView.frame.origin.x + bubbleView.frame.width / 2,
+                                           y: bubbleView.frame.origin.y + bubbleView.frame.height - showAtLeast)
+                let offset = bubbleView.superview!.convert(middleCenter, to: scrollView)
+                self.scrollView!.setContentOffset(offset, animated: false)
+            }
         }
 
         NotificationCenter.default.addObserver(self,
@@ -267,76 +276,79 @@ class MessageMetadataViewController: OWSViewController {
         }
     }
 
+    private func displayableTextIfText() -> String? {
+        let messageCellType = viewItem.messageCellType()
+        guard messageCellType == .textMessage ||
+            messageCellType == .oversizeTextMessage else {
+                return nil
+        }
+        guard let displayableText = viewItem.displayableText() else {
+                return nil
+        }
+        let messageBody = displayableText.fullText
+        guard messageBody.characters.count > 0  else {
+            return nil
+        }
+        return messageBody
+    }
+
     private func contentRows() -> [UIView] {
         var rows = [UIView]()
 
-        if message.attachmentIds.count > 0 {
+        if let messageBody = displayableTextIfText() {
+
+            self.messageBody = messageBody
+
+            let isIncoming = self.message as? TSIncomingMessage != nil
+
+            // UITextView can't render extremely long text due to constraints
+            // on the size of its backing buffer, especially when we're 
+            // embedding it "full-size' within a UIScrollView as we do in this view.
+            //
+            // TODO: We could use CoreText instead, or we could dynamically
+            //       manipulate the size/position of our UITextView to
+            //       reflect scroll state.
+            let bodyLabel = UITextView()
+            bodyLabel.font = UIFont.ows_dynamicTypeBody()
+            bodyLabel.backgroundColor = UIColor.clear
+            bodyLabel.isOpaque = false
+            bodyLabel.isEditable = false
+            bodyLabel.isSelectable = true
+            bodyLabel.textContainerInset = UIEdgeInsets.zero
+            bodyLabel.contentInset = UIEdgeInsets.zero
+            bodyLabel.isScrollEnabled = false
+            bodyLabel.textColor = isIncoming ? UIColor.black : UIColor.white
+            bodyLabel.text = messageBody
+
+            let bubbleImageData = isIncoming ? bubbleFactory.incoming : bubbleFactory.outgoing
+
+            let leadingMargin: CGFloat = isIncoming ? 15 : 10
+            let trailingMargin: CGFloat = isIncoming ? 10 : 15
+
+            let bubbleView = UIImageView(image: bubbleImageData.messageBubbleImage)
+            self.bubbleView = bubbleView
+
+            bubbleView.layer.cornerRadius = 10
+            bubbleView.addSubview(bodyLabel)
+
+            bodyLabel.autoPinEdge(toSuperviewEdge: .leading, withInset: leadingMargin)
+            bodyLabel.autoPinEdge(toSuperviewEdge: .trailing, withInset: trailingMargin)
+            bodyLabel.autoPinHeightToSuperview(withMargin: 10)
+
+            let row = UIView()
+            row.addSubview(bubbleView)
+            bubbleView.autoPinHeightToSuperview()
+            bubbleView.autoPinLeadingToSuperview(withMargin: 10)
+            bubbleView.autoPinTrailingToSuperview(withMargin: 10)
+            rows.append(row)
+        } else if message.attachmentIds.count > 0 {
             rows += addAttachmentRows()
-        } else if let messageBody = message.body {
-            // TODO: We should also display "oversize text messages" in a
-            //       similar way.
-            if messageBody.characters.count > 0 {
-                self.messageBody = messageBody
-
-                let isIncoming = self.message as? TSIncomingMessage != nil
-
-                let bodyLabel = UILabel()
-                bodyLabel.textColor = isIncoming ? UIColor.black : UIColor.white
-                bodyLabel.font = UIFont.ows_regularFont(withSize: 16)
-                bodyLabel.text = messageBody
-                bodyLabel.numberOfLines = 0
-                bodyLabel.lineBreakMode = .byWordWrapping
-
-                let bubbleImageData = isIncoming ? bubbleFactory.incoming : bubbleFactory.outgoing
-
-                let leadingMargin: CGFloat = isIncoming ? 15 : 10
-                let trailingMargin: CGFloat = isIncoming ? 10 : 15
-
-                let bubbleView = UIImageView(image: bubbleImageData.messageBubbleImage)
-                self.bubbleView = bubbleView
-
-                bubbleView.layer.cornerRadius = 10
-                bubbleView.addSubview(bodyLabel)
-
-                bodyLabel.autoPinEdge(toSuperviewEdge: .leading, withInset: leadingMargin)
-                bodyLabel.autoPinEdge(toSuperviewEdge: .trailing, withInset: trailingMargin)
-                bodyLabel.autoPinHeightToSuperview(withMargin: 10)
-
-                // Try to hug content both horizontally and vertically, but *prefer* wide and short, to narrow and tall.
-                // While never exceeding max width, and never cropping content.
-                bodyLabel.setContentHuggingPriority(UILayoutPriorityDefaultLow, for: .horizontal)
-                bodyLabel.setContentHuggingPriority(UILayoutPriorityDefaultHigh, for: .vertical)
-                bodyLabel.setContentCompressionResistancePriority(UILayoutPriorityRequired, for: .vertical)
-                bodyLabel.autoSetDimension(.width, toSize: ScaleFromIPhone5(210), relation: .lessThanOrEqual)
-
-                let bubbleSpacer = UIView()
-
-                let row = UIView()
-                row.addSubview(bubbleView)
-                row.addSubview(bubbleSpacer)
-
-                bubbleView.autoPinHeightToSuperview()
-                bubbleSpacer.autoPinHeightToSuperview()
-                bubbleSpacer.setContentHuggingLow()
-
-                if isIncoming {
-                    bubbleView.autoPinLeadingToSuperview(withMargin: 10)
-                    bubbleSpacer.autoPinLeading(toTrailingOf: bubbleView)
-                    bubbleSpacer.autoPinTrailingToSuperview(withMargin: 10)
-                } else {
-                    bubbleSpacer.autoPinLeadingToSuperview(withMargin: 10)
-                    bubbleView.autoPinLeading(toTrailingOf: bubbleSpacer)
-                    bubbleView.autoPinTrailingToSuperview(withMargin: 10)
-                }
-
-                rows.append(row)
-            } else {
-                // Neither attachment nor body.
-                owsFail("\(self.TAG) Message has neither attachment nor body.")
-                rows.append(valueRow(name: NSLocalizedString("MESSAGE_METADATA_VIEW_NO_ATTACHMENT_OR_BODY",
-                                                             comment: "Label for messages without a body or attachment in the 'message metadata' view."),
-                                     value: ""))
-            }
+        } else {
+            // Neither attachment nor body.
+            owsFail("\(self.TAG) Message has neither attachment nor body.")
+            rows.append(valueRow(name: NSLocalizedString("MESSAGE_METADATA_VIEW_NO_ATTACHMENT_OR_BODY",
+                                                         comment: "Label for messages without a body or attachment in the 'message metadata' view."),
+                                 value: ""))
         }
 
         let spacer = UIView()
diff --git a/Signal/src/ViewControllers/ModalActivityIndicatorViewController.swift b/Signal/src/ViewControllers/ModalActivityIndicatorViewController.swift
index e66df9a6d..3398e2f35 100644
--- a/Signal/src/ViewControllers/ModalActivityIndicatorViewController.swift
+++ b/Signal/src/ViewControllers/ModalActivityIndicatorViewController.swift
@@ -23,11 +23,9 @@ class ModalActivityIndicatorViewController: OWSViewController {
 
     // MARK: Initializers
 
-    @available(*, unavailable, message:"use canCancel:completion: constructor instead.")
+    @available(*, unavailable, message:"use other constructor instead.")
     required init?(coder aDecoder: NSCoder) {
-        self.canCancel = false
-        super.init(coder: aDecoder)
-        owsFail("\(self.TAG) invalid constructor")
+        fatalError("\(#function) is unimplemented.")
     }
 
     required init(canCancel: Bool) {
diff --git a/Signal/src/ViewControllers/OversizeTextMessageViewController.swift b/Signal/src/ViewControllers/OversizeTextMessageViewController.swift
deleted file mode 100644
index ec4ea3387..000000000
--- a/Signal/src/ViewControllers/OversizeTextMessageViewController.swift
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-//  Copyright (c) 2017 Open Whisper Systems. All rights reserved.
-//
-
-import Foundation
-import WebRTC
-import PromiseKit
-
-class OversizeTextMessageViewController: OWSViewController {
-
-    let TAG = "[OversizeTextMessageViewController]"
-
-    let displayableText: String
-    let attachmentStream: TSAttachmentStream
-
-    // MARK: Initializers
-
-    @available(*, unavailable, message:"use message: constructor instead.")
-    required init?(coder aDecoder: NSCoder) {
-        displayableText = ""
-        attachmentStream = TSAttachmentStream(contentType:"", sourceFilename:"")
-        super.init(coder: aDecoder)
-    }
-
-    required init(displayableText: String, attachmentStream: TSAttachmentStream) {
-        self.displayableText = displayableText
-        self.attachmentStream = attachmentStream
-        super.init(nibName: nil, bundle: nil)
-    }
-
-    // MARK: View Lifecycle
-
-    override func viewDidLoad() {
-        super.viewDidLoad()
-
-        self.navigationItem.title = NSLocalizedString("OVERSIZE_TEXT_MESSAGE_VIEW_TITLE",
-                                                      comment: "The title of the 'oversize text message' view.")
-
-        self.view.backgroundColor = UIColor.white
-
-        let textView = UITextView()
-        textView.textColor = UIColor.black
-        textView.text = displayableText
-        textView.font = UIFont.ows_dynamicTypeBody()
-        textView.isEditable = false
-        textView.textContainerInset = UIEdgeInsets(top: 8, left: 4, bottom: 8, right: 4)
-        self.view.addSubview(textView)
-        textView.autoPinWidthToSuperview()
-        textView.autoPin(toTopLayoutGuideOf : self, withInset: 0)
-
-        let footerBar = UIToolbar()
-        footerBar.barTintColor = UIColor.ows_signalBrandBlue()
-        footerBar.setItems([
-            UIBarButtonItem(barButtonSystemItem:.flexibleSpace,
-                            target:nil,
-                            action:nil),
-            UIBarButtonItem(barButtonSystemItem:.action,
-                            target:self,
-                            action:#selector(shareWasPressed)),
-            UIBarButtonItem(barButtonSystemItem:.flexibleSpace,
-                            target:nil,
-                            action:nil)
-            ], animated: false)
-        self.view.addSubview(footerBar)
-        footerBar.autoPinWidthToSuperview()
-        footerBar.autoPin(toBottomLayoutGuideOf : self, withInset: 0)
-        footerBar.autoPinEdge(.top, to:.bottom, of:textView)
-    }
-
-    func shareWasPressed(sender: UIButton) {
-        Logger.info("\(TAG) sharing oversize text.")
-
-        AttachmentSharing.showShareUI(for:attachmentStream.mediaURL())
-    }
-}
diff --git a/Signal/src/views/AudioProgressView.swift b/Signal/src/views/AudioProgressView.swift
index 1aef8f365..5e0d41749 100644
--- a/Signal/src/views/AudioProgressView.swift
+++ b/Signal/src/views/AudioProgressView.swift
@@ -45,14 +45,9 @@ import UIKit
         }
     }
 
-    @available(*, unavailable, message:"use init() constructor instead.")
+    @available(*, unavailable, message:"use other constructor instead.")
     required init?(coder aDecoder: NSCoder) {
-        self.horizontalBarLayer = CAShapeLayer()
-        self.progressLayer = CAShapeLayer()
-
-        super.init(coder: aDecoder)
-
-        owsFail("\(self.tag) Invalid constructor")
+        fatalError("\(#function) is unimplemented.")
     }
 
     public required init() {
diff --git a/Signal/src/views/OWSFlatButton.swift b/Signal/src/views/OWSFlatButton.swift
index 27fd169d7..8fdfff34f 100644
--- a/Signal/src/views/OWSFlatButton.swift
+++ b/Signal/src/views/OWSFlatButton.swift
@@ -30,13 +30,9 @@ import Foundation
         createContent()
     }
 
-    @available(*, unavailable, message:"use default constructor instead.")
+    @available(*, unavailable, message:"use other constructor instead.")
     required init?(coder aDecoder: NSCoder) {
-        button = UIButton(type:.custom)
-
-        super.init(coder: aDecoder)
-
-        owsFail("\(self.TAG) invalid constructor")
+        fatalError("\(#function) is unimplemented.")
     }
 
     private func createContent() {
diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings
index 6feb95e68..6da470e39 100644
--- a/Signal/translations/en.lproj/Localizable.strings
+++ b/Signal/translations/en.lproj/Localizable.strings
@@ -76,18 +76,12 @@
 /* No comment provided by engineer. */
 "ATTACHMENT" = "Attachment";
 
-/* Title for the 'attachment approval' dialog. */
-"ATTACHMENT_APPROVAL_DIALOG_TITLE" = "Attachment";
-
 /* Format string for file extension label in call interstitial view */
 "ATTACHMENT_APPROVAL_FILE_EXTENSION_FORMAT" = "File type: %@";
 
 /* Format string for file size label in call interstitial view. Embeds: {{file size as 'N mb' or 'N kb'}}. */
 "ATTACHMENT_APPROVAL_FILE_SIZE_FORMAT" = "Size: %@";
 
-/* Label for 'send' button in the 'attachment approval' dialog. */
-"ATTACHMENT_APPROVAL_SEND_BUTTON" = "Send";
-
 /* Generic filename for an attachment with no known name */
 "ATTACHMENT_DEFAULT_FILENAME" = "Attachment";
 
@@ -238,6 +232,9 @@
 /* Accessibility label for hang up call */
 "CALL_VIEW_HANGUP_LABEL" = "End call";
 
+/* Accessibility label for muting the microphone */
+"CALL_VIEW_MUTE_LABEL" = "Mute";
+
 /* Reminder to the user of the benefits of enabling CallKit and disabling CallKit privacy. */
 "CALL_VIEW_SETTINGS_NAG_DESCRIPTION_ALL" = "You can answer calls directly from your lock screen and see the name and phone number for incoming calls if you change your settings.\n\nSee the privacy settings for details.";
 
@@ -256,9 +253,6 @@
 /* Accessibility label to switch to video call */
 "CALL_VIEW_SWITCH_TO_VIDEO_LABEL" = "Switch to video call";
 
-/* Accessibility label for muting the microphone */
-"CALL_VIEW_MUTE_LABEL" = "Mute";
-
 /* notification action */
 "CALLBACK_BUTTON_TITLE" = "Call Back";
 
@@ -400,6 +394,9 @@
 /* Title for the group of buttons show for unknown contacts offering to add them to contacts, etc. */
 "CONVERSATION_VIEW_CONTACTS_OFFER_TITLE" = "This user is not in your contacts.";
 
+/* Indicator on truncated text messages that they can be tapped to see the entire text message. */
+"CONVERSATION_VIEW_OVERSIZE_TEXT_TAP_FOR_MORE" = "Tap For More";
+
 /* Message shown in conversation view that offers to block an unknown user. */
 "CONVERSATION_VIEW_UNKNOWN_CONTACT_BLOCK_OFFER" = "Block This User";
 
@@ -818,10 +815,10 @@
 "LIST_GROUP_MEMBERS_ACTION" = "Group Members";
 
 /* No comment provided by engineer. */
-"LOGGING_SECTION" = "Logging";
+"load_earlier_messages" = "Load Earlier Messages";
 
 /* No comment provided by engineer. */
-"ME_STRING" = "Me";
+"LOGGING_SECTION" = "Logging";
 
 /* media picker option to take photo or video */
 "MEDIA_FROM_CAMERA_BUTTON" = "Camera";
@@ -883,8 +880,7 @@
 /* Title for the 'message metadata' view. */
 "MESSAGE_METADATA_VIEW_TITLE" = "Message";
 
-/* message footer for delivered messages
-   message status for message delivered to their recipient. */
+/* message status for message delivered to their recipient. */
 "MESSAGE_STATUS_DELIVERED" = "Delivered";
 
 /* message footer for failed messages */
@@ -958,24 +954,9 @@
    Alert title when camera is not authorized */
 "MISSING_CAMERA_PERMISSION_TITLE" = "Signal needs to access your camera.";
 
-/* No comment provided by engineer. */
-"MSGVIEW_MISSED_CALL_BECAUSE_OF_CHANGED_IDENTITY" = "Missed call because their safety number has changed.";
-
 /* notification title. Embeds {{caller's name or phone number}} */
 "MSGVIEW_MISSED_CALL_WITH_NAME" = "Missed call from %@.";
 
-/* No comment provided by engineer. */
-"MSGVIEW_RECEIVED_CALL" = "You received a call from %@.";
-
-/* No comment provided by engineer. */
-"MSGVIEW_THEY_TRIED_TO_CALL_YOU" = "%@ tried to call you.";
-
-/* No comment provided by engineer. */
-"MSGVIEW_YOU_CALLED" = "You called %@.";
-
-/* No comment provided by engineer. */
-"MSGVIEW_YOU_TRIED_TO_CALL" = "You tried to call %@.";
-
 /* No comment provided by engineer. */
 "MULTIDEVICE_PAIRING_MAX_DESC" = "You can not pair any more devices.";
 
@@ -1036,6 +1017,9 @@
 /* The alert title if user tries to exit the new group view without saving changes. */
 "NEW_GROUP_VIEW_UNSAVED_CHANGES_TITLE" = "Unsaved Changes";
 
+/* No comment provided by engineer. */
+"new_message" = "New Message";
+
 /* A label for the 'add by phone number' button in the 'new non-contact conversation' view */
 "NEW_NONCONTACT_CONVERSATION_VIEW_BUTTON" = "Search";
 
@@ -1092,7 +1076,7 @@
 "OUTGOING_INCOMPLETE_CALL" = "Unanswered outgoing call";
 
 /* A display format for oversize text messages. */
-"OVERSIZE_TEXT_DISPLAY_FORMAT" = "%@… [Tap For More]";
+"OVERSIZE_TEXT_DISPLAY_FORMAT" = "%@…";
 
 /* The title of the 'oversize text message' view. */
 "OVERSIZE_TEXT_MESSAGE_VIEW_TITLE" = "Message";