From 9ccb2640261ede4695ca1aa1d52bfc2fd48954f5 Mon Sep 17 00:00:00 2001 From: cccc Date: Mon, 14 May 2018 09:13:48 +0800 Subject: [PATCH 01/35] Add voiceButton and change the inputBar UI --- Sources/Views/MessageInputBar.swift | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Sources/Views/MessageInputBar.swift b/Sources/Views/MessageInputBar.swift index e9f754531..535b6b432 100644 --- a/Sources/Views/MessageInputBar.swift +++ b/Sources/Views/MessageInputBar.swift @@ -163,6 +163,13 @@ open class MessageInputBar: UIView { textView.messageInputBar = self return textView }() + + open var inputVoiceButton: UIView = { + let textView = UIView() + textView.backgroundColor = UIColor.red + textView.translatesAutoresizingMaskIntoConstraints = false + return textView + }() /// A InputBarButtonItem used as the send button and initially placed in the rightStackView open var sendButton: InputBarButtonItem = { @@ -383,13 +390,19 @@ open class MessageInputBar: UIView { contentView.addSubview(bottomStackView) contentView.addSubview(attachmentsView) contentView.addSubview(separatorLine) + separatorLine.backgroundColor = UIColor.red separatorLine.isHidden = true - setStackViewItems([sendButton], forStack: .right, animated: false) + + contentView.addSubview(sendButton) + contentView.addSubview(inputVoiceButton) + inputVoiceButton.isHidden = true +// setStackViewItems([sendButton], forStack: .right, animated: false) } /// Sets up the initial constraints of each subview private func setupConstraints() { - + inputVoiceButton.addConstraints(inputTextView.topAnchor, left: inputTextView.leftAnchor, bottom: inputTextView.bottomAnchor, right:inputTextView.rightAnchor) + sendButton.addConstraints(bottom:inputTextView.bottomAnchor, right: inputTextView.rightAnchor, rightConstant: 2, widthConstant: 38, heightConstant: 38) // The constraints within the MessageInputBar separatorLine.addConstraints(inputTextView.topAnchor, left: inputTextView.leftAnchor, right: inputTextView.rightAnchor, heightConstant: 0.5) backgroundViewBottomAnchor = backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor) @@ -813,6 +826,10 @@ open class MessageInputBar: UIView { delegate?.messageInputBar(self, didPressSendButtonWith: inputTextView.text) } + open func didSelectInputVoiceButton() { + delegate?.messageInputBar(self, didPressSendButtonWith: inputTextView.text) + } + open func insertReplyView() { topStackView.addArrangedSubview(replyView) } From c7a51e3f0194201856dfdc2a32b437ec6636ccf1 Mon Sep 17 00:00:00 2001 From: cccc Date: Fri, 18 May 2018 18:13:12 +0800 Subject: [PATCH 02/35] Change sendButton --- Sources/Views/InputStackView.swift | 2 +- Sources/Views/MessageInputBar.swift | 28 +++++++++++++++++----------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Sources/Views/InputStackView.swift b/Sources/Views/InputStackView.swift index f5ea38566..b595e5d77 100644 --- a/Sources/Views/InputStackView.swift +++ b/Sources/Views/InputStackView.swift @@ -41,7 +41,7 @@ open class InputStackView: UIStackView { /// - bottom: Left Stack View /// - top: Top Stack View public enum Position { - case left, right, bottom, top + case left, right, bottom, top, other } // MARK: Initialization diff --git a/Sources/Views/MessageInputBar.swift b/Sources/Views/MessageInputBar.swift index 535b6b432..67c119bdd 100644 --- a/Sources/Views/MessageInputBar.swift +++ b/Sources/Views/MessageInputBar.swift @@ -165,10 +165,10 @@ open class MessageInputBar: UIView { }() open var inputVoiceButton: UIView = { - let textView = UIView() - textView.backgroundColor = UIColor.red - textView.translatesAutoresizingMaskIntoConstraints = false - return textView + let inputVoiceButton = UIView() + inputVoiceButton.backgroundColor = UIColor.red + inputVoiceButton.translatesAutoresizingMaskIntoConstraints = false + return inputVoiceButton }() /// A InputBarButtonItem used as the send button and initially placed in the rightStackView @@ -392,8 +392,6 @@ open class MessageInputBar: UIView { contentView.addSubview(separatorLine) separatorLine.backgroundColor = UIColor.red separatorLine.isHidden = true - - contentView.addSubview(sendButton) contentView.addSubview(inputVoiceButton) inputVoiceButton.isHidden = true // setStackViewItems([sendButton], forStack: .right, animated: false) @@ -402,7 +400,6 @@ open class MessageInputBar: UIView { /// Sets up the initial constraints of each subview private func setupConstraints() { inputVoiceButton.addConstraints(inputTextView.topAnchor, left: inputTextView.leftAnchor, bottom: inputTextView.bottomAnchor, right:inputTextView.rightAnchor) - sendButton.addConstraints(bottom:inputTextView.bottomAnchor, right: inputTextView.rightAnchor, rightConstant: 2, widthConstant: 38, heightConstant: 38) // The constraints within the MessageInputBar separatorLine.addConstraints(inputTextView.topAnchor, left: inputTextView.leftAnchor, right: inputTextView.rightAnchor, heightConstant: 0.5) backgroundViewBottomAnchor = backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor) @@ -622,6 +619,9 @@ open class MessageInputBar: UIView { case .top: topStackView.setNeedsLayout() topStackView.layoutIfNeeded() + case .other: + rightStackView.setNeedsLayout() + rightStackView.layoutIfNeeded() } } } @@ -721,6 +721,16 @@ open class MessageInputBar: UIView { } guard superview != nil else { return } topStackView.layoutIfNeeded() + case .other: + rightStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } + rightStackViewItems = items + rightStackViewItems.forEach { + $0.messageInputBar = self + $0.parentStackViewPosition = position + rightStackView.addArrangedSubview($0) + } + guard superview != nil else { return } + rightStackView.layoutIfNeeded() } invalidateIntrinsicContentSize() } @@ -826,10 +836,6 @@ open class MessageInputBar: UIView { delegate?.messageInputBar(self, didPressSendButtonWith: inputTextView.text) } - open func didSelectInputVoiceButton() { - delegate?.messageInputBar(self, didPressSendButtonWith: inputTextView.text) - } - open func insertReplyView() { topStackView.addArrangedSubview(replyView) } From 9ba002ad42cfc3350497011c53c182b4b9c70509 Mon Sep 17 00:00:00 2001 From: cccc Date: Mon, 21 May 2018 18:57:05 +0800 Subject: [PATCH 03/35] Change sendButton and voiceButton --- Sources/Views/MessageInputBar.swift | 72 ++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/Sources/Views/MessageInputBar.swift b/Sources/Views/MessageInputBar.swift index 67c119bdd..e2b4885f1 100644 --- a/Sources/Views/MessageInputBar.swift +++ b/Sources/Views/MessageInputBar.swift @@ -145,6 +145,7 @@ open class MessageInputBar: UIView { ## Important Notes ## 1. It's axis is initially set to .horizontal */ + open let otherStackView = InputStackView(axis: .horizontal, spacing: 0) open let rightStackView = InputStackView(axis: .horizontal, spacing: 0) /** @@ -164,11 +165,20 @@ open class MessageInputBar: UIView { return textView }() - open var inputVoiceButton: UIView = { - let inputVoiceButton = UIView() - inputVoiceButton.backgroundColor = UIColor.red - inputVoiceButton.translatesAutoresizingMaskIntoConstraints = false - return inputVoiceButton + open var inputVoiceButton: InputBarButtonItem = { + return InputBarButtonItem() + .onEnabled { + $0.imageView?.tintColor = nil + }.onDisabled { + $0.imageView?.tintColor = COLOR_TINT_DARK_GRAY + } + .configure { + $0.backgroundColor = UIColor.lightGray + $0.layer.cornerRadius = 19.0 + $0.translatesAutoresizingMaskIntoConstraints = false + $0.title = INOUT_VOICE + $0.titleLabel?.font = UIFont.preferredFont(forTextStyle: .headline) + } }() /// A InputBarButtonItem used as the send button and initially placed in the rightStackView @@ -291,6 +301,11 @@ open class MessageInputBar: UIView { rightStackViewLayoutSet?.width?.constant = rightStackViewWidthConstant } } + public private(set) var otherStackViewWidthConstant: CGFloat = 52 { + didSet { + otherStackViewLayoutSet?.width?.constant = otherStackViewWidthConstant + } + } /// The InputBarItems held in the leftStackView public private(set) var leftStackViewItems: [InputBarButtonItem] = [] @@ -298,6 +313,8 @@ open class MessageInputBar: UIView { /// The InputBarItems held in the rightStackView public private(set) var rightStackViewItems: [InputBarButtonItem] = [] + public private(set) var otherStackViewItems: [InputBarButtonItem] = [] + /// The InputBarItems held in the bottomStackView public private(set) var bottomStackViewItems: [InputBarButtonItem] = [] @@ -309,7 +326,7 @@ open class MessageInputBar: UIView { /// Returns a flatMap of all the items in each of the UIStackViews public var items: [InputBarButtonItem] { - return [leftStackViewItems, rightStackViewItems, bottomStackViewItems, nonStackViewItems].flatMap { $0 } + return [leftStackViewItems, rightStackViewItems, otherStackViewItems, bottomStackViewItems, nonStackViewItems].flatMap { $0 } } // MARK: - Auto-Layout Management @@ -319,6 +336,7 @@ open class MessageInputBar: UIView { private var topStackViewLayoutSet: NSLayoutConstraintSet? private var leftStackViewLayoutSet: NSLayoutConstraintSet? private var rightStackViewLayoutSet: NSLayoutConstraintSet? + private var otherStackViewLayoutSet: NSLayoutConstraintSet? private var bottomStackViewLayoutSet: NSLayoutConstraintSet? private var contentViewLayoutSet: NSLayoutConstraintSet? private var borderViewLayoutSet: NSLayoutConstraintSet? @@ -386,6 +404,7 @@ open class MessageInputBar: UIView { addSubview(contentView) contentView.addSubview(inputTextView) contentView.addSubview(leftStackView) + contentView.addSubview(otherStackView) contentView.addSubview(rightStackView) contentView.addSubview(bottomStackView) contentView.addSubview(attachmentsView) @@ -394,12 +413,13 @@ open class MessageInputBar: UIView { separatorLine.isHidden = true contentView.addSubview(inputVoiceButton) inputVoiceButton.isHidden = true -// setStackViewItems([sendButton], forStack: .right, animated: false) + + } /// Sets up the initial constraints of each subview private func setupConstraints() { - inputVoiceButton.addConstraints(inputTextView.topAnchor, left: inputTextView.leftAnchor, bottom: inputTextView.bottomAnchor, right:inputTextView.rightAnchor) + inputVoiceButton.addConstraints(inputTextView.topAnchor, left: inputTextView.leftAnchor, bottom: inputTextView.bottomAnchor, right:inputTextView.rightAnchor,leftConstant: -1, rightConstant: -1) // The constraints within the MessageInputBar separatorLine.addConstraints(inputTextView.topAnchor, left: inputTextView.leftAnchor, right: inputTextView.rightAnchor, heightConstant: 0.5) backgroundViewBottomAnchor = backgroundView.bottomAnchor.constraint(equalTo: bottomAnchor) @@ -452,7 +472,7 @@ open class MessageInputBar: UIView { top: inputTextView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: textViewPadding.top + attachmentViewHeight), bottom: inputTextView.bottomAnchor.constraint(equalTo: bottomStackView.topAnchor, constant: -textViewPadding.bottom), left: inputTextView.leftAnchor.constraint(equalTo: leftStackView.rightAnchor, constant: textViewPadding.left), - right: inputTextView.rightAnchor.constraint(equalTo: rightStackView.leftAnchor, constant: -textViewPadding.right) + right: inputTextView.rightAnchor.constraint(equalTo: otherStackView.leftAnchor, constant: -textViewPadding.right) ) maxTextViewHeight = calculateMaxTextViewHeight() textViewHeightAnchor = inputTextView.heightAnchor.constraint(equalToConstant: maxTextViewHeight) @@ -467,10 +487,17 @@ open class MessageInputBar: UIView { rightStackViewLayoutSet = NSLayoutConstraintSet( top: rightStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0), bottom: rightStackView.bottomAnchor.constraint(equalTo: inputTextView.bottomAnchor, constant: 0), - right: rightStackView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: 0), + right: rightStackView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: 15), width: rightStackView.widthAnchor.constraint(equalToConstant: rightStackViewWidthConstant) ) + otherStackViewLayoutSet = NSLayoutConstraintSet( + top: otherStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0), + bottom: otherStackView.bottomAnchor.constraint(equalTo: inputTextView.bottomAnchor, constant: 0), + right: otherStackView.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -36), + width: otherStackView.widthAnchor.constraint(equalToConstant: otherStackViewWidthConstant) + ) + bottomStackViewLayoutSet = NSLayoutConstraintSet( top: bottomStackView.topAnchor.constraint(equalTo: inputTextView.bottomAnchor, constant: textViewPadding.bottom), bottom: bottomStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0), @@ -620,8 +647,8 @@ open class MessageInputBar: UIView { topStackView.setNeedsLayout() topStackView.layoutIfNeeded() case .other: - rightStackView.setNeedsLayout() - rightStackView.layoutIfNeeded() + otherStackView.setNeedsLayout() + otherStackView.layoutIfNeeded() } } } @@ -649,6 +676,7 @@ open class MessageInputBar: UIView { textViewLayoutSet?.activate() leftStackViewLayoutSet?.activate() rightStackViewLayoutSet?.activate() + otherStackViewLayoutSet?.activate() bottomStackViewLayoutSet?.activate() topStackViewLayoutSet?.activate() borderViewLayoutSet?.activate() @@ -662,6 +690,7 @@ open class MessageInputBar: UIView { textViewLayoutSet?.deactivate() leftStackViewLayoutSet?.deactivate() rightStackViewLayoutSet?.deactivate() + otherStackViewLayoutSet?.deactivate() bottomStackViewLayoutSet?.deactivate() topStackViewLayoutSet?.deactivate() borderViewLayoutSet?.deactivate() @@ -722,15 +751,15 @@ open class MessageInputBar: UIView { guard superview != nil else { return } topStackView.layoutIfNeeded() case .other: - rightStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } - rightStackViewItems = items - rightStackViewItems.forEach { + otherStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } + otherStackViewItems = items + otherStackViewItems.forEach { $0.messageInputBar = self $0.parentStackViewPosition = position - rightStackView.addArrangedSubview($0) + otherStackView.addArrangedSubview($0) } guard superview != nil else { return } - rightStackView.layoutIfNeeded() + otherStackView.layoutIfNeeded() } invalidateIntrinsicContentSize() } @@ -768,6 +797,15 @@ open class MessageInputBar: UIView { } } + open func setOtherStackViewWidthConstant(to newValue: CGFloat, animated: Bool) { + performLayout(animated) { + self.otherStackViewWidthConstant = newValue + self.layoutStackViews([.right]) + guard self.superview != nil else { return } + self.layoutIfNeeded() + } + } + // MARK: - Notifications/Hooks /// Invalidates the intrinsicContentSize From 8554af6a2154c06f4f81557e73cd8788a57453a3 Mon Sep 17 00:00:00 2001 From: cccc Date: Thu, 24 May 2018 21:56:49 +0800 Subject: [PATCH 04/35] Add voiceMessageCell and change voice ui --- .../MessagesViewController+DataSource.swift | 5 + .../Controllers/MessagesViewController.swift | 1 + Sources/Extensions/UIView+Extensions.swift | 22 +++ .../MessagesCollectionViewFlowLayout.swift | 4 + Sources/Models/MessageData.swift | 5 +- Sources/Views/Cells/MediaMessageCell.swift | 14 ++ .../Cells/MessageCollectionViewCell.swift | 17 ++- Sources/Views/Cells/VoiceMessageCell.swift | 125 ++++++++++++++++++ 8 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 Sources/Views/Cells/VoiceMessageCell.swift diff --git a/Sources/Controllers/MessagesViewController+DataSource.swift b/Sources/Controllers/MessagesViewController+DataSource.swift index 939ee9c88..197792db6 100644 --- a/Sources/Controllers/MessagesViewController+DataSource.swift +++ b/Sources/Controllers/MessagesViewController+DataSource.swift @@ -81,6 +81,11 @@ extension MessagesViewController: UICollectionViewDataSource { messagesDataSource.configCell(cell, for: message, at: indexPath) cell.configure(with: message, at: indexPath, and: messagesCollectionView) return cell + case .audio(_): + let cell = messagesCollectionView.dequeueReusableCell(VoiceMessageCell.self, for: indexPath) + messagesDataSource.configCell(cell, for: message, at: indexPath) + cell.configure(with: message, at: indexPath, and: messagesCollectionView) + return cell } } diff --git a/Sources/Controllers/MessagesViewController.swift b/Sources/Controllers/MessagesViewController.swift index b05d8a5ba..ea07f3968 100644 --- a/Sources/Controllers/MessagesViewController.swift +++ b/Sources/Controllers/MessagesViewController.swift @@ -150,6 +150,7 @@ open class MessagesViewController: UIViewController { messagesCollectionView.register(LocationMessageCell.self) messagesCollectionView.register(PhotoMessageCell.self) messagesCollectionView.register(DocumentMessageCell.self) + messagesCollectionView.register(VoiceMessageCell.self) messagesCollectionView.register(MessageFooterView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter) messagesCollectionView.register(MessageHeaderView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader) diff --git a/Sources/Extensions/UIView+Extensions.swift b/Sources/Extensions/UIView+Extensions.swift index 247e0a6d9..4fd62d241 100644 --- a/Sources/Extensions/UIView+Extensions.swift +++ b/Sources/Extensions/UIView+Extensions.swift @@ -54,6 +54,28 @@ extension UIView { ] NSLayoutConstraint.activate(constraints) } + func rightInSuperview(_ rightConstant: CGFloat = 0) { + guard let superview = self.superview else { + return + } + translatesAutoresizingMaskIntoConstraints = false + let constraints: [NSLayoutConstraint] = [ + rightAnchor.constraint(equalTo: superview.rightAnchor,constant: rightConstant), + centerYAnchor.constraint(equalTo: superview.centerYAnchor) + ] + NSLayoutConstraint.activate(constraints) + } + func leftInSuperview(_ leftConstant: CGFloat = 0) { + guard let superview = self.superview else { + return + } + translatesAutoresizingMaskIntoConstraints = false + let constraints: [NSLayoutConstraint] = [ + leftAnchor.constraint(equalTo: superview.leftAnchor,constant: leftConstant), + centerYAnchor.constraint(equalTo: superview.centerYAnchor) + ] + NSLayoutConstraint.activate(constraints) + } func constraint(equalTo size: CGSize) { guard superview != nil else { return } diff --git a/Sources/Layout/MessagesCollectionViewFlowLayout.swift b/Sources/Layout/MessagesCollectionViewFlowLayout.swift index ce7ffd745..b293b7cfa 100644 --- a/Sources/Layout/MessagesCollectionViewFlowLayout.swift +++ b/Sources/Layout/MessagesCollectionViewFlowLayout.swift @@ -459,6 +459,10 @@ private extension MessagesCollectionViewFlowLayout { let width = messagesLayoutDelegate.widthForLocation(message: message, at: indexPath, with: maxWidth, in: messagesCollectionView) let height = messagesLayoutDelegate.heightForLocation(message: message, at: indexPath, with: maxWidth, in: messagesCollectionView) messageContainerSize = CGSize(width: width, height: height) + case .audio(let data): + let width: CGFloat = data.info["width"] as! CGFloat + let height = data.height + messageContainerSize = CGSize(width: width, height: height) } messageContainerSize.height += messagesLayoutDelegate.replyViewHeight(at: indexPath, diff --git a/Sources/Models/MessageData.swift b/Sources/Models/MessageData.swift index cc4749304..40eaa4cd1 100644 --- a/Sources/Models/MessageData.swift +++ b/Sources/Models/MessageData.swift @@ -52,11 +52,12 @@ public enum MessageData { /// An emoji message. case emoji(String) + case attachment(data: ChatAttachment) // MARK: - Not supported yet -// case audio(Data) + case audio(data: ChatAttachment) // // case system(String) // @@ -85,6 +86,8 @@ public enum MessageData { return "Emoji" case .attachment(_): return "Email" + case .audio(_): + return "Voice" } } } diff --git a/Sources/Views/Cells/MediaMessageCell.swift b/Sources/Views/Cells/MediaMessageCell.swift index 6c496f35d..ce8cbc37d 100644 --- a/Sources/Views/Cells/MediaMessageCell.swift +++ b/Sources/Views/Cells/MediaMessageCell.swift @@ -102,6 +102,20 @@ open class MediaMessageCell: MessageCollectionViewCell { downloadData(for: DownloadInfo(accountId: msg.accountId, messageId: msg.messageId)) } } +// case .audio(let data): +//// playButtonView.isHidden = true +//// if let attachmentCell = self as? DocumentMessageCell { +//// let isOutgoing = +//// messagesCollectionView.messagesDataSource?.isFromCurrentSender(message: message) +//// ?? true +//// +//// attachmentCell.load(attachment: data, isOutgoing: isOutgoing) +//// //Preload attachment data +//// if let msg = message as? EdisonMessage { +//// downloadData(for: DownloadInfo(accountId: msg.accountId, messageId: msg.messageId)) +//// } +//// } +// break default: break } diff --git a/Sources/Views/Cells/MessageCollectionViewCell.swift b/Sources/Views/Cells/MessageCollectionViewCell.swift index faa24ab28..44bc0c40e 100644 --- a/Sources/Views/Cells/MessageCollectionViewCell.swift +++ b/Sources/Views/Cells/MessageCollectionViewCell.swift @@ -46,7 +46,13 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab containerView.layer.masksToBounds = true return containerView }() - + + open lazy var voiceTimeView: UILabel = { + let voiceTimeView = UILabel() +// voiceTimeView.text = "0s" + voiceTimeView.translatesAutoresizingMaskIntoConstraints = false + return voiceTimeView + }() open var cellTopLabel: UILabel = { let label = UILabel() label.numberOfLines = 0 @@ -83,6 +89,7 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab setupSubviews() setupCustomMenuItems() setupReplyLabelConstraint() + setupVoiceTimeViewonstraint() } required public init?(coder aDecoder: NSCoder) { @@ -91,6 +98,7 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab open func setupSubviews() { contentView.addSubview(messageContainerView) + contentView.addSubview(voiceTimeView) contentView.addSubview(avatarView) contentView.addSubview(accessoryView) contentView.addSubview(cellTopLabel) @@ -100,6 +108,7 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab open func insertReplyView(isOutgoing: Bool) { messageContainerView.stackView.insertArrangedSubview(replyView, at: 0) + replyView.backgroundColor = UIColor.red replyView.layoutMargins.left = isOutgoing ? 15 : 20 } @@ -114,6 +123,12 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab replyLabel.centerYAnchor.constraint(equalTo: messageContainerView.centerYAnchor) ]) } + open func setupVoiceTimeViewonstraint() { + NSLayoutConstraint.activate([ + voiceTimeView.rightAnchor.constraint(equalTo: messageContainerView.leftAnchor, constant: -3), + voiceTimeView.centerYAnchor.constraint(equalTo: messageContainerView.centerYAnchor) + ]) + } open override func prepareForReuse() { super.prepareForReuse() diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift new file mode 100644 index 000000000..f25e43dec --- /dev/null +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -0,0 +1,125 @@ +// +// VoiceMessageCell.swift +// Email +// +// Created by cccc on 2018/5/24. +// Copyright © 2018年 Easilydo. All rights reserved. +// + +import UIKit + +open class VoiceMessageCell: MessageCollectionViewCell { + open override class func reuseIdentifier() -> String { return "messagekit.cell.voicemessage" } + + // MARK: - Properties + + var messageId = "" + var isDownloadingData = false + var giveUpRetry = false //if true, there is non-recoverable error, do not download data again + var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid + + public override init(frame: CGRect) { + super.init(frame: frame) + BroadcastCenter.addObserver(self, selector: #selector(self.appWillEnterBackground(noti:)), notification: .AppPrepareEnterBackground) + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + BroadcastCenter.removeObserver(self) + } + + + open lazy var voiceImageView: UIImageView = { + let voiceImageView = UIImageView() + voiceImageView.image = EdoImageNoCache("chat-image-attachment-icon") + voiceImageView.translatesAutoresizingMaskIntoConstraints = false + return voiceImageView + }() + +// open lazy var voiceTimeView: UILabel = { +// let voiceTimeView = UILabel() +//// voiceTimeView.text = "0s" +// voiceTimeView.translatesAutoresizingMaskIntoConstraints = false +// return voiceTimeView +// }() + + open var imageView = UIImageView() + + + // MARK: - Methods + + open func setupConstraints() { + voiceImageView.rightInSuperview(-5) + voiceImageView.constraint(equalTo: CGSize(width: 35, height: 35)) + +// voiceTimeView.leftInSuperview(5) +// voiceTimeView.constraint(equalTo: CGSize(width: 35, height: 35)) + + } + + open override func setupSubviews() { + super.setupSubviews() + messageContainerView.stackView.addArrangedSubview(imageView) + imageView.addSubview(voiceImageView) +// imageView.addSubview(voiceTimeView) + setupConstraints() + } + + open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) { + super.configure(with: message, at: indexPath, and: messagesCollectionView) + switch message.data { + case .audio(let data): + super.voiceTimeView.text = "\(data.duration)s" + super.voiceTimeView.textColor = UIColor.lightGray + break + default: + break + } + } + + // MARK: - Download data logic + func downloadData(for downloadInfo: DownloadInfo) { + guard !isDownloadingData && !giveUpRetry else { return } + messageId = downloadInfo.messageId + self.isDownloadingData = true + self.doDownloadData(for: downloadInfo) { doNotRetryDownload in + self.giveUpRetry = doNotRetryDownload + self.isDownloadingData = false + if self.backgroundTask != UIBackgroundTaskInvalid { + UIApplication.shared.endBackgroundTask(self.backgroundTask) + self.backgroundTask = UIBackgroundTaskInvalid + } + } + } + + //If download data process has a non-recoverable error, so that it won't retry + //To be overriden by subclass + func hasNonRecoverableError() -> Bool { + return false + } + + //finished(doNotRetryDownload: Bool), if doNotRetryDownload is true, there is non-recoverable error, do not download data again + func doDownloadData(for downloadInfo: DownloadInfo, finishedAndDoNotRetry: ((Bool)->())? = nil) { + finishedAndDoNotRetry?(true) + //To be override by subclass + } + + @objc func appWillEnterBackground(noti:Notification) { + if isDownloadingData { + backgroundTask = UIApplication.shared.beginBackgroundTask(expirationHandler: { + UIApplication.shared.endBackgroundTask(self.backgroundTask) + NMLog("backgroundTask expired") + self.backgroundTask = UIBackgroundTaskInvalid + }) + } + } + + override open func prepareForReuse() { + super.prepareForReuse() + isDownloadingData = false + messageId = "" + } +} From c687e410111d0539c270c5b467640238cc99df46 Mon Sep 17 00:00:00 2001 From: cccc Date: Fri, 25 May 2018 15:08:53 +0800 Subject: [PATCH 05/35] add voiceTimeLabel size to change loadingView UI --- Sources/Layout/MessagesCollectionViewFlowLayout.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sources/Layout/MessagesCollectionViewFlowLayout.swift b/Sources/Layout/MessagesCollectionViewFlowLayout.swift index b293b7cfa..4b2307810 100644 --- a/Sources/Layout/MessagesCollectionViewFlowLayout.swift +++ b/Sources/Layout/MessagesCollectionViewFlowLayout.swift @@ -409,6 +409,9 @@ private extension MessagesCollectionViewFlowLayout { switch attributes.message.data { case .text, .attributedText: return baseMaxWidth - attributes.messageLabelHorizontalInsets + case .audio: + //czy: add voiceTimeLabel size + return baseMaxWidth - attributes.messageLabelHorizontalInsets - 25 default: return baseMaxWidth } From 22b54b84e4996d6a0990453fb1be903139c04a13 Mon Sep 17 00:00:00 2001 From: cccc Date: Tue, 29 May 2018 19:42:56 +0800 Subject: [PATCH 06/35] add voicePlayView --- .../MessagesCollectionViewFlowLayout.swift | 5 ++- .../Cells/MessageCollectionViewCell.swift | 22 ++++++++++- Sources/Views/Cells/VoiceMessageCell.swift | 39 ++++++++++++++++++- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/Sources/Layout/MessagesCollectionViewFlowLayout.swift b/Sources/Layout/MessagesCollectionViewFlowLayout.swift index 4b2307810..32544ce05 100644 --- a/Sources/Layout/MessagesCollectionViewFlowLayout.swift +++ b/Sources/Layout/MessagesCollectionViewFlowLayout.swift @@ -463,7 +463,10 @@ private extension MessagesCollectionViewFlowLayout { let height = messagesLayoutDelegate.heightForLocation(message: message, at: indexPath, with: maxWidth, in: messagesCollectionView) messageContainerSize = CGSize(width: width, height: height) case .audio(let data): - let width: CGFloat = data.info["width"] as! CGFloat + var width = CGFloat() + if let w: CGFloat = data.info["width"] as? CGFloat { + width = w + } let height = data.height messageContainerSize = CGSize(width: width, height: height) } diff --git a/Sources/Views/Cells/MessageCollectionViewCell.swift b/Sources/Views/Cells/MessageCollectionViewCell.swift index 44bc0c40e..2dcc7be33 100644 --- a/Sources/Views/Cells/MessageCollectionViewCell.swift +++ b/Sources/Views/Cells/MessageCollectionViewCell.swift @@ -53,6 +53,15 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab voiceTimeView.translatesAutoresizingMaskIntoConstraints = false return voiceTimeView }() + + open lazy var voicePlayView: UIView = { + let voicePlayView = UIView() + voicePlayView.layer.cornerRadius = 2 + voicePlayView.backgroundColor = UIColor.red + voicePlayView.isHidden = true + voicePlayView.translatesAutoresizingMaskIntoConstraints = false + return voicePlayView + }() open var cellTopLabel: UILabel = { let label = UILabel() label.numberOfLines = 0 @@ -90,6 +99,7 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab setupCustomMenuItems() setupReplyLabelConstraint() setupVoiceTimeViewonstraint() + setupVoicePlayViewonstraint() } required public init?(coder aDecoder: NSCoder) { @@ -99,6 +109,7 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab open func setupSubviews() { contentView.addSubview(messageContainerView) contentView.addSubview(voiceTimeView) + contentView.addSubview(voicePlayView) contentView.addSubview(avatarView) contentView.addSubview(accessoryView) contentView.addSubview(cellTopLabel) @@ -125,10 +136,19 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab } open func setupVoiceTimeViewonstraint() { NSLayoutConstraint.activate([ - voiceTimeView.rightAnchor.constraint(equalTo: messageContainerView.leftAnchor, constant: -3), + voiceTimeView.rightAnchor.constraint(equalTo: messageContainerView.leftAnchor, constant: -4), voiceTimeView.centerYAnchor.constraint(equalTo: messageContainerView.centerYAnchor) ]) } + open func setupVoicePlayViewonstraint() { + + NSLayoutConstraint.activate([ + voicePlayView.rightAnchor.constraint(equalTo: voiceTimeView.rightAnchor), + voicePlayView.topAnchor.constraint(equalTo: messageContainerView.topAnchor, constant: 5), + voicePlayView.widthAnchor.constraint(equalToConstant: 4), + voicePlayView.heightAnchor.constraint(equalToConstant: 4), + ]) + } open override func prepareForReuse() { super.prepareForReuse() diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index f25e43dec..8264fa3b2 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -17,6 +17,8 @@ open class VoiceMessageCell: MessageCollectionViewCell { var isDownloadingData = false var giveUpRetry = false //if true, there is non-recoverable error, do not download data again var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid + var duration = 0 + var vociePlayed = false public override init(frame: CGRect) { super.init(frame: frame) @@ -34,7 +36,6 @@ open class VoiceMessageCell: MessageCollectionViewCell { open lazy var voiceImageView: UIImageView = { let voiceImageView = UIImageView() - voiceImageView.image = EdoImageNoCache("chat-image-attachment-icon") voiceImageView.translatesAutoresizingMaskIntoConstraints = false return voiceImageView }() @@ -72,8 +73,44 @@ open class VoiceMessageCell: MessageCollectionViewCell { super.configure(with: message, at: indexPath, and: messagesCollectionView) switch message.data { case .audio(let data): + vociePlayed = data.voicePlayed + if !vociePlayed { + self.voicePlayView.isHidden = false + } else { + self.voicePlayView.isHidden = true + } + duration = data.duration super.voiceTimeView.text = "\(data.duration)s" super.voiceTimeView.textColor = UIColor.lightGray + + var isOwn = false + if let bool = messagesCollectionView.messagesDataSource?.isFromCurrentSender(message: message) { + isOwn = bool + } + if isOwn { + voiceImageView.image = EdoImageNoCache("im_voice_right_full") + voiceImageView.animationDuration = 1 + var images=[UIImage]() + for i in 1...3{ + if let img = UIImage(named: "voice_paly_right_\(i)") { + images.append(img) + } + } + voiceImageView.animationImages = images + voiceImageView.animationRepeatCount=0 + + }else { + voiceImageView.image = EdoImageNoCache("im_voice_pressed") + voiceImageView.animationDuration = 1 + var images=[UIImage]() + for i in 1...3{ + if let img = UIImage(named: "voice_paly_left_\(i)") { + images.append(img) + } + } + voiceImageView.animationImages = images + voiceImageView.animationRepeatCount=0 + } break default: break From 6308b188ce8b9637e968369e685dc2c24a119c35 Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Wed, 30 May 2018 15:14:50 +0800 Subject: [PATCH 07/35] download voice data --- Sources/Views/Cells/MediaMessageCell.swift | 24 +++++++-------- Sources/Views/Cells/VoiceMessageCell.swift | 36 +++++++++++++++++++--- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/Sources/Views/Cells/MediaMessageCell.swift b/Sources/Views/Cells/MediaMessageCell.swift index ce8cbc37d..0e92fe09e 100644 --- a/Sources/Views/Cells/MediaMessageCell.swift +++ b/Sources/Views/Cells/MediaMessageCell.swift @@ -103,18 +103,18 @@ open class MediaMessageCell: MessageCollectionViewCell { } } // case .audio(let data): -//// playButtonView.isHidden = true -//// if let attachmentCell = self as? DocumentMessageCell { -//// let isOutgoing = -//// messagesCollectionView.messagesDataSource?.isFromCurrentSender(message: message) -//// ?? true -//// -//// attachmentCell.load(attachment: data, isOutgoing: isOutgoing) -//// //Preload attachment data -//// if let msg = message as? EdisonMessage { -//// downloadData(for: DownloadInfo(accountId: msg.accountId, messageId: msg.messageId)) -//// } -//// } +// playButtonView.isHidden = true +// if let attachmentCell = self as? DocumentMessageCell { +// let isOutgoing = +// messagesCollectionView.messagesDataSource?.isFromCurrentSender(message: message) +// ?? true +// +// attachmentCell.load(attachment: data, isOutgoing: isOutgoing) +// //Preload attachment data +// if let msg = message as? EdisonMessage { +// downloadData(for: DownloadInfo(accountId: msg.accountId, messageId: msg.messageId)) +// } +// } // break default: break diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 8264fa3b2..6e6e4ff46 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -82,7 +82,16 @@ open class VoiceMessageCell: MessageCollectionViewCell { duration = data.duration super.voiceTimeView.text = "\(data.duration)s" super.voiceTimeView.textColor = UIColor.lightGray - + if let msg = message as? EdisonMessage { + if isEmpty(msg.mediaPath) { + let loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) + loading.frame = self.accessoryView.bounds + self.accessoryView.addSubview(loading) + loading.startAnimating() + downloadData(for: DownloadInfo(accountId: msg.accountId, messageId: msg.messageId)) + } + } + var isOwn = false if let bool = messagesCollectionView.messagesDataSource?.isFromCurrentSender(message: message) { isOwn = bool @@ -99,7 +108,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { voiceImageView.animationImages = images voiceImageView.animationRepeatCount=0 - }else { + } else { voiceImageView.image = EdoImageNoCache("im_voice_pressed") voiceImageView.animationDuration = 1 var images=[UIImage]() @@ -140,8 +149,27 @@ open class VoiceMessageCell: MessageCollectionViewCell { //finished(doNotRetryDownload: Bool), if doNotRetryDownload is true, there is non-recoverable error, do not download data again func doDownloadData(for downloadInfo: DownloadInfo, finishedAndDoNotRetry: ((Bool)->())? = nil) { - finishedAndDoNotRetry?(true) - //To be override by subclass + guard let _ = EmailDAL.getChatMessage(msgId: downloadInfo.messageId) else { + finishedAndDoNotRetry?(true) //do not download again + return + } + guard let _ = EmailDAL.getChatAccount(accountId: downloadInfo.accountId) else { + finishedAndDoNotRetry?(true) + return + } + XMPPAdapter.downloadData(accountId: downloadInfo.accountId, + chatMsgId: downloadInfo.messageId) { (messageId, filePath) in + EDOMainthread { +// var hasNonRecoverableError = false + if messageId == self.messageId { + self.loadingView()?.stopAnimating() + BroadcastCenter.postNotification(.ChatFriendJoinedApp) + } else { + XMPPMgrLog("voice is no longer needed") + } + finishedAndDoNotRetry?(true) + } + } } @objc func appWillEnterBackground(noti:Notification) { From b7796ad18f1eee4e4fe219b29ef2cbc34ce9b960 Mon Sep 17 00:00:00 2001 From: cccc Date: Wed, 30 May 2018 15:15:52 +0800 Subject: [PATCH 08/35] Change loading view --- .../MessageIntermediateLayoutAttributes.swift | 25 +++++++++++++++- .../MessagesCollectionViewFlowLayout.swift | 15 ++++++++++ ...ssagesCollectionViewLayoutAttributes.swift | 2 ++ .../Protocols/MessagesLayoutDelegate.swift | 11 +++++++ .../Cells/MessageCollectionViewCell.swift | 29 ++++++++++--------- 5 files changed, 68 insertions(+), 14 deletions(-) diff --git a/Sources/Layout/MessageIntermediateLayoutAttributes.swift b/Sources/Layout/MessageIntermediateLayoutAttributes.swift index e4615d5d3..07ceb2b59 100644 --- a/Sources/Layout/MessageIntermediateLayoutAttributes.swift +++ b/Sources/Layout/MessageIntermediateLayoutAttributes.swift @@ -88,7 +88,7 @@ final class MessageIntermediateLayoutAttributes { case .cellLeading: origin.x = messageContainerFrame.maxX + accessoryViewPadding.left case .cellTrailing: - origin.x = messageContainerFrame.minX - accessoryViewPadding.right - accessoryViewSize.width + origin.x = messageContainerFrame.minX - accessoryViewPadding.right - accessoryViewSize.width - voiceTimeViewSize.width case .natural: fatalError(MessageKitError.avatarPositionUnresolved) } @@ -99,6 +99,7 @@ final class MessageIntermediateLayoutAttributes { // MessageContainerView var messageContainerSize: CGSize = .zero + var messageContainerMaxWidth: CGFloat = 0 var messageContainerPadding: UIEdgeInsets = .zero var messageLabelInsets: UIEdgeInsets = .zero @@ -123,6 +124,28 @@ final class MessageIntermediateLayoutAttributes { }() + var voiceTimeViewSize: CGSize = .zero + var voiceTimeViewPadding: UIEdgeInsets = .zero + lazy var voiceTimeViewframe: CGRect = { + + guard voiceTimeViewSize != .zero else { return .zero } + + var origin: CGPoint = .zero + origin.y = messageContainerFrame.origin.y + messageContainerSize.height * 0.5 - + voiceTimeViewSize.height * 0.5 + + switch avatarPosition.horizontal { + case .cellLeading: + origin.x = messageContainerFrame.maxX + voiceTimeViewPadding.left + case .cellTrailing: + origin.x = messageContainerFrame.minX - voiceTimeViewPadding.right - voiceTimeViewSize.width + case .natural: + fatalError(MessageKitError.avatarPositionUnresolved) + } + + return CGRect(origin: origin, size: voiceTimeViewSize) + }() + // Cell Top Label var topLabelAlignment: LabelAlignment = .cellLeading(.zero) var topLabelSize: CGSize = .zero diff --git a/Sources/Layout/MessagesCollectionViewFlowLayout.swift b/Sources/Layout/MessagesCollectionViewFlowLayout.swift index 32544ce05..e391151aa 100644 --- a/Sources/Layout/MessagesCollectionViewFlowLayout.swift +++ b/Sources/Layout/MessagesCollectionViewFlowLayout.swift @@ -243,6 +243,10 @@ fileprivate extension MessagesCollectionViewFlowLayout { attributes.accessoryViewSize = accessoryViewSize(for: attributes) attributes.accessoryViewPadding = accessoryViewPadding(for: attributes) + // voiceTimeView + attributes.voiceTimeViewSize = voiceTimeViewSize(for: attributes) + attributes.voiceTimeViewPadding = voiceTimeViewPadding(for: attributes) + // MessageContainerView attributes.messageContainerMaxWidth = messageContainerMaxWidth(for: attributes) attributes.messageContainerSize = messageContainerSize(for: attributes) @@ -275,6 +279,7 @@ fileprivate extension MessagesCollectionViewFlowLayout { intermediateAttributes.cellFrame = attributes.frame attributes.messageContainerFrame = intermediateAttributes.messageContainerFrame + attributes.voiceTimeViewframe = intermediateAttributes.voiceTimeViewframe attributes.topLabelFrame = intermediateAttributes.topLabelFrame attributes.bottomLabelFrame = intermediateAttributes.bottomLabelFrame attributes.avatarFrame = intermediateAttributes.avatarFrame @@ -649,6 +654,16 @@ fileprivate extension MessagesCollectionViewFlowLayout { /// - attributes: The `MessageIntermediateLayoutAttributes` containing the `MessageType` object. func accessoryViewPadding(for attributes: MessageIntermediateLayoutAttributes) -> UIEdgeInsets { return messagesLayoutDelegate.accessoryViewPadding(for: attributes.message, at: attributes.indexPath, in: messagesCollectionView) + + } + + func voiceTimeViewSize(for attributes: MessageIntermediateLayoutAttributes) -> CGSize { + return messagesLayoutDelegate.voiceTimeViewSize(for: attributes.message, at: attributes.indexPath, in: messagesCollectionView) + } + + func voiceTimeViewPadding(for attributes: MessageIntermediateLayoutAttributes) -> UIEdgeInsets { + return messagesLayoutDelegate.voiceTimeViewPadding(for: attributes.message, at: attributes.indexPath, in: messagesCollectionView) + } } diff --git a/Sources/Layout/MessagesCollectionViewLayoutAttributes.swift b/Sources/Layout/MessagesCollectionViewLayoutAttributes.swift index 9080d89a4..c8b6f50de 100644 --- a/Sources/Layout/MessagesCollectionViewLayoutAttributes.swift +++ b/Sources/Layout/MessagesCollectionViewLayoutAttributes.swift @@ -35,6 +35,7 @@ final class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttrib var messageLabelFont: UIFont = UIFont.preferredFont(forTextStyle: .body) var messageContainerFrame: CGRect = .zero + var voiceTimeViewframe: CGRect = .zero var messageLabelInsets: UIEdgeInsets = .zero var topLabelFrame: CGRect = .zero @@ -48,6 +49,7 @@ final class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttrib copy.avatarFrame = avatarFrame copy.accessoryViewFrame = accessoryViewFrame copy.messageContainerFrame = messageContainerFrame + copy.voiceTimeViewframe = voiceTimeViewframe copy.messageLabelFont = messageLabelFont copy.messageLabelInsets = messageLabelInsets copy.topLabelFrame = topLabelFrame diff --git a/Sources/Protocols/MessagesLayoutDelegate.swift b/Sources/Protocols/MessagesLayoutDelegate.swift index fcaa6f4a6..7f0916a21 100644 --- a/Sources/Protocols/MessagesLayoutDelegate.swift +++ b/Sources/Protocols/MessagesLayoutDelegate.swift @@ -55,6 +55,8 @@ public protocol MessagesLayoutDelegate: AnyObject { /// The default value returned by this method is zero. func accessoryViewPadding(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets + func voiceTimeViewPadding(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets + /// Specifies the vertical and horizontal alignment for the `EdisonProfileView` in a `MessageCollectionViewCell`. /// /// - Parameters: @@ -114,6 +116,8 @@ public protocol MessagesLayoutDelegate: AnyObject { /// The default value returned by this method is a size of `0 x 0`. func accessoryViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize + func voiceTimeViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize + /// Specifies the size to use for a `MessageHeaderView`. /// /// - Parameters: @@ -231,6 +235,10 @@ public extension MessagesLayoutDelegate { return .zero } + func voiceTimeViewPadding(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIEdgeInsets { + return .zero + } + func cellTopLabelAlignment(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> LabelAlignment { guard let dataSource = messagesCollectionView.messagesDataSource else { fatalError(MessageKitError.nilMessagesDataSource) @@ -256,6 +264,9 @@ public extension MessagesLayoutDelegate { func accessoryViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize { return .zero } + func voiceTimeViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize { + return .zero + } func headerViewSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize { return .zero diff --git a/Sources/Views/Cells/MessageCollectionViewCell.swift b/Sources/Views/Cells/MessageCollectionViewCell.swift index 2dcc7be33..700c0b055 100644 --- a/Sources/Views/Cells/MessageCollectionViewCell.swift +++ b/Sources/Views/Cells/MessageCollectionViewCell.swift @@ -47,12 +47,14 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab return containerView }() - open lazy var voiceTimeView: UILabel = { - let voiceTimeView = UILabel() -// voiceTimeView.text = "0s" - voiceTimeView.translatesAutoresizingMaskIntoConstraints = false - return voiceTimeView - }() + + open var voiceTimeView = UILabel() +// open lazy var voiceTimeView: UILabel = { +// let voiceTimeView = UILabel() +//// voiceTimeView.text = "0s" +// voiceTimeView.translatesAutoresizingMaskIntoConstraints = false +// return voiceTimeView +// }() open lazy var voicePlayView: UIView = { let voicePlayView = UIView() @@ -98,7 +100,7 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab setupSubviews() setupCustomMenuItems() setupReplyLabelConstraint() - setupVoiceTimeViewonstraint() +// setupVoiceTimeViewonstraint() setupVoicePlayViewonstraint() } @@ -134,12 +136,12 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab replyLabel.centerYAnchor.constraint(equalTo: messageContainerView.centerYAnchor) ]) } - open func setupVoiceTimeViewonstraint() { - NSLayoutConstraint.activate([ - voiceTimeView.rightAnchor.constraint(equalTo: messageContainerView.leftAnchor, constant: -4), - voiceTimeView.centerYAnchor.constraint(equalTo: messageContainerView.centerYAnchor) - ]) - } +// open func setupVoiceTimeViewonstraint() { +// NSLayoutConstraint.activate([ +// voiceTimeView.rightAnchor.constraint(equalTo: messageContainerView.leftAnchor, constant: -4), +// voiceTimeView.centerYAnchor.constraint(equalTo: messageContainerView.centerYAnchor) +// ]) +// } open func setupVoicePlayViewonstraint() { NSLayoutConstraint.activate([ @@ -179,6 +181,7 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab cellTopLabel.frame = attributes.topLabelFrame cellBottomLabel.frame = attributes.bottomLabelFrame messageContainerView.frame = attributes.messageContainerFrame + voiceTimeView.frame = attributes.voiceTimeViewframe accessoryView.frame = attributes.accessoryViewFrame } } From 3f75cea313f9405f59ee39568f3bc8e5f5532094 Mon Sep 17 00:00:00 2001 From: cccc Date: Wed, 30 May 2018 15:48:11 +0800 Subject: [PATCH 09/35] change voiceMessageCell width --- .../Layout/MessagesCollectionViewFlowLayout.swift | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Sources/Layout/MessagesCollectionViewFlowLayout.swift b/Sources/Layout/MessagesCollectionViewFlowLayout.swift index e391151aa..da0ebe656 100644 --- a/Sources/Layout/MessagesCollectionViewFlowLayout.swift +++ b/Sources/Layout/MessagesCollectionViewFlowLayout.swift @@ -416,7 +416,7 @@ private extension MessagesCollectionViewFlowLayout { return baseMaxWidth - attributes.messageLabelHorizontalInsets case .audio: //czy: add voiceTimeLabel size - return baseMaxWidth - attributes.messageLabelHorizontalInsets - 25 + return baseMaxWidth - attributes.messageLabelHorizontalInsets default: return baseMaxWidth } @@ -468,11 +468,13 @@ private extension MessagesCollectionViewFlowLayout { let height = messagesLayoutDelegate.heightForLocation(message: message, at: indexPath, with: maxWidth, in: messagesCollectionView) messageContainerSize = CGSize(width: width, height: height) case .audio(let data): - var width = CGFloat() - if let w: CGFloat = data.info["width"] as? CGFloat { - width = w - } - let height = data.height + + //计算宽度或者固定宽度 + let minWidth: CGFloat = 60 + let maxWidth: CGFloat = screenWidth() > 320 ? 240 : 200 + let proportion:CGFloat = CGFloat(Double(data.duration)/60.0) + let width: CGFloat = minWidth + proportion * maxWidth + let height: CGFloat = 35 messageContainerSize = CGSize(width: width, height: height) } From 3e6d14d9fa3707502f8fa57f16c3b12182f14f57 Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Wed, 30 May 2018 16:18:30 +0800 Subject: [PATCH 10/35] changeVoiceplayed --- Sources/Views/Cells/VoiceMessageCell.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 6e6e4ff46..1ed22f586 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -69,6 +69,14 @@ open class VoiceMessageCell: MessageCollectionViewCell { setupConstraints() } + func changeVoicePlayed(voicePlay : Bool) { + if !voicePlay { + self.voicePlayView.isHidden = false + } else { + self.voicePlayView.isHidden = true + } + } + open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) { super.configure(with: message, at: indexPath, and: messagesCollectionView) switch message.data { From 9d6eae2e906ff30059494b0685848fb1f2c91b95 Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Wed, 30 May 2018 16:21:23 +0800 Subject: [PATCH 11/35] Revert "changeVoiceplayed" This reverts commit 3e6d14d9fa3707502f8fa57f16c3b12182f14f57. --- Sources/Views/Cells/VoiceMessageCell.swift | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 1ed22f586..6e6e4ff46 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -69,14 +69,6 @@ open class VoiceMessageCell: MessageCollectionViewCell { setupConstraints() } - func changeVoicePlayed(voicePlay : Bool) { - if !voicePlay { - self.voicePlayView.isHidden = false - } else { - self.voicePlayView.isHidden = true - } - } - open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) { super.configure(with: message, at: indexPath, and: messagesCollectionView) switch message.data { From 278e64e7b23dbe432357bb86799372fcb336eaf7 Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Wed, 30 May 2018 16:49:45 +0800 Subject: [PATCH 12/35] VoicePlayed --- Sources/Views/Cells/VoiceMessageCell.swift | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 6e6e4ff46..a1d78fce2 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -69,6 +69,14 @@ open class VoiceMessageCell: MessageCollectionViewCell { setupConstraints() } + func changeVoicePlayed(voicePlay : Bool) { + if !voicePlay { + self.voicePlayView.isHidden = false + } else { + self.voicePlayView.isHidden = true + } + } + open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) { super.configure(with: message, at: indexPath, and: messagesCollectionView) switch message.data { @@ -149,7 +157,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { //finished(doNotRetryDownload: Bool), if doNotRetryDownload is true, there is non-recoverable error, do not download data again func doDownloadData(for downloadInfo: DownloadInfo, finishedAndDoNotRetry: ((Bool)->())? = nil) { - guard let _ = EmailDAL.getChatMessage(msgId: downloadInfo.messageId) else { + guard let msg = EmailDAL.getChatMessage(msgId: downloadInfo.messageId) else { finishedAndDoNotRetry?(true) //do not download again return } @@ -163,7 +171,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { // var hasNonRecoverableError = false if messageId == self.messageId { self.loadingView()?.stopAnimating() - BroadcastCenter.postNotification(.ChatFriendJoinedApp) + BroadcastCenter.postNotification(.MsgMessageVoiceUpdate, information: [.ConversationId: msg.conversationId]) } else { XMPPMgrLog("voice is no longer needed") } From b51f88f228b4cbe3cf09b1f611fb5314ccc967b2 Mon Sep 17 00:00:00 2001 From: cccc Date: Wed, 30 May 2018 21:00:36 +0800 Subject: [PATCH 13/35] change red ball --- Sources/Views/Cells/VoiceMessageCell.swift | 31 +++++++++++++++------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 6e6e4ff46..913180115 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -52,13 +52,21 @@ open class VoiceMessageCell: MessageCollectionViewCell { // MARK: - Methods - open func setupConstraints() { + open func setupRightConstraints() { voiceImageView.rightInSuperview(-5) voiceImageView.constraint(equalTo: CGSize(width: 35, height: 35)) // voiceTimeView.leftInSuperview(5) // voiceTimeView.constraint(equalTo: CGSize(width: 35, height: 35)) + } + open func setupLeftConstraints() { + voiceImageView.leftInSuperview(5) + voiceImageView.constraint(equalTo: CGSize(width: 35, height: 35)) + + // voiceTimeView.leftInSuperview(5) + // voiceTimeView.constraint(equalTo: CGSize(width: 35, height: 35)) + } open override func setupSubviews() { @@ -66,7 +74,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { messageContainerView.stackView.addArrangedSubview(imageView) imageView.addSubview(voiceImageView) // imageView.addSubview(voiceTimeView) - setupConstraints() + } open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) { @@ -74,11 +82,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { switch message.data { case .audio(let data): vociePlayed = data.voicePlayed - if !vociePlayed { - self.voicePlayView.isHidden = false - } else { - self.voicePlayView.isHidden = true - } + duration = data.duration super.voiceTimeView.text = "\(data.duration)s" super.voiceTimeView.textColor = UIColor.lightGray @@ -101,25 +105,32 @@ open class VoiceMessageCell: MessageCollectionViewCell { voiceImageView.animationDuration = 1 var images=[UIImage]() for i in 1...3{ - if let img = UIImage(named: "voice_paly_right_\(i)") { + if let img = EdoImageNoCache("voice_paly_right_\(i)") { images.append(img) } } voiceImageView.animationImages = images voiceImageView.animationRepeatCount=0 - + setupRightConstraints() } else { voiceImageView.image = EdoImageNoCache("im_voice_pressed") voiceImageView.animationDuration = 1 var images=[UIImage]() for i in 1...3{ - if let img = UIImage(named: "voice_paly_left_\(i)") { + if let img = EdoImageNoCache("voice_paly_left_\(i)") { images.append(img) } } voiceImageView.animationImages = images voiceImageView.animationRepeatCount=0 + setupLeftConstraints() + if !vociePlayed { + self.voicePlayView.isHidden = false + } else { + self.voicePlayView.isHidden = true + } } + break default: break From 3411cdfea4c93d1dfcc972a561fb9ef20f82aa13 Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Thu, 31 May 2018 10:54:58 +0800 Subject: [PATCH 14/35] loadingView --- Sources/Views/Cells/VoiceMessageCell.swift | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index a1d78fce2..5bb76f975 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -92,10 +92,14 @@ open class VoiceMessageCell: MessageCollectionViewCell { super.voiceTimeView.textColor = UIColor.lightGray if let msg = message as? EdisonMessage { if isEmpty(msg.mediaPath) { - let loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) - loading.frame = self.accessoryView.bounds - self.accessoryView.addSubview(loading) - loading.startAnimating() + if let loading = loadingView() { + loading.startAnimating() + } else { + let loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) + loading.frame = self.accessoryView.bounds + self.accessoryView.addSubview(loading) + loading.startAnimating() + } downloadData(for: DownloadInfo(accountId: msg.accountId, messageId: msg.messageId)) } } From 3f46f69a04e953df4271d5af090691907897276d Mon Sep 17 00:00:00 2001 From: cccc Date: Thu, 31 May 2018 16:00:31 +0800 Subject: [PATCH 15/35] Change NSLayoutConstraint about left and right voiceMessageCell --- .../MessageIntermediateLayoutAttributes.swift | 2 +- Sources/Views/Cells/VoiceMessageCell.swift | 47 +++++++++++-------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/Sources/Layout/MessageIntermediateLayoutAttributes.swift b/Sources/Layout/MessageIntermediateLayoutAttributes.swift index 07ceb2b59..85b966676 100644 --- a/Sources/Layout/MessageIntermediateLayoutAttributes.swift +++ b/Sources/Layout/MessageIntermediateLayoutAttributes.swift @@ -86,7 +86,7 @@ final class MessageIntermediateLayoutAttributes { switch avatarPosition.horizontal { case .cellLeading: - origin.x = messageContainerFrame.maxX + accessoryViewPadding.left + origin.x = messageContainerFrame.maxX + accessoryViewPadding.left + accessoryViewSize.width case .cellTrailing: origin.x = messageContainerFrame.minX - accessoryViewPadding.right - accessoryViewSize.width - voiceTimeViewSize.width case .natural: diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 9091dae00..f66adb241 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -12,6 +12,9 @@ open class VoiceMessageCell: MessageCollectionViewCell { open override class func reuseIdentifier() -> String { return "messagekit.cell.voicemessage" } // MARK: - Properties + private var voiceImageViewRightConstraint = NSLayoutConstraint() + private var voiceImageViewLeftConstraint = NSLayoutConstraint() + private var voiceImageViewConstraints = [NSLayoutConstraint]() var messageId = "" var isDownloadingData = false @@ -40,41 +43,38 @@ open class VoiceMessageCell: MessageCollectionViewCell { return voiceImageView }() -// open lazy var voiceTimeView: UILabel = { -// let voiceTimeView = UILabel() -//// voiceTimeView.text = "0s" -// voiceTimeView.translatesAutoresizingMaskIntoConstraints = false -// return voiceTimeView -// }() - open var imageView = UIImageView() - // MARK: - Methods open func setupRightConstraints() { - voiceImageView.rightInSuperview(-5) - voiceImageView.constraint(equalTo: CGSize(width: 35, height: 35)) - -// voiceTimeView.leftInSuperview(5) -// voiceTimeView.constraint(equalTo: CGSize(width: 35, height: 35)) + NSLayoutConstraint.deactivate(voiceImageViewConstraints) + voiceImageViewRightConstraint = voiceImageView.rightAnchor.constraint(equalTo: imageView.rightAnchor, constant: -5) + voiceImageViewConstraints = [ + voiceImageViewRightConstraint, + voiceImageView.centerYAnchor.constraint(equalTo: imageView.centerYAnchor) + ] + NSLayoutConstraint.activate(voiceImageViewConstraints) } open func setupLeftConstraints() { - voiceImageView.leftInSuperview(5) - voiceImageView.constraint(equalTo: CGSize(width: 35, height: 35)) - - // voiceTimeView.leftInSuperview(5) - // voiceTimeView.constraint(equalTo: CGSize(width: 35, height: 35)) - + NSLayoutConstraint.deactivate(voiceImageViewConstraints) + voiceImageViewLeftConstraint = voiceImageView.leftAnchor.constraint(equalTo: imageView.leftAnchor, constant: 5) + voiceImageViewConstraints = [ + voiceImageViewLeftConstraint, + voiceImageView.centerYAnchor.constraint(equalTo: imageView.centerYAnchor) + ] + NSLayoutConstraint.activate(voiceImageViewConstraints) } open override func setupSubviews() { super.setupSubviews() messageContainerView.stackView.addArrangedSubview(imageView) imageView.addSubview(voiceImageView) -// imageView.addSubview(voiceTimeView) + voiceImageView.constraint(equalTo: CGSize(width: 35, height: 35)) + + } func changeVoicePlayed(voicePlay : Bool) { @@ -119,7 +119,10 @@ open class VoiceMessageCell: MessageCollectionViewCell { } voiceImageView.animationImages = images voiceImageView.animationRepeatCount=0 + setupRightConstraints() + self.layoutIfNeeded() + self.layoutSubviews() } else { voiceImageView.image = EdoImageNoCache("im_voice_pressed") voiceImageView.animationDuration = 1 @@ -131,7 +134,11 @@ open class VoiceMessageCell: MessageCollectionViewCell { } voiceImageView.animationImages = images voiceImageView.animationRepeatCount=0 + setupLeftConstraints() + self.layoutIfNeeded() + self.layoutSubviews() + if !vociePlayed { self.voicePlayView.isHidden = false } else { From 9992553d890aeea88020238523597ddc2a21ad33 Mon Sep 17 00:00:00 2001 From: cccc Date: Thu, 31 May 2018 18:08:11 +0800 Subject: [PATCH 16/35] change about voiceMessageCell red ball --- Sources/Views/Cells/VoiceMessageCell.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 5506cd3cd..6ad0c29d5 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -123,7 +123,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { } voiceImageView.animationImages = images voiceImageView.animationRepeatCount=0 - + self.voicePlayView.isHidden = true setupRightConstraints() self.layoutIfNeeded() self.layoutSubviews() From 95f9652b6b0cee396ba1bd3d1b0e5234ccda61ff Mon Sep 17 00:00:00 2001 From: cccc Date: Fri, 1 Jun 2018 15:03:42 +0800 Subject: [PATCH 17/35] change the voiceTime --- .../Cells/MessageCollectionViewCell.swift | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/Sources/Views/Cells/MessageCollectionViewCell.swift b/Sources/Views/Cells/MessageCollectionViewCell.swift index 700c0b055..23bf08419 100644 --- a/Sources/Views/Cells/MessageCollectionViewCell.swift +++ b/Sources/Views/Cells/MessageCollectionViewCell.swift @@ -49,12 +49,7 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab open var voiceTimeView = UILabel() -// open lazy var voiceTimeView: UILabel = { -// let voiceTimeView = UILabel() -//// voiceTimeView.text = "0s" -// voiceTimeView.translatesAutoresizingMaskIntoConstraints = false -// return voiceTimeView -// }() + open lazy var voicePlayView: UIView = { let voicePlayView = UIView() @@ -100,7 +95,6 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab setupSubviews() setupCustomMenuItems() setupReplyLabelConstraint() -// setupVoiceTimeViewonstraint() setupVoicePlayViewonstraint() } @@ -110,6 +104,7 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab open func setupSubviews() { contentView.addSubview(messageContainerView) + voiceTimeView.textAlignment = .center contentView.addSubview(voiceTimeView) contentView.addSubview(voicePlayView) contentView.addSubview(avatarView) @@ -136,12 +131,7 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab replyLabel.centerYAnchor.constraint(equalTo: messageContainerView.centerYAnchor) ]) } -// open func setupVoiceTimeViewonstraint() { -// NSLayoutConstraint.activate([ -// voiceTimeView.rightAnchor.constraint(equalTo: messageContainerView.leftAnchor, constant: -4), -// voiceTimeView.centerYAnchor.constraint(equalTo: messageContainerView.centerYAnchor) -// ]) -// } + open func setupVoicePlayViewonstraint() { NSLayoutConstraint.activate([ @@ -181,7 +171,7 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab cellTopLabel.frame = attributes.topLabelFrame cellBottomLabel.frame = attributes.bottomLabelFrame messageContainerView.frame = attributes.messageContainerFrame - voiceTimeView.frame = attributes.voiceTimeViewframe + voiceTimeView.frame = attributes.voiceTimeViewframe accessoryView.frame = attributes.accessoryViewFrame } } From 19481ceff926bde41e0e29b2ec3d1938526177c6 Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Fri, 1 Jun 2018 15:13:46 +0800 Subject: [PATCH 18/35] voice need add a bool in callback. --- Sources/Views/Cells/DocumentMessageCell.swift | 2 +- Sources/Views/Cells/PhotoMessageCell.swift | 2 +- Sources/Views/Cells/VoiceMessageCell.swift | 24 ++++++++++++------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Sources/Views/Cells/DocumentMessageCell.swift b/Sources/Views/Cells/DocumentMessageCell.swift index 82176b26e..caea6db9e 100644 --- a/Sources/Views/Cells/DocumentMessageCell.swift +++ b/Sources/Views/Cells/DocumentMessageCell.swift @@ -24,7 +24,7 @@ class DocumentMessageCell: MediaMessageCell { let mailAcctId = chatAcct.mailAcctId XMPPAdapter.downloadData(accountId: downloadInfo.accountId, - chatMsgId: downloadInfo.messageId) { (messageId, filePath) in + chatMsgId: downloadInfo.messageId) { (messageId, filePath, _) in if let path = filePath, let data = NSData(contentsOfFile: path) as Data? { EmailAdapter.convertEmailDataFromChatToEdoMessage(data: data, emailId: messageId, mailAcctId: mailAcctId) diff --git a/Sources/Views/Cells/PhotoMessageCell.swift b/Sources/Views/Cells/PhotoMessageCell.swift index a0874b2f6..c648da49d 100644 --- a/Sources/Views/Cells/PhotoMessageCell.swift +++ b/Sources/Views/Cells/PhotoMessageCell.swift @@ -15,7 +15,7 @@ class PhotoMessageCell: MediaMessageCell { override func doDownloadData(for downloadInfo: DownloadInfo, finishedAndDoNotRetry:((Bool)->())? = nil) { XMPPAdapter.downloadData(accountId: downloadInfo.accountId, chatMsgId: downloadInfo.messageId, - forThumb: downloadInfo.isThumbnail) { (messageId, filePath) in + forThumb: downloadInfo.isThumbnail) { (messageId, filePath, _) in EDOMainthread { var hasNonRecoverableError = false if messageId == self.messageId { diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 6ad0c29d5..f16424354 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -96,14 +96,6 @@ open class VoiceMessageCell: MessageCollectionViewCell { super.voiceTimeView.textColor = UIColor.lightGray if let msg = message as? EdisonMessage { if isEmpty(msg.mediaPath) { - if let loading = loadingView() { - loading.startAnimating() - } else { - let loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) - loading.frame = self.accessoryView.bounds - self.accessoryView.addSubview(loading) - loading.startAnimating() - } downloadData(for: DownloadInfo(accountId: msg.accountId, messageId: msg.messageId)) } } @@ -161,6 +153,17 @@ open class VoiceMessageCell: MessageCollectionViewCell { guard !isDownloadingData && !giveUpRetry else { return } messageId = downloadInfo.messageId self.isDownloadingData = true + if let loading = loadingView() { + loading.startAnimating() + } else { + for view in self.accessoryView.subviews { + view.removeFromSuperview() + } + let loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) + loading.frame = self.accessoryView.bounds + self.accessoryView.addSubview(loading) + loading.startAnimating() + } self.doDownloadData(for: downloadInfo) { doNotRetryDownload in self.giveUpRetry = doNotRetryDownload self.isDownloadingData = false @@ -188,12 +191,15 @@ open class VoiceMessageCell: MessageCollectionViewCell { return } XMPPAdapter.downloadData(accountId: downloadInfo.accountId, - chatMsgId: downloadInfo.messageId) { (messageId, filePath) in + chatMsgId: downloadInfo.messageId) { (messageId, filePath, success) in EDOMainthread { // var hasNonRecoverableError = false if messageId == self.messageId { self.loadingView()?.stopAnimating() BroadcastCenter.postNotification(.MsgMessageVoiceUpdate, information: [.ConversationId: msg.conversationId]) + if !success { + //TODO: add a download failure warning + } } else { XMPPMgrLog("voice is no longer needed") } From 2c1b981aea08ce2db2979fef79ccf66302c501f5 Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Fri, 1 Jun 2018 15:19:29 +0800 Subject: [PATCH 19/35] retry download --- Sources/Views/Cells/VoiceMessageCell.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index f16424354..56293d804 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -22,6 +22,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid var duration = 0 var vociePlayed = false + var downloadInfo = DownloadInfo(accountId: "", messageId: "") public override init(frame: CGRect) { super.init(frame: frame) @@ -96,7 +97,8 @@ open class VoiceMessageCell: MessageCollectionViewCell { super.voiceTimeView.textColor = UIColor.lightGray if let msg = message as? EdisonMessage { if isEmpty(msg.mediaPath) { - downloadData(for: DownloadInfo(accountId: msg.accountId, messageId: msg.messageId)) + self.downloadInfo = DownloadInfo(accountId: msg.accountId, messageId: msg.messageId) + downloadData(for: self.downloadInfo) } } @@ -173,7 +175,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { } } } - + //If download data process has a non-recoverable error, so that it won't retry //To be overriden by subclass func hasNonRecoverableError() -> Bool { @@ -207,7 +209,12 @@ open class VoiceMessageCell: MessageCollectionViewCell { } } } - + + //TODO: retry download + func retrydownload() { + downloadData(for: self.downloadInfo) + } + @objc func appWillEnterBackground(noti:Notification) { if isDownloadingData { backgroundTask = UIApplication.shared.beginBackgroundTask(expirationHandler: { From 0ddf48ca06973cc67df1d6275f565c3eebdaf921 Mon Sep 17 00:00:00 2001 From: cccc Date: Mon, 4 Jun 2018 20:12:54 +0800 Subject: [PATCH 20/35] add download message error and retry --- Sources/Views/Cells/VoiceMessageCell.swift | 44 ++++++++++++++++++---- Sources/Views/MessagesCollectionView.swift | 2 + 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 56293d804..4a129a2ba 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -7,6 +7,10 @@ // import UIKit +public protocol VoiceMessageCellDelegate: MessageLabelDelegate { + func didTapTopAgainDownloadVoiceView(in cell: VoiceMessageCell) +} + open class VoiceMessageCell: MessageCollectionViewCell { open override class func reuseIdentifier() -> String { return "messagekit.cell.voicemessage" } @@ -16,6 +20,8 @@ open class VoiceMessageCell: MessageCollectionViewCell { private var voiceImageViewLeftConstraint = NSLayoutConstraint() private var voiceImageViewConstraints = [NSLayoutConstraint]() + open weak var voiceMessageCellDelegate: VoiceMessageCellDelegate? + var messageId = "" var isDownloadingData = false var giveUpRetry = false //if true, there is non-recoverable error, do not download data again @@ -46,6 +52,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { open var imageView = UIImageView() + open var againDownloadVoiceView = UIView() // MARK: - Methods open func setupRightConstraints() { @@ -70,14 +77,27 @@ open class VoiceMessageCell: MessageCollectionViewCell { open override func setupSubviews() { super.setupSubviews() + messageContainerView.stackView.addArrangedSubview(imageView) imageView.addSubview(voiceImageView) voiceImageView.constraint(equalTo: CGSize(width: 35, height: 35)) - + let alertVoiceImageView = UIImageView() + alertVoiceImageView.image = EdoImageNoCache("alert-icon") + alertVoiceImageView.translatesAutoresizingMaskIntoConstraints = false + alertVoiceImageView.frame = againDownloadVoiceView.frame + againDownloadVoiceView.isHidden = true + contentView.addSubview(againDownloadVoiceView) + againDownloadVoiceView.addSubview(alertVoiceImageView) + againDownloadVoiceView.addConstraintsForSubviewWithSameSize(alertVoiceImageView) } - + open override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) { + super.apply(layoutAttributes) + if let attributes = layoutAttributes as? MessagesCollectionViewLayoutAttributes { + againDownloadVoiceView.frame = attributes.accessoryViewFrame + } + } func changeVoicePlayed(voicePlay : Bool) { if !voicePlay { self.voicePlayView.isHidden = false @@ -87,6 +107,8 @@ open class VoiceMessageCell: MessageCollectionViewCell { } open override func configure(with message: MessageType, at indexPath: IndexPath, and messagesCollectionView: MessagesCollectionView) { + + self.voiceMessageCellDelegate = messagesCollectionView.voiceMessageCellDelegate super.configure(with: message, at: indexPath, and: messagesCollectionView) switch message.data { case .audio(let data): @@ -121,6 +143,8 @@ open class VoiceMessageCell: MessageCollectionViewCell { setupRightConstraints() self.layoutIfNeeded() self.layoutSubviews() + + self.againDownloadVoiceView.removeFromSuperview() } else { voiceImageView.image = EdoImageNoCache("im_voice_pressed") voiceImageView.animationDuration = 1 @@ -142,6 +166,9 @@ open class VoiceMessageCell: MessageCollectionViewCell { } else { self.voicePlayView.isHidden = true } + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGestureRecognizer(_:))) + self.againDownloadVoiceView.addGestureRecognizer(tapGestureRecognizer) + self.contentView.addSubview(againDownloadVoiceView) } break @@ -149,7 +176,9 @@ open class VoiceMessageCell: MessageCollectionViewCell { break } } - + @objc func tapGestureRecognizer(_ tapGesture :UITapGestureRecognizer) { + self.voiceMessageCellDelegate?.didTapTopAgainDownloadVoiceView(in: self) + } // MARK: - Download data logic func downloadData(for downloadInfo: DownloadInfo) { guard !isDownloadingData && !giveUpRetry else { return } @@ -158,9 +187,6 @@ open class VoiceMessageCell: MessageCollectionViewCell { if let loading = loadingView() { loading.startAnimating() } else { - for view in self.accessoryView.subviews { - view.removeFromSuperview() - } let loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) loading.frame = self.accessoryView.bounds self.accessoryView.addSubview(loading) @@ -200,7 +226,10 @@ open class VoiceMessageCell: MessageCollectionViewCell { self.loadingView()?.stopAnimating() BroadcastCenter.postNotification(.MsgMessageVoiceUpdate, information: [.ConversationId: msg.conversationId]) if !success { + //TODO: add a download failure warning + self.againDownloadVoiceView.isHidden = false + } } else { XMPPMgrLog("voice is no longer needed") @@ -211,7 +240,8 @@ open class VoiceMessageCell: MessageCollectionViewCell { } //TODO: retry download - func retrydownload() { + @objc func retrydownload() { + self.giveUpRetry = false downloadData(for: self.downloadInfo) } diff --git a/Sources/Views/MessagesCollectionView.swift b/Sources/Views/MessagesCollectionView.swift index dca0e17d1..f7f8bb3b4 100644 --- a/Sources/Views/MessagesCollectionView.swift +++ b/Sources/Views/MessagesCollectionView.swift @@ -39,6 +39,8 @@ open class MessagesCollectionView: UICollectionView, UIGestureRecognizerDelegate open weak var messagesLayoutDelegate: MessagesLayoutDelegate? open weak var messageCellDelegate: MessageCellDelegate? + + open weak var voiceMessageCellDelegate: VoiceMessageCellDelegate? open var showsDateHeaderAfterTimeInterval: TimeInterval = 3600 From 9859de7b200a40a308d8bffc0f45ba3621d58ce0 Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Tue, 5 Jun 2018 12:06:34 +0800 Subject: [PATCH 21/35] add voiceCell menu. reply a voice cell's width --- Sources/Controllers/MessagesViewController+Delegate.swift | 2 +- Sources/Layout/MessagesCollectionViewFlowLayout.swift | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/Controllers/MessagesViewController+Delegate.swift b/Sources/Controllers/MessagesViewController+Delegate.swift index 2e144a8d8..82feaadb8 100644 --- a/Sources/Controllers/MessagesViewController+Delegate.swift +++ b/Sources/Controllers/MessagesViewController+Delegate.swift @@ -69,7 +69,7 @@ extension MessagesViewController: UICollectionViewDelegateFlowLayout { let message = messagesDataSource.messageForItem(at: indexPath, in: messagesCollectionView) switch message.data { - case .text, .attributedText, .emoji, .photo, .attachment: + case .text, .attributedText, .emoji, .photo, .attachment, .audio: selectedIndexPathForMenu = indexPath return true default: diff --git a/Sources/Layout/MessagesCollectionViewFlowLayout.swift b/Sources/Layout/MessagesCollectionViewFlowLayout.swift index da0ebe656..88840c913 100644 --- a/Sources/Layout/MessagesCollectionViewFlowLayout.swift +++ b/Sources/Layout/MessagesCollectionViewFlowLayout.swift @@ -476,6 +476,7 @@ private extension MessagesCollectionViewFlowLayout { let width: CGFloat = minWidth + proportion * maxWidth let height: CGFloat = 35 messageContainerSize = CGSize(width: width, height: height) + messageContainerSize.width = max(messageContainerSize.width, replyWithLabelInsets) } messageContainerSize.height += messagesLayoutDelegate.replyViewHeight(at: indexPath, From ffe43c0fe03ba111ef212ec55b93404047dd18e4 Mon Sep 17 00:00:00 2001 From: cccc Date: Thu, 7 Jun 2018 09:50:38 +0800 Subject: [PATCH 22/35] Change download voice UI --- Sources/Views/Cells/VoiceMessageCell.swift | 170 ++++++++++++--------- 1 file changed, 96 insertions(+), 74 deletions(-) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 4a129a2ba..03e2ad6bf 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -32,7 +32,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { public override init(frame: CGRect) { super.init(frame: frame) - BroadcastCenter.addObserver(self, selector: #selector(self.appWillEnterBackground(noti:)), notification: .AppPrepareEnterBackground) +// BroadcastCenter.addObserver(self, selector: #selector(self.appWillEnterBackground(noti:)), notification: .AppPrepareEnterBackground) } required public init?(coder aDecoder: NSCoder) { @@ -117,12 +117,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { duration = data.duration super.voiceTimeView.text = "\(data.duration)s" super.voiceTimeView.textColor = UIColor.lightGray - if let msg = message as? EdisonMessage { - if isEmpty(msg.mediaPath) { - self.downloadInfo = DownloadInfo(accountId: msg.accountId, messageId: msg.messageId) - downloadData(for: self.downloadInfo) - } - } + var isOwn = false if let bool = messagesCollectionView.messagesDataSource?.isFromCurrentSender(message: message) { @@ -170,6 +165,33 @@ open class VoiceMessageCell: MessageCollectionViewCell { self.againDownloadVoiceView.addGestureRecognizer(tapGestureRecognizer) self.contentView.addSubview(againDownloadVoiceView) } + if let msg = message as? EdisonMessage { + switch msg.downloadState { + case XMPPConstants.ChatMsgVoiceDownloadState.downloading: + if let loading = loadingView() { + loading.startAnimating() + } else { + let loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) + loading.frame = self.accessoryView.bounds + self.accessoryView.addSubview(loading) + loading.startAnimating() + } + + break + case XMPPConstants.ChatMsgVoiceDownloadState.downloadSuccess: + self.againDownloadVoiceView.isHidden = true + break + case XMPPConstants.ChatMsgVoiceDownloadState.downloadFailed: + if let loading = loadingView() { + loading.stopAnimating() + } + self.againDownloadVoiceView.isHidden = false + + break + default: break + + } + } break default: @@ -180,27 +202,27 @@ open class VoiceMessageCell: MessageCollectionViewCell { self.voiceMessageCellDelegate?.didTapTopAgainDownloadVoiceView(in: self) } // MARK: - Download data logic - func downloadData(for downloadInfo: DownloadInfo) { - guard !isDownloadingData && !giveUpRetry else { return } - messageId = downloadInfo.messageId - self.isDownloadingData = true - if let loading = loadingView() { - loading.startAnimating() - } else { - let loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) - loading.frame = self.accessoryView.bounds - self.accessoryView.addSubview(loading) - loading.startAnimating() - } - self.doDownloadData(for: downloadInfo) { doNotRetryDownload in - self.giveUpRetry = doNotRetryDownload - self.isDownloadingData = false - if self.backgroundTask != UIBackgroundTaskInvalid { - UIApplication.shared.endBackgroundTask(self.backgroundTask) - self.backgroundTask = UIBackgroundTaskInvalid - } - } - } +// func downloadData(for downloadInfo: DownloadInfo) { +// guard !isDownloadingData && !giveUpRetry else { return } +// messageId = downloadInfo.messageId +// self.isDownloadingData = true +// if let loading = loadingView() { +// loading.startAnimating() +// } else { +// let loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) +// loading.frame = self.accessoryView.bounds +// self.accessoryView.addSubview(loading) +// loading.startAnimating() +// } +// self.doDownloadData(for: downloadInfo) { doNotRetryDownload in +// self.giveUpRetry = doNotRetryDownload +// self.isDownloadingData = false +// if self.backgroundTask != UIBackgroundTaskInvalid { +// UIApplication.shared.endBackgroundTask(self.backgroundTask) +// self.backgroundTask = UIBackgroundTaskInvalid +// } +// } +// } //If download data process has a non-recoverable error, so that it won't retry //To be overriden by subclass @@ -209,55 +231,55 @@ open class VoiceMessageCell: MessageCollectionViewCell { } //finished(doNotRetryDownload: Bool), if doNotRetryDownload is true, there is non-recoverable error, do not download data again - func doDownloadData(for downloadInfo: DownloadInfo, finishedAndDoNotRetry: ((Bool)->())? = nil) { - guard let msg = EmailDAL.getChatMessage(msgId: downloadInfo.messageId) else { - finishedAndDoNotRetry?(true) //do not download again - return - } - guard let _ = EmailDAL.getChatAccount(accountId: downloadInfo.accountId) else { - finishedAndDoNotRetry?(true) - return - } - XMPPAdapter.downloadData(accountId: downloadInfo.accountId, - chatMsgId: downloadInfo.messageId) { (messageId, filePath, success) in - EDOMainthread { -// var hasNonRecoverableError = false - if messageId == self.messageId { - self.loadingView()?.stopAnimating() - BroadcastCenter.postNotification(.MsgMessageVoiceUpdate, information: [.ConversationId: msg.conversationId]) - if !success { - - //TODO: add a download failure warning - self.againDownloadVoiceView.isHidden = false - - } - } else { - XMPPMgrLog("voice is no longer needed") - } - finishedAndDoNotRetry?(true) - } - } - } +// func doDownloadData(for downloadInfo: DownloadInfo, finishedAndDoNotRetry: ((Bool)->())? = nil) { +// guard let msg = EmailDAL.getChatMessage(msgId: downloadInfo.messageId) else { +// finishedAndDoNotRetry?(true) //do not download again +// return +// } +// guard let _ = EmailDAL.getChatAccount(accountId: downloadInfo.accountId) else { +// finishedAndDoNotRetry?(true) +// return +// } +// XMPPAdapter.downloadData(accountId: downloadInfo.accountId, +// chatMsgId: downloadInfo.messageId) { (messageId, filePath, success) in +// EDOMainthread { +//// var hasNonRecoverableError = false +// if messageId == self.messageId { +// self.loadingView()?.stopAnimating() +// BroadcastCenter.postNotification(.MsgMessageVoiceUpdate, information: [.ConversationId: msg.conversationId]) +// if !success { +// +// //TODO: add a download failure warning +// self.againDownloadVoiceView.isHidden = false +// +// } +// } else { +// XMPPMgrLog("voice is no longer needed") +// } +// finishedAndDoNotRetry?(true) +// } +// } +// } //TODO: retry download @objc func retrydownload() { - self.giveUpRetry = false - downloadData(for: self.downloadInfo) +// self.giveUpRetry = false +// downloadData(for: self.downloadInfo) } - @objc func appWillEnterBackground(noti:Notification) { - if isDownloadingData { - backgroundTask = UIApplication.shared.beginBackgroundTask(expirationHandler: { - UIApplication.shared.endBackgroundTask(self.backgroundTask) - NMLog("backgroundTask expired") - self.backgroundTask = UIBackgroundTaskInvalid - }) - } - } - - override open func prepareForReuse() { - super.prepareForReuse() - isDownloadingData = false - messageId = "" - } +// @objc func appWillEnterBackground(noti:Notification) { +// if isDownloadingData { +// backgroundTask = UIApplication.shared.beginBackgroundTask(expirationHandler: { +// UIApplication.shared.endBackgroundTask(self.backgroundTask) +// NMLog("backgroundTask expired") +// self.backgroundTask = UIBackgroundTaskInvalid +// }) +// } +// } + +// override open func prepareForReuse() { +// super.prepareForReuse() +// isDownloadingData = false +// messageId = "" +// } } From d23f7a136166320a369ab03d0602aaeb52e212ff Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Thu, 7 Jun 2018 10:58:57 +0800 Subject: [PATCH 23/35] download and refresh --- Sources/Views/Cells/VoiceMessageCell.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 03e2ad6bf..bfd526131 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -168,6 +168,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { if let msg = message as? EdisonMessage { switch msg.downloadState { case XMPPConstants.ChatMsgVoiceDownloadState.downloading: + self.againDownloadVoiceView.isHidden = true if let loading = loadingView() { loading.startAnimating() } else { From f3d039d5b5a7fa3e3028cc7ad2c651dff654c5d3 Mon Sep 17 00:00:00 2001 From: cccc Date: Thu, 7 Jun 2018 15:05:24 +0800 Subject: [PATCH 24/35] download voice again --- Sources/Views/Cells/VoiceMessageCell.swift | 100 ++++----------------- 1 file changed, 15 insertions(+), 85 deletions(-) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index bfd526131..04efd040e 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -22,17 +22,15 @@ open class VoiceMessageCell: MessageCollectionViewCell { open weak var voiceMessageCellDelegate: VoiceMessageCellDelegate? - var messageId = "" + var message : EdisonMessage? var isDownloadingData = false var giveUpRetry = false //if true, there is non-recoverable error, do not download data again var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid var duration = 0 var vociePlayed = false - var downloadInfo = DownloadInfo(accountId: "", messageId: "") public override init(frame: CGRect) { super.init(frame: frame) -// BroadcastCenter.addObserver(self, selector: #selector(self.appWillEnterBackground(noti:)), notification: .AppPrepareEnterBackground) } required public init?(coder aDecoder: NSCoder) { @@ -161,9 +159,6 @@ open class VoiceMessageCell: MessageCollectionViewCell { } else { self.voicePlayView.isHidden = true } - let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGestureRecognizer(_:))) - self.againDownloadVoiceView.addGestureRecognizer(tapGestureRecognizer) - self.contentView.addSubview(againDownloadVoiceView) } if let msg = message as? EdisonMessage { switch msg.downloadState { @@ -186,8 +181,11 @@ open class VoiceMessageCell: MessageCollectionViewCell { if let loading = loadingView() { loading.stopAnimating() } + self.message = msg self.againDownloadVoiceView.isHidden = false - + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGestureRecognizer(_:))) + self.againDownloadVoiceView.addGestureRecognizer(tapGestureRecognizer) + self.contentView.addSubview(againDownloadVoiceView) break default: break @@ -202,85 +200,17 @@ open class VoiceMessageCell: MessageCollectionViewCell { @objc func tapGestureRecognizer(_ tapGesture :UITapGestureRecognizer) { self.voiceMessageCellDelegate?.didTapTopAgainDownloadVoiceView(in: self) } - // MARK: - Download data logic -// func downloadData(for downloadInfo: DownloadInfo) { -// guard !isDownloadingData && !giveUpRetry else { return } -// messageId = downloadInfo.messageId -// self.isDownloadingData = true -// if let loading = loadingView() { -// loading.startAnimating() -// } else { -// let loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) -// loading.frame = self.accessoryView.bounds -// self.accessoryView.addSubview(loading) -// loading.startAnimating() -// } -// self.doDownloadData(for: downloadInfo) { doNotRetryDownload in -// self.giveUpRetry = doNotRetryDownload -// self.isDownloadingData = false -// if self.backgroundTask != UIBackgroundTaskInvalid { -// UIApplication.shared.endBackgroundTask(self.backgroundTask) -// self.backgroundTask = UIBackgroundTaskInvalid -// } -// } -// } - - //If download data process has a non-recoverable error, so that it won't retry - //To be overriden by subclass - func hasNonRecoverableError() -> Bool { - return false - } - //finished(doNotRetryDownload: Bool), if doNotRetryDownload is true, there is non-recoverable error, do not download data again -// func doDownloadData(for downloadInfo: DownloadInfo, finishedAndDoNotRetry: ((Bool)->())? = nil) { -// guard let msg = EmailDAL.getChatMessage(msgId: downloadInfo.messageId) else { -// finishedAndDoNotRetry?(true) //do not download again -// return -// } -// guard let _ = EmailDAL.getChatAccount(accountId: downloadInfo.accountId) else { -// finishedAndDoNotRetry?(true) -// return -// } -// XMPPAdapter.downloadData(accountId: downloadInfo.accountId, -// chatMsgId: downloadInfo.messageId) { (messageId, filePath, success) in -// EDOMainthread { -//// var hasNonRecoverableError = false -// if messageId == self.messageId { -// self.loadingView()?.stopAnimating() -// BroadcastCenter.postNotification(.MsgMessageVoiceUpdate, information: [.ConversationId: msg.conversationId]) -// if !success { -// -// //TODO: add a download failure warning -// self.againDownloadVoiceView.isHidden = false -// -// } -// } else { -// XMPPMgrLog("voice is no longer needed") -// } -// finishedAndDoNotRetry?(true) -// } -// } -// } - - //TODO: retry download - @objc func retrydownload() { -// self.giveUpRetry = false -// downloadData(for: self.downloadInfo) + //TODO: loadingView Animating + @objc func loadingViewAnimating() { + if let loading = loadingView() { + loading.startAnimating() + } else { + let loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) + loading.frame = self.accessoryView.bounds + self.accessoryView.addSubview(loading) + loading.startAnimating() + } } -// @objc func appWillEnterBackground(noti:Notification) { -// if isDownloadingData { -// backgroundTask = UIApplication.shared.beginBackgroundTask(expirationHandler: { -// UIApplication.shared.endBackgroundTask(self.backgroundTask) -// NMLog("backgroundTask expired") -// self.backgroundTask = UIBackgroundTaskInvalid -// }) -// } -// } - -// override open func prepareForReuse() { -// super.prepareForReuse() -// isDownloadingData = false -// messageId = "" -// } } From 858401376dede52bd773fc1dd12ef2141d7f5ea6 Mon Sep 17 00:00:00 2001 From: cccc Date: Thu, 7 Jun 2018 17:43:20 +0800 Subject: [PATCH 25/35] Change download voice --- Sources/Views/Cells/VoiceMessageCell.swift | 65 +++++++++++----------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 04efd040e..5a88a8014 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -8,7 +8,7 @@ import UIKit public protocol VoiceMessageCellDelegate: MessageLabelDelegate { - func didTapTopAgainDownloadVoiceView(in cell: VoiceMessageCell) + func didTapTopAgainDownloadVoiceView(in messageId: String) } @@ -159,36 +159,37 @@ open class VoiceMessageCell: MessageCollectionViewCell { } else { self.voicePlayView.isHidden = true } - } - if let msg = message as? EdisonMessage { - switch msg.downloadState { - case XMPPConstants.ChatMsgVoiceDownloadState.downloading: - self.againDownloadVoiceView.isHidden = true - if let loading = loadingView() { - loading.startAnimating() - } else { - let loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) - loading.frame = self.accessoryView.bounds - self.accessoryView.addSubview(loading) - loading.startAnimating() - } - - break - case XMPPConstants.ChatMsgVoiceDownloadState.downloadSuccess: - self.againDownloadVoiceView.isHidden = true - break - case XMPPConstants.ChatMsgVoiceDownloadState.downloadFailed: - if let loading = loadingView() { - loading.stopAnimating() + + if let msg = message as? EdisonMessage { + switch msg.downloadState { + case XMPPConstants.ChatMsgVoiceDownloadState.downloading: + self.againDownloadVoiceView.isHidden = true + if let loading = loadingView() { + loading.startAnimating() + } else { + let loading = UIActivityIndicatorView(activityIndicatorStyle: .gray) + loading.frame = self.accessoryView.bounds + self.accessoryView.addSubview(loading) + loading.startAnimating() + } + + break + case XMPPConstants.ChatMsgVoiceDownloadState.downloadSuccess: + self.againDownloadVoiceView.isHidden = true + break + case XMPPConstants.ChatMsgVoiceDownloadState.downloadFailed: + if let loading = loadingView() { + loading.stopAnimating() + } + self.message = msg + self.againDownloadVoiceView.isHidden = false + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGestureRecognizer(_:))) + self.againDownloadVoiceView.addGestureRecognizer(tapGestureRecognizer) + self.contentView.addSubview(againDownloadVoiceView) + break + default: break + } - self.message = msg - self.againDownloadVoiceView.isHidden = false - let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGestureRecognizer(_:))) - self.againDownloadVoiceView.addGestureRecognizer(tapGestureRecognizer) - self.contentView.addSubview(againDownloadVoiceView) - break - default: break - } } @@ -198,7 +199,9 @@ open class VoiceMessageCell: MessageCollectionViewCell { } } @objc func tapGestureRecognizer(_ tapGesture :UITapGestureRecognizer) { - self.voiceMessageCellDelegate?.didTapTopAgainDownloadVoiceView(in: self) + if let messageId = self.message?.messageId { + self.voiceMessageCellDelegate?.didTapTopAgainDownloadVoiceView(in: messageId) + } } //TODO: loadingView Animating From 974276118a1b65a6b80101b93c0144a6bfdb492a Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Tue, 12 Jun 2018 10:50:49 +0800 Subject: [PATCH 26/35] max voice cell width --- Sources/Layout/MessagesCollectionViewFlowLayout.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Layout/MessagesCollectionViewFlowLayout.swift b/Sources/Layout/MessagesCollectionViewFlowLayout.swift index 88840c913..7d50b5243 100644 --- a/Sources/Layout/MessagesCollectionViewFlowLayout.swift +++ b/Sources/Layout/MessagesCollectionViewFlowLayout.swift @@ -473,7 +473,7 @@ private extension MessagesCollectionViewFlowLayout { let minWidth: CGFloat = 60 let maxWidth: CGFloat = screenWidth() > 320 ? 240 : 200 let proportion:CGFloat = CGFloat(Double(data.duration)/60.0) - let width: CGFloat = minWidth + proportion * maxWidth + let width: CGFloat = minWidth + proportion * maxWidth * 2/5.0 let height: CGFloat = 35 messageContainerSize = CGSize(width: width, height: height) messageContainerSize.width = max(messageContainerSize.width, replyWithLabelInsets) From 8206f90540d9114fde3af224e73b96ebf29a7aa4 Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Wed, 13 Jun 2018 16:03:45 +0800 Subject: [PATCH 27/35] should continue animating when refresh. --- Sources/Views/Cells/VoiceMessageCell.swift | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 5a88a8014..34c26d656 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -121,6 +121,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { if let bool = messagesCollectionView.messagesDataSource?.isFromCurrentSender(message: message) { isOwn = bool } + let isAnimation = ChatAudio.sharedInstance.messageId == message.messageId if isOwn { voiceImageView.image = EdoImageNoCache("im_voice_right_full") voiceImageView.animationDuration = 1 @@ -132,6 +133,9 @@ open class VoiceMessageCell: MessageCollectionViewCell { } voiceImageView.animationImages = images voiceImageView.animationRepeatCount=0 + if isAnimation { + voiceImageView.startAnimating() + } self.voicePlayView.isHidden = true setupRightConstraints() self.layoutIfNeeded() @@ -149,7 +153,9 @@ open class VoiceMessageCell: MessageCollectionViewCell { } voiceImageView.animationImages = images voiceImageView.animationRepeatCount=0 - + if isAnimation { + voiceImageView.startAnimating() + } setupLeftConstraints() self.layoutIfNeeded() self.layoutSubviews() From 26b64bd0f2e8f0a7357e19e572e0d573b97348aa Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Fri, 15 Jun 2018 13:55:56 +0800 Subject: [PATCH 28/35] =?UTF-8?q?don't=20show=200=E2=80=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/Views/Cells/VoiceMessageCell.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 34c26d656..0a58e9692 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -113,9 +113,11 @@ open class VoiceMessageCell: MessageCollectionViewCell { vociePlayed = data.voicePlayed duration = data.duration - super.voiceTimeView.text = "\(data.duration)s" - super.voiceTimeView.textColor = UIColor.lightGray - + //may not cause. If duration = 0,should be code or server bug. + if duration != 0 { + super.voiceTimeView.text = "\(data.duration)″" + super.voiceTimeView.textColor = UIColor.lightGray + } var isOwn = false if let bool = messagesCollectionView.messagesDataSource?.isFromCurrentSender(message: message) { From 3e7c5533c9663dbd26984926451fee9cb26e6dd4 Mon Sep 17 00:00:00 2001 From: cccc Date: Wed, 20 Jun 2018 15:21:37 +0800 Subject: [PATCH 29/35] add some change about reply --- Sources/Views/Cells/MessageCollectionViewCell.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Sources/Views/Cells/MessageCollectionViewCell.swift b/Sources/Views/Cells/MessageCollectionViewCell.swift index 23bf08419..4975585e8 100644 --- a/Sources/Views/Cells/MessageCollectionViewCell.swift +++ b/Sources/Views/Cells/MessageCollectionViewCell.swift @@ -89,6 +89,8 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab open weak var delegate: MessageCellDelegate? + open var isOwnToReply = false + public override init(frame: CGRect) { super.init(frame: frame) contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] @@ -173,6 +175,7 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab messageContainerView.frame = attributes.messageContainerFrame voiceTimeView.frame = attributes.voiceTimeViewframe accessoryView.frame = attributes.accessoryViewFrame +// replyLabel.frame = attributes.accessoryViewFrame } } @@ -201,6 +204,11 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab cellBottomLabel.attributedText = bottomText setupSwipeReplyGesture(delegate: messagesCollectionView) + + + if let bool = messagesCollectionView.messagesDataSource?.isFromCurrentSender(message: message) { + isOwnToReply = bool + } } /// Handle tap gesture on contentView and its subviews like messageContainerView, cellTopLabel, cellBottomLabel, avatarView .... From 6b6dbca612b511590658275423a5d5bef1d31bae Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Thu, 21 Jun 2018 11:08:16 +0800 Subject: [PATCH 30/35] if msg.mediaPath is not empty. should set downloadState as success --- Sources/Views/Cells/VoiceMessageCell.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 0a58e9692..a8a01912d 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -169,6 +169,19 @@ open class VoiceMessageCell: MessageCollectionViewCell { } if let msg = message as? EdisonMessage { + guard isEmpty(msg.mediaPath) else { + self.againDownloadVoiceView.isHidden = true + if msg.downloadState != XMPPConstants.ChatMsgVoiceDownloadState.downloadSuccess { + EmailDAL.updateAsync(dbType:.ChatDB, { (db) in + if let msg = EmailDAL.getChatMessage(accountId: msg.accountId, msgId: msg.messageId) { + db.write { + msg.downloadState = XMPPConstants.ChatMsgVoiceDownloadState.downloadSuccess + } + } + }) + } + return + } switch msg.downloadState { case XMPPConstants.ChatMsgVoiceDownloadState.downloading: self.againDownloadVoiceView.isHidden = true From 2c34ee99caf952ba6e799ad67e03cee22ca2c313 Mon Sep 17 00:00:00 2001 From: cccc Date: Thu, 21 Jun 2018 20:34:56 +0800 Subject: [PATCH 31/35] add messageContainerBaseView to do some about replyView UI --- .../MessagesViewController+DataSource.swift | 3 +- .../MessageIntermediateLayoutAttributes.swift | 47 ++++++++++++++----- .../MessagesCollectionViewFlowLayout.swift | 12 ++++- ...ssagesCollectionViewLayoutAttributes.swift | 2 + .../Cells/MessageCollectionViewCell.swift | 15 ++++-- Sources/Views/Cells/VoiceMessageCell.swift | 5 +- 6 files changed, 66 insertions(+), 18 deletions(-) diff --git a/Sources/Controllers/MessagesViewController+DataSource.swift b/Sources/Controllers/MessagesViewController+DataSource.swift index 197792db6..607acb4e6 100644 --- a/Sources/Controllers/MessagesViewController+DataSource.swift +++ b/Sources/Controllers/MessagesViewController+DataSource.swift @@ -83,7 +83,8 @@ extension MessagesViewController: UICollectionViewDataSource { return cell case .audio(_): let cell = messagesCollectionView.dequeueReusableCell(VoiceMessageCell.self, for: indexPath) - messagesDataSource.configCell(cell, for: message, at: indexPath) +// messagesDataSource.configCell(cell, for: message, at: indexPath) + print("++++++++++++cellForItem:\(String(describing: cell.message?.messageId)), indexPath.section:\(indexPath.section + 1)") cell.configure(with: message, at: indexPath, and: messagesCollectionView) return cell } diff --git a/Sources/Layout/MessageIntermediateLayoutAttributes.swift b/Sources/Layout/MessageIntermediateLayoutAttributes.swift index 85b966676..8f188e365 100644 --- a/Sources/Layout/MessageIntermediateLayoutAttributes.swift +++ b/Sources/Layout/MessageIntermediateLayoutAttributes.swift @@ -61,11 +61,11 @@ final class MessageIntermediateLayoutAttributes { case .cellBottom: origin.y = cellFrame.height - avatarSize.height case .messageTop: - origin.y = messageContainerFrame.minY + origin.y = messageContainerBaseViewFrame.minY case .messageBottom: - origin.y = messageContainerFrame.maxY - avatarSize.height + origin.y = messageContainerBaseViewFrame.maxY - avatarSize.height case .messageCenter: - origin.y = messageContainerFrame.midY - (avatarSize.height/2) + origin.y = messageContainerBaseViewFrame.midY - (avatarSize.height/2) } return CGRect(origin: origin, size: avatarSize) @@ -81,20 +81,45 @@ final class MessageIntermediateLayoutAttributes { guard accessoryViewSize != .zero else { return .zero } var origin: CGPoint = .zero - origin.y = messageContainerFrame.origin.y + messageContainerSize.height * 0.5 - + origin.y = messageContainerBaseViewFrame.origin.y + messageContainerSize.height * 0.5 - accessoryViewSize.height * 0.5 switch avatarPosition.horizontal { case .cellLeading: - origin.x = messageContainerFrame.maxX + accessoryViewPadding.left + accessoryViewSize.width + origin.x = messageContainerBaseViewFrame.maxX + accessoryViewPadding.left + accessoryViewSize.width case .cellTrailing: - origin.x = messageContainerFrame.minX - accessoryViewPadding.right - accessoryViewSize.width - voiceTimeViewSize.width + origin.x = messageContainerBaseViewFrame.minX - accessoryViewPadding.right - accessoryViewSize.width - voiceTimeViewSize.width case .natural: fatalError(MessageKitError.avatarPositionUnresolved) } return CGRect(origin: origin, size: accessoryViewSize) + }() + // messageContainerBaseViewFrame + var messageContainerBaseViewSize: CGSize = .zero + + var messageContainerBaseViewMaxWidth: CGFloat = 0 + var messageContainerBaseViewPadding: UIEdgeInsets = .zero + + lazy var messageContainerBaseViewFrame: CGRect = { + + guard messageContainerBaseViewSize != .zero else { return .zero } + + var origin: CGPoint = .zero + origin.y = topLabelSize.height + messageContainerBaseViewPadding.top + topLabelVerticalPadding + + switch avatarPosition.horizontal { + case .cellLeading: + origin.x = avatarSize.width + messageContainerPadding.left + case .cellTrailing: + origin.x = cellFrame.width - avatarSize.width - messageContainerBaseViewSize.width - messageContainerBaseViewPadding.right + case .natural: + fatalError(MessageKitError.avatarPositionUnresolved) + } + + return CGRect(origin: origin, size: messageContainerBaseViewSize) + }() // MessageContainerView @@ -167,9 +192,9 @@ final class MessageIntermediateLayoutAttributes { case .cellTrailing: origin.x = cellFrame.width - topLabelSize.width - topLabelPadding.right case .messageLeading: - origin.x = messageContainerFrame.minX + topLabelPadding.left + origin.x = messageContainerBaseViewFrame.minX + topLabelPadding.left case .messageTrailing: - origin.x = messageContainerFrame.maxX - topLabelSize.width - topLabelPadding.right + origin.x = messageContainerBaseViewFrame.maxX - topLabelSize.width - topLabelPadding.right } return CGRect(origin: origin, size: topLabelSize) @@ -187,7 +212,7 @@ final class MessageIntermediateLayoutAttributes { var origin: CGPoint = .zero - origin.y = messageContainerFrame.maxY + messageContainerPadding.bottom + bottomLabelPadding.top + origin.y = messageContainerBaseViewFrame.maxY + messageContainerPadding.bottom + bottomLabelPadding.top switch bottomLabelAlignment { case .cellLeading: @@ -197,9 +222,9 @@ final class MessageIntermediateLayoutAttributes { case .cellTrailing: origin.x = cellFrame.width - bottomLabelSize.width - bottomLabelPadding.right case .messageLeading: - origin.x = messageContainerFrame.minX + bottomLabelPadding.left + origin.x = messageContainerBaseViewFrame.minX + bottomLabelPadding.left case .messageTrailing: - origin.x = messageContainerFrame.maxX - bottomLabelSize.width - bottomLabelPadding.right + origin.x = messageContainerBaseViewFrame.maxX - bottomLabelSize.width - bottomLabelPadding.right } return CGRect(origin: origin, size: bottomLabelSize) diff --git a/Sources/Layout/MessagesCollectionViewFlowLayout.swift b/Sources/Layout/MessagesCollectionViewFlowLayout.swift index 7d50b5243..42f277d69 100644 --- a/Sources/Layout/MessagesCollectionViewFlowLayout.swift +++ b/Sources/Layout/MessagesCollectionViewFlowLayout.swift @@ -237,6 +237,9 @@ fileprivate extension MessagesCollectionViewFlowLayout { attributes.avatarPosition = avatarPosition(for: attributes) attributes.avatarSize = avatarSize(for: attributes) attributes.messageContainerPadding = messageContainerPadding(for: attributes) + + attributes.messageContainerBaseViewPadding = messageContainerPadding(for: attributes) + attributes.messageLabelInsets = messageLabelInsets(for: attributes) // AccessoryView @@ -251,6 +254,10 @@ fileprivate extension MessagesCollectionViewFlowLayout { attributes.messageContainerMaxWidth = messageContainerMaxWidth(for: attributes) attributes.messageContainerSize = messageContainerSize(for: attributes) + // messageContainerBaseViewFrame + attributes.messageContainerBaseViewMaxWidth = messageContainerMaxWidth(for: attributes) + attributes.messageContainerBaseViewSize = messageContainerSize(for: attributes, voiceReplyWidth: 40) + // Cell Bottom Label attributes.bottomLabelAlignment = cellBottomLabelAlignment(for: attributes) attributes.bottomLabelMaxWidth = cellBottomLabelMaxWidth(for: attributes) @@ -278,6 +285,7 @@ fileprivate extension MessagesCollectionViewFlowLayout { intermediateAttributes.cellFrame = attributes.frame + attributes.messageContainerBaseViewFrame = intermediateAttributes.messageContainerBaseViewFrame attributes.messageContainerFrame = intermediateAttributes.messageContainerFrame attributes.voiceTimeViewframe = intermediateAttributes.voiceTimeViewframe attributes.topLabelFrame = intermediateAttributes.topLabelFrame @@ -428,7 +436,7 @@ private extension MessagesCollectionViewFlowLayout { /// /// - Parameters: /// - attributes: The `MessageIntermediateLayoutAttributes` to consider when calculating the `MessageContainerView` size. - func messageContainerSize(for attributes: MessageIntermediateLayoutAttributes) -> CGSize { + func messageContainerSize(for attributes: MessageIntermediateLayoutAttributes, voiceReplyWidth: CGFloat = 0) -> CGSize { let message = attributes.message let indexPath = attributes.indexPath @@ -476,7 +484,7 @@ private extension MessagesCollectionViewFlowLayout { let width: CGFloat = minWidth + proportion * maxWidth * 2/5.0 let height: CGFloat = 35 messageContainerSize = CGSize(width: width, height: height) - messageContainerSize.width = max(messageContainerSize.width, replyWithLabelInsets) + messageContainerSize.width = max(messageContainerSize.width, replyWithLabelInsets) + voiceReplyWidth } messageContainerSize.height += messagesLayoutDelegate.replyViewHeight(at: indexPath, diff --git a/Sources/Layout/MessagesCollectionViewLayoutAttributes.swift b/Sources/Layout/MessagesCollectionViewLayoutAttributes.swift index c8b6f50de..d0aec7374 100644 --- a/Sources/Layout/MessagesCollectionViewLayoutAttributes.swift +++ b/Sources/Layout/MessagesCollectionViewLayoutAttributes.swift @@ -34,6 +34,7 @@ final class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttrib var accessoryViewFrame: CGRect = .zero var messageLabelFont: UIFont = UIFont.preferredFont(forTextStyle: .body) + var messageContainerBaseViewFrame: CGRect = .zero var messageContainerFrame: CGRect = .zero var voiceTimeViewframe: CGRect = .zero var messageLabelInsets: UIEdgeInsets = .zero @@ -49,6 +50,7 @@ final class MessagesCollectionViewLayoutAttributes: UICollectionViewLayoutAttrib copy.avatarFrame = avatarFrame copy.accessoryViewFrame = accessoryViewFrame copy.messageContainerFrame = messageContainerFrame + copy.messageContainerBaseViewFrame = messageContainerBaseViewFrame copy.voiceTimeViewframe = voiceTimeViewframe copy.messageLabelFont = messageLabelFont copy.messageLabelInsets = messageLabelInsets diff --git a/Sources/Views/Cells/MessageCollectionViewCell.swift b/Sources/Views/Cells/MessageCollectionViewCell.swift index 4975585e8..e4ad15d39 100644 --- a/Sources/Views/Cells/MessageCollectionViewCell.swift +++ b/Sources/Views/Cells/MessageCollectionViewCell.swift @@ -50,6 +50,12 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab open var voiceTimeView = UILabel() + open var messageContainerBaseView : UIView = { + let containerView = UIView() +// containerView.backgroundColor = UIColor.red + return containerView + }() + open lazy var voicePlayView: UIView = { let voicePlayView = UIView() @@ -105,6 +111,9 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab } open func setupSubviews() { + + contentView.addSubview(messageContainerBaseView) + contentView.addSubview(messageContainerView) voiceTimeView.textAlignment = .center contentView.addSubview(voiceTimeView) @@ -129,8 +138,8 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab open func setupReplyLabelConstraint() { NSLayoutConstraint.activate([ - replyLabel.leftAnchor.constraint(equalTo: messageContainerView.rightAnchor, constant: 15), - replyLabel.centerYAnchor.constraint(equalTo: messageContainerView.centerYAnchor) + replyLabel.leftAnchor.constraint(equalTo: messageContainerBaseView.rightAnchor, constant: 15), + replyLabel.centerYAnchor.constraint(equalTo: messageContainerBaseView.centerYAnchor) ]) } @@ -172,10 +181,10 @@ open class MessageCollectionViewCell: UICollectionViewCell, CollectionViewReusab avatarView.frame = attributes.avatarFrame cellTopLabel.frame = attributes.topLabelFrame cellBottomLabel.frame = attributes.bottomLabelFrame + messageContainerBaseView.frame = attributes.messageContainerBaseViewFrame messageContainerView.frame = attributes.messageContainerFrame voiceTimeView.frame = attributes.voiceTimeViewframe accessoryView.frame = attributes.accessoryViewFrame -// replyLabel.frame = attributes.accessoryViewFrame } } diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 0a58e9692..3531d3ba8 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -111,7 +111,9 @@ open class VoiceMessageCell: MessageCollectionViewCell { switch message.data { case .audio(let data): vociePlayed = data.voicePlayed - + self.tag = message.messageId.hashValue +// print("+++++++++self.tag:\(self.tag), messageID:\(message.messageId.hashValue)") + duration = data.duration //may not cause. If duration = 0,should be code or server bug. if duration != 0 { @@ -208,6 +210,7 @@ open class VoiceMessageCell: MessageCollectionViewCell { } @objc func tapGestureRecognizer(_ tapGesture :UITapGestureRecognizer) { if let messageId = self.message?.messageId { + print("+++++++++self.tag:\(self.tag), messageID:\(String(describing: self.message?.messageId.hashValue)), isequle:\(self.tag == self.message?.messageId.hashValue)") self.voiceMessageCellDelegate?.didTapTopAgainDownloadVoiceView(in: messageId) } } From a2a373e5e72a0139d675f6cacd34999c85dd681e Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Wed, 27 Jun 2018 14:32:00 +0800 Subject: [PATCH 32/35] delete failed state --- .../MessagesViewController+DataSource.swift | 3 +-- Sources/Views/Cells/VoiceMessageCell.swift | 20 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Sources/Controllers/MessagesViewController+DataSource.swift b/Sources/Controllers/MessagesViewController+DataSource.swift index 607acb4e6..197792db6 100644 --- a/Sources/Controllers/MessagesViewController+DataSource.swift +++ b/Sources/Controllers/MessagesViewController+DataSource.swift @@ -83,8 +83,7 @@ extension MessagesViewController: UICollectionViewDataSource { return cell case .audio(_): let cell = messagesCollectionView.dequeueReusableCell(VoiceMessageCell.self, for: indexPath) -// messagesDataSource.configCell(cell, for: message, at: indexPath) - print("++++++++++++cellForItem:\(String(describing: cell.message?.messageId)), indexPath.section:\(indexPath.section + 1)") + messagesDataSource.configCell(cell, for: message, at: indexPath) cell.configure(with: message, at: indexPath, and: messagesCollectionView) return cell } diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index 43b71627c..e61d7d4ef 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -200,16 +200,16 @@ open class VoiceMessageCell: MessageCollectionViewCell { case XMPPConstants.ChatMsgVoiceDownloadState.downloadSuccess: self.againDownloadVoiceView.isHidden = true break - case XMPPConstants.ChatMsgVoiceDownloadState.downloadFailed: - if let loading = loadingView() { - loading.stopAnimating() - } - self.message = msg - self.againDownloadVoiceView.isHidden = false - let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGestureRecognizer(_:))) - self.againDownloadVoiceView.addGestureRecognizer(tapGestureRecognizer) - self.contentView.addSubview(againDownloadVoiceView) - break +// case XMPPConstants.ChatMsgVoiceDownloadState.downloadFailed: +// if let loading = loadingView() { +// loading.stopAnimating() +// } +// self.message = msg +// self.againDownloadVoiceView.isHidden = false +// let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGestureRecognizer(_:))) +// self.againDownloadVoiceView.addGestureRecognizer(tapGestureRecognizer) +// self.contentView.addSubview(againDownloadVoiceView) +// break default: break } From 6953898b02c9012a180914990fad6591dba49fe7 Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Wed, 27 Jun 2018 18:27:03 +0800 Subject: [PATCH 33/35] miss commit --- Sources/Controllers/MessagesViewController+DataSource.swift | 3 +++ Sources/Views/Cells/GifMessageCell.swift | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/Controllers/MessagesViewController+DataSource.swift b/Sources/Controllers/MessagesViewController+DataSource.swift index 29d44682d..a8579b861 100644 --- a/Sources/Controllers/MessagesViewController+DataSource.swift +++ b/Sources/Controllers/MessagesViewController+DataSource.swift @@ -83,6 +83,9 @@ extension MessagesViewController: UICollectionViewDataSource { return cell case .audio(_): let cell = messagesCollectionView.dequeueReusableCell(VoiceMessageCell.self, for: indexPath) + messagesDataSource.configCell(cell, for: message, at: indexPath) + cell.configure(with: message, at: indexPath, and: messagesCollectionView) + return cell case .gif, .sticker: let cell = messagesCollectionView.dequeueReusableCell(GifMessageCell.self, for: indexPath) messagesDataSource.configCell(cell, for: message, at: indexPath) diff --git a/Sources/Views/Cells/GifMessageCell.swift b/Sources/Views/Cells/GifMessageCell.swift index ec75ddbc6..ee5306eea 100644 --- a/Sources/Views/Cells/GifMessageCell.swift +++ b/Sources/Views/Cells/GifMessageCell.swift @@ -37,7 +37,7 @@ class GifMessageCell: MediaMessageCell { } XMPPAdapter.downloadData(accountId: downloadInfo.accountId, - chatMsgId: downloadInfo.messageId) { [weak self] (msgId, filePath) in + chatMsgId: downloadInfo.messageId) { [weak self] (msgId, filePath, _) in EDOMainthread { defer { finishedAndDoNotRetry?(false) From c11bf0e5f8b18ef604183cd609d9407557cb937b Mon Sep 17 00:00:00 2001 From: cccc Date: Sat, 30 Jun 2018 13:30:28 +0800 Subject: [PATCH 34/35] change some about Voice UI --- Sources/Views/MessageInputBar.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Views/MessageInputBar.swift b/Sources/Views/MessageInputBar.swift index f7ea832f7..b3783832c 100644 --- a/Sources/Views/MessageInputBar.swift +++ b/Sources/Views/MessageInputBar.swift @@ -471,7 +471,7 @@ open class MessageInputBar: UIView { top: inputTextView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: textViewPadding.top + attachmentViewHeight), bottom: inputTextView.bottomAnchor.constraint(equalTo: bottomStackView.topAnchor, constant: -textViewPadding.bottom), left: inputTextView.leftAnchor.constraint(equalTo: leftStackView.rightAnchor, constant: textViewPadding.left), - right: inputTextView.rightAnchor.constraint(equalTo: otherStackView.leftAnchor, constant: -textViewPadding.right) + right: inputTextView.rightAnchor.constraint(equalTo: rightStackView.leftAnchor, constant: -textViewPadding.right) ) maxTextViewHeight = calculateMaxTextViewHeight() textViewHeightAnchor = inputTextView.heightAnchor.constraint(equalToConstant: maxTextViewHeight) From 2eef641122c1927b7c39b3b2dbf89188a3e31819 Mon Sep 17 00:00:00 2001 From: zhangcx627 Date: Tue, 17 Jul 2018 14:45:49 +0800 Subject: [PATCH 35/35] download failed --- Sources/Views/Cells/VoiceMessageCell.swift | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Sources/Views/Cells/VoiceMessageCell.swift b/Sources/Views/Cells/VoiceMessageCell.swift index e61d7d4ef..43b71627c 100644 --- a/Sources/Views/Cells/VoiceMessageCell.swift +++ b/Sources/Views/Cells/VoiceMessageCell.swift @@ -200,16 +200,16 @@ open class VoiceMessageCell: MessageCollectionViewCell { case XMPPConstants.ChatMsgVoiceDownloadState.downloadSuccess: self.againDownloadVoiceView.isHidden = true break -// case XMPPConstants.ChatMsgVoiceDownloadState.downloadFailed: -// if let loading = loadingView() { -// loading.stopAnimating() -// } -// self.message = msg -// self.againDownloadVoiceView.isHidden = false -// let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGestureRecognizer(_:))) -// self.againDownloadVoiceView.addGestureRecognizer(tapGestureRecognizer) -// self.contentView.addSubview(againDownloadVoiceView) -// break + case XMPPConstants.ChatMsgVoiceDownloadState.downloadFailed: + if let loading = loadingView() { + loading.stopAnimating() + } + self.message = msg + self.againDownloadVoiceView.isHidden = false + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.tapGestureRecognizer(_:))) + self.againDownloadVoiceView.addGestureRecognizer(tapGestureRecognizer) + self.contentView.addSubview(againDownloadVoiceView) + break default: break }