From 8a9aa7b084a96283ac87e61a9e3e03777b395031 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Mon, 15 Feb 2021 15:07:38 +1100 Subject: [PATCH] Show link preview suggestion if needed --- Session.xcodeproj/project.pbxproj | 4 ++ Session/Conversations V2/ConversationVC.swift | 9 +++ .../Input View/InputView.swift | 15 +++-- .../Views & Modals/LinkPreviewModal.swift | 66 +++++++++++++++++++ 4 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 Session/Conversations V2/Views & Modals/LinkPreviewModal.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 770cfaf2a..0d3b0fb8e 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -562,6 +562,7 @@ C35E8AAE2485E51D00ACB629 /* IP2Country.swift in Sources */ = {isa = PBXBuildFile; fileRef = C35E8AAD2485E51D00ACB629 /* IP2Country.swift */; }; C3645350252449260045C478 /* VoiceMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C364534F252449260045C478 /* VoiceMessageView.swift */; }; C364535C252467900045C478 /* AudioUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C364535B252467900045C478 /* AudioUtilities.swift */; }; + C374EEE225DA26740073A857 /* LinkPreviewModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C374EEE125DA26740073A857 /* LinkPreviewModal.swift */; }; C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */; }; C37F5385255B94F6002AEA92 /* SelectRecipientViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF34E255B6DC8007E1867 /* SelectRecipientViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; C37F5396255B95BD002AEA92 /* OWSAnyTouchGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1604,6 +1605,7 @@ C35E8AAD2485E51D00ACB629 /* IP2Country.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IP2Country.swift; sourceTree = ""; }; C364534F252449260045C478 /* VoiceMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageView.swift; sourceTree = ""; }; C364535B252467900045C478 /* AudioUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioUtilities.swift; sourceTree = ""; }; + C374EEE125DA26740073A857 /* LinkPreviewModal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkPreviewModal.swift; sourceTree = ""; }; C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+Attachment.swift"; sourceTree = ""; }; C379DCFD25673DBC0002D4EB /* TSAttachmentPointer+Conversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSAttachmentPointer+Conversion.swift"; sourceTree = ""; }; C37F53E8255BA9BB002AEA92 /* Environment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Environment.h; sourceTree = ""; }; @@ -2246,6 +2248,7 @@ B821494525D4D6FF009C0F2A /* URLModal.swift */, B821494E25D4E163009C0F2A /* BodyTextView.swift */, B82149B725D60393009C0F2A /* BlockedModal.swift */, + C374EEE125DA26740073A857 /* LinkPreviewModal.swift */, B82149C025D605C6009C0F2A /* InfoBanner.swift */, B8214A2A25D63EB9009C0F2A /* MessagesTableView.swift */, ); @@ -5156,6 +5159,7 @@ C33100092558FF6D00070591 /* UserCell.swift in Sources */, B8269D2925C7A4B400488AB4 /* InputView.swift in Sources */, C3645350252449260045C478 /* VoiceMessageView.swift in Sources */, + C374EEE225DA26740073A857 /* LinkPreviewModal.swift in Sources */, 3496956F21A301A100DCFE74 /* OWSBackupLazyRestore.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Session/Conversations V2/ConversationVC.swift b/Session/Conversations V2/ConversationVC.swift index b36fd2793..81c6bcf10 100644 --- a/Session/Conversations V2/ConversationVC.swift +++ b/Session/Conversations V2/ConversationVC.swift @@ -353,6 +353,15 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, UITableViewD isLoadingMore = true viewModel.loadAnotherPageOfMessages() } + + func showLinkPreviewSuggestionModal() { + let linkPreviewModel = LinkPreviewModal() { [weak self] in + self?.snInputView.autoGenerateLinkPreview() + } + linkPreviewModel.modalPresentationStyle = .overFullScreen + linkPreviewModel.modalTransitionStyle = .crossDissolve + present(linkPreviewModel, animated: true, completion: nil) + } // MARK: Convenience private func getTitle() -> String { diff --git a/Session/Conversations V2/Input View/InputView.swift b/Session/Conversations V2/Input View/InputView.swift index 3f0d79d7c..87cb30968 100644 --- a/Session/Conversations V2/Input View/InputView.swift +++ b/Session/Conversations V2/Input View/InputView.swift @@ -99,7 +99,7 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate, // MARK: Updating func inputTextViewDidChangeSize(_ inputTextView: InputTextView) { invalidateIntrinsicContentSize() - doLinkPreviewThingies() + autoGenerateLinkPreviewIfPossible() } private func handleQuoteDraftChanged() { @@ -117,20 +117,26 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate, quoteView.pin(.bottom, to: .bottom, of: additionalContentContainer, withInset: -6) } - private func doLinkPreviewThingies() { + private func autoGenerateLinkPreviewIfPossible() { additionalContentContainer.subviews.forEach { $0.removeFromSuperview() } quoteDraftInfo = nil - // Suggest that the user enable link previews if they haven't already, and we haven't + // Suggest that the user enable link previews if they haven't already and we haven't // told them about link previews yet let text = inputTextView.text! let userDefaults = UserDefaults.standard if !OWSLinkPreview.allPreviewUrls(forMessageBodyText: text).isEmpty && !SSKPreferences.areLinkPreviewsEnabled && !userDefaults[.hasSeenLinkPreviewSuggestion] { - // TODO: Show suggestion + delegate.showLinkPreviewSuggestionModal() userDefaults[.hasSeenLinkPreviewSuggestion] = true + return } // Check that link previews are enabled guard SSKPreferences.areLinkPreviewsEnabled else { return } + // Proceed + autoGenerateLinkPreview() + } + + func autoGenerateLinkPreview() { // Check that a valid URL is present guard let linkPreviewURL = OWSLinkPreview.previewUrl(forRawBodyText: text, selectedRange: inputTextView.selectedRange) else { return @@ -189,6 +195,7 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate, // MARK: Delegate protocol InputViewDelegate { + func showLinkPreviewSuggestionModal() func handleCameraButtonTapped() func handleLibraryButtonTapped() func handleGIFButtonTapped() diff --git a/Session/Conversations V2/Views & Modals/LinkPreviewModal.swift b/Session/Conversations V2/Views & Modals/LinkPreviewModal.swift new file mode 100644 index 000000000..eec119760 --- /dev/null +++ b/Session/Conversations V2/Views & Modals/LinkPreviewModal.swift @@ -0,0 +1,66 @@ + +final class LinkPreviewModal : Modal { + private let onLinkPreviewsEnabled: () -> Void + + // MARK: Lifecycle + init(onLinkPreviewsEnabled: @escaping () -> Void) { + self.onLinkPreviewsEnabled = onLinkPreviewsEnabled + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + preconditionFailure("Use init(onLinkPreviewsEnabled:) instead.") + } + + override init(nibName: String?, bundle: Bundle?) { + preconditionFailure("Use init(onLinkPreviewsEnabled:) instead.") + } + + override func populateContentView() { + // Title + let titleLabel = UILabel() + titleLabel.textColor = Colors.text + titleLabel.font = .boldSystemFont(ofSize: Values.largeFontSize) + titleLabel.text = "Enable Link Previews?" + titleLabel.textAlignment = .center + // Message + let messageLabel = UILabel() + messageLabel.textColor = Colors.text + messageLabel.font = .systemFont(ofSize: Values.smallFontSize) + let message = "Session can show previews for URLs. This will make your messaging experience nicer, but to generate a preview Session needs to contact the website in question. You can always disable link previews in the in-app settings." + messageLabel.text = message + messageLabel.numberOfLines = 0 + messageLabel.lineBreakMode = .byWordWrapping + messageLabel.textAlignment = .center + // Enable button + let enableButton = UIButton() + enableButton.set(.height, to: Values.mediumButtonHeight) + enableButton.layer.cornerRadius = Values.modalButtonCornerRadius + enableButton.backgroundColor = Colors.buttonBackground + enableButton.titleLabel!.font = .systemFont(ofSize: Values.smallFontSize) + enableButton.setTitleColor(Colors.text, for: UIControl.State.normal) + enableButton.setTitle("Enable", for: UIControl.State.normal) + enableButton.addTarget(self, action: #selector(enable), for: UIControl.Event.touchUpInside) + // Button stack view + let buttonStackView = UIStackView(arrangedSubviews: [ cancelButton, enableButton ]) + buttonStackView.axis = .horizontal + buttonStackView.spacing = Values.mediumSpacing + buttonStackView.distribution = .fillEqually + // Main stack view + let mainStackView = UIStackView(arrangedSubviews: [ titleLabel, messageLabel, buttonStackView ]) + mainStackView.axis = .vertical + mainStackView.spacing = Values.largeSpacing + contentView.addSubview(mainStackView) + mainStackView.pin(.leading, to: .leading, of: contentView, withInset: Values.largeSpacing) + mainStackView.pin(.top, to: .top, of: contentView, withInset: Values.largeSpacing) + contentView.pin(.trailing, to: .trailing, of: mainStackView, withInset: Values.largeSpacing) + contentView.pin(.bottom, to: .bottom, of: mainStackView, withInset: Values.largeSpacing) + } + + // MARK: Interaction + @objc private func enable() { + SSKPreferences.areLinkPreviewsEnabled = true + presentingViewController?.dismiss(animated: true, completion: nil) + onLinkPreviewsEnabled() + } +}