diff --git a/Yep.xcodeproj/project.pbxproj b/Yep.xcodeproj/project.pbxproj index 15454e5a..ae49e2e8 100644 --- a/Yep.xcodeproj/project.pbxproj +++ b/Yep.xcodeproj/project.pbxproj @@ -96,7 +96,7 @@ 503A54ED1B328ADB002077BD /* NSLocale+Yep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503A54EC1B328ADB002077BD /* NSLocale+Yep.swift */; }; 503CAB431AC00CB100DFE830 /* ConversationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503CAB421AC00CB100DFE830 /* ConversationViewController.swift */; }; 503ED23A1B8ADCE70072187D /* BlackListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503ED2391B8ADCE70072187D /* BlackListViewController.swift */; }; - 5044BF061B5FA74800930ADC /* BubbleMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5044BF051B5FA74800930ADC /* BubbleMenuView.swift */; }; + 503ED23D1B8C12100072187D /* ChatTextContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503ED23C1B8C12100072187D /* ChatTextContainerView.swift */; }; 504BDC151B4528A500DBD35D /* Badges.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504BDC141B4528A500DBD35D /* Badges.xcassets */; }; 504CBA3D1B3D04B800663A90 /* ChatTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504CBA3C1B3D04B800663A90 /* ChatTextView.swift */; }; 504F41251ACE2D1D00FBB19A /* SampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504F41241ACE2D1D00FBB19A /* SampleView.swift */; }; @@ -345,7 +345,7 @@ 503A54EC1B328ADB002077BD /* NSLocale+Yep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSLocale+Yep.swift"; path = "Extensions/NSLocale+Yep.swift"; sourceTree = ""; }; 503CAB421AC00CB100DFE830 /* ConversationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationViewController.swift; path = ViewControllers/Conversation/ConversationViewController.swift; sourceTree = ""; }; 503ED2391B8ADCE70072187D /* BlackListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BlackListViewController.swift; path = ViewControllers/BlackList/BlackListViewController.swift; sourceTree = ""; }; - 5044BF051B5FA74800930ADC /* BubbleMenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BubbleMenuView.swift; path = Views/BubbleMenu/BubbleMenuView.swift; sourceTree = ""; }; + 503ED23C1B8C12100072187D /* ChatTextContainerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChatTextContainerView.swift; path = Views/ChatTextContainer/ChatTextContainerView.swift; sourceTree = ""; }; 504BDC141B4528A500DBD35D /* Badges.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Badges.xcassets; sourceTree = ""; }; 504CBA3C1B3D04B800663A90 /* ChatTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChatTextView.swift; path = Views/TextViews/ChatTextView.swift; sourceTree = ""; }; 504F41241ACE2D1D00FBB19A /* SampleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SampleView.swift; path = Views/AudioWaves/SampleView.swift; sourceTree = ""; }; @@ -826,6 +826,7 @@ 504CBA3B1B3D048900663A90 /* TextViews */, 50F2B9791B2EEAE300F840CC /* Labels */, 50A9D4581ACD3943000B2599 /* AudioWaves */, + 503ED23E1B8C13280072187D /* ChatTextContainer */, 5023DE3A1AB697A700B3EE96 /* Cells */, 502AE5221AB71C82005BD199 /* Buttons */, 502AE52F1AB8387D005BD199 /* TextFields */, @@ -843,7 +844,6 @@ 5019F62F1B39BFCB0000D993 /* ConversationMore */, 500A0B201B451A7400D49358 /* Badge */, 504F85AD1B4D21E400F909BE /* DiscoverFilter */, - 5044BF071B5FA75000930ADC /* BubbleMenu */, 8409137E1B7DB178001C89D6 /* FriendRequest */, ); name = Views; @@ -1104,12 +1104,12 @@ name = BlackList; sourceTree = ""; }; - 5044BF071B5FA75000930ADC /* BubbleMenu */ = { + 503ED23E1B8C13280072187D /* ChatTextContainer */ = { isa = PBXGroup; children = ( - 5044BF051B5FA74800930ADC /* BubbleMenuView.swift */, + 503ED23C1B8C12100072187D /* ChatTextContainerView.swift */, ); - name = BubbleMenu; + name = ChatTextContainer; sourceTree = ""; }; 504CBA3B1B3D048900663A90 /* TextViews */ = { @@ -1925,6 +1925,7 @@ 508C2AA41AD661B3002B8097 /* UserStateCell.swift in Sources */, 0A5D83941AC5D3C8000045BF /* YepTabBarController.swift in Sources */, 50E114FC1ABC549300F13000 /* ContactsCell.swift in Sources */, + 503ED23D1B8C12100072187D /* ChatTextContainerView.swift in Sources */, 50F2B9781B2EDF3D00F840CC /* BorderTextField.swift in Sources */, 50CDBE461ACA9F2200459CE0 /* ImageCache.swift in Sources */, 505EC81C1ADFBE1B001D27E0 /* SkillSelectionCell.swift in Sources */, @@ -1984,7 +1985,6 @@ 50CDBE491ACBAD3200459CE0 /* ChatLeftImageCell.swift in Sources */, 5033159C1AC101C80008A209 /* ChatRightTextCell.swift in Sources */, 50E1D7291B870D7500D90A82 /* NSParagraphStyle+Yep.swift in Sources */, - 5044BF061B5FA74800930ADC /* BubbleMenuView.swift in Sources */, 5023DE561AB6CA1000B3EE96 /* AvatarCache.swift in Sources */, 5023DE371AB6979600B3EE96 /* ConversationCell.swift in Sources */, 502AE5351AB8649F005BD199 /* LoginByMobileViewController.swift in Sources */, diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index a2cbe6f9..9022716c 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -84,18 +84,8 @@ class ConversationViewController: BaseViewController { @IBOutlet weak var swipeUpView: UIView! @IBOutlet weak var swipeUpPromptLabel: UILabel! - lazy var menuDirectionUpThreshold: CGFloat = { - return self.topBarsHeight + 60 - }() - var currentMenu: BubbleMenuView? - var isTryingShowFriendRequestView = false - func removeOldMenu() { - currentMenu?.hide() - currentMenu = nil - } - var originalNavigationControllerDelegate: UINavigationControllerDelegate? var waverView: YepWaverView! @@ -557,8 +547,6 @@ class ConversationViewController: BaseViewController { messageToolbar.stateTransitionAction = { [weak self] (messageToolbar, previousState, currentState) in - self?.removeOldMenu() - if let strongSelf = self { switch (previousState, currentState) { @@ -751,12 +739,6 @@ class ConversationViewController: BaseViewController { } } - override func viewWillDisappear(animated: Bool) { - super.viewWillDisappear(animated) - - removeOldMenu() - } - override func viewDidDisappear(animated: Bool) { super.viewDidDisappear(animated) @@ -1202,8 +1184,6 @@ class ConversationViewController: BaseViewController { func moreAction() { - removeOldMenu() - messageToolbar.state = .Default moreView.showProfileAction = { [weak self] in @@ -1973,33 +1953,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.configureWithMessage(message, textContentLabelWidth: textContentLabelWidthOfMessage(message), collectionView: collectionView, indexPath: indexPath) - cell.longPressAction = { [weak self] cell in - - self?.removeOldMenu() - - if let strongSelf = self { - - let copyItem = BubbleMenuView.Item(type: .Normal, title: NSLocalizedString("Copy", comment: "")) { menu in - print("copy\n") - - UIPasteboard.generalPasteboard().string = cell.textContentTextView.text - - menu.hide() - self?.currentMenu = nil - } - - let bubbleFrame = cell.convertRect(cell.bubbleBodyImageView.frame, toView: strongSelf.view) - - let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(bubbleFrame) < strongSelf.menuDirectionUpThreshold ? .Up : .Down - - let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem]) - - strongSelf.currentMenu = menu - - menu.showInView(strongSelf.view, withBubbleFrame: bubbleFrame) - } - } - cell.tapAvatarAction = { [weak self] user in self?.performSegueWithIdentifier("showProfile", sender: user) } @@ -2182,109 +2135,77 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } }, collectionView: collectionView, indexPath: indexPath) - cell.longPressAction = { [weak self] cell in + cell.longPressAction = { [weak self] in + dispatch_async(dispatch_get_main_queue()) { + if let strongSelf = self, realm = message.realm { - self?.removeOldMenu() + var sectionDateMessage: Message? - if let strongSelf = self { + if let currentMessageIndex = strongSelf.messages.indexOf(message) { - let copyItem = BubbleMenuView.Item(type: .Normal, title: NSLocalizedString("Copy", comment: "")) { menu in - print("copy\n") + let previousMessageIndex = currentMessageIndex - 1 - UIPasteboard.generalPasteboard().string = cell.textContentTextView.text + if let previousMessage = strongSelf.messages[safe: previousMessageIndex] { - menu.hide() - self?.currentMenu = nil - } - - let deleteItem = BubbleMenuView.Item(type: .Danger, title: NSLocalizedString("Delete", comment: "")) { menu in - print("delete\n") - - 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 - } - } + 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 } } - menu.hide() - self?.currentMenu = nil + 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 } - - let bubbleFrame = cell.convertRect(cell.bubbleBodyImageView.frame, toView: strongSelf.view) - - let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(bubbleFrame) < strongSelf.menuDirectionUpThreshold ? .Up : .Down - - let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem, deleteItem]) - - strongSelf.currentMenu = menu - - menu.showInView(strongSelf.view, withBubbleFrame: bubbleFrame) } } @@ -2340,8 +2261,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi func scrollViewDidScroll(scrollView: UIScrollView) { pullToRefreshView.scrollViewDidScroll(scrollView) - - removeOldMenu() } func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift deleted file mode 100644 index e4b1b322..00000000 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ /dev/null @@ -1,269 +0,0 @@ -// -// BubbleMenuView.swift -// Yep -// -// Created by NIX on 15/7/22. -// Copyright (c) 2015年 Catch Inc. All rights reserved. -// - -import UIKit - -class BubbleMenuView: UIView { - - enum ArrowDirection { - case Up - case Down - } - - struct Item { - - enum Type { - case Normal - case Danger - } - let type: Type - - let title: String - - let action: BubbleMenuView -> Void - } - - var arrowDirection: ArrowDirection - var items: [Item] - - var buttons = [UIButton]() - - init(arrowDirection: ArrowDirection, items: [Item]) { - - self.arrowDirection = arrowDirection - self.items = items - - super.init(frame: CGRectZero) - - makeUI() - } - - required init(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: Actions - - func tapButton(button: UIButton) { - if let index = find(buttons, button) { - let action = items[index].action - action(self) - } - } - - func showInView(view: UIView, withBubbleFrame bubbleFrame: CGRect) { - - // position - - setTranslatesAutoresizingMaskIntoConstraints(false) - view.addSubview(self) - - var vConstant = CGRectGetMidY(bubbleFrame) - CGRectGetMidY(view.frame) - - let menuV: NSLayoutConstraint - - switch arrowDirection { - - case .Up: - vConstant += ceil(CGRectGetHeight(bubbleFrame) * 0.5) - offsetV - - menuV = NSLayoutConstraint(item: self, attribute: .Top, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: vConstant) - - case .Down: - vConstant -= ceil(CGRectGetHeight(bubbleFrame) * 0.5) - offsetV - - menuV = NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: vConstant) - } - - let centerXConstant = CGRectGetMidX(bubbleFrame) - CGRectGetMidX(view.frame) - - let menuCenterX = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) - - NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) - - - // animation - - transform = CGAffineTransformMakeScale(0.0001, 0.0001) - - UIView.animateWithDuration(0.25, delay: 0.0, usingSpringWithDamping: 0.65, initialSpringVelocity: 0.0, options: UIViewAnimationOptions(0), animations: { _ in - self.transform = CGAffineTransformMakeScale(1.0, 1.0) - }, completion: { finished in - self.transform = CGAffineTransformIdentity - }) - } - - func hide() { - - UIView.animateWithDuration(0.1, delay: 0.0, options: .CurveEaseInOut, animations: { _ in - self.transform = CGAffineTransformMakeScale(0.0001, 0.0001) - - }, completion: { finished in - self.removeFromSuperview() - }) - } - - // MARK: UI - - let arrowHeight: CGFloat = 8 - let buttonGap: CGFloat = 16 - let offsetV: CGFloat = -1 - - func makeUI() { - - backgroundColor = UIColor.clearColor() - - var format = "H:|" - - for (index, item) in enumerate(items) { - - let button = UIButton() - - switch item.type { - - case .Normal: - - button.setTitleColor(UIColor.whiteColor(), forState: .Normal) - button.setTitleColor(UIColor.lightGrayColor(), forState: .Highlighted) - - case .Danger: - - let dangerRed = UIColor(red: 1, green: 0.4, blue: 0.4, alpha: 1) - - button.setTitleColor(dangerRed, forState: .Normal) - button.setTitleColor(dangerRed.colorWithAlphaComponent(0.3), forState: .Highlighted) - } - - button.setTitle(item.title, forState: .Normal) - button.addTarget(self, action: "tapButton:", forControlEvents: .TouchUpInside) - - button.setTranslatesAutoresizingMaskIntoConstraints(false) - - addSubview(button) - - buttons.append(button) - - if index == 0 { - format += "-[button\(index)]" - } else { - format += "-(\(buttonGap))-[button\(index)(==button0)]" - } - } - - format += "-|" - - var views = [NSObject: AnyObject]() - - for (index, button) in enumerate(buttons) { - let key = "button\(index)" - views[key] = button - } - - let hConstraints = NSLayoutConstraint.constraintsWithVisualFormat(format, options: .AlignAllCenterY, metrics: nil, views: views) - - NSLayoutConstraint.activateConstraints(hConstraints) - - if let firstButton = buttons.first { - - let firstButtonTop = NSLayoutConstraint(item: firstButton, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0) - - switch arrowDirection { - - case .Up: - - let firstButtonTop = NSLayoutConstraint(item: firstButton, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: arrowHeight) - let firstButtonBottom = NSLayoutConstraint(item: firstButton, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: 0) - - NSLayoutConstraint.activateConstraints([firstButtonTop, firstButtonBottom]) - - case .Down: - - let firstButtonTop = NSLayoutConstraint(item: firstButton, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0) - let firstButtonBottom = NSLayoutConstraint(item: firstButton, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: -arrowHeight) - - NSLayoutConstraint.activateConstraints([firstButtonTop, firstButtonBottom]) - } - } - } - - override func drawRect(rect: CGRect) { - - UIColor.blackColor().colorWithAlphaComponent(0.6).setFill() - - // bubble - - var roundedRect = rect - - switch arrowDirection { - - case .Up: - roundedRect.origin.y += arrowHeight - roundedRect.size.height -= arrowHeight - - case .Down: - roundedRect.size.height -= arrowHeight - } - - let bubblePath = UIBezierPath(roundedRect: roundedRect, cornerRadius: 5) - bubblePath.fill() - - - // arrow - - switch arrowDirection { - - case .Up: - let topX = CGRectGetMidX(rect) - let topY = CGRectGetMinY(rect) - - let arrowPath = UIBezierPath() - arrowPath.moveToPoint(CGPointMake(topX, topY)) - arrowPath.addLineToPoint(CGPointMake(topX - (arrowHeight - 1), topY + arrowHeight)) - arrowPath.addLineToPoint(CGPointMake(topX + (arrowHeight - 1), topY + arrowHeight)) - arrowPath.closePath() - arrowPath.fill() - - case .Down: - let buttomX = CGRectGetMidX(rect) - let buttomY = CGRectGetMaxY(rect) - - let arrowPath = UIBezierPath() - arrowPath.moveToPoint(CGPointMake(buttomX, buttomY)) - arrowPath.addLineToPoint(CGPointMake(buttomX - (arrowHeight - 1), buttomY - arrowHeight)) - arrowPath.addLineToPoint(CGPointMake(buttomX + (arrowHeight - 1), buttomY - arrowHeight)) - arrowPath.closePath() - arrowPath.fill() - } - - - // lines - - UIColor.whiteColor().colorWithAlphaComponent(0.3).setStroke() - - for (index, button) in enumerate(buttons) { - if index > 0 { - let line = UIBezierPath() - - let x = CGRectGetMinX(button.frame) - buttonGap * 0.5 - let y = CGRectGetMaxY(rect) - - line.moveToPoint(CGPoint(x: x , y: 0)) - line.addLineToPoint(CGPoint(x: x, y: y)) - - line.lineWidth = 1 - - line.stroke() - } - } - } - -} - - - - diff --git a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift index e6cf210b..53d697a2 100644 --- a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift +++ b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift @@ -15,13 +15,12 @@ class ChatLeftTextCell: ChatBaseCell { @IBOutlet weak var bubbleBodyImageView: UIImageView! @IBOutlet weak var bubbleTailImageView: UIImageView! + @IBOutlet weak var textContainerView: ChatTextContainerView! @IBOutlet weak var textContentTextView: ChatTextView! @IBOutlet weak var textContentTextViewTrailingConstraint: NSLayoutConstraint! @IBOutlet weak var textContentTextViewLeadingConstraint: NSLayoutConstraint! //@IBOutlet weak var textContentTextViewWidthConstraint: NSLayoutConstraint! - var longPressAction: (ChatLeftTextCell -> Void)? - override func awakeFromNib() { super.awakeFromNib() @@ -38,7 +37,12 @@ class ChatLeftTextCell: ChatBaseCell { ] let longPress = UILongPressGestureRecognizer(target: self, action: "handleLongPress:") - textContentTextView.addGestureRecognizer(longPress) + textContainerView.addGestureRecognizer(longPress) + longPress.delegate = self + + textContainerView.copyTextAction = { [weak self] in + UIPasteboard.generalPasteboard().string = self?.textContentTextView.text + } textContentTextViewTrailingConstraint.constant = YepConfig.chatTextGapBetweenWallAndContentLabel() - YepConfig.ChatCell.magicWidth textContentTextViewLeadingConstraint.constant = YepConfig.chatCellGapBetweenTextContentLabelAndAvatar() @@ -49,7 +53,17 @@ class ChatLeftTextCell: ChatBaseCell { func handleLongPress(longPress: UILongPressGestureRecognizer) { if longPress.state == .Began { - longPressAction?(self) + + 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) + } } } @@ -75,3 +89,16 @@ class ChatLeftTextCell: ChatBaseCell { } } +extension ChatLeftTextCell: UIGestureRecognizerDelegate { + + func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { + + return true + } + + func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOfGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { + + return true + } +} + diff --git a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.xib b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.xib index ec38e26a..21da2757 100644 --- a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.xib +++ b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.xib @@ -34,32 +34,44 @@ - + - - - - - - + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - + + + + @@ -68,9 +80,10 @@ + - - + + diff --git a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift index c3dbe1c2..cdb90a17 100644 --- a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift +++ b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift @@ -15,6 +15,7 @@ class ChatRightTextCell: ChatRightBaseCell { @IBOutlet weak var bubbleBodyImageView: UIImageView! @IBOutlet weak var bubbleTailImageView: UIImageView! + @IBOutlet weak var textContainerView: ChatTextContainerView! @IBOutlet weak var textContentTextView: ChatTextView! @IBOutlet weak var textContentTextViewTrailingConstraint: NSLayoutConstraint! @IBOutlet weak var textContentTextViewLeadingConstraint: NSLayoutConstraint! @@ -23,7 +24,7 @@ class ChatRightTextCell: ChatRightBaseCell { typealias MediaTapAction = () -> Void var mediaTapAction: MediaTapAction? - var longPressAction: (ChatRightTextCell -> Void)? + var longPressAction: (() -> Void)? override func awakeFromNib() { super.awakeFromNib() @@ -42,7 +43,16 @@ class ChatRightTextCell: ChatRightBaseCell { ] let longPress = UILongPressGestureRecognizer(target: self, action: "handleLongPress:") - textContentTextView.addGestureRecognizer(longPress) + textContainerView.addGestureRecognizer(longPress) + longPress.delegate = self + + textContainerView.copyTextAction = { [weak self] in + UIPasteboard.generalPasteboard().string = self?.textContentTextView.text + } + + textContainerView.deleteTextMessageAction = { [weak self] in + self?.longPressAction?() + } textContentTextViewTrailingConstraint.constant = YepConfig.chatCellGapBetweenTextContentLabelAndAvatar() textContentTextViewLeadingConstraint.constant = YepConfig.chatTextGapBetweenWallAndContentLabel() - YepConfig.ChatCell.magicWidth @@ -57,7 +67,18 @@ class ChatRightTextCell: ChatRightBaseCell { func handleLongPress(longPress: UILongPressGestureRecognizer) { if longPress.state == .Began { - longPressAction?(self) + + 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) + } } } @@ -89,3 +110,17 @@ class ChatRightTextCell: ChatRightBaseCell { } } } + +extension ChatRightTextCell: UIGestureRecognizerDelegate { + + func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { + + return true + } + + func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOfGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { + + return true + } +} + diff --git a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.xib b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.xib index 3dbef92f..1a199ef8 100644 --- a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.xib +++ b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.xib @@ -34,14 +34,6 @@ - - - - - - - - @@ -50,25 +42,45 @@ + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + - - + + - - - + @@ -80,9 +92,10 @@ + - - + + diff --git a/Yep/Views/ChatTextContainer/ChatTextContainerView.swift b/Yep/Views/ChatTextContainer/ChatTextContainerView.swift new file mode 100644 index 00000000..8c6a079a --- /dev/null +++ b/Yep/Views/ChatTextContainer/ChatTextContainerView.swift @@ -0,0 +1,39 @@ +// +// ChatTextContainerView.swift +// Yep +// +// Created by nixzhu on 15/8/25. +// Copyright (c) 2015年 Catch Inc. All rights reserved. +// + +import UIKit + +class ChatTextContainerView: UIView { + + override func canBecomeFirstResponder() -> Bool { + return true + } + + override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool { + if action == "copyText" { + return true + } else if action == "deleteTextMessage" { + return true + } + + return false + } + + var copyTextAction: (() -> Void)? + var deleteTextMessageAction: (() -> Void)? + + func copyText() { + println("copyText") + copyTextAction?() + } + + func deleteTextMessage() { + println("deleteTextMessage") + deleteTextMessageAction?() + } +}