diff --git a/Yep/AppDelegate.swift b/Yep/AppDelegate.swift index f7cf031b..17157f68 100644 --- a/Yep/AppDelegate.swift +++ b/Yep/AppDelegate.swift @@ -90,9 +90,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate { let isLogined = YepUserDefaults.isLogined if isLogined { - sync() - startFaye() + delay(1.0, work: {[weak self] () -> Void in + self?.sync() + self?.startFaye() + }) // 记录启动通知类型 if let @@ -238,15 +240,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate { if application.applicationState != .Active { self.remoteNotificationType = remoteNotificationType } - - completionHandler(UIBackgroundFetchResult.NoData) } else { completionHandler(UIBackgroundFetchResult.NoData) } } else { - completionHandler(UIBackgroundFetchResult.NewData) + completionHandler(UIBackgroundFetchResult.NoData) } } @@ -292,14 +292,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } func sync() { - - syncMyInfoAndDoFurtherAction { - syncFriendshipsAndDoFurtherAction { - syncGroupsAndDoFurtherAction { - syncUnreadMessagesAndDoFurtherAction { messageIDs in - tryPostNewMessagesReceivedNotificationWithMessageIDs(messageIDs, withMessageAge: .New) - } - } + syncGroupsAndDoFurtherAction { + syncUnreadMessagesAndDoFurtherAction { messageIDs in + tryPostNewMessagesReceivedNotificationWithMessageIDs(messageIDs, withMessageAge: .New) } } diff --git a/Yep/Base.lproj/Main.storyboard b/Yep/Base.lproj/Main.storyboard index 5ac28a41..e7013f09 100644 --- a/Yep/Base.lproj/Main.storyboard +++ b/Yep/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + diff --git a/Yep/Caches/AvatarCache.swift b/Yep/Caches/AvatarCache.swift index d55ac59a..3463bfda 100644 --- a/Yep/Caches/AvatarCache.swift +++ b/Yep/Caches/AvatarCache.swift @@ -38,7 +38,7 @@ class AvatarCache { } } - func avatarFromURL(url: NSURL, completion: (isFinish: Bool, image: UIImage) -> ()) { + func avatarFromURL(url: NSURL, size: CGFloat, completion: (isFinish: Bool, image: UIImage) -> ()) { completion(isFinish: false, image: UIImage(named: "default_avatar")!) @@ -62,7 +62,7 @@ class AvatarCache { let avatarFileURL = NSFileManager.yepAvatarURLWithName(avatar.avatarFileName), let image = UIImage(contentsOfFile: avatarFileURL.path!) { - let image = image.decodedImage() + let image = image.squareImageOfSize(size).decodedImage() self.cache.setObject(image, forKey: normalImageKey) diff --git a/Yep/Images.xcassets/skill_bubble.imageset/Contents.json b/Yep/Images.xcassets/skill_bubble.imageset/Contents.json index db5d9853..32cc4804 100644 --- a/Yep/Images.xcassets/skill_bubble.imageset/Contents.json +++ b/Yep/Images.xcassets/skill_bubble.imageset/Contents.json @@ -6,19 +6,21 @@ "resizing" : { "mode" : "3-part-horizontal", "center" : { - "mode" : "fill", + "mode" : "tile", "width" : 1 }, - "capInsets" : { + "cap-insets" : { "right" : 12, - "left" : 12 + "left" : 13 } } } ], "info" : { "version" : 1, - "author" : "xcode", + "author" : "xcode" + }, + "properties" : { "template-rendering-intent" : "template" } } \ No newline at end of file diff --git a/Yep/Info.plist b/Yep/Info.plist index 6b0c5f10..56147ea4 100644 --- a/Yep/Info.plist +++ b/Yep/Info.plist @@ -32,7 +32,7 @@ CFBundleVersion - 107 + 113 Fabric APIKey diff --git a/Yep/Realm/Models.swift b/Yep/Realm/Models.swift index 44e786a1..0b367109 100644 --- a/Yep/Realm/Models.swift +++ b/Yep/Realm/Models.swift @@ -563,7 +563,7 @@ func latestMessageInRealm(realm: Realm, withConversationType conversationType: C return realm.objects(Message).filter(predicate).sorted("updatedUnixTime", ascending: false).first } -func saveFeedWithFeedData(feedData: DiscoveredFeed, group: Group, inRealm realm: Realm) { +func saveFeedWithFeedDataWithoutFullGroup(feedData: DiscoveredFeed, group: Group, inRealm realm: Realm) { // try sync group first @@ -578,12 +578,17 @@ func saveFeedWithFeedData(feedData: DiscoveredFeed, group: Group, inRealm realm: syncGroupWithGroupInfo(groupInfo, inRealm: realm) }) - // save feed + saveFeedWithFeedDataWithFullGroup(feedData, group: group, inRealm: realm) +} + +func saveFeedWithFeedDataWithFullGroup(feedData: DiscoveredFeed, group: Group, inRealm realm: Realm) { + // save feed + if let feed = feedWithFeedID(feedData.id, inRealm: realm) { print("Join Feed \(feed.feedID)") - + } else { let newFeed = Feed() newFeed.feedID = feedData.id @@ -607,9 +612,9 @@ func saveFeedWithFeedData(feedData: DiscoveredFeed, group: Group, inRealm realm: let attachments = attachmentFromDiscoveredAttachment(feedData.attachments, inRealm: realm) newFeed.attachments.appendContentsOf(attachments) - + newFeed.group = group - + let _ = try? realm.write { realm.add(newFeed) } diff --git a/Yep/Services/FayeService.swift b/Yep/Services/FayeService.swift index 54c171da..ce6028de 100644 --- a/Yep/Services/FayeService.swift +++ b/Yep/Services/FayeService.swift @@ -125,7 +125,10 @@ class FayeService: NSObject, MZFayeClientDelegate { message.sendState = MessageSendState.Read.rawValue } - NSNotificationCenter.defaultCenter().postNotificationName(MessageNotification.MessageStateChanged, object: nil) + dispatch_async(dispatch_get_main_queue()) { + NSNotificationCenter.defaultCenter().postNotificationName(MessageNotification.MessageStateChanged, object: nil) + } + } } } @@ -195,7 +198,9 @@ class FayeService: NSObject, MZFayeClientDelegate { message.sendState = MessageSendState.Read.rawValue } - NSNotificationCenter.defaultCenter().postNotificationName(MessageNotification.MessageStateChanged, object: nil) + dispatch_async(dispatch_get_main_queue()) { + NSNotificationCenter.defaultCenter().postNotificationName(MessageNotification.MessageStateChanged, object: nil) + } } } } diff --git a/Yep/Services/YepServiceSync.swift b/Yep/Services/YepServiceSync.swift index b015951a..1ab56068 100644 --- a/Yep/Services/YepServiceSync.swift +++ b/Yep/Services/YepServiceSync.swift @@ -546,7 +546,7 @@ func syncGroupsAndDoFurtherAction(furtherAction: () -> Void) { topic = groupInfo["topic"] as? JSONDictionary, feedData = DiscoveredFeed.fromJSONDictionary(topic), group = group { - saveFeedWithFeedData(feedData, group: group, inRealm: realm) + saveFeedWithFeedDataWithFullGroup(feedData, group: group, inRealm: realm) } } diff --git a/Yep/ViewControllers/Contacts/ContactsViewController.swift b/Yep/ViewControllers/Contacts/ContactsViewController.swift index 69bc6888..976abfc1 100644 --- a/Yep/ViewControllers/Contacts/ContactsViewController.swift +++ b/Yep/ViewControllers/Contacts/ContactsViewController.swift @@ -52,6 +52,9 @@ class ContactsViewController: BaseViewController { override func viewDidLoad() { super.viewDidLoad() + + syncFriendshipsAndDoFurtherAction { + } title = NSLocalizedString("Contacts", comment: "") diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 70e3e231..0914fb4f 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -91,6 +91,8 @@ class ConversationViewController: BaseViewController { var conversationFeed: ConversationFeed? var conversation: Conversation! + + var selectedIndexPathForMenu: NSIndexPath? var realm: Realm! @@ -332,6 +334,8 @@ class ConversationViewController: BaseViewController { override func viewDidLoad() { super.viewDidLoad() + UIMenuController.sharedMenuController().menuItems = [ UIMenuItem(title: NSLocalizedString("Delete", comment: ""), action: "deleteMessage:") ] + realm = try! Realm() // 优先处理侧滑,而不是 scrollView 的上下滚动,避免出现你想侧滑返回的时候,结果触发了 scrollView 的上下滚动 @@ -369,6 +373,10 @@ class ConversationViewController: BaseViewController { NSNotificationCenter.defaultCenter().addObserver(self, selector: "cleanForLogout", name: EditProfileViewController.Notification.Logout, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: "tryInsertInActiveNewMessages:", name: AppDelegate.Notification.applicationDidBecomeActive, object: nil) + + NSNotificationCenter.defaultCenter().addObserver(self, selector: "didRecieveMenuWillShowNotification:", name: UIMenuControllerWillShowMenuNotification, object: nil) + + NSNotificationCenter.defaultCenter().addObserver(self, selector: "didRecieveMenuWillHideNotification:", name: UIMenuControllerWillHideMenuNotification, object: nil) YepUserDefaults.avatarURLString.bindListener(Listener.Avatar) { [weak self] _ in dispatch_async(dispatch_get_main_queue()) { @@ -1388,7 +1396,9 @@ class ConversationViewController: BaseViewController { // MARK: Actions func tapToCollapseMessageToolBar(sender: UITapGestureRecognizer) { - messageToolbar.state = .Default + if selectedIndexPathForMenu == nil { + messageToolbar.state = .Default + } } func checkTypingStatus() { @@ -2221,9 +2231,164 @@ extension ConversationViewController: UIGestureRecognizerDelegate { } // MARK: UICollectionViewDataSource, UICollectionViewDelegate - extension ConversationViewController: UICollectionViewDataSource, UICollectionViewDelegate { + func didRecieveMenuWillHideNotification(notification: NSNotification) { + print("Menu Will hide") + + selectedIndexPathForMenu = nil + + } + + func didRecieveMenuWillShowNotification(notification: NSNotification) { + + print("Menu Will show") + + if let menu = notification.object as? UIMenuController, + selectedIndexPathForMenu = selectedIndexPathForMenu + { + + var bubbleFrame = CGRectZero + + if let cell = conversationCollectionView.cellForItemAtIndexPath(selectedIndexPathForMenu) as? ChatRightTextCell { + bubbleFrame = cell.convertRect(cell.textContainerView.frame, toView: view) + } else if let cell = conversationCollectionView.cellForItemAtIndexPath(selectedIndexPathForMenu) as? ChatLeftTextCell { + bubbleFrame = cell.convertRect(cell.textContainerView.frame, toView: view) + } else { + return + } + + NSNotificationCenter.defaultCenter().removeObserver(self, name: UIMenuControllerWillShowMenuNotification, object: nil) + + menu.setTargetRect(bubbleFrame, inView: view) + + menu.setMenuVisible(true, animated: true) + + NSNotificationCenter.defaultCenter().addObserver(self, selector: "didRecieveMenuWillShowNotification:", name: UIMenuControllerWillShowMenuNotification, object: nil) + + + } + + + } + + func collectionView(collectionView: UICollectionView, canPerformAction action: Selector, forItemAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) -> Bool { + + if action == "copy:" { + return true + + } else if action == "deleteMessage:" { + return true + } + + return false + } + + + func collectionView(collectionView: UICollectionView, performAction action: Selector, forItemAtIndexPath indexPath: NSIndexPath, withSender sender: AnyObject?) { + + if let cell = conversationCollectionView.cellForItemAtIndexPath(indexPath) as? ChatRightTextCell { + if action == "copy:" { + UIPasteboard.generalPasteboard().string = cell.textContentTextView.text + } + } else if let cell = conversationCollectionView.cellForItemAtIndexPath(indexPath) as? ChatLeftTextCell { + if action == "copy:" { + UIPasteboard.generalPasteboard().string = cell.textContentTextView.text + } + } + + } + + func deleteMessageAtIndexPath(message: Message, indexPath: NSIndexPath) { + dispatch_async(dispatch_get_main_queue()) { [weak self] in + 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 + } + + let _ = try? 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 + let _ = try? realm.write { + if let mediaMetaData = message.mediaMetaData { + realm.delete(mediaMetaData) + } + realm.delete(message) + } + strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) + } + + // 必须更新,插入时需要 + strongSelf.lastTimeMessagesCount = strongSelf.messages.count + } + } + } + + func collectionView(collectionView: UICollectionView, shouldShowMenuForItemAtIndexPath indexPath: NSIndexPath) -> Bool { + + selectedIndexPathForMenu = indexPath + + if let _ = conversationCollectionView.cellForItemAtIndexPath(indexPath) as? ChatRightTextCell { + + return true + } else if let _ = conversationCollectionView.cellForItemAtIndexPath(indexPath) as? ChatLeftTextCell { + return true + } else { + selectedIndexPathForMenu = nil + } + + return false + } + func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { return 1 } @@ -2239,7 +2404,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if message.mediaType == MessageMediaType.SectionDate.rawValue { let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatSectionDateCellIdentifier, forIndexPath: indexPath) as! ChatSectionDateCell - + collectionViewConfigCell(collectionView, cell: cell, forItemAtIndexPath: indexPath) return cell } @@ -2254,31 +2419,31 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi case MessageMediaType.Image.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftImageCellIdentifier, forIndexPath: indexPath) as! ChatLeftImageCell - + collectionViewConfigCell(collectionView, cell: cell, forItemAtIndexPath: indexPath) return cell case MessageMediaType.Audio.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftAudioCellIdentifier, forIndexPath: indexPath) as! ChatLeftAudioCell - + collectionViewConfigCell(collectionView, cell: cell, forItemAtIndexPath: indexPath) return cell case MessageMediaType.Video.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftVideoCellIdentifier, forIndexPath: indexPath) as! ChatLeftVideoCell - + collectionViewConfigCell(collectionView, cell: cell, forItemAtIndexPath: indexPath) return cell case MessageMediaType.Location.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftLocationCellIdentifier, forIndexPath: indexPath) as! ChatLeftLocationCell - + collectionViewConfigCell(collectionView, cell: cell, forItemAtIndexPath: indexPath) return cell default: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftTextCellIdentifier, forIndexPath: indexPath) as! ChatLeftTextCell - + collectionViewConfigCell(collectionView, cell: cell, forItemAtIndexPath: indexPath) return cell } @@ -2289,31 +2454,31 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi case MessageMediaType.Image.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightImageCellIdentifier, forIndexPath: indexPath) as! ChatRightImageCell - + collectionViewConfigCell(collectionView, cell: cell, forItemAtIndexPath: indexPath) return cell case MessageMediaType.Audio.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightAudioCellIdentifier, forIndexPath: indexPath) as! ChatRightAudioCell - + collectionViewConfigCell(collectionView, cell: cell, forItemAtIndexPath: indexPath) return cell case MessageMediaType.Video.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightVideoCellIdentifier, forIndexPath: indexPath) as! ChatRightVideoCell - + collectionViewConfigCell(collectionView, cell: cell, forItemAtIndexPath: indexPath) return cell case MessageMediaType.Location.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightLocationCellIdentifier, forIndexPath: indexPath) as! ChatRightLocationCell - + collectionViewConfigCell(collectionView, cell: cell, forItemAtIndexPath: indexPath) return cell default: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightTextCellIdentifier, forIndexPath: indexPath) as! ChatRightTextCell - + collectionViewConfigCell(collectionView, cell: cell, forItemAtIndexPath: indexPath) return cell } } @@ -2330,384 +2495,379 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } - func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) { + func collectionViewConfigCell(collectionView: UICollectionView, cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) { - dispatch_async(dispatch_get_main_queue(),{ [weak self] in - - if let weakSelf = self { + if let message = self.messages[safe: (self.displayedMessagesRange.location + indexPath.item)] { + + if message.mediaType == MessageMediaType.SectionDate.rawValue { - if let message = weakSelf.messages[safe: (weakSelf.displayedMessagesRange.location + indexPath.item)] { + if let cell = cell as? ChatSectionDateCell { + let createdAt = NSDate(timeIntervalSince1970: message.createdUnixTime) - if message.mediaType == MessageMediaType.SectionDate.rawValue { - - if let cell = cell as? ChatSectionDateCell { - let createdAt = NSDate(timeIntervalSince1970: message.createdUnixTime) - - if createdAt.isInCurrentWeek() { - cell.sectionDateLabel.text = weakSelf.sectionDateInCurrentWeekFormatter.stringFromDate(createdAt) - } else { - cell.sectionDateLabel.text = weakSelf.sectionDateFormatter.stringFromDate(createdAt) - } - } - - return + if createdAt.isInCurrentWeek() { + cell.sectionDateLabel.text = self.sectionDateInCurrentWeekFormatter.stringFromDate(createdAt) + } else { + cell.sectionDateLabel.text = self.sectionDateFormatter.stringFromDate(createdAt) } - - if let sender = message.fromFriend { - - if let cell = cell as? ChatBaseCell { - cell.tapAvatarAction = { [weak self] user in - self?.performSegueWithIdentifier("showProfile", sender: user) - } - } + } + + return + } + + if let sender = message.fromFriend { + + if let cell = cell as? ChatBaseCell { + cell.tapAvatarAction = { [weak self] user in + self?.performSegueWithIdentifier("showProfile", sender: user) + } + } - if let cell = cell as? ChatRightBaseCell { - if let _ = weakSelf.conversation.withGroup { - cell.inGroup = true - } - } + if let cell = cell as? ChatRightBaseCell { + if let _ = self.conversation.withGroup { + cell.inGroup = true + } + } + + if sender.friendState != UserFriendState.Me.rawValue { // from Friend + + self.markMessageAsReaded(message) + + switch message.mediaType { - if sender.friendState != UserFriendState.Me.rawValue { // from Friend + case MessageMediaType.Image.rawValue: + + if let cell = cell as? ChatLeftImageCell { - weakSelf.markMessageAsReaded(message) - - switch message.mediaType { + cell.configureWithMessage(message, messageImagePreferredWidth: self.messageImagePreferredWidth, messageImagePreferredHeight: self.messageImagePreferredHeight, messageImagePreferredAspectRatio: self.messageImagePreferredAspectRatio, mediaTapAction: { [weak self] in - case MessageMediaType.Image.rawValue: - - if let cell = cell as? ChatLeftImageCell { + if message.downloadState == MessageDownloadState.Downloaded.rawValue { - cell.configureWithMessage(message, messageImagePreferredWidth: weakSelf.messageImagePreferredWidth, messageImagePreferredHeight: weakSelf.messageImagePreferredHeight, messageImagePreferredAspectRatio: weakSelf.messageImagePreferredAspectRatio, mediaTapAction: { [weak self] in - - if message.downloadState == MessageDownloadState.Downloaded.rawValue { - - if let messageTextView = self?.messageToolbar.messageTextView { - if messageTextView.isFirstResponder() { - self?.messageToolbar.state = .Default - return - } - } - - self?.performSegueWithIdentifier("showMessageMedia", sender: message) - - } else { - //YepAlert.alertSorry(message: NSLocalizedString("Please wait while the image is not ready!", comment: ""), inViewController: self) - } - - }, collectionView: collectionView, indexPath: indexPath) - } - - case MessageMediaType.Audio.rawValue: - - if let cell = cell as? ChatLeftAudioCell { - - let audioPlayedDuration = weakSelf.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 ready!", comment: ""), inViewController: self) - } - - }, collectionView: collectionView, indexPath: indexPath) - } - - case MessageMediaType.Video.rawValue: - - if let cell = cell as? ChatLeftVideoCell { - - cell.configureWithMessage(message, messageImagePreferredWidth: weakSelf.messageImagePreferredWidth, messageImagePreferredHeight: weakSelf.messageImagePreferredHeight, messageImagePreferredAspectRatio: weakSelf.messageImagePreferredAspectRatio, mediaTapAction: { [weak self] in - - if message.downloadState == MessageDownloadState.Downloaded.rawValue { - - if let messageTextView = self?.messageToolbar.messageTextView { - if messageTextView.isFirstResponder() { - self?.messageToolbar.state = .Default - return - } - } - - self?.performSegueWithIdentifier("showMessageMedia", sender: message) - - } else { - //YepAlert.alertSorry(message: NSLocalizedString("Please wait while the video is not ready!", comment: ""), inViewController: self) - } - - }, collectionView: collectionView, indexPath: indexPath) - } - - case MessageMediaType.Location.rawValue: - - if let cell = cell as? ChatLeftLocationCell { - - 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)) - mapItem.name = message.textContent - /* - let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving] - mapItem.openInMapsWithLaunchOptions(launchOptions) - */ - mapItem.openInMapsWithLaunchOptions(nil) - } - - }, collectionView: collectionView, indexPath: indexPath) - } - - default: - - if let cell = cell as? ChatLeftTextCell { - - cell.configureWithMessage(message, textContentLabelWidth: weakSelf.textContentLabelWidthOfMessage(message), collectionView: collectionView, indexPath: indexPath) - } - } - - } else { // from Me - - switch message.mediaType { - - case MessageMediaType.Image.rawValue: - - if let cell = cell as? ChatRightImageCell { - - cell.configureWithMessage(message, messageImagePreferredWidth: weakSelf.messageImagePreferredWidth, messageImagePreferredHeight: weakSelf.messageImagePreferredHeight, messageImagePreferredAspectRatio: weakSelf.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: 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 { - if let messageTextView = self?.messageToolbar.messageTextView { - if messageTextView.isFirstResponder() { - self?.messageToolbar.state = .Default - return - } - } - - self?.performSegueWithIdentifier("showMessageMedia", sender: message) - } - - }, collectionView: collectionView, indexPath: indexPath) - } - - case MessageMediaType.Audio.rawValue: - - if let cell = cell as? ChatRightAudioCell { - - let audioPlayedDuration = weakSelf.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: 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: { - }) - + if let messageTextView = self?.messageToolbar.messageTextView { + if messageTextView.isFirstResponder() { + self?.messageToolbar.state = .Default return } - - self?.playMessageAudioWithMessage(message) - - }, collectionView: collectionView, indexPath: indexPath) + } + + self?.performSegueWithIdentifier("showMessageMedia", sender: message) + + } else { + //YepAlert.alertSorry(message: NSLocalizedString("Please wait while the image is not ready!", comment: ""), inViewController: self) } - case MessageMediaType.Video.rawValue: + }, collectionView: collectionView, indexPath: indexPath) + } + + case MessageMediaType.Audio.rawValue: + + if let cell = cell as? ChatLeftAudioCell { + + let audioPlayedDuration = self.audioPlayedDurationOfMessage(message) + + cell.configureWithMessage(message, audioPlayedDuration: audioPlayedDuration, audioBubbleTapAction: { [weak self] in - if let cell = cell as? ChatRightVideoCell { + if message.downloadState == MessageDownloadState.Downloaded.rawValue { + self?.playMessageAudioWithMessage(message) - cell.configureWithMessage(message, messageImagePreferredWidth: weakSelf.messageImagePreferredWidth, messageImagePreferredHeight: weakSelf.messageImagePreferredHeight, messageImagePreferredAspectRatio: weakSelf.messageImagePreferredAspectRatio, mediaTapAction: { [weak self] in + } else { + //YepAlert.alertSorry(message: NSLocalizedString("Please wait while the audio is not ready!", comment: ""), inViewController: self) + } + + }, collectionView: collectionView, indexPath: indexPath) + } + + case MessageMediaType.Video.rawValue: + + if let cell = cell as? ChatLeftVideoCell { + + cell.configureWithMessage(message, messageImagePreferredWidth: self.messageImagePreferredWidth, messageImagePreferredHeight: self.messageImagePreferredHeight, messageImagePreferredAspectRatio: self.messageImagePreferredAspectRatio, mediaTapAction: { [weak self] in + + if message.downloadState == MessageDownloadState.Downloaded.rawValue { + + if let messageTextView = self?.messageToolbar.messageTextView { + if messageTextView.isFirstResponder() { + self?.messageToolbar.state = .Default + return + } + } + + self?.performSegueWithIdentifier("showMessageMedia", sender: message) + + } else { + //YepAlert.alertSorry(message: NSLocalizedString("Please wait while the video is not ready!", comment: ""), inViewController: self) + } + + }, collectionView: collectionView, indexPath: indexPath) + } + + case MessageMediaType.Location.rawValue: + + if let cell = cell as? ChatLeftLocationCell { + + 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)) + mapItem.name = message.textContent + /* + let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving] + mapItem.openInMapsWithLaunchOptions(launchOptions) + */ + mapItem.openInMapsWithLaunchOptions(nil) + } + + }, collectionView: collectionView, indexPath: indexPath) + } + + default: + + if let cell = cell as? ChatLeftTextCell { + + cell.configureWithMessage(message, textContentLabelWidth: self.textContentLabelWidthOfMessage(message), collectionView: collectionView, indexPath: indexPath) + } + } + + } else { // from Me + + switch message.mediaType { + + case MessageMediaType.Image.rawValue: + + if let cell = cell as? ChatRightImageCell { + + cell.configureWithMessage(message, messageImagePreferredWidth: self.messageImagePreferredWidth, messageImagePreferredHeight: self.messageImagePreferredHeight, messageImagePreferredAspectRatio: self.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: { - if message.sendState == MessageSendState.Failed.rawValue { + resendMessage(message, failureHandler: { [weak self] reason, errorMessage in + defaultFailureHandler(reason, errorMessage: errorMessage) - YepAlert.confirmOrCancel(title: NSLocalizedString("Action", comment: ""), message: NSLocalizedString("Resend video?", comment: ""), confirmTitle: NSLocalizedString("Resend", comment: ""), cancelTitle: NSLocalizedString("Cancel", comment: ""), inViewController: self, withConfirmAction: { + 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 { + if let messageTextView = self?.messageToolbar.messageTextView { + if messageTextView.isFirstResponder() { + self?.messageToolbar.state = .Default + return + } + } + + self?.performSegueWithIdentifier("showMessageMedia", sender: message) + } + + }, collectionView: collectionView, indexPath: indexPath) + } + + case MessageMediaType.Audio.rawValue: + + if let cell = cell as? ChatRightAudioCell { + + let audioPlayedDuration = self.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: 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) + } + + case MessageMediaType.Video.rawValue: + + if let cell = cell as? ChatRightVideoCell { + + cell.configureWithMessage(message, messageImagePreferredWidth: self.messageImagePreferredWidth, messageImagePreferredHeight: self.messageImagePreferredHeight, messageImagePreferredAspectRatio: self.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: 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 { + if let messageTextView = self?.messageToolbar.messageTextView { + if messageTextView.isFirstResponder() { + self?.messageToolbar.state = .Default + return + } + } + + self?.performSegueWithIdentifier("showMessageMedia", sender: message) + } + + }, collectionView: collectionView, indexPath: indexPath) + } + + 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: 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)) + mapItem.name = message.textContent + /* + let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving] + mapItem.openInMapsWithLaunchOptions(launchOptions) + */ + mapItem.openInMapsWithLaunchOptions(nil) + } + } + + }, collectionView: collectionView, indexPath: indexPath) + } + + default: + + if let cell = cell as? ChatRightTextCell { + + cell.configureWithMessage(message, textContentLabelWidth: self.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: 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] { - resendMessage(message, failureHandler: { [weak self] reason, errorMessage in - defaultFailureHandler(reason, errorMessage: 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)") - }) + 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 - }, cancelAction: { - }) + } else { + if strongSelf.displayedMessagesRange.location >= 1 { + strongSelf.displayedMessagesRange.location -= 1 + } + strongSelf.displayedMessagesRange.length -= 1 + } + + let _ = try? 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 { - if let messageTextView = self?.messageToolbar.messageTextView { - if messageTextView.isFirstResponder() { - self?.messageToolbar.state = .Default - return + strongSelf.displayedMessagesRange.length -= 1 + let _ = try? realm.write { + if let mediaMetaData = message.mediaMetaData { + realm.delete(mediaMetaData) } + realm.delete(message) } - - self?.performSegueWithIdentifier("showMessageMedia", sender: message) + strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) } - }, collectionView: collectionView, indexPath: indexPath) - } - - 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: 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)) - mapItem.name = message.textContent - /* - let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving] - mapItem.openInMapsWithLaunchOptions(launchOptions) - */ - mapItem.openInMapsWithLaunchOptions(nil) - } - } - - }, collectionView: collectionView, indexPath: indexPath) - } - - default: - - if let cell = cell as? ChatRightTextCell { - - cell.configureWithMessage(message, textContentLabelWidth: weakSelf.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: 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 - } - - let _ = try? 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 - let _ = try? realm.write { - if let mediaMetaData = message.mediaMetaData { - realm.delete(mediaMetaData) - } - realm.delete(message) - } - strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) - } - - // 必须更新,插入时需要 - strongSelf.lastTimeMessagesCount = strongSelf.messages.count - } - } + // 必须更新,插入时需要 + strongSelf.lastTimeMessagesCount = strongSelf.messages.count } } } @@ -2715,8 +2875,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } } } - - }) + } } func collectionView(collectionView: UICollectionView!, layout collectionViewLayout: UICollectionViewLayout!, sizeForItemAtIndexPath indexPath: NSIndexPath!) -> CGSize { diff --git a/Yep/ViewControllers/Discover/DiscoverViewController.swift b/Yep/ViewControllers/Discover/DiscoverViewController.swift index 50c09d9b..613ed0e3 100644 --- a/Yep/ViewControllers/Discover/DiscoverViewController.swift +++ b/Yep/ViewControllers/Discover/DiscoverViewController.swift @@ -13,6 +13,8 @@ enum DiscoverUserMode: Int { case Card } +var skillSizeCache = [String: CGRect]() + class DiscoverViewController: BaseViewController { @IBOutlet weak var discoverCollectionView: UICollectionView! @@ -60,6 +62,27 @@ class DiscoverViewController: BaseViewController { } }, completion: { discoveredUsers in + + for user in discoveredUsers { + + for skill in user.masterSkills { + + let skillLocalName = skill.localName ?? "" + + let skillID = skill.id + + if let _ = skillSizeCache[skillID] { + + } else { + let rect = skillLocalName.boundingRectWithSize(CGSize(width: CGFloat(FLT_MAX), height: SkillCell.height), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: skillTextAttributes, context: nil) + + skillSizeCache[skillID] = rect + } + + } + + } + dispatch_async(dispatch_get_main_queue()) { [weak self] in self?.discoveredUsers = discoveredUsers self?.activityIndicator.stopAnimating() @@ -182,22 +205,35 @@ extension DiscoverViewController: UICollectionViewDelegate, UICollectionViewData } func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { - let discoveredUser = discoveredUsers[indexPath.row] +// let discoveredUser = discoveredUsers[indexPath.row] switch userMode! { case .Normal: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(NormalUserIdentifier, forIndexPath: indexPath) as! DiscoverNormalUserCell - cell.configureWithDiscoveredUser(discoveredUser, collectionView: collectionView, indexPath: indexPath) +// cell.configureWithDiscoveredUser(discoveredUser, collectionView: collectionView, indexPath: indexPath) return cell case .Card: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(CardUserIdentifier, forIndexPath: indexPath) as! DiscoverCardUserCell - cell.configureWithDiscoveredUser(discoveredUser, collectionView: collectionView, indexPath: indexPath) +// cell.configureWithDiscoveredUser(discoveredUser, collectionView: collectionView, indexPath: indexPath) return cell } + } + + func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) { + let discoveredUser = discoveredUsers[indexPath.row] - + switch userMode! { + case .Normal: + let cell = cell as! DiscoverNormalUserCell + + cell.configureWithDiscoveredUser(discoveredUser, collectionView: collectionView, indexPath: indexPath) + + case .Card: + let cell = cell as! DiscoverCardUserCell + cell.configureWithDiscoveredUser(discoveredUser, collectionView: collectionView, indexPath: indexPath) + } } func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets { diff --git a/Yep/ViewControllers/Feeds/FeedsViewController.swift b/Yep/ViewControllers/Feeds/FeedsViewController.swift index cbb93fae..fa724ec6 100644 --- a/Yep/ViewControllers/Feeds/FeedsViewController.swift +++ b/Yep/ViewControllers/Feeds/FeedsViewController.swift @@ -256,7 +256,7 @@ class FeedsViewController: UIViewController { vc.conversation = feedConversation if let group = group { - saveFeedWithFeedData(feedData, group: group, inRealm: realm) + saveFeedWithFeedDataWithoutFullGroup(feedData, group: group, inRealm: realm) } vc.conversationFeed = ConversationFeed.DiscoveredFeedType(feedData) diff --git a/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift b/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift index 9ba655f3..8706f93d 100644 --- a/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift +++ b/Yep/ViewControllers/Login/LoginVerifyMobileViewController.swift @@ -206,6 +206,9 @@ class LoginVerifyMobileViewController: UIViewController { dispatch_async(dispatch_get_main_queue(), { () -> Void in saveTokenAndUserInfoOfLoginUser(loginUser) + + syncMyInfoAndDoFurtherAction { + } if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate { appDelegate.startMainStory() diff --git a/Yep/ViewControllers/Profile/ProfileViewController.swift b/Yep/ViewControllers/Profile/ProfileViewController.swift index a3e82e48..1448bfdc 100644 --- a/Yep/ViewControllers/Profile/ProfileViewController.swift +++ b/Yep/ViewControllers/Profile/ProfileViewController.swift @@ -480,6 +480,9 @@ class ProfileViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + + syncMyInfoAndDoFurtherAction { + } title = NSLocalizedString("Profile", comment: "") diff --git a/Yep/Views/Cells/ChatLeftAudio/ChatLeftAudioCell.swift b/Yep/Views/Cells/ChatLeftAudio/ChatLeftAudioCell.swift index 6bd3499a..2a6977b0 100644 --- a/Yep/Views/Cells/ChatLeftAudio/ChatLeftAudioCell.swift +++ b/Yep/Views/Cells/ChatLeftAudio/ChatLeftAudioCell.swift @@ -124,7 +124,9 @@ class ChatLeftAudioCell: ChatBaseCell { override func layoutSubviews() { super.layoutSubviews() - updateAudioInfoViews() + dispatch_async(dispatch_get_main_queue()) { [weak self] in + self?.updateAudioInfoViews() + } } func updateAudioInfoViews() { diff --git a/Yep/Views/Cells/ChatLeftImage/ChatLeftImageCell.swift b/Yep/Views/Cells/ChatLeftImage/ChatLeftImageCell.swift index 2083f60f..c3c15148 100644 --- a/Yep/Views/Cells/ChatLeftImage/ChatLeftImageCell.swift +++ b/Yep/Views/Cells/ChatLeftImage/ChatLeftImageCell.swift @@ -97,7 +97,9 @@ class ChatLeftImageCell: ChatBaseCell { loadingProgress = 0 - messageImageView.alpha = 0.0 + dispatch_async(dispatch_get_main_queue()) { [weak self] in + self?.messageImageView.alpha = 0.0 + } if let (imageWidth, imageHeight) = imageMetaOfMessage(message) { @@ -109,8 +111,14 @@ class ChatLeftImageCell: ChatBaseCell { if aspectRatio >= 1 { let width = messageImagePreferredWidth - messageImageView.frame = CGRect(x: CGRectGetMaxX(avatarImageView.frame) + YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble, y: 0, width: width, height: bounds.height) - loadingProgressView.center = CGPoint(x: CGRectGetMidX(messageImageView.frame) + YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(messageImageView.frame)) + + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.messageImageView.frame = CGRect(x: CGRectGetMaxX(strongSelf.avatarImageView.frame) + YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble, y: 0, width: width, height: strongSelf.bounds.height) + strongSelf.loadingProgressView.center = CGPoint(x: CGRectGetMidX(strongSelf.messageImageView.frame) + YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(strongSelf.messageImageView.frame)) + } + } + ImageCache.sharedInstance.imageOfMessage(message, withSize: CGSize(width: messageImagePreferredWidth, height: ceil(messageImagePreferredWidth / aspectRatio)), tailDirection: .Left, completion: { [weak self] progress, image in @@ -123,8 +131,13 @@ class ChatLeftImageCell: ChatBaseCell { } else { let width = messageImagePreferredHeight * aspectRatio - messageImageView.frame = CGRect(x: CGRectGetMaxX(avatarImageView.frame) + YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble, y: 0, width: width, height: bounds.height) - loadingProgressView.center = CGPoint(x: CGRectGetMidX(messageImageView.frame) + YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(messageImageView.frame)) + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.messageImageView.frame = CGRect(x: CGRectGetMaxX(strongSelf.avatarImageView.frame) + YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble, y: 0, width: width, height: strongSelf.bounds.height) + strongSelf.loadingProgressView.center = CGPoint(x: CGRectGetMidX(strongSelf.messageImageView.frame) + YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(strongSelf.messageImageView.frame)) + } + } + ImageCache.sharedInstance.imageOfMessage(message, withSize: CGSize(width: messageImagePreferredHeight * aspectRatio, height: messageImagePreferredHeight), tailDirection: .Left, completion: { [weak self] progress, image in @@ -138,8 +151,13 @@ class ChatLeftImageCell: ChatBaseCell { } else { let width = messageImagePreferredWidth - messageImageView.frame = CGRect(x: CGRectGetMaxX(avatarImageView.frame) + YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble, y: 0, width: width, height: bounds.height) - loadingProgressView.center = CGPoint(x: CGRectGetMidX(messageImageView.frame) + YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(messageImageView.frame)) + + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.messageImageView.frame = CGRect(x: CGRectGetMaxX(strongSelf.avatarImageView.frame) + YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble, y: 0, width: width, height: strongSelf.bounds.height) + strongSelf.loadingProgressView.center = CGPoint(x: CGRectGetMidX(strongSelf.messageImageView.frame) + YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(strongSelf.messageImageView.frame)) + } + } ImageCache.sharedInstance.imageOfMessage(message, withSize: CGSize(width: messageImagePreferredWidth, height: ceil(messageImagePreferredWidth / messageImagePreferredAspectRatio)), tailDirection: .Left, completion: { [weak self] progress, image in diff --git a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift index f93107b1..9c62d5bf 100644 --- a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift +++ b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift @@ -40,10 +40,6 @@ class ChatLeftTextCell: ChatBaseCell { NSUnderlineStyleAttributeName: NSNumber(integer: NSUnderlineStyle.StyleSingle.rawValue), ] - let longPress = UILongPressGestureRecognizer(target: self, action: "handleLongPress:") - longPress.minimumPressDuration = 0.3 - longPress.delegate = self // 由 ChatBaseCell 负责 - textContainerView.addGestureRecognizer(longPress) textContainerView.copyTextAction = { [weak self] in UIPasteboard.generalPasteboard().string = self?.textContentTextView.text @@ -52,20 +48,12 @@ class ChatLeftTextCell: ChatBaseCell { bubbleBodyImageView.tintColor = UIColor.leftBubbleTintColor() bubbleTailImageView.tintColor = UIColor.leftBubbleTintColor() } - - func handleLongPress(longPress: UILongPressGestureRecognizer) { - if longPress.state == .Began { - - if let view = longPress.view, superview = view.superview { - - view.becomeFirstResponder() - - let menu = UIMenuController.sharedMenuController() - let copyItem = UIMenuItem(title: NSLocalizedString("Copy", comment: ""), action:"copyText") - menu.menuItems = [copyItem] - menu.setTargetRect(view.frame, inView: superview) - menu.setMenuVisible(true, animated: true) - } + + override func respondsToSelector(aSelector: Selector) -> Bool { + if ["copy:"].contains(aSelector) { + return true + } else { + return super.respondsToSelector(aSelector) } } @@ -73,27 +61,33 @@ class ChatLeftTextCell: ChatBaseCell { self.user = message.fromFriend - textContentTextView.text = message.textContent - //textContentTextView.attributedText = NSAttributedString(string: message.textContent, attributes: textAttributes) + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.textContentTextView.text = message.textContent + //textContentTextView.attributedText = NSAttributedString(string: message.textContent, attributes: textAttributes) + + //textContentTextView.textAlignment = textContentLabelWidth < YepConfig.minMessageTextLabelWidth ? .Center : .Left + + // 用 sizeThatFits 来对比,不需要 magicWidth 的时候就可以避免了 + var textContentLabelWidth = textContentLabelWidth + let size = strongSelf.textContentTextView.sizeThatFits(CGSize(width: textContentLabelWidth, height: CGFloat.max)) + + // lineHeight 19.088, size.height 35.5 (1 line) 54.5 (2 lines) + strongSelf.textContentTextView.textAlignment = ((size.height - strongSelf.textContentTextView.font!.lineHeight) < 20) ? .Center : .Left + + if size.width != textContentLabelWidth { + textContentLabelWidth += YepConfig.ChatCell.magicWidth + } + + textContentLabelWidth = max(textContentLabelWidth, YepConfig.ChatCell.minTextWidth) + + strongSelf.textContainerView.frame = CGRect(x: CGRectGetMaxX(strongSelf.avatarImageView.frame) + YepConfig.chatCellGapBetweenTextContentLabelAndAvatar(), y: 3, width: textContentLabelWidth, height: strongSelf.bounds.height - 3 * 2) + strongSelf.bubbleBodyImageView.frame = CGRectInset(strongSelf.textContainerView.frame, -12, -3) + strongSelf.bubbleTailImageView.center = CGPoint(x: CGRectGetMinX(strongSelf.bubbleBodyImageView.frame), y: CGRectGetMidY(strongSelf.avatarImageView.frame)) - //textContentTextView.textAlignment = textContentLabelWidth < YepConfig.minMessageTextLabelWidth ? .Center : .Left - - // 用 sizeThatFits 来对比,不需要 magicWidth 的时候就可以避免了 - var textContentLabelWidth = textContentLabelWidth - let size = textContentTextView.sizeThatFits(CGSize(width: textContentLabelWidth, height: CGFloat.max)) - - // lineHeight 19.088, size.height 35.5 (1 line) 54.5 (2 lines) - textContentTextView.textAlignment = ((size.height - textContentTextView.font!.lineHeight) < 20) ? .Center : .Left - - if size.width != textContentLabelWidth { - textContentLabelWidth += YepConfig.ChatCell.magicWidth + } } - textContentLabelWidth = max(textContentLabelWidth, YepConfig.ChatCell.minTextWidth) - - textContainerView.frame = CGRect(x: CGRectGetMaxX(avatarImageView.frame) + YepConfig.chatCellGapBetweenTextContentLabelAndAvatar(), y: 3, width: textContentLabelWidth, height: bounds.height - 3 * 2) - bubbleBodyImageView.frame = CGRectInset(textContainerView.frame, -12, -3) - bubbleTailImageView.center = CGPoint(x: CGRectGetMinX(bubbleBodyImageView.frame), y: CGRectGetMidY(avatarImageView.frame)) if let sender = message.fromFriend { AvatarCache.sharedInstance.roundAvatarOfUser(sender, withRadius: YepConfig.chatCellAvatarSize() * 0.5) { [weak self] roundImage in diff --git a/Yep/Views/Cells/ChatLeftVideo/ChatLeftVideoCell.swift b/Yep/Views/Cells/ChatLeftVideo/ChatLeftVideoCell.swift index f5c700a9..6dee7d42 100644 --- a/Yep/Views/Cells/ChatLeftVideo/ChatLeftVideoCell.swift +++ b/Yep/Views/Cells/ChatLeftVideo/ChatLeftVideoCell.swift @@ -99,7 +99,12 @@ class ChatLeftVideoCell: ChatBaseCell { loadingProgress = 0 - thumbnailImageView.alpha = 0.0 + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.thumbnailImageView.alpha = 0.0 + } + } + if let (videoWidth, videoHeight) = videoMetaOfMessage(message) { @@ -111,9 +116,14 @@ class ChatLeftVideoCell: ChatBaseCell { if aspectRatio >= 1 { let width = messageImagePreferredWidth - thumbnailImageView.frame = CGRect(x: CGRectGetMaxX(avatarImageView.frame) + YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble, y: 0, width: width, height: bounds.height) - playImageView.center = CGPoint(x: CGRectGetMidX(thumbnailImageView.frame) + YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(thumbnailImageView.frame)) - loadingProgressView.center = playImageView.center + + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.thumbnailImageView.frame = CGRect(x: CGRectGetMaxX(strongSelf.avatarImageView.frame) + YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble, y: 0, width: width, height: strongSelf.bounds.height) + strongSelf.playImageView.center = CGPoint(x: CGRectGetMidX(strongSelf.thumbnailImageView.frame) + YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(strongSelf.thumbnailImageView.frame)) + strongSelf.loadingProgressView.center = strongSelf.playImageView.center + } + } ImageCache.sharedInstance.imageOfMessage(message, withSize: CGSize(width: messageImagePreferredWidth, height: ceil(messageImagePreferredWidth / aspectRatio)), tailDirection: .Left, completion: { [weak self] progress, image in @@ -126,9 +136,15 @@ class ChatLeftVideoCell: ChatBaseCell { } else { let width = messageImagePreferredHeight * aspectRatio - thumbnailImageView.frame = CGRect(x: CGRectGetMaxX(avatarImageView.frame) + YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble, y: 0, width: width, height: bounds.height) - playImageView.center = CGPoint(x: CGRectGetMidX(thumbnailImageView.frame) + YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(thumbnailImageView.frame)) - loadingProgressView.center = playImageView.center + + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.thumbnailImageView.frame = CGRect(x: CGRectGetMaxX(strongSelf.avatarImageView.frame) + YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble, y: 0, width: width, height: strongSelf.bounds.height) + strongSelf.playImageView.center = CGPoint(x: CGRectGetMidX(strongSelf.thumbnailImageView.frame) + YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(strongSelf.thumbnailImageView.frame)) + strongSelf.loadingProgressView.center = strongSelf.playImageView.center + } + } + ImageCache.sharedInstance.imageOfMessage(message, withSize: CGSize(width: messageImagePreferredHeight * aspectRatio, height: messageImagePreferredHeight), tailDirection: .Left, completion: { [weak self] progress, image in @@ -142,9 +158,14 @@ class ChatLeftVideoCell: ChatBaseCell { } else { let width = messageImagePreferredWidth - thumbnailImageView.frame = CGRect(x: CGRectGetMaxX(avatarImageView.frame) + YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble, y: 0, width: width, height: bounds.height) - playImageView.center = CGPoint(x: CGRectGetMidX(thumbnailImageView.frame) + YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(thumbnailImageView.frame)) - loadingProgressView.center = playImageView.center + + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.thumbnailImageView.frame = CGRect(x: CGRectGetMaxX(strongSelf.avatarImageView.frame) + YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble, y: 0, width: width, height: strongSelf.bounds.height) + strongSelf.playImageView.center = CGPoint(x: CGRectGetMidX(strongSelf.thumbnailImageView.frame) + YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(strongSelf.thumbnailImageView.frame)) + strongSelf.loadingProgressView.center = strongSelf.playImageView.center + } + } ImageCache.sharedInstance.imageOfMessage(message, withSize: CGSize(width: messageImagePreferredWidth, height: ceil(messageImagePreferredWidth / messageImagePreferredAspectRatio)), tailDirection: .Left, completion: { [weak self] progress, image in diff --git a/Yep/Views/Cells/ChatRightAudio/ChatRightAudioCell.swift b/Yep/Views/Cells/ChatRightAudio/ChatRightAudioCell.swift index 12452796..6711c8ef 100644 --- a/Yep/Views/Cells/ChatRightAudio/ChatRightAudioCell.swift +++ b/Yep/Views/Cells/ChatRightAudio/ChatRightAudioCell.swift @@ -95,14 +95,18 @@ class ChatRightAudioCell: ChatRightBaseCell { } } } + dispatch_async(dispatch_get_main_queue()) { [weak self] in + self?.layoutIfNeeded() + } - layoutIfNeeded() } override func layoutSubviews() { super.layoutSubviews() - updateAudioInfoViews() + dispatch_async(dispatch_get_main_queue()) { [weak self] in + self?.updateAudioInfoViews() + } } func updateAudioInfoViews() { diff --git a/Yep/Views/Cells/ChatRightBase/ChatRightBaseCell.swift b/Yep/Views/Cells/ChatRightBase/ChatRightBaseCell.swift index 7903696a..296de75e 100644 --- a/Yep/Views/Cells/ChatRightBase/ChatRightBaseCell.swift +++ b/Yep/Views/Cells/ChatRightBase/ChatRightBaseCell.swift @@ -87,11 +87,16 @@ class ChatRightBaseCell: ChatBaseCell { animation.toValue = 2 * M_PI animation.duration = 1.0 animation.repeatCount = MAXFLOAT + dispatch_async(dispatch_get_main_queue()) { [weak self] in + self?.dotImageView.layer.addAnimation(animation, forKey: sendingAnimationName) + } - dotImageView.layer.addAnimation(animation, forKey: sendingAnimationName) } func removeSendingAnimation() { - dotImageView.layer.removeAnimationForKey(sendingAnimationName) + dispatch_async(dispatch_get_main_queue()) { [weak self] in + self?.dotImageView.layer.removeAnimationForKey(sendingAnimationName) + } + } } diff --git a/Yep/Views/Cells/ChatRightImage/ChatRightImageCell.swift b/Yep/Views/Cells/ChatRightImage/ChatRightImageCell.swift index d77bc442..b65cb97b 100644 --- a/Yep/Views/Cells/ChatRightImage/ChatRightImageCell.swift +++ b/Yep/Views/Cells/ChatRightImage/ChatRightImageCell.swift @@ -54,12 +54,12 @@ class ChatRightImageCell: ChatRightBaseCell { if let image = image { - dispatch_async(dispatch_get_main_queue()) { + dispatch_async(dispatch_get_main_queue()) { [weak self] in - self.messageImageView.image = image + self?.messageImageView.image = image UIView.animateWithDuration(YepConfig.ChatCell.imageAppearDuration, delay: 0.0, options: .CurveEaseInOut, animations: { () -> Void in - self.messageImageView.alpha = 1.0 + self?.messageImageView.alpha = 1.0 }, completion: { (finished) -> Void in }) } @@ -85,8 +85,10 @@ class ChatRightImageCell: ChatRightBaseCell { } loadingProgress = 0 - - messageImageView.alpha = 0.0 + + dispatch_async(dispatch_get_main_queue()) { [weak self] in + self?.messageImageView.alpha = 0.0 + } if let (imageWidth, imageHeight) = imageMetaOfMessage(message) { @@ -97,9 +99,14 @@ class ChatRightImageCell: ChatRightBaseCell { if aspectRatio >= 1 { let width = messageImagePreferredWidth - messageImageView.frame = CGRect(x: CGRectGetMinX(avatarImageView.frame) - YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble - width, y: 0, width: width, height: bounds.height) - dotImageView.center = CGPoint(x: CGRectGetMinX(messageImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(messageImageView.frame)) - + + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.messageImageView.frame = CGRect(x: CGRectGetMinX(strongSelf.avatarImageView.frame) - YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble - width, y: 0, width: width, height: strongSelf.bounds.height) + strongSelf.dotImageView.center = CGPoint(x: CGRectGetMinX(strongSelf.messageImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(strongSelf.messageImageView.frame)) + } + } + ImageCache.sharedInstance.imageOfMessage(message, withSize: CGSize(width: messageImagePreferredWidth, height: ceil(messageImagePreferredWidth / aspectRatio)), tailDirection: .Right, completion: { [weak self] progress, image in dispatch_async(dispatch_get_main_queue()) { @@ -111,8 +118,13 @@ class ChatRightImageCell: ChatRightBaseCell { } else { let width = messageImagePreferredHeight * aspectRatio - messageImageView.frame = CGRect(x: CGRectGetMinX(avatarImageView.frame) - YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble - width, y: 0, width: width, height: bounds.height) - dotImageView.center = CGPoint(x: CGRectGetMinX(messageImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(messageImageView.frame)) + + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.messageImageView.frame = CGRect(x: CGRectGetMinX(strongSelf.avatarImageView.frame) - YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble - width, y: 0, width: width, height: strongSelf.bounds.height) + strongSelf.dotImageView.center = CGPoint(x: CGRectGetMinX(strongSelf.messageImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(strongSelf.messageImageView.frame)) + } + } ImageCache.sharedInstance.imageOfMessage(message, withSize: CGSize(width: messageImagePreferredHeight * aspectRatio, height: messageImagePreferredHeight), tailDirection: .Right, completion: { [weak self] progress, image in @@ -126,8 +138,14 @@ class ChatRightImageCell: ChatRightBaseCell { } else { let width = messageImagePreferredWidth - messageImageView.frame = CGRect(x: CGRectGetMinX(avatarImageView.frame) - YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble - width, y: 0, width: width, height: bounds.height) - dotImageView.center = CGPoint(x: CGRectGetMinX(messageImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(messageImageView.frame)) + + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.messageImageView.frame = CGRect(x: CGRectGetMinX(strongSelf.avatarImageView.frame) - YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble - width, y: 0, width: width, height: strongSelf.bounds.height) + strongSelf.dotImageView.center = CGPoint(x: CGRectGetMinX(strongSelf.messageImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(strongSelf.messageImageView.frame)) + } + } + ImageCache.sharedInstance.imageOfMessage(message, withSize: CGSize(width: messageImagePreferredWidth, height: ceil(messageImagePreferredWidth / messageImagePreferredAspectRatio)), tailDirection: .Right, completion: { [weak self] progress, image in diff --git a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift index a9e92af0..47c62549 100644 --- a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift +++ b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift @@ -26,19 +26,35 @@ class ChatRightTextCell: ChatRightBaseCell { let fullWidth = UIScreen.mainScreen().bounds.width let halfAvatarSize = YepConfig.chatCellAvatarSize() / 2 + + dispatch_async(dispatch_get_main_queue()) { [weak self] in + self?.avatarImageView.center = CGPoint(x: fullWidth - halfAvatarSize - YepConfig.chatCellGapBetweenWallAndAvatar(), y: halfAvatarSize) + } - avatarImageView.center = CGPoint(x: fullWidth - halfAvatarSize - YepConfig.chatCellGapBetweenWallAndAvatar(), y: halfAvatarSize) + } + + override func respondsToSelector(aSelector: Selector) -> Bool { + if ["deleteMessage:" ,"copy:"].contains(aSelector) { + return true + } else { + return super.respondsToSelector(aSelector) + } + } + + func deleteMessage(object: UIMenuController?) { + if let longPressAction = longPressAction { + longPressAction() + } } override func awakeFromNib() { super.awakeFromNib() - dispatch_async(dispatch_get_main_queue()) { [weak self] in - self?.makeUI() - } + makeUI() textContentTextView.textContainer.lineFragmentPadding = 0 textContentTextView.font = UIFont.chatTextFont() + textContentTextView.backgroundColor = UIColor.clearColor() textContentTextView.textColor = UIColor.whiteColor() @@ -48,11 +64,6 @@ class ChatRightTextCell: ChatRightBaseCell { NSUnderlineStyleAttributeName: NSNumber(integer: NSUnderlineStyle.StyleSingle.rawValue), ] - let longPress = UILongPressGestureRecognizer(target: self, action: "handleLongPress:") - longPress.minimumPressDuration = 0.3 - longPress.delegate = self // 由 ChatBaseCell 负责 - textContainerView.addGestureRecognizer(longPress) - textContainerView.copyTextAction = { [weak self] in UIPasteboard.generalPasteboard().string = self?.textContentTextView.text } @@ -69,22 +80,6 @@ class ChatRightTextCell: ChatRightBaseCell { bubbleBodyImageView.addGestureRecognizer(tap) } - func handleLongPress(longPress: UILongPressGestureRecognizer) { - if longPress.state == .Began { - - if let view = longPress.view, superview = view.superview { - - view.becomeFirstResponder() - - let menu = UIMenuController.sharedMenuController() - let copyItem = UIMenuItem(title: NSLocalizedString("Copy", comment: ""), action:"copyText") - let deleteItem = UIMenuItem(title: NSLocalizedString("Delete", comment: ""), action:"deleteTextMessage") - menu.menuItems = [copyItem, deleteItem] - menu.setTargetRect(view.frame, inView: superview) - menu.setMenuVisible(true, animated: true) - } - } - } func tapMediaView() { mediaTapAction?() @@ -96,30 +91,35 @@ class ChatRightTextCell: ChatRightBaseCell { self.user = message.fromFriend self.mediaTapAction = mediaTapAction + + dispatch_async(dispatch_get_main_queue()) { [weak self] in - textContentTextView.text = message.textContent - //textContentTextView.attributedText = NSAttributedString(string: message.textContent, attributes: textAttributes) - - //textContentTextView.textAlignment = textContentLabelWidth < YepConfig.minMessageTextLabelWidth ? .Center : .Left - - // 用 sizeThatFits 来对比,不需要 magicWidth 的时候就可以避免了 - var textContentLabelWidth = textContentLabelWidth - let size = textContentTextView.sizeThatFits(CGSize(width: textContentLabelWidth, height: CGFloat.max)) - - // lineHeight 19.088, size.height 35.5 (1 line) 54.5 (2 lines) - textContentTextView.textAlignment = ((size.height - textContentTextView.font!.lineHeight) < 20) ? .Center : .Left - - if size.width != textContentLabelWidth { - textContentLabelWidth += YepConfig.ChatCell.magicWidth + if let strongSelf = self { + strongSelf.textContentTextView.text = message.textContent + //textContentTextView.attributedText = NSAttributedString(string: message.textContent, attributes: textAttributes) + + //textContentTextView.textAlignment = textContentLabelWidth < YepConfig.minMessageTextLabelWidth ? .Center : .Left + + // 用 sizeThatFits 来对比,不需要 magicWidth 的时候就可以避免了 + var textContentLabelWidth = textContentLabelWidth + let size = strongSelf.textContentTextView.sizeThatFits(CGSize(width: textContentLabelWidth, height: CGFloat.max)) + + // lineHeight 19.088, size.height 35.5 (1 line) 54.5 (2 lines) + strongSelf.textContentTextView.textAlignment = ((size.height - strongSelf.textContentTextView.font!.lineHeight) < 20) ? .Center : .Left + + if size.width != textContentLabelWidth { + textContentLabelWidth += YepConfig.ChatCell.magicWidth + } + + textContentLabelWidth = max(textContentLabelWidth, YepConfig.ChatCell.minTextWidth) + + strongSelf.textContainerView.frame = CGRect(x: CGRectGetMinX(strongSelf.avatarImageView.frame) - YepConfig.chatCellGapBetweenTextContentLabelAndAvatar() - textContentLabelWidth, y: 3, width: textContentLabelWidth, height: strongSelf.bounds.height - 3 * 2) + strongSelf.bubbleBodyImageView.frame = CGRectInset(strongSelf.textContainerView.frame, -12, -3) + strongSelf.bubbleTailImageView.center = CGPoint(x: CGRectGetMaxX(strongSelf.bubbleBodyImageView.frame), y: CGRectGetMidY(strongSelf.avatarImageView.frame)) + strongSelf.dotImageView.center = CGPoint(x: CGRectGetMinX(strongSelf.bubbleBodyImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(strongSelf.bubbleBodyImageView.frame)) + } } - textContentLabelWidth = max(textContentLabelWidth, YepConfig.ChatCell.minTextWidth) - - textContainerView.frame = CGRect(x: CGRectGetMinX(avatarImageView.frame) - YepConfig.chatCellGapBetweenTextContentLabelAndAvatar() - textContentLabelWidth, y: 3, width: textContentLabelWidth, height: bounds.height - 3 * 2) - bubbleBodyImageView.frame = CGRectInset(textContainerView.frame, -12, -3) - bubbleTailImageView.center = CGPoint(x: CGRectGetMaxX(bubbleBodyImageView.frame), y: CGRectGetMidY(avatarImageView.frame)) - dotImageView.center = CGPoint(x: CGRectGetMinX(bubbleBodyImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(bubbleBodyImageView.frame)) - if let sender = message.fromFriend { AvatarCache.sharedInstance.roundAvatarOfUser(sender, withRadius: YepConfig.chatCellAvatarSize() * 0.5) { [weak self] roundImage in dispatch_async(dispatch_get_main_queue()) { diff --git a/Yep/Views/Cells/ChatRightVideo/ChatRightVideoCell.swift b/Yep/Views/Cells/ChatRightVideo/ChatRightVideoCell.swift index 6bc2645c..e06b55da 100644 --- a/Yep/Views/Cells/ChatRightVideo/ChatRightVideoCell.swift +++ b/Yep/Views/Cells/ChatRightVideo/ChatRightVideoCell.swift @@ -86,7 +86,9 @@ class ChatRightVideoCell: ChatRightBaseCell { } } - thumbnailImageView.alpha = 0.0 + dispatch_async(dispatch_get_main_queue()) { [weak self] in + self?.thumbnailImageView.alpha = 0.0 + } if let (videoWidth, videoHeight) = videoMetaOfMessage(message) { @@ -98,9 +100,13 @@ class ChatRightVideoCell: ChatRightBaseCell { if aspectRatio >= 1 { let width = messageImagePreferredWidth - thumbnailImageView.frame = CGRect(x: CGRectGetMinX(avatarImageView.frame) - YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble - width, y: 0, width: width, height: bounds.height) - playImageView.center = CGPoint(x: CGRectGetMidX(thumbnailImageView.frame) - YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(thumbnailImageView.frame)) - dotImageView.center = CGPoint(x: CGRectGetMinX(thumbnailImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(thumbnailImageView.frame)) + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.thumbnailImageView.frame = CGRect(x: CGRectGetMinX(strongSelf.avatarImageView.frame) - YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble - width, y: 0, width: width, height: strongSelf.bounds.height) + strongSelf.playImageView.center = CGPoint(x: CGRectGetMidX(strongSelf.thumbnailImageView.frame) - YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(strongSelf.thumbnailImageView.frame)) + strongSelf.dotImageView.center = CGPoint(x: CGRectGetMinX(strongSelf.thumbnailImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(strongSelf.thumbnailImageView.frame)) + } + } ImageCache.sharedInstance.imageOfMessage(message, withSize: CGSize(width: messageImagePreferredWidth, height: ceil(messageImagePreferredWidth / aspectRatio)), tailDirection: .Right, completion: { [weak self] progress, image in @@ -113,9 +119,14 @@ class ChatRightVideoCell: ChatRightBaseCell { } else { let width = messageImagePreferredHeight * aspectRatio - thumbnailImageView.frame = CGRect(x: CGRectGetMinX(avatarImageView.frame) - YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble - width, y: 0, width: width, height: bounds.height) - playImageView.center = CGPoint(x: CGRectGetMidX(thumbnailImageView.frame) - YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(thumbnailImageView.frame)) - dotImageView.center = CGPoint(x: CGRectGetMinX(thumbnailImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(thumbnailImageView.frame)) + + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.thumbnailImageView.frame = CGRect(x: CGRectGetMinX(strongSelf.avatarImageView.frame) - YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble - width, y: 0, width: width, height: strongSelf.bounds.height) + strongSelf.playImageView.center = CGPoint(x: CGRectGetMidX(strongSelf.thumbnailImageView.frame) - YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(strongSelf.thumbnailImageView.frame)) + strongSelf.dotImageView.center = CGPoint(x: CGRectGetMinX(strongSelf.thumbnailImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(strongSelf.thumbnailImageView.frame)) + } + } ImageCache.sharedInstance.imageOfMessage(message, withSize: CGSize(width: messageImagePreferredHeight * aspectRatio, height: messageImagePreferredHeight), tailDirection: .Right, completion: { [weak self] progress, image in @@ -129,9 +140,15 @@ class ChatRightVideoCell: ChatRightBaseCell { } else { let width = messageImagePreferredWidth - thumbnailImageView.frame = CGRect(x: CGRectGetMinX(avatarImageView.frame) - YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble - width, y: 0, width: width, height: bounds.height) - playImageView.center = CGPoint(x: CGRectGetMidX(thumbnailImageView.frame) - YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(thumbnailImageView.frame)) - dotImageView.center = CGPoint(x: CGRectGetMinX(thumbnailImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(thumbnailImageView.frame)) + + dispatch_async(dispatch_get_main_queue()) { [weak self] in + if let strongSelf = self { + strongSelf.thumbnailImageView.frame = CGRect(x: CGRectGetMinX(strongSelf.avatarImageView.frame) - YepConfig.ChatCell.gapBetweenAvatarImageViewAndBubble - width, y: 0, width: width, height: strongSelf.bounds.height) + strongSelf.playImageView.center = CGPoint(x: CGRectGetMidX(strongSelf.thumbnailImageView.frame) - YepConfig.ChatCell.playImageViewXOffset, y: CGRectGetMidY(strongSelf.thumbnailImageView.frame)) + strongSelf.dotImageView.center = CGPoint(x: CGRectGetMinX(strongSelf.thumbnailImageView.frame) - YepConfig.ChatCell.gapBetweenDotImageViewAndBubble, y: CGRectGetMidY(strongSelf.thumbnailImageView.frame)) + } + } + ImageCache.sharedInstance.imageOfMessage(message, withSize: CGSize(width: messageImagePreferredWidth, height: ceil(messageImagePreferredWidth / messageImagePreferredAspectRatio)), tailDirection: .Right, completion: { [weak self] progress, image in diff --git a/Yep/Views/Cells/ChatSectionDate/ChatSectionDateCell.xib b/Yep/Views/Cells/ChatSectionDate/ChatSectionDateCell.xib index be996533..71a2b73e 100644 --- a/Yep/Views/Cells/ChatSectionDate/ChatSectionDateCell.xib +++ b/Yep/Views/Cells/ChatSectionDate/ChatSectionDateCell.xib @@ -1,7 +1,8 @@ - + - + + @@ -12,15 +13,18 @@ - + + diff --git a/Yep/Views/Cells/DiscoverCardUser/DiscoverCardUserCell.swift b/Yep/Views/Cells/DiscoverCardUser/DiscoverCardUserCell.swift index 334073ae..bdc12463 100644 --- a/Yep/Views/Cells/DiscoverCardUser/DiscoverCardUserCell.swift +++ b/Yep/Views/Cells/DiscoverCardUser/DiscoverCardUserCell.swift @@ -8,6 +8,8 @@ import UIKit +let skillTextAttributes = [NSFontAttributeName: UIFont.skillDiscoverTextFont()] + class DiscoverCardUserCell: UICollectionViewCell { @IBOutlet weak var serviceImageView: UIImageView! @@ -24,8 +26,6 @@ class DiscoverCardUserCell: UICollectionViewCell { var discoveredUser: DiscoveredUser? - let skillTextAttributes = [NSFontAttributeName: UIFont.skillDiscoverTextFont()] - let discoverCellHeight: CGFloat = 16 override func awakeFromNib() { @@ -33,8 +33,8 @@ class DiscoverCardUserCell: UICollectionViewCell { // Initialization code userSkillsCollectionView.backgroundColor = UIColor.clearColor() contentView.backgroundColor = UIColor.whiteColor() - contentView.layer.cornerRadius = 6 - contentView.layer.masksToBounds = true +// contentView.layer.cornerRadius = 6 +// contentView.layer.masksToBounds = true contentView.layer.borderColor = UIColor.yepCellSeparatorColor().CGColor contentView.layer.borderWidth = 1.0 @@ -56,7 +56,7 @@ class DiscoverCardUserCell: UICollectionViewCell { let avatarURLString = discoveredUser.avatarURLString - AvatarCache.sharedInstance.avatarFromURL(NSURL(string: avatarURLString)!) {[weak self] (isFinish, image) -> () in + AvatarCache.sharedInstance.avatarFromURL(NSURL(string: avatarURLString)!, size: 170) {[weak self] (isFinish, image) -> () in dispatch_async(dispatch_get_main_queue()) { if let _ = collectionView.cellForItemAtIndexPath(indexPath) { self?.avatarImageView.image = image @@ -81,13 +81,16 @@ class DiscoverCardUserCell: UICollectionViewCell { usernameLabel.text = discoveredUser.nickname userSkillsCollectionView.reloadData() - } } extension DiscoverCardUserCell: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int { + return 1 + } + func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { if let discoveredUser = discoveredUser { if discoveredUser.masterSkills.count > 4 { @@ -106,7 +109,19 @@ extension DiscoverCardUserCell: UICollectionViewDelegate, UICollectionViewDataS let skillLocalName = discoveredUser.masterSkills[indexPath.row].localName ?? "" - let rect = skillLocalName.boundingRectWithSize(CGSize(width: CGFloat(FLT_MAX), height: SkillCell.height), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: skillTextAttributes, context: nil) + let skillID = discoveredUser.masterSkills[indexPath.row].id + +// print(skillID) + + var rect = CGRectZero + + if let cacheRect = skillSizeCache[skillID] { + rect = cacheRect + } else { + rect = skillLocalName.boundingRectWithSize(CGSize(width: CGFloat(FLT_MAX), height: SkillCell.height), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: skillTextAttributes, context: nil) + + skillSizeCache[skillID] = rect + } return CGSize(width: rect.width + 12, height: discoverCellHeight) } else { diff --git a/Yep/Views/Cells/ProfileHeader/ProfileHeaderCell.swift b/Yep/Views/Cells/ProfileHeader/ProfileHeaderCell.swift index 2c5c1e63..c650ee5e 100644 --- a/Yep/Views/Cells/ProfileHeader/ProfileHeaderCell.swift +++ b/Yep/Views/Cells/ProfileHeader/ProfileHeaderCell.swift @@ -16,6 +16,8 @@ class ProfileHeaderCell: UICollectionViewCell { @IBOutlet weak var avatarImageView: UIImageView! @IBOutlet weak var avatarBlurImageView: UIImageView! @IBOutlet weak var locationLabel: UILabel! + + var askedForPermission = false struct Listener { static let Avatar = "ProfileHeaderCell.Avatar" @@ -89,9 +91,14 @@ class ProfileHeaderCell: UICollectionViewCell { } } - proposeToAccess(.Location(.WhenInUse), agreed: { - - YepLocationService.turnOn() + proposeToAccess(.Location(.WhenInUse), agreed: { [weak self] in + + if let askedForPermission = self?.askedForPermission { + if !askedForPermission { + self?.askedForPermission = true + YepLocationService.turnOn() + } + } }, rejected: { println("Yep can NOT get Location. :[\n") @@ -124,7 +131,7 @@ class ProfileHeaderCell: UICollectionViewCell { avatarBlurImageView.alpha = 0 } - AvatarCache.sharedInstance.avatarFromURL(NSURL(string: avatarURLString)!) { [weak self] isFinish, image in + AvatarCache.sharedInstance.avatarFromURL(NSURL(string: avatarURLString)!, size: 375) {[weak self] (isFinish, image) -> () in if isFinish { self?.blurImage(image) { blurredImage in diff --git a/Yep/Views/Cells/ProfileSocialAccount/ProfileSocialAccountImagesCell.swift b/Yep/Views/Cells/ProfileSocialAccount/ProfileSocialAccountImagesCell.swift index 2b977390..e3831aa4 100644 --- a/Yep/Views/Cells/ProfileSocialAccount/ProfileSocialAccountImagesCell.swift +++ b/Yep/Views/Cells/ProfileSocialAccount/ProfileSocialAccountImagesCell.swift @@ -23,32 +23,44 @@ class ProfileSocialAccountImagesCell: UICollectionViewCell { let shots = dribbbleWork.shots - if let shot = shots[safe: 0] { + if let shot = shots[safe: 2] { imageView1.kf_setImageWithURL(NSURL(string: shot.images.teaser)!, placeholderImage: nil) + } else { + imageView1.image = nil } if let shot = shots[safe: 1] { imageView2.kf_setImageWithURL(NSURL(string: shot.images.teaser)!, placeholderImage: nil) + } else { + imageView2.image = nil } - if let shot = shots[safe: 2] { + if let shot = shots[safe: 0] { imageView3.kf_setImageWithURL(NSURL(string: shot.images.teaser)!, placeholderImage: nil) + } else { + imageView3.image = nil } case .Instagram(let instagramWork): let medias = instagramWork.medias - if let media = medias[safe: 0] { + if let media = medias[safe: 2] { imageView1.kf_setImageWithURL(NSURL(string: media.images.thumbnail)!, placeholderImage: nil) + } else { + imageView1.image = nil } if let media = medias[safe: 1] { imageView2.kf_setImageWithURL(NSURL(string: media.images.thumbnail)!, placeholderImage: nil) + } else { + imageView2.image = nil } - if let media = medias[safe: 2] { + if let media = medias[safe: 0] { imageView3.kf_setImageWithURL(NSURL(string: media.images.thumbnail)!, placeholderImage: nil) + } else { + imageView3.image = nil } } } diff --git a/Yep/Views/ChatTextContainer/ChatTextContainerView.swift b/Yep/Views/ChatTextContainer/ChatTextContainerView.swift index 8c6a079a..e5da77f7 100644 --- a/Yep/Views/ChatTextContainer/ChatTextContainerView.swift +++ b/Yep/Views/ChatTextContainer/ChatTextContainerView.swift @@ -11,7 +11,7 @@ import UIKit class ChatTextContainerView: UIView { override func canBecomeFirstResponder() -> Bool { - return true + return false } override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {