Browse Source

Merge pull request #963 from deltachat/show_quote

add basic quote view
cyBerta 4 years ago
parent
commit
8f75d44d7c

+ 16 - 0
DcCore/DcCore/DC/Wrapper.swift

@@ -796,6 +796,10 @@ public class DcMsg {
         messagePointer = dc_msg_new(DcContext.shared.contextPointer, type)
     }
 
+    init(pointer: OpaquePointer) {
+        messagePointer = pointer
+    }
+
     deinit {
         dc_msg_unref(messagePointer)
     }
@@ -856,6 +860,18 @@ public class DcMsg {
         }
     }
 
+    public var quoteText: String? {
+        guard let cString = dc_msg_get_quoted_text(messagePointer) else { return nil }
+        let swiftString = String(cString: cString)
+        dc_str_unref(cString)
+        return swiftString
+    }
+
+    public var quoteMessage: DcMsg? {
+        guard let msgpointer = dc_msg_get_quoted_msg(messagePointer) else { return nil }
+        return DcMsg(pointer: msgpointer)
+    }
+
     public var viewtype: MessageViewType? {
         switch dc_msg_get_viewtype(messagePointer) {
         case 0:

+ 14 - 0
DcCore/DcCore/Extensions/UIView+Extensions.swift

@@ -176,6 +176,20 @@ public extension UIView {
         return constraint
     }
 
+    func constraintTrailingToLeadingOf(_ view: UIView, paddingTrailing: CGFloat = 0.0, priority: UILayoutPriority? = .none) -> NSLayoutConstraint {
+        let constraint = NSLayoutConstraint(
+            item: self,
+            attribute: .trailing,
+            relatedBy: .equal,
+            toItem: view,
+            attribute: .leading,
+            multiplier: 1.0,
+            constant: -paddingTrailing)
+        if let priority = priority {
+            constraint.priority = priority
+        }
+        return constraint
+    }
 
     func constraintCenterXTo(_ view: UIView, paddingX: CGFloat = 0.0, priority: UILayoutPriority? = .none) -> NSLayoutConstraint {
         let constraint = NSLayoutConstraint(item: self,

+ 4 - 0
deltachat-ios.xcodeproj/project.pbxproj

@@ -41,6 +41,7 @@
 		305962102346154D00C80F33 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3059620F2346154D00C80F33 /* String+Extension.swift */; };
 		3060119C22DDE24000C1CE6F /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3060119E22DDE24000C1CE6F /* Localizable.strings */; };
 		306011B622E5E7FB00C1CE6F /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 306011B422E5E7FB00C1CE6F /* Localizable.stringsdict */; };
+		30653081254358B10093E196 /* QuoteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30653080254358B10093E196 /* QuoteView.swift */; };
 		306C32322445CDE9001D89F3 /* DcLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 306C32312445CDE9001D89F3 /* DcLogger.swift */; };
 		30734326249A280B00BF9AD1 /* MediaQualityController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30734325249A280B00BF9AD1 /* MediaQualityController.swift */; };
 		307D822E241669C7006D2490 /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 307D822D241669C7006D2490 /* LocationManager.swift */; };
@@ -267,6 +268,7 @@
 		306011C722E5E82E00C1CE6F /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = lt; path = lt.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
 		306011C822E5E83100C1CE6F /* zh-Hant-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-Hant-TW"; path = "zh-Hant-TW.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
 		306011C922E5E83500C1CE6F /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = uk; path = uk.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
+		30653080254358B10093E196 /* QuoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuoteView.swift; sourceTree = "<group>"; };
 		306C32312445CDE9001D89F3 /* DcLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DcLogger.swift; sourceTree = "<group>"; };
 		30734325249A280B00BF9AD1 /* MediaQualityController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaQualityController.swift; sourceTree = "<group>"; };
 		307D822D241669C7006D2490 /* LocationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = "<group>"; };
@@ -535,6 +537,7 @@
 				30EF7323252FF15F00E2C54A /* MessageLabel.swift */,
 				3052C609253F082E007D13EA /* MessageLabelDelegate.swift */,
 				3052C60D253F088E007D13EA /* DetectorType.swift */,
+				30653080254358B10093E196 /* QuoteView.swift */,
 			);
 			path = Views;
 			sourceTree = "<group>";
@@ -1195,6 +1198,7 @@
 				AEE6EC412282DF5700EDC689 /* MailboxViewController.swift in Sources */,
 				AEF53BD5248904BF00D309C1 /* GalleryTimeLabel.swift in Sources */,
 				AEE6EC482283045D00EDC689 /* EditSettingsController.swift in Sources */,
+				30653081254358B10093E196 /* QuoteView.swift in Sources */,
 				30E348DF24F3F819005C93D1 /* ChatTableView.swift in Sources */,
 				30EF7308252F6A3300E2C54A /* PaddingTextView.swift in Sources */,
 				30E348E124F53772005C93D1 /* ImageTextCell.swift in Sources */,

+ 10 - 0
deltachat-ios/Chat/ChatViewController.swift

@@ -1069,6 +1069,16 @@ class ChatViewController: UITableViewController {
 // MARK: - BaseMessageCellDelegate
 extension ChatViewController: BaseMessageCellDelegate {
 
+    @objc func quoteTapped(indexPath: IndexPath) {
+        _ = handleUIMenu()
+        let msg = DcMsg(id: messageIds[indexPath.row])
+        if let quoteMsg = msg.quoteMessage,
+           let index = messageIds.firstIndex(of: quoteMsg.id) {
+            let indexPath = IndexPath(row: index, section: 0)
+            tableView.scrollToRow(at: indexPath, at: .middle, animated: true)
+        }
+    }
+
     @objc func textTapped(indexPath: IndexPath) {
         _ = handleUIMenu()
     }

+ 40 - 3
deltachat-ios/Chat/Views/Cells/BaseMessageCell.swift

@@ -55,6 +55,14 @@ public class BaseMessageCell: UITableViewCell {
 
     public weak var baseDelegate: BaseMessageCellDelegate?
 
+    public lazy var quoteView: QuoteView = {
+        let view = QuoteView()
+        view.translatesAutoresizingMaskIntoConstraints = false
+        view.isUserInteractionEnabled = true
+        view.isHidden = true
+        return view
+    }()
+
     public lazy var messageLabel: PaddingTextView = {
         let view = PaddingTextView()
         view.translatesAutoresizingMaskIntoConstraints = false
@@ -94,7 +102,7 @@ public class BaseMessageCell: UITableViewCell {
     }()
 
     lazy var mainContentView: UIStackView = {
-        let view = UIStackView()
+        let view = UIStackView(arrangedSubviews: [quoteView])
         view.translatesAutoresizingMaskIntoConstraints = false
         view.axis = .vertical
         return view
@@ -103,7 +111,7 @@ public class BaseMessageCell: UITableViewCell {
     lazy var bottomLabel: PaddingTextView = {
         let label = PaddingTextView()
         label.translatesAutoresizingMaskIntoConstraints = false
-        label.font = UIFont.preferredFont(for: .caption1, weight: .regular)
+        label.font = UIFont.preferredFont(for: .caption1, weight: .medium)
         label.setContentHuggingPriority(.defaultHigh, for: .horizontal)
         label.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
         label.layer.cornerRadius = 4
@@ -182,8 +190,13 @@ public class BaseMessageCell: UITableViewCell {
         avatarView.addGestureRecognizer(gestureRecognizer)
 
         let messageLabelGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture(_:)))
-        gestureRecognizer.numberOfTapsRequired = 1
+        messageLabelGestureRecognizer.numberOfTapsRequired = 1
         messageLabel.addGestureRecognizer(messageLabelGestureRecognizer)
+
+        let quoteViewGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(onQuoteTapped))
+        quoteViewGestureRecognizer.numberOfTapsRequired = 1
+        quoteView.addGestureRecognizer(quoteViewGestureRecognizer)
+
     }
 
     @objc
@@ -202,6 +215,12 @@ public class BaseMessageCell: UITableViewCell {
         }
     }
 
+    @objc func onQuoteTapped() {
+        if let tableView = self.superview as? UITableView, let indexPath = tableView.indexPath(for: self) {
+            baseDelegate?.quoteTapped(indexPath: indexPath)
+        }
+    }
+
     // update classes inheriting BaseMessageCell first before calling super.update(...)
     func update(msg: DcMsg, messageStyle: UIRectCorner, isAvatarVisible: Bool, isGroup: Bool) {
         if msg.isFromCurrentSender {
@@ -247,6 +266,22 @@ public class BaseMessageCell: UITableViewCell {
         if !msg.isInfo {
             bottomLabel.attributedText = getFormattedBottomLine(message: msg)
         }
+
+        if let quoteText = msg.quoteText {
+            quoteView.isHidden = false
+            quoteView.quote.text = quoteText
+
+            if let quoteMsg = msg.quoteMessage {
+                let contact = quoteMsg.fromContact
+                quoteView.senderTitle.text = contact.displayName
+                quoteView.senderTitle.textColor = contact.color
+                quoteView.citeBar.backgroundColor = contact.color
+                quoteView.imagePreview.image = quoteMsg.image
+            }
+        } else {
+            quoteView.isHidden = true
+        }
+
         messageLabel.delegate = self
     }
 
@@ -349,6 +384,7 @@ public class BaseMessageCell: UITableViewCell {
         messageLabel.text = nil
         messageLabel.attributedText = nil
         messageLabel.delegate = nil
+        quoteView.prepareForReuse()
     }
 
     // MARK: - Context menu
@@ -407,4 +443,5 @@ public protocol BaseMessageCellDelegate: class {
     func imageTapped(indexPath: IndexPath)
     func avatarTapped(indexPath: IndexPath)
     func textTapped(indexPath: IndexPath)
+    func quoteTapped(indexPath: IndexPath)
 }

+ 77 - 0
deltachat-ios/Chat/Views/QuoteView.swift

@@ -0,0 +1,77 @@
+import UIKit
+import DcCore
+
+public class QuoteView: UIView {
+    public lazy var citeBar: UIView = {
+        let view = UIView()
+        view.backgroundColor = DcColors.grayDateColor
+        view.clipsToBounds = true
+        view.layer.cornerRadius = 1.5
+        view.translatesAutoresizingMaskIntoConstraints = false
+        return view
+    }()
+
+    public lazy var quote: UILabel = {
+        let view = UILabel()
+        view.font = UIFont.preferredFont(for: .subheadline, weight: .regular)
+        view.textColor = DcColors.grayTextColor
+        view.translatesAutoresizingMaskIntoConstraints = false
+        return view
+    }()
+
+    public lazy var senderTitle: UILabel = {
+        let view = UILabel()
+        view.font = UIFont.preferredFont(for: .subheadline, weight: .semibold)
+        view.translatesAutoresizingMaskIntoConstraints = false
+        return view
+    }()
+
+    public lazy var imagePreview: UIImageView = {
+        let view = UIImageView()
+        view.translatesAutoresizingMaskIntoConstraints = false
+        return view
+    }()
+
+    init() {
+        super.init(frame: .zero)
+        setupSubviews()
+    }
+
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    func setupSubviews() {
+        addSubview(citeBar)
+        addSubview(senderTitle)
+        addSubview(imagePreview)
+        addSubview(quote)
+
+        addConstraints([
+            imagePreview.constraintAlignTrailingTo(self, paddingTrailing: 16),
+            imagePreview.constraintHeightTo(36),
+            imagePreview.constraintWidthTo(36),
+            imagePreview.constraintCenterYTo(citeBar),
+            senderTitle.constraintAlignTopTo(self),
+            senderTitle.constraintAlignLeadingTo(self, paddingLeading: 28),
+            senderTitle.constraintTrailingToLeadingOf(imagePreview, paddingTrailing: 8),
+            quote.constraintAlignLeadingTo(self, paddingLeading: 28),
+            quote.constraintToBottomOf(senderTitle),
+            quote.constraintTrailingToLeadingOf(imagePreview, paddingTrailing: 8),
+            quote.constraintAlignBottomTo(self, paddingBottom: 4),
+            citeBar.constraintAlignLeadingTo(self, paddingLeading: 16),
+            citeBar.constraintAlignTopTo(senderTitle, paddingTop: 2),
+            citeBar.constraintAlignBottomTo(quote, paddingBottom: 2),
+            citeBar.constraintWidthTo(3),
+        ])
+    }
+
+    public func prepareForReuse() {
+        quote.text = nil
+        quote.attributedText = nil
+        senderTitle.text = nil
+        senderTitle.attributedText = nil
+        citeBar.backgroundColor = DcColors.grayDateColor
+        imagePreview.image = nil
+    }
+}