diff --git a/Yep/Images.xcassets/icon_dot_failed.imageset/Contents.json b/Yep/Images.xcassets/icon_dot_failed.imageset/Contents.json new file mode 100644 index 00000000..42ea4073 --- /dev/null +++ b/Yep/Images.xcassets/icon_dot_failed.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_dot_failed.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Yep/Images.xcassets/icon_dot_failed.imageset/icon_dot_failed.pdf b/Yep/Images.xcassets/icon_dot_failed.imageset/icon_dot_failed.pdf new file mode 100644 index 00000000..9058d72e Binary files /dev/null and b/Yep/Images.xcassets/icon_dot_failed.imageset/icon_dot_failed.pdf differ diff --git a/Yep/Realm/Models.swift b/Yep/Realm/Models.swift index f4037955..01974c07 100644 --- a/Yep/Realm/Models.swift +++ b/Yep/Realm/Models.swift @@ -238,6 +238,15 @@ class Draft: Object { enum ConversationType: Int { case OneToOne = 0 // 一对一对话 case Group = 1 // 群组对话 + + var nameForServer: String { + switch self { + case .OneToOne: + return "User" + case .Group: + return "Circle" + } + } } class Conversation: Object { diff --git a/Yep/Services/YepService.swift b/Yep/Services/YepService.swift index 4d609903..62a3783d 100644 --- a/Yep/Services/YepService.swift +++ b/Yep/Services/YepService.swift @@ -1042,22 +1042,22 @@ func sendText(text: String, toRecipient recipientID: String, #recipientType: Str moreInfo["text_content"] = text return moreInfo } - sendMessageWithMediaType(.Text, inFilePath: nil, orFileData: nil, metaData: nil, fillMoreInfo: fillMoreInfo, toRecipient: recipientID, recipientType: recipientType, afterCreatedMessage: afterCreatedMessage, failureHandler: failureHandler, completion: completion) + createAndSendMessageWithMediaType(.Text, inFilePath: nil, orFileData: nil, metaData: nil, fillMoreInfo: fillMoreInfo, toRecipient: recipientID, recipientType: recipientType, afterCreatedMessage: afterCreatedMessage, failureHandler: failureHandler, completion: completion) } func sendImageInFilePath(filePath: String?, orFileData fileData: NSData?, #metaData: String?, toRecipient recipientID: String, #recipientType: String, #afterCreatedMessage: (Message) -> Void, #failureHandler: ((Reason, String?) -> Void)?, #completion: (success: Bool) -> Void) { - sendMessageWithMediaType(.Image, inFilePath: filePath, orFileData: fileData, metaData: metaData, fillMoreInfo: nil, toRecipient: recipientID, recipientType: recipientType, afterCreatedMessage: afterCreatedMessage, failureHandler: failureHandler, completion: completion) + createAndSendMessageWithMediaType(.Image, inFilePath: filePath, orFileData: fileData, metaData: metaData, fillMoreInfo: nil, toRecipient: recipientID, recipientType: recipientType, afterCreatedMessage: afterCreatedMessage, failureHandler: failureHandler, completion: completion) } func sendAudioInFilePath(filePath: String?, orFileData fileData: NSData?, #metaData: String?, toRecipient recipientID: String, #recipientType: String, #afterCreatedMessage: (Message) -> Void, #failureHandler: ((Reason, String?) -> Void)?, #completion: (success: Bool) -> Void) { - sendMessageWithMediaType(.Audio, inFilePath: filePath, orFileData: fileData, metaData: metaData, fillMoreInfo: nil, toRecipient: recipientID, recipientType: recipientType, afterCreatedMessage: afterCreatedMessage, failureHandler: failureHandler, completion: completion) + createAndSendMessageWithMediaType(.Audio, inFilePath: filePath, orFileData: fileData, metaData: metaData, fillMoreInfo: nil, toRecipient: recipientID, recipientType: recipientType, afterCreatedMessage: afterCreatedMessage, failureHandler: failureHandler, completion: completion) } func sendVideoInFilePath(filePath: String?, orFileData fileData: NSData?, #metaData: String?, toRecipient recipientID: String, #recipientType: String, #afterCreatedMessage: (Message) -> Void, #failureHandler: ((Reason, String?) -> Void)?, #completion: (success: Bool) -> Void) { - sendMessageWithMediaType(.Video, inFilePath: filePath, orFileData: fileData, metaData: metaData, fillMoreInfo: nil, toRecipient: recipientID, recipientType: recipientType, afterCreatedMessage: afterCreatedMessage, failureHandler: failureHandler, completion: completion) + createAndSendMessageWithMediaType(.Video, inFilePath: filePath, orFileData: fileData, metaData: metaData, fillMoreInfo: nil, toRecipient: recipientID, recipientType: recipientType, afterCreatedMessage: afterCreatedMessage, failureHandler: failureHandler, completion: completion) } func sendLocationWithCoordinate(coordinate: CLLocationCoordinate2D, toRecipient recipientID: String, #recipientType: String, #afterCreatedMessage: (Message) -> Void, #failureHandler: ((Reason, String?) -> Void)?, #completion: (success: Bool) -> Void) { @@ -1069,11 +1069,10 @@ func sendLocationWithCoordinate(coordinate: CLLocationCoordinate2D, toRecipient return moreInfo } - sendMessageWithMediaType(.Location, inFilePath: nil, orFileData: nil, metaData: nil, fillMoreInfo: fillMoreInfo, toRecipient: recipientID, recipientType: recipientType, afterCreatedMessage: afterCreatedMessage, failureHandler: failureHandler, completion: completion) + createAndSendMessageWithMediaType(.Location, inFilePath: nil, orFileData: nil, metaData: nil, fillMoreInfo: fillMoreInfo, toRecipient: recipientID, recipientType: recipientType, afterCreatedMessage: afterCreatedMessage, failureHandler: failureHandler, completion: completion) } - -func sendMessageWithMediaType(mediaType: MessageMediaType, inFilePath filePath: String?, orFileData fileData: NSData?, #metaData: String?, #fillMoreInfo: (JSONDictionary -> JSONDictionary)?, toRecipient recipientID: String, #recipientType: String, #afterCreatedMessage: (Message) -> Void, #failureHandler: ((Reason, String?) -> Void)?, #completion: (success: Bool) -> Void) { +func createAndSendMessageWithMediaType(mediaType: MessageMediaType, inFilePath filePath: String?, orFileData fileData: NSData?, #metaData: String?, #fillMoreInfo: (JSONDictionary -> JSONDictionary)?, toRecipient recipientID: String, #recipientType: String, #afterCreatedMessage: (Message) -> Void, #failureHandler: ((Reason, String?) -> Void)?, #completion: (success: Bool) -> Void) { // 因为 message_id 必须来自远端,线程无法切换,所以这里暂时没用 realmQueue // TOOD: 也许有办法 let realm = Realm() @@ -1148,12 +1147,6 @@ func sendMessageWithMediaType(mediaType: MessageMediaType, inFilePath filePath: realm.commitWrite() - // 发出之前就显示 Message - afterCreatedMessage(message) - - - // 下面开始真正的消息发送 - var messageInfo: JSONDictionary = [ "recipient_id": recipientID, "recipient_type": recipientType, @@ -1182,149 +1175,235 @@ func sendMessageWithMediaType(mediaType: MessageMediaType, inFilePath filePath: realm.commitWrite() - switch mediaType { - case .Text, .Location: - createMessageWithMessageInfo(messageInfo, failureHandler: { (reason, errorMessage) in - if let failureHandler = failureHandler { - failureHandler(reason, errorMessage) - } + // 发出之前就显示 Message + afterCreatedMessage(message) - dispatch_async(dispatch_get_main_queue()) { - - realm.beginWrite() - message.sendState = MessageSendState.Failed.rawValue - realm.commitWrite() - } + // 下面开始真正的消息发送 + sendMessage(message, inFilePath: filePath, orFileData: fileData, metaData: metaData, fillMoreInfo: fillMoreInfo, toRecipient: recipientID, recipientType: recipientType, failureHandler: failureHandler, completion: completion) +} - }, completion: { messageID in +func sendMessage(message: Message, inFilePath filePath: String?, orFileData fileData: NSData?, #metaData: String?, #fillMoreInfo: (JSONDictionary -> JSONDictionary)?, toRecipient recipientID: String, #recipientType: String, #failureHandler: ((Reason, String?) -> Void)?, #completion: (success: Bool) -> Void) { - - dispatch_async(dispatch_get_main_queue()) { - //Add to queue - -// var operation = MessageStateOperation(type: .Sent, messageID: messageID) -// -// ConversationOperationQueue.sharedManager.addNewQperationQueue(operation) - - realm.beginWrite() - message.messageID = messageID - message.sendState = MessageSendState.Successed.rawValue - realm.commitWrite() - - completion(success: true) + if let mediaType = MessageMediaType(rawValue: message.mediaType) { - NSNotificationCenter.defaultCenter().postNotificationName(MessageNotification.MessageStateChanged, object: nil) - } - }) + var messageInfo: JSONDictionary = [ + "recipient_id": recipientID, + "recipient_type": recipientType, + "media_type": mediaType.description, + ] - default: + if let fillMoreInfo = fillMoreInfo { + messageInfo = fillMoreInfo(messageInfo) + } - s3PrivateUploadParams(failureHandler: nil) { s3UploadParams in - uploadFileToS3(inFilePath: filePath, orFileData: fileData, mimeType: mediaType.mineType(), s3UploadParams: s3UploadParams) { (result, error) in + switch mediaType { - // TODO: attachments - switch mediaType { - case .Image: - if let metaData = metaData { - let attachments = ["image": [["file": s3UploadParams.key, "metadata": metaData]]] - messageInfo["attachments"] = attachments - - } else { - let attachments = ["image": [["file": s3UploadParams.key]]] - messageInfo["attachments"] = attachments - } - - case .Audio: - if let metaData = metaData { - let attachments = ["audio": [["file": s3UploadParams.key, "metadata": metaData]]] - messageInfo["attachments"] = attachments - - } else { - let attachments = ["audio": [["file": s3UploadParams.key]]] - messageInfo["attachments"] = attachments - } - - default: - break + case .Text, .Location: + createMessageWithMessageInfo(messageInfo, failureHandler: { (reason, errorMessage) in + if let failureHandler = failureHandler { + failureHandler(reason, errorMessage) } - let doCreateMessage = { - createMessageWithMessageInfo(messageInfo, failureHandler: { (reason, errorMessage) in - if let failureHandler = failureHandler { - failureHandler(reason, errorMessage) - } + dispatch_async(dispatch_get_main_queue()) { - dispatch_async(dispatch_get_main_queue()) { - realm.beginWrite() - message.sendState = MessageSendState.Failed.rawValue - realm.commitWrite() - } + let realm = message.realm - }, completion: { messageID in - dispatch_async(dispatch_get_main_queue()) { - realm.beginWrite() - message.messageID = messageID - message.sendState = MessageSendState.Successed.rawValue - realm.commitWrite() - -// var operation = MessageStateOperation(type: .Sent, messageID: messageID) -// -// ConversationOperationQueue.sharedManager.addNewQperationQueue(operation) - - completion(success: true) - - NSNotificationCenter.defaultCenter().postNotificationName(MessageNotification.MessageStateChanged, object: nil) - } - - }) - } - - // 对于 Video 还要再传 thumbnail,…… - if mediaType == .Video { - - var thumbnailData: NSData? - - if - let filePath = filePath, - let image = thumbnailImageOfVideoInVideoURL(NSURL(fileURLWithPath: filePath)!) { - thumbnailData = UIImageJPEGRepresentation(image, YepConfig.messageImageCompressionQuality()) + realm?.write { + message.sendState = MessageSendState.Failed.rawValue } - s3PrivateUploadParams(failureHandler: nil) { thumbnailS3UploadParams in - uploadFileToS3(inFilePath: nil, orFileData: thumbnailData, mimeType: MessageMediaType.Image.mineType(), s3UploadParams: thumbnailS3UploadParams) { (result, error) in + NSNotificationCenter.defaultCenter().postNotificationName(MessageNotification.MessageStateChanged, object: nil) + } - if let metaData = metaData { - let attachments = [ - "video": [ - ["file": s3UploadParams.key, "metadata": metaData] - ], - "thumbnail": [["file": thumbnailS3UploadParams.key]] - ] - messageInfo["attachments"] = attachments + }, completion: { messageID in - } else { - let attachments = [ - "video": [ - ["file": s3UploadParams.key] - ], - "thumbnail": [["file": thumbnailS3UploadParams.key]] - ] - messageInfo["attachments"] = attachments + dispatch_async(dispatch_get_main_queue()) { + let realm = message.realm + realm?.write { + message.messageID = messageID + message.sendState = MessageSendState.Successed.rawValue + } + + completion(success: true) + + NSNotificationCenter.defaultCenter().postNotificationName(MessageNotification.MessageStateChanged, object: nil) + } + }) + + default: + + s3PrivateUploadParams(failureHandler: nil) { s3UploadParams in + uploadFileToS3(inFilePath: filePath, orFileData: fileData, mimeType: mediaType.mineType(), s3UploadParams: s3UploadParams) { (result, error) in + + // TODO: attachments + switch mediaType { + case .Image: + if let metaData = metaData { + let attachments = ["image": [["file": s3UploadParams.key, "metadata": metaData]]] + messageInfo["attachments"] = attachments + + } else { + let attachments = ["image": [["file": s3UploadParams.key]]] + messageInfo["attachments"] = attachments + } + + case .Audio: + if let metaData = metaData { + let attachments = ["audio": [["file": s3UploadParams.key, "metadata": metaData]]] + messageInfo["attachments"] = attachments + + } else { + let attachments = ["audio": [["file": s3UploadParams.key]]] + messageInfo["attachments"] = attachments + } + + default: + break + } + + let doCreateMessage = { + createMessageWithMessageInfo(messageInfo, failureHandler: { (reason, errorMessage) in + if let failureHandler = failureHandler { + failureHandler(reason, errorMessage) } - doCreateMessage() - } + dispatch_async(dispatch_get_main_queue()) { + let realm = message.realm + realm?.write { + message.sendState = MessageSendState.Failed.rawValue + } + + NSNotificationCenter.defaultCenter().postNotificationName(MessageNotification.MessageStateChanged, object: nil) + } + + }, completion: { messageID in + dispatch_async(dispatch_get_main_queue()) { + let realm = message.realm + realm?.write { + message.messageID = messageID + message.sendState = MessageSendState.Successed.rawValue + } + + completion(success: true) + + NSNotificationCenter.defaultCenter().postNotificationName(MessageNotification.MessageStateChanged, object: nil) + } + }) } - } else { - doCreateMessage() + // 对于 Video 还要再传 thumbnail,…… + if mediaType == .Video { + + var thumbnailData: NSData? + + if + let filePath = filePath, + let image = thumbnailImageOfVideoInVideoURL(NSURL(fileURLWithPath: filePath)!) { + thumbnailData = UIImageJPEGRepresentation(image, YepConfig.messageImageCompressionQuality()) + } + + s3PrivateUploadParams(failureHandler: nil) { thumbnailS3UploadParams in + uploadFileToS3(inFilePath: nil, orFileData: thumbnailData, mimeType: MessageMediaType.Image.mineType(), s3UploadParams: thumbnailS3UploadParams) { (result, error) in + + if let metaData = metaData { + let attachments = [ + "video": [ + ["file": s3UploadParams.key, "metadata": metaData] + ], + "thumbnail": [["file": thumbnailS3UploadParams.key]] + ] + messageInfo["attachments"] = attachments + + } else { + let attachments = [ + "video": [ + ["file": s3UploadParams.key] + ], + "thumbnail": [["file": thumbnailS3UploadParams.key]] + ] + messageInfo["attachments"] = attachments + } + + doCreateMessage() + } + } + + } else { + doCreateMessage() + } } } } } } +func resendMessage(message: Message, #failureHandler: ((Reason, String?) -> Void)?, #completion: (success: Bool) -> Void) { + + var recipientID: String? + var recipientType: String? + + if let conversation = message.conversation { + if conversation.type == ConversationType.OneToOne.rawValue { + recipientID = conversation.withFriend?.userID + recipientType = ConversationType.OneToOne.nameForServer + + } else if conversation.type == ConversationType.Group.rawValue { + recipientID = conversation.withGroup?.groupID + recipientType = ConversationType.Group.nameForServer + } + } + + if let + recipientID = recipientID, + recipientType = recipientType, + messageMediaType = MessageMediaType(rawValue: message.mediaType) { + + switch messageMediaType { + + case .Text: + + let fillMoreInfo: JSONDictionary -> JSONDictionary = { info in + var moreInfo = info + moreInfo["text_content"] = message.textContent + return moreInfo + } + + sendMessage(message, inFilePath: nil, orFileData: nil, metaData: nil, fillMoreInfo: fillMoreInfo, toRecipient: recipientID, recipientType: recipientType, failureHandler: failureHandler, completion: completion) + + case .Image: + let filePath = NSFileManager.yepMessageImageURLWithName(message.localAttachmentName)?.path + + sendMessage(message, inFilePath: filePath, orFileData: nil, metaData: message.metaData, fillMoreInfo: nil, toRecipient: recipientID, recipientType: recipientType, failureHandler: failureHandler, completion: completion) + + case .Video: + let filePath = NSFileManager.yepMessageVideoURLWithName(message.localAttachmentName)?.path + + sendMessage(message, inFilePath: filePath, orFileData: nil, metaData: message.metaData, fillMoreInfo: nil, toRecipient: recipientID, recipientType: recipientType, failureHandler: failureHandler, completion: completion) + + case .Audio: + let filePath = NSFileManager.yepMessageAudioURLWithName(message.localAttachmentName)?.path + + sendMessage(message, inFilePath: filePath, orFileData: nil, metaData: message.metaData, fillMoreInfo: nil, toRecipient: recipientID, recipientType: recipientType, failureHandler: failureHandler, completion: completion) + + case .Location: + if let coordinate = message.coordinate { + let fillMoreInfo: JSONDictionary -> JSONDictionary = { info in + var moreInfo = info + moreInfo["longitude"] = coordinate.longitude + moreInfo["latitude"] = coordinate.latitude + return moreInfo + } + + sendMessage(message, inFilePath: nil, orFileData: nil, metaData: nil, fillMoreInfo: fillMoreInfo, toRecipient: recipientID, recipientType: recipientType, failureHandler: failureHandler, completion: completion) + } + + default: + break + } + } +} + func markAsReadMessage(message: Message ,#failureHandler: ((Reason, String?) -> Void)?, #completion: (Bool) -> Void) { if message.readed || message.messageID.isEmpty { diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 503585be..1f8b3a44 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -14,8 +14,6 @@ import MapKit struct MessageNotification { - static let MessageSent = "MessageSentNotification" - static let MessageRead = "MessageReadNotification" static let MessageStateChanged = "MessageStateChangedNotification" } @@ -1640,7 +1638,24 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: { - self.performSegueWithIdentifier("showMessageMedia", sender: message) + if message.sendState == MessageSendState.Failed.rawValue { + + YepAlert.confirmOrCancel(title: NSLocalizedString("Action", comment: ""), message: NSLocalizedString("Resend image?", comment: ""), confirmTitle: NSLocalizedString("Resend", comment: ""), cancelTitle: NSLocalizedString("Cancel", comment: ""), inViewController: self, withConfirmAction: { + + resendMessage(message, failureHandler: { (reason, errorMessage) in + defaultFailureHandler(reason, errorMessage) + // TODO: resendImage 错误提醒 + + }, completion: { success in + println("resendImage: \(success)") + }) + + }, cancelAction: { + }) + + } else { + self.performSegueWithIdentifier("showMessageMedia", sender: message) + } }) return cell @@ -1652,6 +1667,26 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.configureWithMessage(message, audioPlayedDuration: audioPlayedDuration, audioBubbleTapAction: { message in + if let message = message { + if message.sendState == MessageSendState.Failed.rawValue { + + YepAlert.confirmOrCancel(title: NSLocalizedString("Action", comment: ""), message: NSLocalizedString("Resend audio?", comment: ""), confirmTitle: NSLocalizedString("Resend", comment: ""), cancelTitle: NSLocalizedString("Cancel", comment: ""), inViewController: self, withConfirmAction: { + + resendMessage(message, failureHandler: { (reason, errorMessage) in + defaultFailureHandler(reason, errorMessage) + // TODO: resendAudio 错误提醒 + + }, completion: { success in + println("resendAudio: \(success)") + }) + + }, cancelAction: { + }) + + return + } + } + self.playMessageAudioWithMessage(message) }) @@ -1662,7 +1697,24 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: { - self.performSegueWithIdentifier("showMessageMedia", sender: message) + if message.sendState == MessageSendState.Failed.rawValue { + + YepAlert.confirmOrCancel(title: NSLocalizedString("Action", comment: ""), message: NSLocalizedString("Resend video?", comment: ""), confirmTitle: NSLocalizedString("Resend", comment: ""), cancelTitle: NSLocalizedString("Cancel", comment: ""), inViewController: self, withConfirmAction: { + + resendMessage(message, failureHandler: { (reason, errorMessage) in + defaultFailureHandler(reason, errorMessage) + // TODO: resendVideo 错误提醒 + + }, completion: { success in + println("resendVideo: \(success)") + }) + + }, cancelAction: { + }) + + } else { + self.performSegueWithIdentifier("showMessageMedia", sender: message) + } }) return cell @@ -1671,14 +1723,32 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightLocationCellIdentifier, forIndexPath: indexPath) as! ChatRightLocationCell cell.configureWithMessage(message, mediaTapAction: { - if let coordinate = message.coordinate { - let locationCoordinate = CLLocationCoordinate2D(latitude: coordinate.latitude, longitude: coordinate.longitude) - let mapItem = MKMapItem(placemark: MKPlacemark(coordinate: locationCoordinate, addressDictionary: nil)) - /* - let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving] - mapItem.openInMapsWithLaunchOptions(launchOptions) - */ - mapItem.openInMapsWithLaunchOptions(nil) + + if message.sendState == MessageSendState.Failed.rawValue { + + YepAlert.confirmOrCancel(title: NSLocalizedString("Action", comment: ""), message: NSLocalizedString("Resend location?", comment: ""), confirmTitle: NSLocalizedString("Resend", comment: ""), cancelTitle: NSLocalizedString("Cancel", comment: ""), inViewController: self, withConfirmAction: { + + resendMessage(message, failureHandler: { (reason, errorMessage) in + defaultFailureHandler(reason, errorMessage) + // TODO: resendLocation 错误提醒 + + }, completion: { success in + println("resendLocation: \(success)") + }) + + }, cancelAction: { + }) + + } else { + if let coordinate = message.coordinate { + let locationCoordinate = CLLocationCoordinate2D(latitude: coordinate.latitude, longitude: coordinate.longitude) + let mapItem = MKMapItem(placemark: MKPlacemark(coordinate: locationCoordinate, addressDictionary: nil)) + /* + let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving] + mapItem.openInMapsWithLaunchOptions(launchOptions) + */ + mapItem.openInMapsWithLaunchOptions(nil) + } } }) @@ -1687,7 +1757,24 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi default: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightTextCellIdentifier, forIndexPath: indexPath) as! ChatRightTextCell - cell.configureWithMessage(message, textContentLabelWidth: textContentLabelWidthOfMessage(message)) + cell.configureWithMessage(message, textContentLabelWidth: textContentLabelWidthOfMessage(message), mediaTapAction: { + + if message.sendState == MessageSendState.Failed.rawValue { + + YepAlert.confirmOrCancel(title: NSLocalizedString("Action", comment: ""), message: NSLocalizedString("Resend text?", comment: ""), confirmTitle: NSLocalizedString("Resend", comment: ""), cancelTitle: NSLocalizedString("Cancel", comment: ""), inViewController: self, withConfirmAction: { + + resendMessage(message, failureHandler: { (reason, errorMessage) in + defaultFailureHandler(reason, errorMessage) + // TODO: resendText 错误提醒 + + }, completion: { success in + println("resendText: \(success)") + }) + + }, cancelAction: { + }) + } + }) return cell } diff --git a/Yep/Views/Cells/ChatRightBase/ChatRightBaseCell.swift b/Yep/Views/Cells/ChatRightBase/ChatRightBaseCell.swift index 2ca53067..23c56d78 100644 --- a/Yep/Views/Cells/ChatRightBase/ChatRightBaseCell.swift +++ b/Yep/Views/Cells/ChatRightBase/ChatRightBaseCell.swift @@ -35,7 +35,8 @@ class ChatRightBaseCell: UICollectionViewCell { removeSendingAnimation() case MessageSendState.Failed: - dotImageView.hidden = true + dotImageView.image = UIImage(named: "icon_dot_failed") + dotImageView.hidden = false removeSendingAnimation() diff --git a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift index d1889398..3427b1a2 100644 --- a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift +++ b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift @@ -22,6 +22,9 @@ class ChatRightTextCell: ChatRightBaseCell { @IBOutlet weak var textContentLabelTrailingConstraint: NSLayoutConstraint! @IBOutlet weak var textContentLabelLeadingConstraint: NSLayoutConstraint! @IBOutlet weak var textContentLabelWidthConstraint: NSLayoutConstraint! + + typealias MediaTapAction = () -> Void + var mediaTapAction: MediaTapAction? override func awakeFromNib() { super.awakeFromNib() @@ -48,11 +51,22 @@ class ChatRightTextCell: ChatRightBaseCell { bubbleBodyImageView.tintColor = UIColor.rightBubbleTintColor() bubbleTailImageView.tintColor = UIColor.rightBubbleTintColor() + + bubbleBodyImageView.userInteractionEnabled = true + let tap = UITapGestureRecognizer(target: self, action: "tapMediaView") + bubbleBodyImageView.addGestureRecognizer(tap) + } + + func tapMediaView() { + mediaTapAction?() } - func configureWithMessage(message: Message, textContentLabelWidth: CGFloat) { + func configureWithMessage(message: Message, textContentLabelWidth: CGFloat, mediaTapAction: MediaTapAction?) { + self.message = message - + + self.mediaTapAction = mediaTapAction + textContentLabel.text = message.textContent textContentLabelWidthConstraint.constant = max(YepConfig.minMessageTextLabelWidth, textContentLabelWidth)