From 7f387b49d195417083528c087904d9564077bc76 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 12:53:18 +0800 Subject: [PATCH 01/21] add BubbleMenuView --- Yep.xcodeproj/project.pbxproj | 12 ++ Yep/Base.lproj/Main.storyboard | 2 +- .../ConversationViewController.swift | 27 +++- Yep/Views/BubbleMenu/BubbleMenuView.swift | 136 ++++++++++++++++++ 4 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 Yep/Views/BubbleMenu/BubbleMenuView.swift diff --git a/Yep.xcodeproj/project.pbxproj b/Yep.xcodeproj/project.pbxproj index 21ff1372..ac671dc0 100644 --- a/Yep.xcodeproj/project.pbxproj +++ b/Yep.xcodeproj/project.pbxproj @@ -97,6 +97,7 @@ 5039594F1B05E6E000797A3E /* ProfileSocialAccountGithubCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5039594D1B05E6E000797A3E /* ProfileSocialAccountGithubCell.xib */; }; 503A54ED1B328ADB002077BD /* NSLocale+Yep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503A54EC1B328ADB002077BD /* NSLocale+Yep.swift */; }; 503CAB431AC00CB100DFE830 /* ConversationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503CAB421AC00CB100DFE830 /* ConversationViewController.swift */; }; + 5044BF061B5FA74800930ADC /* BubbleMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5044BF051B5FA74800930ADC /* BubbleMenuView.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 */; }; @@ -321,6 +322,7 @@ 5039594D1B05E6E000797A3E /* ProfileSocialAccountGithubCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ProfileSocialAccountGithubCell.xib; path = Views/Cells/ProfileSocialAccount/ProfileSocialAccountGithubCell.xib; sourceTree = ""; }; 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 = ""; }; + 5044BF051B5FA74800930ADC /* BubbleMenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BubbleMenuView.swift; path = Views/BubbleMenu/BubbleMenuView.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 = ""; }; @@ -782,6 +784,7 @@ 5019F62F1B39BFCB0000D993 /* ConversationMore */, 500A0B201B451A7400D49358 /* Badge */, 504F85AD1B4D21E400F909BE /* DiscoverFilter */, + 5044BF071B5FA75000930ADC /* BubbleMenu */, ); name = Views; sourceTree = ""; @@ -1030,6 +1033,14 @@ name = Conversation; sourceTree = ""; }; + 5044BF071B5FA75000930ADC /* BubbleMenu */ = { + isa = PBXGroup; + children = ( + 5044BF051B5FA74800930ADC /* BubbleMenuView.swift */, + ); + name = BubbleMenu; + sourceTree = ""; + }; 504CBA3B1B3D048900663A90 /* TextViews */ = { isa = PBXGroup; children = ( @@ -1802,6 +1813,7 @@ 5023DE2A1AB685BA00B3EE96 /* ContactsViewController.swift in Sources */, 50CDBE491ACBAD3200459CE0 /* ChatLeftImageCell.swift in Sources */, 5033159C1AC101C80008A209 /* ChatRightTextCell.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/Base.lproj/Main.storyboard b/Yep/Base.lproj/Main.storyboard index d9095c0b..24bc0f63 100644 --- a/Yep/Base.lproj/Main.storyboard +++ b/Yep/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index f601d591..418879b2 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -634,8 +634,6 @@ class ConversationViewController: BaseViewController { override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) - - conversationCollectionViewHasBeenMovedToBottomOnce = true FayeService.sharedManager.delegate = self @@ -668,6 +666,31 @@ class ConversationViewController: BaseViewController { self.navigationController?.setNavigationBarHidden(false, animated: true) self.setNeedsStatusBarAppearanceUpdate() + + + // test menu + + if true { + let menu = BubbleMenuView(titles: ["Copy", "Delete"]) + menu.setTranslatesAutoresizingMaskIntoConstraints(false) + view.addSubview(menu) + + let menuCenterY = NSLayoutConstraint(item: menu, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: 0) + let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: 0) + + NSLayoutConstraint.activateConstraints([menuCenterY, menuCenterX]) + } + + if true { + let menu = BubbleMenuView(titles: ["Copy"]) + menu.setTranslatesAutoresizingMaskIntoConstraints(false) + view.addSubview(menu) + + let menuCenterY = NSLayoutConstraint(item: menu, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: -100) + let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: 0) + + NSLayoutConstraint.activateConstraints([menuCenterY, menuCenterX]) + } } private func markMessageAsReaded(message: Message) { diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift new file mode 100644 index 00000000..a9bb30ed --- /dev/null +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -0,0 +1,136 @@ +// +// BubbleMenuView.swift +// Yep +// +// Created by NIX on 15/7/22. +// Copyright (c) 2015年 Catch Inc. All rights reserved. +// + +import UIKit + +class BubbleMenuView: UIView { + + var titles: [String] + + var buttons = [UIButton]() + + init(titles: [String]) { + self.titles = titles + super.init(frame: CGRectZero) + + makeUI() + } + + required init(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + let arrowHeight: CGFloat = 8 + let buttonGap: CGFloat = 12 + + func makeUI() { + + //backgroundColor = UIColor.redColor() + backgroundColor = UIColor.clearColor() + + var format = "H:|" + + for (index, title) in enumerate(titles) { + + let button = UIButton() + //button.backgroundColor = UIColor.blueColor().colorWithAlphaComponent(0.5) + + button.setTitle(title, forState: .Normal) + button.setTranslatesAutoresizingMaskIntoConstraints(false) + + addSubview(button) + + buttons.append(button) + + if index == 0 { + format += "-[button\(index)]" + } else { + format += "-(\(buttonGap))-[button\(index)(==button0)]" + } + } + + format += "-|" + + //let format = "H:|[label0][label1][label2]|" + + 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) + let firstButtonBottom = NSLayoutConstraint(item: firstButton, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: -arrowHeight) + + NSLayoutConstraint.activateConstraints([firstButtonTop, firstButtonBottom]) + } + } + +// override func intrinsicContentSize() -> CGSize { +// return CGSize(width: 80 * titles.count, height: 80) +// } + + + override func drawRect(rect: CGRect) { + + UIColor.blackColor().colorWithAlphaComponent(0.7).setFill() + + // bubble + + var roundedRect = rect + roundedRect.size.height -= arrowHeight + let bubblePath = UIBezierPath(roundedRect: roundedRect, cornerRadius: 5) + bubblePath.fill() + + + // arrow + + 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() + } + } + } + +} + + + + From 6bfab45aabd726f225bd49b1f9c7a5c67214d401 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 13:08:55 +0800 Subject: [PATCH 02/21] set BubbleMenuView Item action --- .../ConversationViewController.swift | 20 ++++++++- Yep/Views/BubbleMenu/BubbleMenuView.swift | 42 ++++++++++++------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 418879b2..efdc796e 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -671,7 +671,17 @@ class ConversationViewController: BaseViewController { // test menu if true { - let menu = BubbleMenuView(titles: ["Copy", "Delete"]) + + let copyItem = BubbleMenuView.Item(title: "Copy") { + print("copy\n") + } + + let deleteItem = BubbleMenuView.Item(title: "Delete") { + print("delete\n") + } + + let menu = BubbleMenuView(items: [copyItem, deleteItem]) + menu.setTranslatesAutoresizingMaskIntoConstraints(false) view.addSubview(menu) @@ -682,7 +692,13 @@ class ConversationViewController: BaseViewController { } if true { - let menu = BubbleMenuView(titles: ["Copy"]) + + let copyItem = BubbleMenuView.Item(title: "Copy") { + print("copy\n") + } + + let menu = BubbleMenuView(items: [copyItem]) + menu.setTranslatesAutoresizingMaskIntoConstraints(false) view.addSubview(menu) diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index a9bb30ed..19a5a73d 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -10,12 +10,19 @@ import UIKit class BubbleMenuView: UIView { - var titles: [String] + var items: [Item] var buttons = [UIButton]() - init(titles: [String]) { - self.titles = titles + struct Item { + let title: String + let action: () -> Void + } + + init(items: [Item]) { + + self.items = items + super.init(frame: CGRectZero) makeUI() @@ -25,22 +32,36 @@ class BubbleMenuView: UIView { 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() + } + } + + // MARK: UI + let arrowHeight: CGFloat = 8 let buttonGap: CGFloat = 12 func makeUI() { - //backgroundColor = UIColor.redColor() backgroundColor = UIColor.clearColor() var format = "H:|" - for (index, title) in enumerate(titles) { + for (index, item) in enumerate(items) { let button = UIButton() - //button.backgroundColor = UIColor.blueColor().colorWithAlphaComponent(0.5) - button.setTitle(title, forState: .Normal) + button.setTitleColor(UIColor.whiteColor(), forState: .Normal) + button.setTitleColor(UIColor.lightGrayColor(), forState: .Highlighted) + + button.setTitle(item.title, forState: .Normal) + button.addTarget(self, action: "tapButton:", forControlEvents: .TouchUpInside) + button.setTranslatesAutoresizingMaskIntoConstraints(false) addSubview(button) @@ -56,8 +77,6 @@ class BubbleMenuView: UIView { format += "-|" - //let format = "H:|[label0][label1][label2]|" - var views = [NSObject: AnyObject]() for (index, button) in enumerate(buttons) { @@ -78,11 +97,6 @@ class BubbleMenuView: UIView { } } -// override func intrinsicContentSize() -> CGSize { -// return CGSize(width: 80 * titles.count, height: 80) -// } - - override func drawRect(rect: CGRect) { UIColor.blackColor().colorWithAlphaComponent(0.7).setFill() From e865b5a7c73f63cf5e62d4f1d5d30849a96c95cc Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 14:30:45 +0800 Subject: [PATCH 03/21] cell longPress show menu --- .../ConversationViewController.swift | 103 ++++++++++++++++++ .../ChatRightText/ChatRightTextCell.swift | 29 +++-- Yep/Views/TextViews/ChatTextView.swift | 8 +- 3 files changed, 125 insertions(+), 15 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index efdc796e..e264f7d7 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -668,6 +668,7 @@ class ConversationViewController: BaseViewController { self.setNeedsStatusBarAppearanceUpdate() + /* // test menu if true { @@ -707,6 +708,7 @@ class ConversationViewController: BaseViewController { NSLayoutConstraint.activateConstraints([menuCenterY, menuCenterX]) } + */ } private func markMessageAsReaded(message: Message) { @@ -2102,6 +2104,106 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } }, collectionView: collectionView, indexPath: indexPath) + cell.longPressAction = { [weak self] cell in + + if let strongSelf = self { + + let copyItem = BubbleMenuView.Item(title: "Copy") { + print("copy\n") + + UIPasteboard.generalPasteboard().string = cell.textContentTextView.text + } + + let deleteItem = BubbleMenuView.Item(title: "Delete") { + 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 + } + } + } + + 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 menu = BubbleMenuView(items: [copyItem, deleteItem]) + + menu.setTranslatesAutoresizingMaskIntoConstraints(false) + + strongSelf.view.addSubview(menu) + + let menuCenterY = NSLayoutConstraint(item: menu, attribute: .CenterY, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: 0) + let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: 0) + + NSLayoutConstraint.activateConstraints([menuCenterY, menuCenterX]) + } + } + + /* cell.deleteMessageAction = { [weak self] in dispatch_async(dispatch_get_main_queue()) { if let strongSelf = self, realm = message.realm { @@ -2175,6 +2277,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } } } + */ return cell } diff --git a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift index 15641756..156b559a 100644 --- a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift +++ b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift @@ -22,10 +22,13 @@ class ChatRightTextCell: ChatRightBaseCell { @IBOutlet weak var textContentTextViewLeadingConstraint: NSLayoutConstraint! @IBOutlet weak var textContentTextViewWidthConstraint: NSLayoutConstraint! - var deleteMessageAction: (() -> Void)? typealias MediaTapAction = () -> Void var mediaTapAction: MediaTapAction? + + var longPressAction: (ChatRightTextCell -> Void)? + //var deleteMessageAction: (() -> Void)? + override func awakeFromNib() { super.awakeFromNib() @@ -43,11 +46,11 @@ class ChatRightTextCell: ChatRightBaseCell { NSUnderlineStyleAttributeName: NSNumber(integer: NSUnderlineStyle.StyleSingle.rawValue), ] - textContentTextView.deleteEnabled = true - textContentTextView.deleteAction = { [weak self] in - println("delete text message?") - self?.deleteMessageAction?() - } +// textContentTextView.deleteEnabled = true +// textContentTextView.deleteAction = { [weak self] in +// println("delete text message?") +// self?.deleteMessageAction?() +// } let longPress = UILongPressGestureRecognizer(target: self, action: "handleLongPress:") textContentTextView.addGestureRecognizer(longPress) @@ -65,13 +68,15 @@ class ChatRightTextCell: ChatRightBaseCell { func handleLongPress(longPress: UILongPressGestureRecognizer) { if longPress.state == .Began { - if let view = longPress.view, superview = view.superview { - view.becomeFirstResponder() +// if let view = longPress.view, superview = view.superview { +// view.becomeFirstResponder() +// +// let menu = UIMenuController.sharedMenuController() +// menu.setTargetRect(view.frame, inView: superview) +// menu.setMenuVisible(true, animated: true) +// } - let menu = UIMenuController.sharedMenuController() - menu.setTargetRect(view.frame, inView: superview) - menu.setMenuVisible(true, animated: true) - } + longPressAction?(self) } } diff --git a/Yep/Views/TextViews/ChatTextView.swift b/Yep/Views/TextViews/ChatTextView.swift index f81fcd8e..9f44ffd6 100644 --- a/Yep/Views/TextViews/ChatTextView.swift +++ b/Yep/Views/TextViews/ChatTextView.swift @@ -10,10 +10,11 @@ import UIKit class ChatTextView: UITextView { -// override func canBecomeFirstResponder() -> Bool { -// return false -// } + override func canBecomeFirstResponder() -> Bool { + return false + } + /* var deleteEnabled = false var deleteAction: (() -> Void)? @@ -32,4 +33,5 @@ class ChatTextView: UITextView { return action == Selector("copy:") } } + */ } From de3c3150325c34e346664420cbbe4c62a2bcf41a Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 14:34:15 +0800 Subject: [PATCH 04/21] hide logic --- .../Conversation/ConversationViewController.swift | 8 ++++++-- Yep/Views/BubbleMenu/BubbleMenuView.swift | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index e264f7d7..817bd24b 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -2108,13 +2108,15 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if let strongSelf = self { - let copyItem = BubbleMenuView.Item(title: "Copy") { + let copyItem = BubbleMenuView.Item(title: "Copy") { bubbleMenuView in print("copy\n") UIPasteboard.generalPasteboard().string = cell.textContentTextView.text + + bubbleMenuView.hide() } - let deleteItem = BubbleMenuView.Item(title: "Delete") { + let deleteItem = BubbleMenuView.Item(title: "Delete") { bubbleMenuView in print("delete\n") dispatch_async(dispatch_get_main_queue()) { @@ -2188,6 +2190,8 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi strongSelf.lastTimeMessagesCount = strongSelf.messages.count } } + + bubbleMenuView.hide() } let menu = BubbleMenuView(items: [copyItem, deleteItem]) diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 19a5a73d..6f1f6b63 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -16,7 +16,7 @@ class BubbleMenuView: UIView { struct Item { let title: String - let action: () -> Void + let action: BubbleMenuView -> Void } init(items: [Item]) { @@ -37,10 +37,14 @@ class BubbleMenuView: UIView { func tapButton(button: UIButton) { if let index = find(buttons, button) { let action = items[index].action - action() + action(self) } } + func hide() { + removeFromSuperview() + } + // MARK: UI let arrowHeight: CGFloat = 8 From 12676b4345927f9b2c8c7387d0536ed61ee9bf1c Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 14:35:29 +0800 Subject: [PATCH 05/21] local string --- .../Conversation/ConversationViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 817bd24b..0305a14b 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -2108,7 +2108,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if let strongSelf = self { - let copyItem = BubbleMenuView.Item(title: "Copy") { bubbleMenuView in + let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { bubbleMenuView in print("copy\n") UIPasteboard.generalPasteboard().string = cell.textContentTextView.text @@ -2116,7 +2116,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi bubbleMenuView.hide() } - let deleteItem = BubbleMenuView.Item(title: "Delete") { bubbleMenuView in + let deleteItem = BubbleMenuView.Item(title: NSLocalizedString("Delete", comment: "")) { bubbleMenuView in print("delete\n") dispatch_async(dispatch_get_main_queue()) { From d2a58061b8d1c57da637d1ad71c465f3a98dbc71 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 14:52:02 +0800 Subject: [PATCH 06/21] menu position --- .../ConversationViewController.swift | 20 +++++++++++++------ Yep/Views/BubbleMenu/BubbleMenuView.swift | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 0305a14b..bf7f220e 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -2108,15 +2108,15 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if let strongSelf = self { - let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { bubbleMenuView in + let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { menu in print("copy\n") UIPasteboard.generalPasteboard().string = cell.textContentTextView.text - bubbleMenuView.hide() + menu.hide() } - let deleteItem = BubbleMenuView.Item(title: NSLocalizedString("Delete", comment: "")) { bubbleMenuView in + let deleteItem = BubbleMenuView.Item(title: NSLocalizedString("Delete", comment: "")) { menu in print("delete\n") dispatch_async(dispatch_get_main_queue()) { @@ -2191,7 +2191,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } } - bubbleMenuView.hide() + menu.hide() } let menu = BubbleMenuView(items: [copyItem, deleteItem]) @@ -2200,8 +2200,16 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi strongSelf.view.addSubview(menu) - let menuCenterY = NSLayoutConstraint(item: menu, attribute: .CenterY, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: 0) - let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: 0) + let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) + + var centerYConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(strongSelf.conversationCollectionView.frame) + centerYConstant -= CGRectGetHeight(textViewFrame) - menu.offsetY + + let menuCenterY = NSLayoutConstraint(item: menu, attribute: .CenterY, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: centerYConstant) + + let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(strongSelf.conversationCollectionView.frame) + + let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) NSLayoutConstraint.activateConstraints([menuCenterY, menuCenterX]) } diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 6f1f6b63..0b83ad18 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -49,6 +49,7 @@ class BubbleMenuView: UIView { let arrowHeight: CGFloat = 8 let buttonGap: CGFloat = 12 + let offsetY: CGFloat = 8 func makeUI() { From 3a546c8adca7cf2298b33ac6e481bcbd300bc48e Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 15:32:13 +0800 Subject: [PATCH 07/21] ArrowDirection --- .../ConversationViewController.swift | 27 +++++-- Yep/Views/BubbleMenu/BubbleMenuView.swift | 78 +++++++++++++++---- 2 files changed, 83 insertions(+), 22 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index bf7f220e..aaa97bc9 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -2194,24 +2194,39 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi menu.hide() } - let menu = BubbleMenuView(items: [copyItem, deleteItem]) + let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) + + let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < 64 + 80 ? .Up : .Down + + let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem, deleteItem]) menu.setTranslatesAutoresizingMaskIntoConstraints(false) strongSelf.view.addSubview(menu) - let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) - var centerYConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(strongSelf.conversationCollectionView.frame) - centerYConstant -= CGRectGetHeight(textViewFrame) - menu.offsetY + var vConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(strongSelf.conversationCollectionView.frame) - let menuCenterY = NSLayoutConstraint(item: menu, attribute: .CenterY, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: centerYConstant) + let menuV: NSLayoutConstraint + + switch arrowDirection { + + case .Up: + vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV + + menuV = NSLayoutConstraint(item: menu, attribute: .Top, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) + + case .Down: + vConstant -= ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV + + menuV = NSLayoutConstraint(item: menu, attribute: .Bottom, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) + } let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(strongSelf.conversationCollectionView.frame) let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) - NSLayoutConstraint.activateConstraints([menuCenterY, menuCenterX]) + NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) } } diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 0b83ad18..5c36bbeb 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -10,17 +10,24 @@ import UIKit class BubbleMenuView: UIView { - var items: [Item] - - var buttons = [UIButton]() + enum ArrowDirection { + case Up + case Down + } struct Item { let title: String let action: BubbleMenuView -> Void } - init(items: [Item]) { + var arrowDirection: ArrowDirection + var items: [Item] + var buttons = [UIButton]() + + init(arrowDirection: ArrowDirection, items: [Item]) { + + self.arrowDirection = arrowDirection self.items = items super.init(frame: CGRectZero) @@ -49,7 +56,7 @@ class BubbleMenuView: UIView { let arrowHeight: CGFloat = 8 let buttonGap: CGFloat = 12 - let offsetY: CGFloat = 8 + let offsetV: CGFloat = 1 func makeUI() { @@ -96,9 +103,23 @@ class BubbleMenuView: UIView { if let firstButton = buttons.first { 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]) + 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]) + } } } @@ -109,22 +130,47 @@ class BubbleMenuView: UIView { // bubble var roundedRect = rect - roundedRect.size.height -= arrowHeight + + 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 - let buttomX = CGRectGetMidX(rect) - let buttomY = CGRectGetMaxY(rect) + switch arrowDirection { - 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() + 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 From 69f9060cdfb33674bf64c4e9cc20fe29b7cf7157 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 15:41:18 +0800 Subject: [PATCH 08/21] hide currentMenu when new menu show, vc disappear, or user scroll --- .../ConversationViewController.swift | 32 +++++++++++++------ Yep/Views/BubbleMenu/BubbleMenuView.swift | 2 +- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index aaa97bc9..b2cf7589 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -109,6 +109,8 @@ class ConversationViewController: BaseViewController { @IBOutlet weak var takePhotoButton: MessageTypeButton! @IBOutlet weak var addLocationButton: MessageTypeButton! + var currentMenu: BubbleMenuView? + var originalNavigationControllerDelegate: UINavigationControllerDelegate? var waverView: YepWaverView! @@ -741,6 +743,12 @@ class ConversationViewController: BaseViewController { } } + override func viewWillDisappear(animated: Bool) { + super.viewWillDisappear(animated) + + currentMenu?.hide() + } + override func viewDidDisappear(animated: Bool) { super.viewDidDisappear(animated) @@ -2106,7 +2114,9 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.longPressAction = { [weak self] cell in - if let strongSelf = self { + self?.currentMenu?.hide() + + if let strongSelf = self { let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { menu in print("copy\n") @@ -2185,7 +2195,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) } - + // 必须更新,插入时需要 strongSelf.lastTimeMessagesCount = strongSelf.messages.count } @@ -2199,7 +2209,9 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < 64 + 80 ? .Up : .Down let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem, deleteItem]) - + + strongSelf.currentMenu = menu + menu.setTranslatesAutoresizingMaskIntoConstraints(false) strongSelf.view.addSubview(menu) @@ -2213,19 +2225,19 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi case .Up: vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV - + menuV = NSLayoutConstraint(item: menu, attribute: .Top, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) - + case .Down: vConstant -= ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV - + menuV = NSLayoutConstraint(item: menu, attribute: .Bottom, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) } - + let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(strongSelf.conversationCollectionView.frame) - + let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) - + NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) } } @@ -2355,6 +2367,8 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi func scrollViewDidScroll(scrollView: UIScrollView) { pullToRefreshView.scrollViewDidScroll(scrollView) + + currentMenu?.hide() } func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 5c36bbeb..4f439eb1 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -56,7 +56,7 @@ class BubbleMenuView: UIView { let arrowHeight: CGFloat = 8 let buttonGap: CGFloat = 12 - let offsetV: CGFloat = 1 + let offsetV: CGFloat = 2 func makeUI() { From 009bc18bde40275fcce4eca707633957c294d439 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 16:01:07 +0800 Subject: [PATCH 09/21] longPressAction for ChatLeftTextCell show menu --- .../ConversationViewController.swift | 52 +++++++++++++++++++ .../Cells/ChatLeftText/ChatLeftTextCell.swift | 20 ++++--- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index b2cf7589..8e625a14 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -1935,6 +1935,58 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.configureWithMessage(message, textContentLabelWidth: textContentLabelWidthOfMessage(message), collectionView: collectionView, indexPath: indexPath) + cell.longPressAction = { [weak self] cell in + + self?.currentMenu?.hide() + + if let strongSelf = self { + + let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { menu in + print("copy\n") + + UIPasteboard.generalPasteboard().string = cell.textContentTextView.text + + menu.hide() + } + + let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) + + let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < 64 + 80 ? .Up : .Down + + let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem]) + + strongSelf.currentMenu = menu + + menu.setTranslatesAutoresizingMaskIntoConstraints(false) + + strongSelf.view.addSubview(menu) + + + var vConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(strongSelf.conversationCollectionView.frame) + + let menuV: NSLayoutConstraint + + switch arrowDirection { + + case .Up: + vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV + + menuV = NSLayoutConstraint(item: menu, attribute: .Top, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) + + case .Down: + vConstant -= ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV + + menuV = NSLayoutConstraint(item: menu, attribute: .Bottom, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) + } + + let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(strongSelf.conversationCollectionView.frame) + + let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) + + NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) + } + } + return cell } diff --git a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift index de7f7919..66467118 100644 --- a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift +++ b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift @@ -22,6 +22,8 @@ class ChatLeftTextCell: UICollectionViewCell { @IBOutlet weak var textContentTextViewLeadingConstraint: NSLayoutConstraint! @IBOutlet weak var textContentTextViewWidthConstraint: NSLayoutConstraint! + var longPressAction: (ChatLeftTextCell -> Void)? + override func awakeFromNib() { super.awakeFromNib() @@ -58,15 +60,17 @@ class ChatLeftTextCell: UICollectionViewCell { } func handleLongPress(longPress: UILongPressGestureRecognizer) { - if longPress.state == .Began { - if let view = longPress.view, superview = view.superview { - view.becomeFirstResponder() +// if longPress.state == .Began { +// if let view = longPress.view, superview = view.superview { +// view.becomeFirstResponder() +// +// let menu = UIMenuController.sharedMenuController() +// menu.setTargetRect(view.frame, inView: superview) +// menu.setMenuVisible(true, animated: true) +// } +// } - let menu = UIMenuController.sharedMenuController() - menu.setTargetRect(view.frame, inView: superview) - menu.setMenuVisible(true, animated: true) - } - } + longPressAction?(self) } func configureWithMessage(message: Message, textContentLabelWidth: CGFloat, collectionView: UICollectionView, indexPath: NSIndexPath) { From 435519d49615132952522695e58c1dbf274d55e3 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 16:09:22 +0800 Subject: [PATCH 10/21] refactor show BubbleMenuView --- .../ConversationViewController.swift | 56 +------------------ Yep/Views/BubbleMenu/BubbleMenuView.swift | 29 ++++++++++ 2 files changed, 31 insertions(+), 54 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 8e625a14..7cc7a0e2 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -1957,33 +1957,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi strongSelf.currentMenu = menu - menu.setTranslatesAutoresizingMaskIntoConstraints(false) - - strongSelf.view.addSubview(menu) - - - var vConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(strongSelf.conversationCollectionView.frame) - - let menuV: NSLayoutConstraint - - switch arrowDirection { - - case .Up: - vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV - - menuV = NSLayoutConstraint(item: menu, attribute: .Top, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) - - case .Down: - vConstant -= ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV - - menuV = NSLayoutConstraint(item: menu, attribute: .Bottom, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) - } - - let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(strongSelf.conversationCollectionView.frame) - - let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) - - NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) + menu.showInView(strongSelf.view, withTextViewFrame: textViewFrame) } } @@ -2264,33 +2238,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi strongSelf.currentMenu = menu - menu.setTranslatesAutoresizingMaskIntoConstraints(false) - - strongSelf.view.addSubview(menu) - - - var vConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(strongSelf.conversationCollectionView.frame) - - let menuV: NSLayoutConstraint - - switch arrowDirection { - - case .Up: - vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV - - menuV = NSLayoutConstraint(item: menu, attribute: .Top, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) - - case .Down: - vConstant -= ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV - - menuV = NSLayoutConstraint(item: menu, attribute: .Bottom, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) - } - - let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(strongSelf.conversationCollectionView.frame) - - let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) - - NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) + menu.showInView(strongSelf.view, withTextViewFrame: textViewFrame) } } diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 4f439eb1..f5251986 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -48,6 +48,35 @@ class BubbleMenuView: UIView { } } + func showInView(view: UIView, withTextViewFrame textViewFrame: CGRect) { + + setTranslatesAutoresizingMaskIntoConstraints(false) + view.addSubview(self) + + var vConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(view.frame) + + let menuV: NSLayoutConstraint + + switch arrowDirection { + + case .Up: + vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - offsetV + + menuV = NSLayoutConstraint(item: self, attribute: .Top, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: vConstant) + + case .Down: + vConstant -= ceil(CGRectGetHeight(textViewFrame) * 0.5) - offsetV + + menuV = NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: vConstant) + } + + let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(view.frame) + + let menuCenterX = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) + + NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) + } + func hide() { removeFromSuperview() } From 1934a5858c06471c2af16efb7e8af69d894c398a Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 16:12:17 +0800 Subject: [PATCH 11/21] clean code --- .../ConversationViewController.swift | 76 ------------------- .../Cells/ChatLeftText/ChatLeftTextCell.swift | 23 +----- .../ChatRightText/ChatRightTextCell.swift | 16 ---- Yep/Views/TextViews/ChatTextView.swift | 21 ----- 4 files changed, 3 insertions(+), 133 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 7cc7a0e2..15b51a04 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -2242,82 +2242,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } } - /* - cell.deleteMessageAction = { [weak self] in - dispatch_async(dispatch_get_main_queue()) { - if let strongSelf = self, realm = message.realm { - - var sectionDateMessage: Message? - - if let currentMessageIndex = strongSelf.messages.indexOf(message) { - - let previousMessageIndex = currentMessageIndex - 1 - - if let previousMessage = strongSelf.messages[safe: previousMessageIndex] { - - if previousMessage.mediaType == MessageMediaType.SectionDate.rawValue { - sectionDateMessage = previousMessage - } - } - } - - let currentIndexPath: NSIndexPath - if let index = strongSelf.messages.indexOf(message) { - currentIndexPath = NSIndexPath(forItem: index - strongSelf.displayedMessagesRange.location, inSection: indexPath.section) - } else { - currentIndexPath = indexPath - } - - if let sectionDateMessage = sectionDateMessage { - - var canDeleteTwoMessages = false // 考虑刚好的边界情况,例如消息为本束的最后一条,而 sectionDate 在上一束中 - if strongSelf.displayedMessagesRange.length >= 2 { - strongSelf.displayedMessagesRange.length -= 2 - canDeleteTwoMessages = true - - } else { - if strongSelf.displayedMessagesRange.location >= 1 { - strongSelf.displayedMessagesRange.location -= 1 - } - strongSelf.displayedMessagesRange.length -= 1 - } - - realm.write { - if let mediaMetaData = sectionDateMessage.mediaMetaData { - realm.delete(mediaMetaData) - } - if let mediaMetaData = message.mediaMetaData { - realm.delete(mediaMetaData) - } - realm.delete(sectionDateMessage) - realm.delete(message) - } - - if canDeleteTwoMessages { - let previousIndexPath = NSIndexPath(forItem: currentIndexPath.item - 1, inSection: currentIndexPath.section) - strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([previousIndexPath, currentIndexPath]) - } else { - strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) - } - - } else { - strongSelf.displayedMessagesRange.length -= 1 - realm.write { - if let mediaMetaData = message.mediaMetaData { - realm.delete(mediaMetaData) - } - realm.delete(message) - } - strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) - } - - // 必须更新,插入时需要 - strongSelf.lastTimeMessagesCount = strongSelf.messages.count - } - } - } - */ - return cell } } diff --git a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift index 66467118..9cb14931 100644 --- a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift +++ b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift @@ -40,15 +40,6 @@ class ChatLeftTextCell: UICollectionViewCell { NSUnderlineStyleAttributeName: NSNumber(integer: NSUnderlineStyle.StyleSingle.rawValue), ] -// textContentTextView.editable = false -// if let gestureRecognizers = textContentTextView.gestureRecognizers as? [UIGestureRecognizer] { -// for recognizer in gestureRecognizers { -// if recognizer.isKindOfClass(UILongPressGestureRecognizer.self) { -// recognizer.enabled = false -// } -// } -// } - let longPress = UILongPressGestureRecognizer(target: self, action: "handleLongPress:") textContentTextView.addGestureRecognizer(longPress) @@ -60,17 +51,9 @@ class ChatLeftTextCell: UICollectionViewCell { } func handleLongPress(longPress: UILongPressGestureRecognizer) { -// if longPress.state == .Began { -// if let view = longPress.view, superview = view.superview { -// view.becomeFirstResponder() -// -// let menu = UIMenuController.sharedMenuController() -// menu.setTargetRect(view.frame, inView: superview) -// menu.setMenuVisible(true, animated: true) -// } -// } - - longPressAction?(self) + if longPress.state == .Began { + longPressAction?(self) + } } func configureWithMessage(message: Message, textContentLabelWidth: CGFloat, collectionView: UICollectionView, indexPath: NSIndexPath) { diff --git a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift index 156b559a..66e9bf20 100644 --- a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift +++ b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift @@ -25,9 +25,7 @@ class ChatRightTextCell: ChatRightBaseCell { typealias MediaTapAction = () -> Void var mediaTapAction: MediaTapAction? - var longPressAction: (ChatRightTextCell -> Void)? - //var deleteMessageAction: (() -> Void)? override func awakeFromNib() { super.awakeFromNib() @@ -46,12 +44,6 @@ class ChatRightTextCell: ChatRightBaseCell { NSUnderlineStyleAttributeName: NSNumber(integer: NSUnderlineStyle.StyleSingle.rawValue), ] -// textContentTextView.deleteEnabled = true -// textContentTextView.deleteAction = { [weak self] in -// println("delete text message?") -// self?.deleteMessageAction?() -// } - let longPress = UILongPressGestureRecognizer(target: self, action: "handleLongPress:") textContentTextView.addGestureRecognizer(longPress) @@ -68,14 +60,6 @@ class ChatRightTextCell: ChatRightBaseCell { func handleLongPress(longPress: UILongPressGestureRecognizer) { if longPress.state == .Began { -// if let view = longPress.view, superview = view.superview { -// view.becomeFirstResponder() -// -// let menu = UIMenuController.sharedMenuController() -// menu.setTargetRect(view.frame, inView: superview) -// menu.setMenuVisible(true, animated: true) -// } - longPressAction?(self) } } diff --git a/Yep/Views/TextViews/ChatTextView.swift b/Yep/Views/TextViews/ChatTextView.swift index 9f44ffd6..c9b44672 100644 --- a/Yep/Views/TextViews/ChatTextView.swift +++ b/Yep/Views/TextViews/ChatTextView.swift @@ -13,25 +13,4 @@ class ChatTextView: UITextView { override func canBecomeFirstResponder() -> Bool { return false } - - /* - var deleteEnabled = false - var deleteAction: (() -> Void)? - - override func copy(sender: AnyObject?) { - UIPasteboard.generalPasteboard().string = text - } - - override func delete(sender: AnyObject?) { - deleteAction?() - } - - override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool { - if deleteEnabled { - return action == Selector("copy:") || action == Selector("delete:") - } else { - return action == Selector("copy:") - } - } - */ } From 39831795193e1cc0afe4f56972caa881588faa88 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 16:18:30 +0800 Subject: [PATCH 12/21] use menuDirectionUpThreshold --- Yep/Configs/YepConfig.swift | 4 ++++ .../Conversation/ConversationViewController.swift | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Yep/Configs/YepConfig.swift b/Yep/Configs/YepConfig.swift index c7431915..735b9801 100644 --- a/Yep/Configs/YepConfig.swift +++ b/Yep/Configs/YepConfig.swift @@ -81,6 +81,10 @@ class YepConfig { return 100 } + struct Conversation { + static let menuDirectionUpThreshold: CGFloat = 64 + 60 + } + struct AudioRecord { static let shortestDuration: NSTimeInterval = 0.5 static let longestDuration: NSTimeInterval = 60 diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 15b51a04..245026e3 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -1951,7 +1951,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) - let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < 64 + 80 ? .Up : .Down + let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < YepConfig.Conversation.menuDirectionUpThreshold ? .Up : .Down let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem]) @@ -2232,7 +2232,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) - let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < 64 + 80 ? .Up : .Down + let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < YepConfig.Conversation.menuDirectionUpThreshold ? .Up : .Down let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem, deleteItem]) From 25ed49bd26e73e25b68fcd27da642b21974d82f0 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 16:30:44 +0800 Subject: [PATCH 13/21] show / hide animation --- Yep/Views/BubbleMenu/BubbleMenuView.swift | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index f5251986..17e5794f 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -50,6 +50,8 @@ class BubbleMenuView: UIView { func showInView(view: UIView, withTextViewFrame textViewFrame: CGRect) { + // position + setTranslatesAutoresizingMaskIntoConstraints(false) view.addSubview(self) @@ -75,16 +77,33 @@ class BubbleMenuView: UIView { 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() { - removeFromSuperview() + + 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 = 12 + let buttonGap: CGFloat = 16 let offsetV: CGFloat = 2 func makeUI() { From 0451f27181d7748207945255b380d7f48e1a3274 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 16:45:54 +0800 Subject: [PATCH 14/21] better removeOldMenu logic --- .../ConversationViewController.swift | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 245026e3..2550c8a3 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -111,6 +111,11 @@ class ConversationViewController: BaseViewController { var currentMenu: BubbleMenuView? + func removeOldMenu() { + currentMenu?.hide() + currentMenu = nil + } + var originalNavigationControllerDelegate: UINavigationControllerDelegate? var waverView: YepWaverView! @@ -527,6 +532,8 @@ class ConversationViewController: BaseViewController { messageToolbar.stateTransitionAction = { [weak self] (messageToolbar, previousState, currentState) in + self?.removeOldMenu() + if let strongSelf = self { switch (previousState, currentState) { @@ -746,7 +753,7 @@ class ConversationViewController: BaseViewController { override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) - currentMenu?.hide() + removeOldMenu() } override func viewDidDisappear(animated: Bool) { @@ -1020,6 +1027,8 @@ class ConversationViewController: BaseViewController { func moreAction() { + removeOldMenu() + messageToolbar.state = .Default moreView.showProfileAction = { [weak self] in @@ -1937,7 +1946,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.longPressAction = { [weak self] cell in - self?.currentMenu?.hide() + self?.removeOldMenu() if let strongSelf = self { @@ -1947,6 +1956,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi UIPasteboard.generalPasteboard().string = cell.textContentTextView.text menu.hide() + self?.currentMenu = nil } let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) @@ -2140,7 +2150,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.longPressAction = { [weak self] cell in - self?.currentMenu?.hide() + self?.removeOldMenu() if let strongSelf = self { @@ -2150,6 +2160,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi UIPasteboard.generalPasteboard().string = cell.textContentTextView.text menu.hide() + self?.currentMenu = nil } let deleteItem = BubbleMenuView.Item(title: NSLocalizedString("Delete", comment: "")) { menu in @@ -2228,6 +2239,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } menu.hide() + self?.currentMenu = nil } let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) @@ -2292,7 +2304,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi func scrollViewDidScroll(scrollView: UIScrollView) { pullToRefreshView.scrollViewDidScroll(scrollView) - currentMenu?.hide() + removeOldMenu() } func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { From d6dd86b7c195c2622c8731ee4a91f5ae2f72fa0f Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 17:08:04 +0800 Subject: [PATCH 15/21] BubbleMenuView Item Type --- .../ConversationViewController.swift | 8 ++++-- Yep/Views/BubbleMenu/BubbleMenuView.swift | 28 ++++++++++++++++--- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 2550c8a3..97907d97 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -1860,6 +1860,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi markMessageAsReaded(message) switch message.mediaType { + case MessageMediaType.Image.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftImageCellIdentifier, forIndexPath: indexPath) as! ChatLeftImageCell @@ -1950,7 +1951,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if let strongSelf = self { - let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { menu in + let copyItem = BubbleMenuView.Item(type: .Normal, title: NSLocalizedString("Copy", comment: "")) { menu in print("copy\n") UIPasteboard.generalPasteboard().string = cell.textContentTextView.text @@ -1977,6 +1978,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } else { // from Me switch message.mediaType { + case MessageMediaType.Image.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightImageCellIdentifier, forIndexPath: indexPath) as! ChatRightImageCell @@ -2154,7 +2156,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if let strongSelf = self { - let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { menu in + let copyItem = BubbleMenuView.Item(type: .Normal, title: NSLocalizedString("Copy", comment: "")) { menu in print("copy\n") UIPasteboard.generalPasteboard().string = cell.textContentTextView.text @@ -2163,7 +2165,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi self?.currentMenu = nil } - let deleteItem = BubbleMenuView.Item(title: NSLocalizedString("Delete", comment: "")) { menu in + let deleteItem = BubbleMenuView.Item(type: .Danger, title: NSLocalizedString("Delete", comment: "")) { menu in print("delete\n") dispatch_async(dispatch_get_main_queue()) { diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 17e5794f..175927c0 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -16,7 +16,15 @@ class BubbleMenuView: UIView { } struct Item { + + enum Type { + case Normal + case Danger + } + let type: Type + let title: String + let action: BubbleMenuView -> Void } @@ -104,7 +112,7 @@ class BubbleMenuView: UIView { let arrowHeight: CGFloat = 8 let buttonGap: CGFloat = 16 - let offsetV: CGFloat = 2 + let offsetV: CGFloat = 1 func makeUI() { @@ -116,8 +124,20 @@ class BubbleMenuView: UIView { let button = UIButton() - button.setTitleColor(UIColor.whiteColor(), forState: .Normal) - button.setTitleColor(UIColor.lightGrayColor(), forState: .Highlighted) + 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.18, blue: 0.40, 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) @@ -173,7 +193,7 @@ class BubbleMenuView: UIView { override func drawRect(rect: CGRect) { - UIColor.blackColor().colorWithAlphaComponent(0.7).setFill() + UIColor.blackColor().colorWithAlphaComponent(0.6).setFill() // bubble From 6badf46e6418935d0b8df78b259257c324c82acf Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 17:28:45 +0800 Subject: [PATCH 16/21] use bubbleFrame to show menu --- .../Conversation/ConversationViewController.swift | 12 ++++++------ Yep/Views/BubbleMenu/BubbleMenuView.swift | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 97907d97..d284208a 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -1960,15 +1960,15 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi self?.currentMenu = nil } - let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) + let bubbleFrame = cell.convertRect(cell.bubbleBodyImageView.frame, toView: strongSelf.view) - let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < YepConfig.Conversation.menuDirectionUpThreshold ? .Up : .Down + let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(bubbleFrame) < YepConfig.Conversation.menuDirectionUpThreshold ? .Up : .Down let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem]) strongSelf.currentMenu = menu - menu.showInView(strongSelf.view, withTextViewFrame: textViewFrame) + menu.showInView(strongSelf.view, withBubbleFrame: bubbleFrame) } } @@ -2244,15 +2244,15 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi self?.currentMenu = nil } - let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) + let bubbleFrame = cell.convertRect(cell.bubbleBodyImageView.frame, toView: strongSelf.view) - let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < YepConfig.Conversation.menuDirectionUpThreshold ? .Up : .Down + let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(bubbleFrame) < YepConfig.Conversation.menuDirectionUpThreshold ? .Up : .Down let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem, deleteItem]) strongSelf.currentMenu = menu - menu.showInView(strongSelf.view, withTextViewFrame: textViewFrame) + menu.showInView(strongSelf.view, withBubbleFrame: bubbleFrame) } } diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 175927c0..e4b1b322 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -56,31 +56,31 @@ class BubbleMenuView: UIView { } } - func showInView(view: UIView, withTextViewFrame textViewFrame: CGRect) { + func showInView(view: UIView, withBubbleFrame bubbleFrame: CGRect) { // position setTranslatesAutoresizingMaskIntoConstraints(false) view.addSubview(self) - var vConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(view.frame) + var vConstant = CGRectGetMidY(bubbleFrame) - CGRectGetMidY(view.frame) let menuV: NSLayoutConstraint switch arrowDirection { case .Up: - vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - offsetV + 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(textViewFrame) * 0.5) - offsetV + 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(textViewFrame) - CGRectGetMidX(view.frame) + let centerXConstant = CGRectGetMidX(bubbleFrame) - CGRectGetMidX(view.frame) let menuCenterX = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) @@ -112,7 +112,7 @@ class BubbleMenuView: UIView { let arrowHeight: CGFloat = 8 let buttonGap: CGFloat = 16 - let offsetV: CGFloat = 1 + let offsetV: CGFloat = -1 func makeUI() { @@ -133,7 +133,7 @@ class BubbleMenuView: UIView { case .Danger: - let dangerRed = UIColor(red: 1, green: 0.18, blue: 0.40, alpha: 1) + 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) From 6a365169d1fe521c64b390490bb4ddd236e6b74e Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 22:35:42 +0800 Subject: [PATCH 17/21] fix CocoaPods --- Podfile | 27 ++++++++++++++++----------- Yep.xcodeproj/project.pbxproj | 16 ++++++++++++---- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/Podfile b/Podfile index 43263c35..20050a77 100644 --- a/Podfile +++ b/Podfile @@ -2,14 +2,19 @@ source 'https://github.com/CocoaPods/Specs.git' platform :ios, '8.0' use_frameworks! -pod 'Ruler' -pod 'Proposer' -pod 'APAddressBook/Swift' -pod 'FXBlurView' -pod 'Kingfisher' -pod 'TPKeyboardAvoiding', '~> 1.2' -#pod 'WebViewJavascriptBridge' -pod 'pop' -pod 'AFNetworking' -pod 'MZFayeClient', :path => '../CatchLib-iOS/MZFayeClient/' -pod 'RealmSwift' +def pods + pod 'Ruler' + pod 'Proposer' + pod 'APAddressBook/Swift' + pod 'FXBlurView' + pod 'Kingfisher' + pod 'TPKeyboardAvoiding', '~> 1.2' + pod 'pop' + pod 'AFNetworking' + pod 'MZFayeClient', :path => '../CatchLib-iOS/MZFayeClient/' + pod 'RealmSwift' +end + +target 'Yep' do + pods +end diff --git a/Yep.xcodeproj/project.pbxproj b/Yep.xcodeproj/project.pbxproj index ac671dc0..d0d13467 100644 --- a/Yep.xcodeproj/project.pbxproj +++ b/Yep.xcodeproj/project.pbxproj @@ -211,6 +211,7 @@ 50EB8CCE1AEA1B38001AC1EE /* MessageMediaViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50EB8CCD1AEA1B38001AC1EE /* MessageMediaViewController.swift */; }; 50F2B9781B2EDF3D00F840CC /* BorderTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50F2B9771B2EDF3D00F840CC /* BorderTextField.swift */; }; 50F2B97B1B2EEAF800F840CC /* NavigationTitleLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50F2B97A1B2EEAF800F840CC /* NavigationTitleLabel.swift */; }; + B00500D7E943DDD27CF9C562 /* Pods_Yep.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3146F0F60F2A38BC6E0FA66 /* Pods_Yep.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -272,6 +273,7 @@ 0AEB1CC31B0E6A4B00178C9C /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Crashlytics.framework; sourceTree = ""; }; 0AEB1CC51B0E742400178C9C /* Double+Yep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Double+Yep.swift"; path = "Extensions/Double+Yep.swift"; sourceTree = ""; }; 2268251A75FF6766DC31CCFB /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; + 4EEAF88E6C6D61E595249DF5 /* Pods-Yep.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Yep.release.xcconfig"; path = "Pods/Target Support Files/Pods-Yep/Pods-Yep.release.xcconfig"; sourceTree = ""; }; 500A0B1B1B450C2100D49358 /* EditNicknameAndBadgeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EditNicknameAndBadgeViewController.swift; path = ViewControllers/EditNicknameAndBadge/EditNicknameAndBadgeViewController.swift; sourceTree = ""; }; 500A0B1E1B451A6F00D49358 /* BadgeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BadgeView.swift; path = Views/Badge/BadgeView.swift; sourceTree = ""; }; 501560D61B427FD6000933F0 /* Results+Yep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Results+Yep.swift"; path = "Extensions/Results+Yep.swift"; sourceTree = ""; }; @@ -436,7 +438,9 @@ 50EB8CCD1AEA1B38001AC1EE /* MessageMediaViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MessageMediaViewController.swift; path = ViewControllers/MessageMedia/MessageMediaViewController.swift; sourceTree = ""; }; 50F2B9771B2EDF3D00F840CC /* BorderTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BorderTextField.swift; path = Views/TextFields/BorderTextField.swift; sourceTree = ""; }; 50F2B97A1B2EEAF800F840CC /* NavigationTitleLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NavigationTitleLabel.swift; path = Views/Labels/NavigationTitleLabel.swift; sourceTree = ""; }; + 88C96122C478C4D134F634F6 /* Pods-Yep.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Yep.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Yep/Pods-Yep.debug.xcconfig"; sourceTree = ""; }; B33BE6A6016453F6673C8317 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; + C3146F0F60F2A38BC6E0FA66 /* Pods_Yep.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Yep.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FD88F6095DB46DFAD41AB5DB /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -460,6 +464,7 @@ 0AEB1CC21B0E69B500178C9C /* Fabric.framework in Frameworks */, 0AD7EA5E1AC3ED1200617758 /* CFNetwork.framework in Frameworks */, 15606C18E1487982869C0A42 /* Pods.framework in Frameworks */, + B00500D7E943DDD27CF9C562 /* Pods_Yep.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1466,6 +1471,8 @@ children = ( 2268251A75FF6766DC31CCFB /* Pods.debug.xcconfig */, B33BE6A6016453F6673C8317 /* Pods.release.xcconfig */, + 88C96122C478C4D134F634F6 /* Pods-Yep.debug.xcconfig */, + 4EEAF88E6C6D61E595249DF5 /* Pods-Yep.release.xcconfig */, ); name = Pods; sourceTree = ""; @@ -1489,6 +1496,7 @@ 0AD7EA5B1AC3ECD700617758 /* libPushSDK-1.8.3.a */, 0AD7EA511AC3EA6F00617758 /* JPushSDK.framework */, FD88F6095DB46DFAD41AB5DB /* Pods.framework */, + C3146F0F60F2A38BC6E0FA66 /* Pods_Yep.framework */, ); name = Frameworks; sourceTree = ""; @@ -1668,7 +1676,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Yep/Pods-Yep-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 67B15DACB809FA624B07B937 /* Copy Pods Resources */ = { @@ -1683,7 +1691,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Yep/Pods-Yep-resources.sh\"\n"; showEnvVarsInLog = 0; }; 6F60E0EF8ADE99106F3718B9 /* Check Pods Manifest.lock */ = { @@ -1983,7 +1991,7 @@ }; 0A8F54CB1AB67D11004AD60E /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2268251A75FF6766DC31CCFB /* Pods.debug.xcconfig */; + baseConfigurationReference = 88C96122C478C4D134F634F6 /* Pods-Yep.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; @@ -2010,7 +2018,7 @@ }; 0A8F54CC1AB67D11004AD60E /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = B33BE6A6016453F6673C8317 /* Pods.release.xcconfig */; + baseConfigurationReference = 4EEAF88E6C6D61E595249DF5 /* Pods-Yep.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; From d41156cfcce840dba6ffc8f45d4fbb7ef52cb328 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Fri, 24 Jul 2015 11:59:08 +0800 Subject: [PATCH 18/21] add SkillCell.Skill for SkillHome; fix no cover skill no go to SkillHome --- .../Profile/ProfileViewController.swift | 28 ++++++---------- .../SkillHome/SkillHomeViewController.swift | 13 ++++---- Yep/Views/Cells/Skill/SkillCell.swift | 32 +++++++++++++------ 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/Yep/ViewControllers/Profile/ProfileViewController.swift b/Yep/ViewControllers/Profile/ProfileViewController.swift index a10dd43c..051f6a78 100644 --- a/Yep/ViewControllers/Profile/ProfileViewController.swift +++ b/Yep/ViewControllers/Profile/ProfileViewController.swift @@ -433,9 +433,7 @@ class ProfileViewController: UIViewController { vc.preferedState = SkillHomeState(rawValue: preferedState) } - vc.skillID = skillInfo["skillID"] as? String - vc.skillLocalName = skillInfo["skillLocalName"] as? String - vc.skillCoverURLString = skillInfo["skillCoverURLString"] as? String + vc.skill = skillInfo["skill"] as? SkillCell.Skill vc.afterUpdatedSkillCoverAction = { [weak self] in self?.updateProfileCollectionView() @@ -828,20 +826,16 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel switch profileUser { case .DiscoveredUserType(let discoveredUser): let skill = discoveredUser.masterSkills[indexPath.item] - cell.skillID = skill.id - cell.skillLocalName = skill.localName - cell.skillCoverURLString = skill.coverURLString + cell.skill = SkillCell.Skill(ID: skill.id, localName: skill.localName, coverURLString: skill.coverURLString) case .UserType(let user): let userSkill = user.masterSkills[indexPath.item] - cell.skillID = userSkill.skillID - cell.skillLocalName = userSkill.localName - cell.skillCoverURLString = userSkill.coverURLString + cell.skill = SkillCell.Skill(ID: userSkill.skillID, localName: userSkill.localName, coverURLString: userSkill.coverURLString) } } - cell.tapAction = { [weak self] skillID, skillLocalName, skillCoverURLString in - self?.performSegueWithIdentifier("showSkillHome", sender: ["preferedState": SkillHomeState.Master.rawValue, "skillID": skillID, "skillLocalName": skillLocalName, "skillCoverURLString": skillCoverURLString]) + cell.tapAction = { [weak self] skill in + self?.performSegueWithIdentifier("showSkillHome", sender: ["skill": skill, "preferedState": SkillHomeState.Master.rawValue]) } return cell @@ -853,20 +847,16 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel switch profileUser { case .DiscoveredUserType(let discoveredUser): let skill = discoveredUser.learningSkills[indexPath.item] - cell.skillID = skill.id - cell.skillLocalName = skill.localName - cell.skillCoverURLString = skill.coverURLString + cell.skill = SkillCell.Skill(ID: skill.id, localName: skill.localName, coverURLString: skill.coverURLString) case .UserType(let user): let userSkill = user.learningSkills[indexPath.item] - cell.skillID = userSkill.skillID - cell.skillLocalName = userSkill.localName - cell.skillCoverURLString = userSkill.coverURLString + cell.skill = SkillCell.Skill(ID: userSkill.skillID, localName: userSkill.localName, coverURLString: userSkill.coverURLString) } } - cell.tapAction = { [weak self] skillID, skillLocalName, skillCoverURLString in - self?.performSegueWithIdentifier("showSkillHome", sender: ["preferedState": SkillHomeState.Learning.rawValue, "skillID": skillID, "skillLocalName": skillLocalName, "skillCoverURLString": skillCoverURLString]) + cell.tapAction = { [weak self] skill in + self?.performSegueWithIdentifier("showSkillHome", sender: ["skill": skill, "preferedState": SkillHomeState.Learning.rawValue]) } return cell diff --git a/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift b/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift index 0ab78ec5..4a608565 100644 --- a/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift +++ b/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift @@ -31,11 +31,10 @@ class SkillHomeViewController: CustomNavigationBarViewController { return tempTableView; }() - var skillID: String? - - var skillLocalName: String? { + var skill: SkillCell.Skill? { willSet { - title = newValue + title = newValue?.localName + skillCoverURLString = newValue?.coverURLString } } @@ -124,7 +123,7 @@ class SkillHomeViewController: CustomNavigationBarViewController { learningtTableView.delegate = self learningtTableView.tag = SkillHomeState.Learning.hashValue - if let skillID = skillID { + if let skillID = skill?.ID { discoverUserBySkillID(skillID) } @@ -242,7 +241,7 @@ class SkillHomeViewController: CustomNavigationBarViewController { NSFontAttributeName: UIFont.skillHomeTextLargeFont() ] - let titleAttr = NSMutableAttributedString(string: skillLocalName ?? "", attributes:textAttributes) + let titleAttr = NSMutableAttributedString(string: skill?.localName ?? "", attributes:textAttributes) titleLabel.attributedText = titleAttr titleLabel.textAlignment = NSTextAlignment.Center @@ -369,7 +368,7 @@ extension SkillHomeViewController: UIImagePickerControllerDelegate, UINavigation let data = UIImageJPEGRepresentation(fixedImage, 0.7) - if let skillID = skillID { + if let skillID = skill?.ID { YepHUD.showActivityIndicator() diff --git a/Yep/Views/Cells/Skill/SkillCell.swift b/Yep/Views/Cells/Skill/SkillCell.swift index 5b30ee77..2fb2b0dd 100644 --- a/Yep/Views/Cells/Skill/SkillCell.swift +++ b/Yep/Views/Cells/Skill/SkillCell.swift @@ -31,15 +31,25 @@ class SkillCell: UICollectionViewCell { } } - var skillID: String? - var skillLocalName: String? { - willSet { - skillLabel.text = newValue + class Skill: NSObject { + let ID: String + let localName: String + let coverURLString: String? + + init(ID: String, localName: String, coverURLString: String?) { + self.ID = ID + self.localName = localName + self.coverURLString = coverURLString } } - var skillCoverURLString: String? - var tapAction: ((skillID: String, skillLocalName: String, skillCoverURLString: String) -> Void)? + var skill: Skill? { + willSet { + skillLabel.text = newValue?.localName + } + } + + var tapAction: ((skill: Skill) -> Void)? override func touchesBegan(touches: Set, withEvent event: UIEvent) { tapped = true @@ -48,10 +58,14 @@ class SkillCell: UICollectionViewCell { override func touchesEnded(touches: Set, withEvent event: UIEvent) { delay(0.15) { [weak self] in - self?.tapped = false - if let skillID = self?.skillID, skillLocalName = self?.skillLocalName, skillCoverURLString = self?.skillCoverURLString { - self?.tapAction?(skillID: skillID, skillLocalName: skillLocalName, skillCoverURLString: skillCoverURLString) + if let strongSelf = self { + + strongSelf.tapped = false + + if let skill = strongSelf.skill { + strongSelf.tapAction?(skill: skill) + } } } } From 223a7a9fe76ec2ddb0857e18a86eb8395f60d4ad Mon Sep 17 00:00:00 2001 From: nixzhu Date: Fri, 24 Jul 2015 12:22:52 +0800 Subject: [PATCH 19/21] default cover --- Yep/ViewControllers/SkillHome/SkillHomeViewController.swift | 4 +--- Yep/Views/SkillHomeHeaderView/SkillHomeHeaderView.swift | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift b/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift index 4a608565..c5d79d2e 100644 --- a/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift +++ b/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift @@ -40,9 +40,7 @@ class SkillHomeViewController: CustomNavigationBarViewController { var skillCoverURLString: String? { willSet { - if let coverURLString = newValue { - headerView?.skillCoverURLString = coverURLString - } + headerView?.skillCoverURLString = newValue } } diff --git a/Yep/Views/SkillHomeHeaderView/SkillHomeHeaderView.swift b/Yep/Views/SkillHomeHeaderView/SkillHomeHeaderView.swift index b0cc36dd..02c30215 100644 --- a/Yep/Views/SkillHomeHeaderView/SkillHomeHeaderView.swift +++ b/Yep/Views/SkillHomeHeaderView/SkillHomeHeaderView.swift @@ -15,6 +15,9 @@ class SkillHomeHeaderView: UIView { willSet { if let coverURLString = newValue, URL = NSURL(string: coverURLString) { headerImageView.kf_setImageWithURL(URL, placeholderImage: UIImage(named: "Cover3")) + + } else { + headerImageView.image = UIImage(named: "Cover3") } } } From 31257f835381d0b1f1f6962ed1b084456cbc348b Mon Sep 17 00:00:00 2001 From: nixzhu Date: Fri, 24 Jul 2015 12:44:00 +0800 Subject: [PATCH 20/21] add Category to SkillCell.Skill --- Yep/Realm/Models.swift | 7 +++++++ Yep/Services/YepService.swift | 7 +++++++ .../Profile/ProfileViewController.swift | 8 ++++---- Yep/Views/Cells/Skill/SkillCell.swift | 11 ++++++++++- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Yep/Realm/Models.swift b/Yep/Realm/Models.swift index 81b25cdd..7de6409f 100644 --- a/Yep/Realm/Models.swift +++ b/Yep/Realm/Models.swift @@ -48,6 +48,13 @@ class UserSkill: Object { dynamic var category: UserSkillCategory? + var skillCategory: SkillCell.Skill.Category? { + if let category = category { + return SkillCell.Skill.Category(rawValue: category.name) + } + return nil + } + dynamic var skillID: String = "" dynamic var name: String = "" dynamic var localName: String = "" diff --git a/Yep/Services/YepService.swift b/Yep/Services/YepService.swift index d268231c..c4d39ee8 100644 --- a/Yep/Services/YepService.swift +++ b/Yep/Services/YepService.swift @@ -157,6 +157,13 @@ struct Skill: Hashable { let category: SkillCategory? + var skillCategory: SkillCell.Skill.Category? { + if let category = category { + return SkillCell.Skill.Category(rawValue: category.name) + } + return nil + } + let id: String let name: String let localName: String diff --git a/Yep/ViewControllers/Profile/ProfileViewController.swift b/Yep/ViewControllers/Profile/ProfileViewController.swift index 051f6a78..edfb5c71 100644 --- a/Yep/ViewControllers/Profile/ProfileViewController.swift +++ b/Yep/ViewControllers/Profile/ProfileViewController.swift @@ -826,11 +826,11 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel switch profileUser { case .DiscoveredUserType(let discoveredUser): let skill = discoveredUser.masterSkills[indexPath.item] - cell.skill = SkillCell.Skill(ID: skill.id, localName: skill.localName, coverURLString: skill.coverURLString) + cell.skill = SkillCell.Skill(ID: skill.id, localName: skill.localName, coverURLString: skill.coverURLString, category: skill.skillCategory) case .UserType(let user): let userSkill = user.masterSkills[indexPath.item] - cell.skill = SkillCell.Skill(ID: userSkill.skillID, localName: userSkill.localName, coverURLString: userSkill.coverURLString) + cell.skill = SkillCell.Skill(ID: userSkill.skillID, localName: userSkill.localName, coverURLString: userSkill.coverURLString, category: userSkill.skillCategory) } } @@ -847,11 +847,11 @@ extension ProfileViewController: UICollectionViewDataSource, UICollectionViewDel switch profileUser { case .DiscoveredUserType(let discoveredUser): let skill = discoveredUser.learningSkills[indexPath.item] - cell.skill = SkillCell.Skill(ID: skill.id, localName: skill.localName, coverURLString: skill.coverURLString) + cell.skill = SkillCell.Skill(ID: skill.id, localName: skill.localName, coverURLString: skill.coverURLString, category: skill.skillCategory) case .UserType(let user): let userSkill = user.learningSkills[indexPath.item] - cell.skill = SkillCell.Skill(ID: userSkill.skillID, localName: userSkill.localName, coverURLString: userSkill.coverURLString) + cell.skill = SkillCell.Skill(ID: userSkill.skillID, localName: userSkill.localName, coverURLString: userSkill.coverURLString, category: userSkill.skillCategory) } } diff --git a/Yep/Views/Cells/Skill/SkillCell.swift b/Yep/Views/Cells/Skill/SkillCell.swift index 2fb2b0dd..4bb1f457 100644 --- a/Yep/Views/Cells/Skill/SkillCell.swift +++ b/Yep/Views/Cells/Skill/SkillCell.swift @@ -36,10 +36,19 @@ class SkillCell: UICollectionViewCell { let localName: String let coverURLString: String? - init(ID: String, localName: String, coverURLString: String?) { + enum Category: String { + case Art = "Art" + case Technology = "Technology" + case Sport = "Sport" + case LifeStyle = "Life Style" + } + let category: Category + + init(ID: String, localName: String, coverURLString: String?, category: Category?) { self.ID = ID self.localName = localName self.coverURLString = coverURLString + self.category = category ?? .Art } } From 7fba0ad1e8dc03a7ee96af4b1a38df07ac5f33d6 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Fri, 24 Jul 2015 13:14:43 +0800 Subject: [PATCH 21/21] skill gradient cover --- .../gradient_art.imageset/Contents.json | 24 ++++++++++++++++++ .../gradient_art.imageset/gradient_art.pdf | Bin 0 -> 7098 bytes .../gradient_life.imageset/Contents.json | 24 ++++++++++++++++++ .../gradient_life.imageset/gradient_life.pdf | Bin 0 -> 6832 bytes .../gradient_sport.imageset/Contents.json | 24 ++++++++++++++++++ .../gradient_sport.pdf | Bin 0 -> 6988 bytes .../gradient_tech.imageset/Contents.json | 24 ++++++++++++++++++ .../gradient_tech.imageset/gradient_tech.pdf | Bin 0 -> 7018 bytes .../SkillHome/SkillHomeViewController.swift | 3 +++ Yep/Views/Cells/Skill/SkillCell.swift | 13 ++++++++++ .../SkillHomeHeaderView.swift | 5 ++-- 11 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 Yep/Images.xcassets/gradient_art.imageset/Contents.json create mode 100644 Yep/Images.xcassets/gradient_art.imageset/gradient_art.pdf create mode 100644 Yep/Images.xcassets/gradient_life.imageset/Contents.json create mode 100644 Yep/Images.xcassets/gradient_life.imageset/gradient_life.pdf create mode 100644 Yep/Images.xcassets/gradient_sport.imageset/Contents.json create mode 100644 Yep/Images.xcassets/gradient_sport.imageset/gradient_sport.pdf create mode 100644 Yep/Images.xcassets/gradient_tech.imageset/Contents.json create mode 100644 Yep/Images.xcassets/gradient_tech.imageset/gradient_tech.pdf diff --git a/Yep/Images.xcassets/gradient_art.imageset/Contents.json b/Yep/Images.xcassets/gradient_art.imageset/Contents.json new file mode 100644 index 00000000..decfc8e0 --- /dev/null +++ b/Yep/Images.xcassets/gradient_art.imageset/Contents.json @@ -0,0 +1,24 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "gradient_art.pdf", + "resizing" : { + "mode" : "3-part-horizontal", + "center" : { + "mode" : "fill", + "width" : 1 + }, + "capInsets" : { + "right" : 187, + "left" : 187 + } + } + } + ], + "info" : { + "version" : 1, + "author" : "xcode", + "template-rendering-intent" : "original" + } +} \ No newline at end of file diff --git a/Yep/Images.xcassets/gradient_art.imageset/gradient_art.pdf b/Yep/Images.xcassets/gradient_art.imageset/gradient_art.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3c73bd6581cae485ad4eb9f53bb16ae39bec34c3 GIT binary patch literal 7098 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 literal 0 HcmV?d00001 diff --git a/Yep/Images.xcassets/gradient_life.imageset/Contents.json b/Yep/Images.xcassets/gradient_life.imageset/Contents.json new file mode 100644 index 00000000..314307b1 --- /dev/null +++ b/Yep/Images.xcassets/gradient_life.imageset/Contents.json @@ -0,0 +1,24 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "gradient_life.pdf", + "resizing" : { + "mode" : "3-part-horizontal", + "center" : { + "mode" : "fill", + "width" : 1 + }, + "capInsets" : { + "right" : 187, + "left" : 187 + } + } + } + ], + "info" : { + "version" : 1, + "author" : "xcode", + "template-rendering-intent" : "original" + } +} \ No newline at end of file diff --git a/Yep/Images.xcassets/gradient_life.imageset/gradient_life.pdf b/Yep/Images.xcassets/gradient_life.imageset/gradient_life.pdf new file mode 100644 index 0000000000000000000000000000000000000000..cd06a2555d4e36a37a1926a5a363fac2fc16127a GIT binary patch literal 6832 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 NAV9plD%z@`{{ak;4dDO) literal 0 HcmV?d00001 diff --git a/Yep/Images.xcassets/gradient_sport.imageset/Contents.json b/Yep/Images.xcassets/gradient_sport.imageset/Contents.json new file mode 100644 index 00000000..72f9ccef --- /dev/null +++ b/Yep/Images.xcassets/gradient_sport.imageset/Contents.json @@ -0,0 +1,24 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "gradient_sport.pdf", + "resizing" : { + "mode" : "3-part-horizontal", + "center" : { + "mode" : "fill", + "width" : 1 + }, + "capInsets" : { + "right" : 187, + "left" : 187 + } + } + } + ], + "info" : { + "version" : 1, + "author" : "xcode", + "template-rendering-intent" : "original" + } +} \ No newline at end of file diff --git a/Yep/Images.xcassets/gradient_sport.imageset/gradient_sport.pdf b/Yep/Images.xcassets/gradient_sport.imageset/gradient_sport.pdf new file mode 100644 index 0000000000000000000000000000000000000000..75146b313368c88309d130962135822c1dbe41ff GIT binary patch literal 6988 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 O5il5tk55@s1@u3dDNhmr literal 0 HcmV?d00001 diff --git a/Yep/Images.xcassets/gradient_tech.imageset/Contents.json b/Yep/Images.xcassets/gradient_tech.imageset/Contents.json new file mode 100644 index 00000000..ddf7fa8d --- /dev/null +++ b/Yep/Images.xcassets/gradient_tech.imageset/Contents.json @@ -0,0 +1,24 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "gradient_tech.pdf", + "resizing" : { + "mode" : "3-part-horizontal", + "center" : { + "mode" : "fill", + "width" : 1 + }, + "capInsets" : { + "right" : 187, + "left" : 187 + } + } + } + ], + "info" : { + "version" : 1, + "author" : "xcode", + "template-rendering-intent" : "original" + } +} \ No newline at end of file diff --git a/Yep/Images.xcassets/gradient_tech.imageset/gradient_tech.pdf b/Yep/Images.xcassets/gradient_tech.imageset/gradient_tech.pdf new file mode 100644 index 0000000000000000000000000000000000000000..91298276dcebfd69d74b8edd31d6795a2e071c66 GIT binary patch literal 7018 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 literal 0 HcmV?d00001 diff --git a/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift b/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift index c5d79d2e..9c487286 100644 --- a/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift +++ b/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift @@ -99,6 +99,9 @@ class SkillHomeViewController: CustomNavigationBarViewController { override func viewDidLoad() { super.viewDidLoad() + if let skillCategory = skill?.category { + headerView.skillCategory = skillCategory + } headerView.skillCoverURLString = skillCoverURLString masterTableView.separatorColor = UIColor.yepCellSeparatorColor() diff --git a/Yep/Views/Cells/Skill/SkillCell.swift b/Yep/Views/Cells/Skill/SkillCell.swift index 4bb1f457..8b8027bf 100644 --- a/Yep/Views/Cells/Skill/SkillCell.swift +++ b/Yep/Views/Cells/Skill/SkillCell.swift @@ -41,6 +41,19 @@ class SkillCell: UICollectionViewCell { case Technology = "Technology" case Sport = "Sport" case LifeStyle = "Life Style" + + var gradientImage: UIImage? { + switch self { + case .Art: + return UIImage(named: "gradient_art") + case .Technology: + return UIImage(named: "gradient_tech") + case .Sport: + return UIImage(named: "gradient_sport") + case .LifeStyle: + return UIImage(named: "gradient_life") + } + } } let category: Category diff --git a/Yep/Views/SkillHomeHeaderView/SkillHomeHeaderView.swift b/Yep/Views/SkillHomeHeaderView/SkillHomeHeaderView.swift index 02c30215..23ff21c9 100644 --- a/Yep/Views/SkillHomeHeaderView/SkillHomeHeaderView.swift +++ b/Yep/Views/SkillHomeHeaderView/SkillHomeHeaderView.swift @@ -11,13 +11,14 @@ import Kingfisher class SkillHomeHeaderView: UIView { + var skillCategory: SkillCell.Skill.Category = .Art var skillCoverURLString: String? { willSet { if let coverURLString = newValue, URL = NSURL(string: coverURLString) { - headerImageView.kf_setImageWithURL(URL, placeholderImage: UIImage(named: "Cover3")) + headerImageView.kf_setImageWithURL(URL, placeholderImage: skillCategory.gradientImage) } else { - headerImageView.image = UIImage(named: "Cover3") + headerImageView.image = skillCategory.gradientImage } } }