From 455e62f86210d564cf7bffca104fdbef6c9fab36 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Sun, 6 Sep 2015 22:49:31 +0800 Subject: [PATCH 1/7] move cell configure in willDisplayCell --- .../ConversationViewController.swift | 676 ++++++++++-------- 1 file changed, 379 insertions(+), 297 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 7b1c04fe..139d0b59 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -1899,14 +1899,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatSectionDateCellIdentifier, forIndexPath: indexPath) as! ChatSectionDateCell - let createdAt = NSDate(timeIntervalSince1970: message.createdUnixTime) - - if createdAt.isInCurrentWeek() { - cell.sectionDateLabel.text = sectionDateInCurrentWeekFormatter.stringFromDate(createdAt) - } else { - cell.sectionDateLabel.text = sectionDateFormatter.stringFromDate(createdAt) - } - return cell } @@ -1922,88 +1914,24 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftImageCellIdentifier, forIndexPath: indexPath) as! ChatLeftImageCell - cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: { [weak self] in - - if message.downloadState == MessageDownloadState.Downloaded.rawValue { - self?.performSegueWithIdentifier("showMessageMedia", sender: message) - - } else { - YepAlert.alertSorry(message: NSLocalizedString("Please wait while the image is not dready!", comment: ""), inViewController: self) - } - - }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } - return cell case MessageMediaType.Audio.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftAudioCellIdentifier, forIndexPath: indexPath) as! ChatLeftAudioCell - let audioPlayedDuration = audioPlayedDurationOfMessage(message) - - cell.configureWithMessage(message, audioPlayedDuration: audioPlayedDuration, audioBubbleTapAction: { [weak self] in - - if message.downloadState == MessageDownloadState.Downloaded.rawValue { - self?.playMessageAudioWithMessage(message) - - } else { - YepAlert.alertSorry(message: NSLocalizedString("Please wait while the audio is not dready!", comment: ""), inViewController: self) - } - - }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } - return cell case MessageMediaType.Video.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftVideoCellIdentifier, forIndexPath: indexPath) as! ChatLeftVideoCell - cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: { [weak self] in - - if message.downloadState == MessageDownloadState.Downloaded.rawValue { - self?.performSegueWithIdentifier("showMessageMedia", sender: message) - - } else { - YepAlert.alertSorry(message: NSLocalizedString("Please wait while the video is not dready!", comment: ""), inViewController: self) - } - - }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } - return cell case MessageMediaType.Location.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftLocationCellIdentifier, forIndexPath: indexPath) as! ChatLeftLocationCell - cell.configureWithMessage(message, mediaTapAction: { [weak self] in - 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) - } - - }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } - return cell default: @@ -2012,10 +1940,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.configureWithMessage(message, textContentLabelWidth: textContentLabelWidthOfMessage(message), collectionView: collectionView, indexPath: indexPath) - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } - return cell } @@ -2027,251 +1951,30 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightImageCellIdentifier, forIndexPath: indexPath) as! ChatRightImageCell - cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: { [weak self] in - - 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: { [weak self] reason, errorMessage in - defaultFailureHandler(reason, errorMessage) - - YepAlert.alertSorry(message: NSLocalizedString("Failed to resend image!\nPlease make sure your iPhone is connected to the Internet.", comment: ""), inViewController: self) - - }, completion: { success in - println("resendImage: \(success)") - }) - - }, cancelAction: { - }) - - } else { - self?.performSegueWithIdentifier("showMessageMedia", sender: message) - } - - }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } - return cell case MessageMediaType.Audio.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightAudioCellIdentifier, forIndexPath: indexPath) as! ChatRightAudioCell - let audioPlayedDuration = audioPlayedDurationOfMessage(message) - - cell.configureWithMessage(message, audioPlayedDuration: audioPlayedDuration, audioBubbleTapAction: { [weak self] in - - 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: { [weak self] reason, errorMessage in - defaultFailureHandler(reason, errorMessage) - - YepAlert.alertSorry(message: NSLocalizedString("Failed to resend audio!\nPlease make sure your iPhone is connected to the Internet.", comment: ""), inViewController: self) - - }, completion: { success in - println("resendAudio: \(success)") - }) - - }, cancelAction: { - }) - - return - } - - self?.playMessageAudioWithMessage(message) - - }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } - return cell case MessageMediaType.Video.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightVideoCellIdentifier, forIndexPath: indexPath) as! ChatRightVideoCell - cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: { [weak self] in - - 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: { [weak self] reason, errorMessage in - defaultFailureHandler(reason, errorMessage) - - YepAlert.alertSorry(message: NSLocalizedString("Failed to resend video!\nPlease make sure your iPhone is connected to the Internet.", comment: ""), inViewController: self) - - }, completion: { success in - println("resendVideo: \(success)") - }) - - }, cancelAction: { - }) - - } else { - self?.performSegueWithIdentifier("showMessageMedia", sender: message) - } - - }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } - return cell case MessageMediaType.Location.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightLocationCellIdentifier, forIndexPath: indexPath) as! ChatRightLocationCell - cell.configureWithMessage(message, mediaTapAction: { [weak self] in - - 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: { [weak self] reason, errorMessage in - defaultFailureHandler(reason, errorMessage) - - YepAlert.alertSorry(message: NSLocalizedString("Failed to resend location!\nPlease make sure your iPhone is connected to the Internet.", comment: ""), inViewController: self) - - }, 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) - } - } - - }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } - return cell default: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightTextCellIdentifier, forIndexPath: indexPath) as! ChatRightTextCell - cell.configureWithMessage(message, textContentLabelWidth: textContentLabelWidthOfMessage(message), mediaTapAction: { [weak self] in - - 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: { [weak self] reason, errorMessage in - defaultFailureHandler(reason, errorMessage) - - YepAlert.alertSorry(message: NSLocalizedString("Failed to resend text!\nPlease make sure your iPhone is connected to the Internet.", comment: ""), inViewController: self) - - }, completion: { success in - println("resendText: \(success)") - }) - - }, cancelAction: { - }) - } - }, collectionView: collectionView, indexPath: indexPath) - - cell.longPressAction = { [weak self] in - dispatch_async(dispatch_get_main_queue()) { - if let strongSelf = self, realm = message.realm { - - var sectionDateMessage: Message? - - if let currentMessageIndex = strongSelf.messages.indexOf(message) { - - let previousMessageIndex = currentMessageIndex - 1 - - if let previousMessage = strongSelf.messages[safe: previousMessageIndex] { - - if previousMessage.mediaType == MessageMediaType.SectionDate.rawValue { - sectionDateMessage = previousMessage - } - } - } - - let currentIndexPath: NSIndexPath - if let index = strongSelf.messages.indexOf(message) { - currentIndexPath = NSIndexPath(forItem: index - strongSelf.displayedMessagesRange.location, inSection: indexPath.section) - } else { - currentIndexPath = indexPath - } - - if let sectionDateMessage = sectionDateMessage { - - var canDeleteTwoMessages = false // 考虑刚好的边界情况,例如消息为本束的最后一条,而 sectionDate 在上一束中 - if strongSelf.displayedMessagesRange.length >= 2 { - strongSelf.displayedMessagesRange.length -= 2 - canDeleteTwoMessages = true - - } else { - if strongSelf.displayedMessagesRange.location >= 1 { - strongSelf.displayedMessagesRange.location -= 1 - } - strongSelf.displayedMessagesRange.length -= 1 - } - - realm.write { - if let mediaMetaData = sectionDateMessage.mediaMetaData { - realm.delete(mediaMetaData) - } - if let mediaMetaData = message.mediaMetaData { - realm.delete(mediaMetaData) - } - realm.delete(sectionDateMessage) - realm.delete(message) - } - - if canDeleteTwoMessages { - let previousIndexPath = NSIndexPath(forItem: currentIndexPath.item - 1, inSection: currentIndexPath.section) - strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([previousIndexPath, currentIndexPath]) - } else { - strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) - } - - } else { - strongSelf.displayedMessagesRange.length -= 1 - realm.write { - if let mediaMetaData = message.mediaMetaData { - realm.delete(mediaMetaData) - } - realm.delete(message) - } - strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) - } - - // 必须更新,插入时需要 - strongSelf.lastTimeMessagesCount = strongSelf.messages.count - } - } - } - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } - return cell } } @@ -2288,6 +1991,385 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } + func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) { + + if let message = messages[safe: (displayedMessagesRange.location + indexPath.item)] { + + if message.mediaType == MessageMediaType.SectionDate.rawValue { + + if let cell = cell as? ChatSectionDateCell { + let createdAt = NSDate(timeIntervalSince1970: message.createdUnixTime) + + if createdAt.isInCurrentWeek() { + cell.sectionDateLabel.text = sectionDateInCurrentWeekFormatter.stringFromDate(createdAt) + } else { + cell.sectionDateLabel.text = sectionDateFormatter.stringFromDate(createdAt) + } + } + + return + } + + if let sender = message.fromFriend { + + if sender.friendState != UserFriendState.Me.rawValue { // from Friend + + markMessageAsReaded(message) + + switch message.mediaType { + + case MessageMediaType.Image.rawValue: + + if let cell = cell as? ChatLeftImageCell { + + cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: { [weak self] in + + if message.downloadState == MessageDownloadState.Downloaded.rawValue { + self?.performSegueWithIdentifier("showMessageMedia", sender: message) + + } else { + YepAlert.alertSorry(message: NSLocalizedString("Please wait while the image is not dready!", comment: ""), inViewController: self) + } + + }, collectionView: collectionView, indexPath: indexPath) + + cell.tapAvatarAction = { [weak self] user in + self?.performSegueWithIdentifier("showProfile", sender: user) + } + } + + case MessageMediaType.Audio.rawValue: + + if let cell = cell as? ChatLeftAudioCell { + + let audioPlayedDuration = audioPlayedDurationOfMessage(message) + + cell.configureWithMessage(message, audioPlayedDuration: audioPlayedDuration, audioBubbleTapAction: { [weak self] in + + if message.downloadState == MessageDownloadState.Downloaded.rawValue { + self?.playMessageAudioWithMessage(message) + + } else { + YepAlert.alertSorry(message: NSLocalizedString("Please wait while the audio is not dready!", comment: ""), inViewController: self) + } + + }, collectionView: collectionView, indexPath: indexPath) + + cell.tapAvatarAction = { [weak self] user in + self?.performSegueWithIdentifier("showProfile", sender: user) + } + } + + case MessageMediaType.Video.rawValue: + + if let cell = cell as? ChatLeftVideoCell { + + cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: { [weak self] in + + if message.downloadState == MessageDownloadState.Downloaded.rawValue { + self?.performSegueWithIdentifier("showMessageMedia", sender: message) + + } else { + YepAlert.alertSorry(message: NSLocalizedString("Please wait while the video is not dready!", comment: ""), inViewController: self) + } + + }, collectionView: collectionView, indexPath: indexPath) + + cell.tapAvatarAction = { [weak self] user in + self?.performSegueWithIdentifier("showProfile", sender: user) + } + } + + + case MessageMediaType.Location.rawValue: + + if let cell = cell as? ChatLeftLocationCell { + + cell.configureWithMessage(message, mediaTapAction: { [weak self] in + 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) + } + + }, collectionView: collectionView, indexPath: indexPath) + + cell.tapAvatarAction = { [weak self] user in + self?.performSegueWithIdentifier("showProfile", sender: user) + } + } + + default: + + if let cell = cell as? ChatLeftTextCell { + + cell.configureWithMessage(message, textContentLabelWidth: textContentLabelWidthOfMessage(message), collectionView: collectionView, indexPath: indexPath) + + cell.tapAvatarAction = { [weak self] user in + self?.performSegueWithIdentifier("showProfile", sender: user) + } + } + } + + } else { // from Me + + switch message.mediaType { + + case MessageMediaType.Image.rawValue: + + if let cell = cell as? ChatRightImageCell { + + cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: { [weak self] in + + 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: { [weak self] reason, errorMessage in + defaultFailureHandler(reason, errorMessage) + + YepAlert.alertSorry(message: NSLocalizedString("Failed to resend image!\nPlease make sure your iPhone is connected to the Internet.", comment: ""), inViewController: self) + + }, completion: { success in + println("resendImage: \(success)") + }) + + }, cancelAction: { + }) + + } else { + self?.performSegueWithIdentifier("showMessageMedia", sender: message) + } + + }, collectionView: collectionView, indexPath: indexPath) + + cell.tapAvatarAction = { [weak self] user in + self?.performSegueWithIdentifier("showProfile", sender: user) + } + } + + case MessageMediaType.Audio.rawValue: + + if let cell = cell as? ChatRightAudioCell { + + let audioPlayedDuration = audioPlayedDurationOfMessage(message) + + cell.configureWithMessage(message, audioPlayedDuration: audioPlayedDuration, audioBubbleTapAction: { [weak self] in + + 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: { [weak self] reason, errorMessage in + defaultFailureHandler(reason, errorMessage) + + YepAlert.alertSorry(message: NSLocalizedString("Failed to resend audio!\nPlease make sure your iPhone is connected to the Internet.", comment: ""), inViewController: self) + + }, completion: { success in + println("resendAudio: \(success)") + }) + + }, cancelAction: { + }) + + return + } + + self?.playMessageAudioWithMessage(message) + + }, collectionView: collectionView, indexPath: indexPath) + + cell.tapAvatarAction = { [weak self] user in + self?.performSegueWithIdentifier("showProfile", sender: user) + } + } + + case MessageMediaType.Video.rawValue: + + if let cell = cell as? ChatRightVideoCell { + + cell.configureWithMessage(message, messageImagePreferredWidth: messageImagePreferredWidth, messageImagePreferredHeight: messageImagePreferredHeight, messageImagePreferredAspectRatio: messageImagePreferredAspectRatio, mediaTapAction: { [weak self] in + + 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: { [weak self] reason, errorMessage in + defaultFailureHandler(reason, errorMessage) + + YepAlert.alertSorry(message: NSLocalizedString("Failed to resend video!\nPlease make sure your iPhone is connected to the Internet.", comment: ""), inViewController: self) + + }, completion: { success in + println("resendVideo: \(success)") + }) + + }, cancelAction: { + }) + + } else { + self?.performSegueWithIdentifier("showMessageMedia", sender: message) + } + + }, collectionView: collectionView, indexPath: indexPath) + + cell.tapAvatarAction = { [weak self] user in + self?.performSegueWithIdentifier("showProfile", sender: user) + } + } + + case MessageMediaType.Location.rawValue: + + if let cell = cell as? ChatRightLocationCell { + + cell.configureWithMessage(message, mediaTapAction: { [weak self] in + + 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: { [weak self] reason, errorMessage in + defaultFailureHandler(reason, errorMessage) + + YepAlert.alertSorry(message: NSLocalizedString("Failed to resend location!\nPlease make sure your iPhone is connected to the Internet.", comment: ""), inViewController: self) + + }, 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) + } + } + + }, collectionView: collectionView, indexPath: indexPath) + + cell.tapAvatarAction = { [weak self] user in + self?.performSegueWithIdentifier("showProfile", sender: user) + } + } + + default: + + if let cell = cell as? ChatRightTextCell { + + cell.configureWithMessage(message, textContentLabelWidth: textContentLabelWidthOfMessage(message), mediaTapAction: { [weak self] in + + 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: { [weak self] reason, errorMessage in + defaultFailureHandler(reason, errorMessage) + + YepAlert.alertSorry(message: NSLocalizedString("Failed to resend text!\nPlease make sure your iPhone is connected to the Internet.", comment: ""), inViewController: self) + + }, completion: { success in + println("resendText: \(success)") + }) + + }, cancelAction: { + }) + } + }, collectionView: collectionView, indexPath: indexPath) + + cell.longPressAction = { [weak self] in + dispatch_async(dispatch_get_main_queue()) { + if let strongSelf = self, realm = message.realm { + + var sectionDateMessage: Message? + + if let currentMessageIndex = strongSelf.messages.indexOf(message) { + + let previousMessageIndex = currentMessageIndex - 1 + + if let previousMessage = strongSelf.messages[safe: previousMessageIndex] { + + if previousMessage.mediaType == MessageMediaType.SectionDate.rawValue { + sectionDateMessage = previousMessage + } + } + } + + let currentIndexPath: NSIndexPath + if let index = strongSelf.messages.indexOf(message) { + currentIndexPath = NSIndexPath(forItem: index - strongSelf.displayedMessagesRange.location, inSection: indexPath.section) + } else { + currentIndexPath = indexPath + } + + if let sectionDateMessage = sectionDateMessage { + + var canDeleteTwoMessages = false // 考虑刚好的边界情况,例如消息为本束的最后一条,而 sectionDate 在上一束中 + if strongSelf.displayedMessagesRange.length >= 2 { + strongSelf.displayedMessagesRange.length -= 2 + canDeleteTwoMessages = true + + } else { + if strongSelf.displayedMessagesRange.location >= 1 { + strongSelf.displayedMessagesRange.location -= 1 + } + strongSelf.displayedMessagesRange.length -= 1 + } + + realm.write { + if let mediaMetaData = sectionDateMessage.mediaMetaData { + realm.delete(mediaMetaData) + } + if let mediaMetaData = message.mediaMetaData { + realm.delete(mediaMetaData) + } + realm.delete(sectionDateMessage) + realm.delete(message) + } + + if canDeleteTwoMessages { + let previousIndexPath = NSIndexPath(forItem: currentIndexPath.item - 1, inSection: currentIndexPath.section) + strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([previousIndexPath, currentIndexPath]) + } else { + strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) + } + + } else { + strongSelf.displayedMessagesRange.length -= 1 + realm.write { + if let mediaMetaData = message.mediaMetaData { + realm.delete(mediaMetaData) + } + realm.delete(message) + } + strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) + } + + // 必须更新,插入时需要 + strongSelf.lastTimeMessagesCount = strongSelf.messages.count + } + } + } + + cell.tapAvatarAction = { [weak self] user in + self?.performSegueWithIdentifier("showProfile", sender: user) + } + } + } + } + } + } + } + func collectionView(collectionView: UICollectionView!, layout collectionViewLayout: UICollectionViewLayout!, sizeForItemAtIndexPath indexPath: NSIndexPath!) -> CGSize { if let message = messages[safe: (displayedMessagesRange.location + indexPath.item)] { From ec408d5f36e5c38ecfc2d968280e466c41cd152d Mon Sep 17 00:00:00 2001 From: nixzhu Date: Sun, 6 Sep 2015 23:01:40 +0800 Subject: [PATCH 2/7] reduce cell.tapAvatarAction --- .../ConversationViewController.swift | 47 +++---------------- 1 file changed, 6 insertions(+), 41 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 139d0b59..723aed6c 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -2012,6 +2012,12 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if let sender = message.fromFriend { + if let cell = cell as? ChatBaseCell { + cell.tapAvatarAction = { [weak self] user in + self?.performSegueWithIdentifier("showProfile", sender: user) + } + } + if sender.friendState != UserFriendState.Me.rawValue { // from Friend markMessageAsReaded(message) @@ -2032,10 +2038,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } } case MessageMediaType.Audio.rawValue: @@ -2054,10 +2056,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } } case MessageMediaType.Video.rawValue: @@ -2074,13 +2072,8 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } } - case MessageMediaType.Location.rawValue: if let cell = cell as? ChatLeftLocationCell { @@ -2097,10 +2090,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } } default: @@ -2108,10 +2097,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if let cell = cell as? ChatLeftTextCell { cell.configureWithMessage(message, textContentLabelWidth: textContentLabelWidthOfMessage(message), collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } } } @@ -2146,10 +2131,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } } case MessageMediaType.Audio.rawValue: @@ -2182,10 +2163,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi self?.playMessageAudioWithMessage(message) }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } } case MessageMediaType.Video.rawValue: @@ -2215,10 +2192,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } } case MessageMediaType.Location.rawValue: @@ -2256,10 +2229,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } }, collectionView: collectionView, indexPath: indexPath) - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } } default: @@ -2359,10 +2328,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } } } - - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } } } } From 1d29d9dec465b25f984d7e86942ec82daf3604a6 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Sun, 6 Sep 2015 23:10:01 +0800 Subject: [PATCH 3/7] completion defaultRoundAvatar first --- Yep/Caches/AvatarCache.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Yep/Caches/AvatarCache.swift b/Yep/Caches/AvatarCache.swift index 31aeba5c..59dfbc1c 100644 --- a/Yep/Caches/AvatarCache.swift +++ b/Yep/Caches/AvatarCache.swift @@ -198,8 +198,9 @@ class AvatarCache { func roundAvatarWithAvatarURLString(avatarURLString: String, withRadius radius: CGFloat, completion: (UIImage) -> ()) { + completion(defaultRoundAvatarOfRadius(radius)) + if avatarURLString.isEmpty { - completion(defaultRoundAvatarOfRadius(radius)) return } @@ -242,7 +243,6 @@ class AvatarCache { } } default: - completion(defaultRoundAvatarOfRadius(radius)) break } } @@ -334,12 +334,13 @@ class AvatarCache { func roundAvatarOfUser(user: User, withRadius radius: CGFloat, completion: (UIImage) -> ()) { + completion(defaultRoundAvatarOfRadius(radius)) + // 为下面切换线程准备,Realm 不能跨线程访问 let avatarURLString = user.avatarURLString let userID = user.userID if avatarURLString.isEmpty { - completion(defaultRoundAvatarOfRadius(radius)) return } @@ -382,7 +383,6 @@ class AvatarCache { } } default: - completion(defaultRoundAvatarOfRadius(radius)) break } } From 66148664eda792f0fbbd6cc6bf2b39a8b250069d Mon Sep 17 00:00:00 2001 From: nixzhu Date: Sun, 6 Sep 2015 23:16:03 +0800 Subject: [PATCH 4/7] do not set placeholder nil --- Yep/ViewControllers/Login/LoginByMobileViewController.swift | 2 +- Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift | 2 +- .../Register/RegisterPickMobileViewController.swift | 2 +- .../Register/RegisterPickNameViewController.swift | 2 +- .../Register/RegisterVerifyMobileViewController.swift | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Yep/ViewControllers/Login/LoginByMobileViewController.swift b/Yep/ViewControllers/Login/LoginByMobileViewController.swift index 7596d47e..175e0b1f 100644 --- a/Yep/ViewControllers/Login/LoginByMobileViewController.swift +++ b/Yep/ViewControllers/Login/LoginByMobileViewController.swift @@ -41,7 +41,7 @@ class LoginByMobileViewController: BaseViewController { areaCodeTextField.delegate = self areaCodeTextField.addTarget(self, action: "textFieldDidChange:", forControlEvents: .EditingChanged) - mobileNumberTextField.placeholder = nil + //mobileNumberTextField.placeholder = "" mobileNumberTextField.delegate = self mobileNumberTextField.addTarget(self, action: "textFieldDidChange:", forControlEvents: .EditingChanged) diff --git a/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift b/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift index 0315bdc8..d1e36b5d 100644 --- a/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift +++ b/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift @@ -58,7 +58,7 @@ class LoginVerifyMobileViewController: UIViewController { verifyMobileNumberPromptLabel.text = NSLocalizedString("Input verification code send to", comment: "") phoneNumberLabel.text = "+" + areaCode + " " + mobile - verifyCodeTextField.placeholder = nil + //verifyCodeTextField.placeholder = "" verifyCodeTextField.delegate = self verifyCodeTextField.addTarget(self, action: "textFieldDidChange:", forControlEvents: .EditingChanged) diff --git a/Yep/ViewControllers/Register/RegisterPickMobileViewController.swift b/Yep/ViewControllers/Register/RegisterPickMobileViewController.swift index 8c86a9f6..541cc616 100644 --- a/Yep/ViewControllers/Register/RegisterPickMobileViewController.swift +++ b/Yep/ViewControllers/Register/RegisterPickMobileViewController.swift @@ -39,7 +39,7 @@ class RegisterPickMobileViewController: UIViewController { areaCodeTextField.delegate = self areaCodeTextField.addTarget(self, action: "textFieldDidChange:", forControlEvents: .EditingChanged) - mobileNumberTextField.placeholder = nil + //mobileNumberTextField.placeholder = "" mobileNumberTextField.delegate = self mobileNumberTextField.addTarget(self, action: "textFieldDidChange:", forControlEvents: .EditingChanged) diff --git a/Yep/ViewControllers/Register/RegisterPickNameViewController.swift b/Yep/ViewControllers/Register/RegisterPickNameViewController.swift index b85c4818..6a915865 100644 --- a/Yep/ViewControllers/Register/RegisterPickNameViewController.swift +++ b/Yep/ViewControllers/Register/RegisterPickNameViewController.swift @@ -63,7 +63,7 @@ class RegisterPickNameViewController: BaseViewController { let tap = UITapGestureRecognizer(target: self, action: "tapTerms") promptTermsLabel.addGestureRecognizer(tap) - nameTextField.placeholder = nil + //nameTextField.placeholder = "" nameTextField.delegate = self nameTextField.addTarget(self, action: "textFieldDidChange:", forControlEvents: .EditingChanged) diff --git a/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift b/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift index cc74ce42..18536a8c 100644 --- a/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift +++ b/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift @@ -58,7 +58,7 @@ class RegisterVerifyMobileViewController: UIViewController { verifyMobileNumberPromptLabel.text = NSLocalizedString("Input verification code send to", comment: "") phoneNumberLabel.text = "+" + areaCode + " " + mobile - verifyCodeTextField.placeholder = nil + //verifyCodeTextField.placeholder = "" verifyCodeTextField.delegate = self verifyCodeTextField.addTarget(self, action: "textFieldDidChange:", forControlEvents: .EditingChanged) From 8663e8bc5d51cb3c5b9137b0f893434a36dda0f3 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Sun, 6 Sep 2015 23:44:36 +0800 Subject: [PATCH 5/7] use haveAppropriateInput in textFieldShouldReturn --- Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift | 2 +- .../Register/RegisterVerifyMobileViewController.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift b/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift index d1e36b5d..02726660 100644 --- a/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift +++ b/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift @@ -202,7 +202,7 @@ class LoginVerifyMobileViewController: UIViewController { extension LoginVerifyMobileViewController: UITextFieldDelegate { func textFieldShouldReturn(textField: UITextField) -> Bool { - if !textField.text.isEmpty { + if haveAppropriateInput { login() } diff --git a/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift b/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift index 18536a8c..b3073cb1 100644 --- a/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift +++ b/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift @@ -197,7 +197,7 @@ class RegisterVerifyMobileViewController: UIViewController { extension RegisterVerifyMobileViewController: UITextFieldDelegate { func textFieldShouldReturn(textField: UITextField) -> Bool { - if !textField.text.isEmpty { + if haveAppropriateInput { verifyRegisterMobile() } From 4d15c3f1b6afa71c040a4d09a65f8341ae005e65 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Mon, 7 Sep 2015 00:15:49 +0800 Subject: [PATCH 6/7] handle activeAgain in SMS code --- .../Login/LoginVerifyMobileViewController.swift | 6 ++++++ .../Register/RegisterVerifyMobileViewController.swift | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift b/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift index 02726660..50b87f4c 100644 --- a/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift +++ b/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift @@ -55,6 +55,8 @@ class LoginVerifyMobileViewController: UIViewController { navigationItem.rightBarButtonItem = nextButton + NSNotificationCenter.defaultCenter().addObserver(self, selector: "activeAgain:", name: AppDelegate.Notification.applicationDidBecomeActive, object: nil) + verifyMobileNumberPromptLabel.text = NSLocalizedString("Input verification code send to", comment: "") phoneNumberLabel.text = "+" + areaCode + " " + mobile @@ -87,6 +89,10 @@ class LoginVerifyMobileViewController: UIViewController { // MARK: Actions + func activeAgain(notification: NSNotification) { + verifyCodeTextField.becomeFirstResponder() + } + func tryCallMe(timer: NSTimer) { if !haveAppropriateInput { if callMeInSeconds > 1 { diff --git a/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift b/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift index b3073cb1..78a40974 100644 --- a/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift +++ b/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift @@ -55,6 +55,8 @@ class RegisterVerifyMobileViewController: UIViewController { navigationItem.rightBarButtonItem = nextButton + NSNotificationCenter.defaultCenter().addObserver(self, selector: "activeAgain:", name: AppDelegate.Notification.applicationDidBecomeActive, object: nil) + verifyMobileNumberPromptLabel.text = NSLocalizedString("Input verification code send to", comment: "") phoneNumberLabel.text = "+" + areaCode + " " + mobile @@ -87,6 +89,10 @@ class RegisterVerifyMobileViewController: UIViewController { // MARK: Actions + func activeAgain(notification: NSNotification) { + verifyCodeTextField.becomeFirstResponder() + } + func tryCallMe(timer: NSTimer) { if !haveAppropriateInput { if callMeInSeconds > 1 { From b1a7729d47c777df5d4729e8546c176cca23a613 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Mon, 7 Sep 2015 00:17:00 +0800 Subject: [PATCH 7/7] do not use textFieldShouldReturn in SMS code --- .../Login/LoginVerifyMobileViewController.swift | 4 +++- .../Register/RegisterVerifyMobileViewController.swift | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift b/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift index 50b87f4c..7627b786 100644 --- a/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift +++ b/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift @@ -206,7 +206,8 @@ class LoginVerifyMobileViewController: UIViewController { } extension LoginVerifyMobileViewController: UITextFieldDelegate { - + + /* func textFieldShouldReturn(textField: UITextField) -> Bool { if haveAppropriateInput { login() @@ -214,5 +215,6 @@ extension LoginVerifyMobileViewController: UITextFieldDelegate { return true } + */ } diff --git a/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift b/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift index 78a40974..48d7971d 100644 --- a/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift +++ b/Yep/ViewControllers/Register/RegisterVerifyMobileViewController.swift @@ -201,7 +201,8 @@ class RegisterVerifyMobileViewController: UIViewController { } extension RegisterVerifyMobileViewController: UITextFieldDelegate { - + + /* func textFieldShouldReturn(textField: UITextField) -> Bool { if haveAppropriateInput { verifyRegisterMobile() @@ -209,5 +210,6 @@ extension RegisterVerifyMobileViewController: UITextFieldDelegate { return true } + */ }