From 6830d4e8cbf5df00fbcd3bf0fa11c0e207341147 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 5 Apr 2018 15:55:59 -0400 Subject: [PATCH] Apply message bubble view to message details view. --- Signal.xcodeproj/project.pbxproj | 6 +- .../ConversationViewController.m | 6 +- .../LongTextViewController.swift | 100 ++++++++++++++++++ .../MessageDetailViewController.swift | 24 +---- .../translations/en.lproj/Localizable.strings | 6 +- SignalMessaging/utils/DisplayableText.swift | 6 +- 6 files changed, 114 insertions(+), 34 deletions(-) create mode 100644 Signal/src/ViewControllers/LongTextViewController.swift diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 8d10968c9..f443f7ec0 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -154,6 +154,7 @@ 347850711FDAEB17007B8332 /* OWSUserProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 3478506F1FDAEB16007B8332 /* OWSUserProfile.m */; }; 347850721FDAEB17007B8332 /* OWSUserProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 347850701FDAEB16007B8332 /* OWSUserProfile.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3496744D2076768700080B5F /* OWSMessageBubbleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3496744C2076768700080B5F /* OWSMessageBubbleView.m */; }; + 3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3496744E2076ACCE00080B5F /* LongTextViewController.swift */; }; 34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */; }; 34A910601FFEB114000C4745 /* OWSBackup.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A9105F1FFEB114000C4745 /* OWSBackup.m */; }; 34B0796D1FCF46B100E248C2 /* MainAppContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B0796B1FCF46B000E248C2 /* MainAppContext.m */; }; @@ -729,6 +730,7 @@ 3495BC911F1426B800B478F5 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = translations/ar.lproj/Localizable.strings; sourceTree = ""; }; 3496744B2076768600080B5F /* OWSMessageBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageBubbleView.h; sourceTree = ""; }; 3496744C2076768700080B5F /* OWSMessageBubbleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageBubbleView.m; sourceTree = ""; }; + 3496744E2076ACCE00080B5F /* LongTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LongTextViewController.swift; sourceTree = ""; }; 34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS2FARegistrationViewController.m; sourceTree = ""; }; 34A55F3620485464002CC6DE /* OWS2FARegistrationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS2FARegistrationViewController.h; sourceTree = ""; }; 34A9105E1FFEB113000C4745 /* OWSBackup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackup.h; sourceTree = ""; }; @@ -1590,8 +1592,10 @@ 34B3F8501E8DF1700035BE1A /* NewContactThreadViewController.m */, 34B3F8541E8DF1700035BE1A /* NewGroupViewController.h */, 34B3F8551E8DF1700035BE1A /* NewGroupViewController.m */, + 3496744E2076ACCE00080B5F /* LongTextViewController.swift */, 34A55F3620485464002CC6DE /* OWS2FARegistrationViewController.h */, 34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */, + 45D2AC01204885170033C692 /* OWS2FAReminderViewController.swift */, 345BC30A2047030600257B7C /* OWS2FASettingsViewController.h */, 345BC30B2047030600257B7C /* OWS2FASettingsViewController.m */, 34C42D591F45F7A80072EC04 /* OWSNavigationController.h */, @@ -1604,7 +1608,6 @@ 34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */, 340FC897204DAC8D007AEB0F /* ThreadSettings */, 34D1F0BE1F8EC1760066283D /* Utils */, - 45D2AC01204885170033C692 /* OWS2FAReminderViewController.swift */, ); path = ViewControllers; sourceTree = ""; @@ -3183,6 +3186,7 @@ 34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */, 340FC8AD204DAC8D007AEB0F /* OWSLinkedDevicesTableViewController.m in Sources */, 340FC8AA204DAC8D007AEB0F /* NotificationSettingsViewController.m in Sources */, + 3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */, 34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */, 34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */, 34D1F0AC1F867BFC0066283D /* OWSExpirationTimerView.m in Sources */, diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 61b4cf186..d23e0b733 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -2101,11 +2101,7 @@ typedef enum : NSUInteger { OWSAssert(conversationItem); OWSAssert([conversationItem.interaction isKindOfClass:[TSMessage class]]); - TSMessage *message = (TSMessage *)conversationItem.interaction; - MessageDetailViewController *view = - [[MessageDetailViewController alloc] initWithViewItem:conversationItem - message:message - mode:MessageMetadataViewModeFocusOnMessage]; + LongTextViewController *view = [[LongTextViewController alloc] initWithViewItem:conversationItem]; [self.navigationController pushViewController:view animated:YES]; } diff --git a/Signal/src/ViewControllers/LongTextViewController.swift b/Signal/src/ViewControllers/LongTextViewController.swift new file mode 100644 index 000000000..8dd23d156 --- /dev/null +++ b/Signal/src/ViewControllers/LongTextViewController.swift @@ -0,0 +1,100 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +import Foundation +import SignalServiceKit +import SignalMessaging + +@objc +public class LongTextViewController: OWSViewController { + + // MARK: Properties + + let viewItem: ConversationViewItem + + let messageBody: String + + var messageTextView: UITextView? + + // MARK: Initializers + + @available(*, unavailable, message:"use other constructor instead.") + public required init?(coder aDecoder: NSCoder) { + fatalError("\(#function) is unimplemented.") + } + + public required init(viewItem: ConversationViewItem) { + self.viewItem = viewItem + + self.messageBody = LongTextViewController.displayableText(viewItem: viewItem) + + super.init(nibName: nil, bundle: nil) + } + + private class func displayableText(viewItem: ConversationViewItem) -> String { + guard viewItem.hasBodyText else { + return "" + } + guard let displayableText = viewItem.displayableBodyText() else { + return "" + } + let messageBody = displayableText.fullText + return messageBody + } + + // MARK: View Lifecycle + + public override func viewDidLoad() { + super.viewDidLoad() + + self.navigationItem.title = NSLocalizedString("LONG_TEXT_VIEW_TITLE", + comment: "Title for the 'long text message' view.") + + createViews() + } + + // MARK: - Create Views + + private func createViews() { + view.backgroundColor = UIColor.white + + let messageTextView = UITextView() + self.messageTextView = messageTextView + messageTextView.font = UIFont.ows_dynamicTypeBody + messageTextView.backgroundColor = UIColor.white + messageTextView.isOpaque = true + messageTextView.isEditable = false + messageTextView.isSelectable = true + messageTextView.isScrollEnabled = true + messageTextView.showsHorizontalScrollIndicator = false + messageTextView.showsVerticalScrollIndicator = true + messageTextView.isUserInteractionEnabled = true + messageTextView.textColor = UIColor.black + messageTextView.text = messageBody + + view.addSubview(messageTextView) + messageTextView.autoPinLeadingToSuperviewMargin() + messageTextView.autoPinTrailingToSuperviewMargin() + messageTextView.autoPin(toTopLayoutGuideOf: self, withInset: 0) + + let footer = UIToolbar() + footer.barTintColor = UIColor.ows_materialBlue + view.addSubview(footer) + footer.autoPinWidthToSuperview(withMargin: 0) + footer.autoPinEdge(.top, to: .bottom, of: messageTextView) + footer.autoPin(toBottomLayoutGuideOf: self, withInset: 0) + + footer.items = [ + UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil), + UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(shareButtonPressed)), + UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) + ] + } + + // MARK: - Actions + + func shareButtonPressed() { + AttachmentSharing.showShareUI(forText: messageBody) + } +} diff --git a/Signal/src/ViewControllers/MessageDetailViewController.swift b/Signal/src/ViewControllers/MessageDetailViewController.swift index ad39e61ab..3f1651c68 100644 --- a/Signal/src/ViewControllers/MessageDetailViewController.swift +++ b/Signal/src/ViewControllers/MessageDetailViewController.swift @@ -493,28 +493,6 @@ class MessageDetailViewController: OWSViewController, MediaDetailPresenter, Medi AttachmentSharing.showShareUI(forAttachment: attachmentStream) } - func copyToPasteboard() { - if let messageBody = messageBody { - UIPasteboard.general.string = messageBody - return - } - - guard let attachmentStream = attachmentStream else { - Logger.error("\(logTag) Message has neither attachment nor message body.") - return - } - guard let utiType = MIMETypeUtil.utiType(forMIMEType: attachmentStream.contentType) else { - Logger.error("\(logTag) Attachment has invalid MIME type: \(attachmentStream.contentType).") - return - } - guard let dataSource = dataSource else { - Logger.error("\(logTag) Attachment missing data source.") - return - } - let data = dataSource.data() - UIPasteboard.general.setData(data, forPasteboardType: utiType) - } - // MARK: - Actions // This method should be called after self.databaseConnection.beginLongLivedReadTransaction(). @@ -633,6 +611,8 @@ class MessageDetailViewController: OWSViewController, MediaDetailPresenter, Medi case .default: break case .oversizeText: + let viewController = LongTextViewController(viewItem: viewItem) + self.navigationController?.pushViewController(viewController, animated: true) break case .media: // TODO: Show/play media. diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 54c943161..5ce351ba6 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -971,6 +971,9 @@ /* No comment provided by engineer. */ "LOGGING_SECTION" = "Logging"; +/* Title for the 'long text message' view. */ +"LONG_TEXT_VIEW_TITLE" = "Message"; + /* nav bar button item */ "MEDIA_DETAIL_VIEW_ALL_MEDIA_BUTTON" = "All Media"; @@ -1010,9 +1013,6 @@ /* Label for the MIME type of attachments in the 'message metadata' view. */ "MESSAGE_METADATA_VIEW_ATTACHMENT_MIME_TYPE" = "MIME type"; -/* Label for 'missing' attachments in the 'message metadata' view. */ -"MESSAGE_METADATA_VIEW_ATTACHMENT_MISSING_FILE" = "Missing Attachment"; - /* Label for 'not yet downloaded' attachments in the 'message metadata' view. */ "MESSAGE_METADATA_VIEW_ATTACHMENT_NOT_YET_DOWNLOADED" = "Not yet downloaded"; diff --git a/SignalMessaging/utils/DisplayableText.swift b/SignalMessaging/utils/DisplayableText.swift index dc7e96b41..c5bbb26eb 100644 --- a/SignalMessaging/utils/DisplayableText.swift +++ b/SignalMessaging/utils/DisplayableText.swift @@ -217,20 +217,20 @@ extension String { @objc public class func displayableText(_ rawText: String) -> DisplayableText { // Only show up to N characters of text. - let kMaxTextDisplayLength = 1024 + let kMaxTextDisplayLength = 512 let fullText = rawText.filterStringForDisplay() var isTextTruncated = false var displayText = fullText if displayText.count > kMaxTextDisplayLength { // Trim whitespace before _AND_ after slicing the snipper from the string. let snippet = String(displayText.prefix(kMaxTextDisplayLength)).ows_stripped() - displayText = String(format:NSLocalizedString("OVERSIZE_TEXT_DISPLAY_FORMAT", comment: + displayText = String(format: NSLocalizedString("OVERSIZE_TEXT_DISPLAY_FORMAT", comment: "A display format for oversize text messages."), snippet) isTextTruncated = true } - let displayableText = DisplayableText(fullText: fullText, displayText: displayText, isTextTruncated:isTextTruncated) + let displayableText = DisplayableText(fullText: fullText, displayText: displayText, isTextTruncated: isTextTruncated) return displayableText } }