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 21ff1372..d0d13467 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 */; }; @@ -210,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 */ @@ -271,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 = ""; }; @@ -321,6 +324,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 = ""; }; @@ -434,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 */ @@ -458,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; }; @@ -782,6 +789,7 @@ 5019F62F1B39BFCB0000D993 /* ConversationMore */, 500A0B201B451A7400D49358 /* Badge */, 504F85AD1B4D21E400F909BE /* DiscoverFilter */, + 5044BF071B5FA75000930ADC /* BubbleMenu */, ); name = Views; sourceTree = ""; @@ -1030,6 +1038,14 @@ name = Conversation; sourceTree = ""; }; + 5044BF071B5FA75000930ADC /* BubbleMenu */ = { + isa = PBXGroup; + children = ( + 5044BF051B5FA74800930ADC /* BubbleMenuView.swift */, + ); + name = BubbleMenu; + sourceTree = ""; + }; 504CBA3B1B3D048900663A90 /* TextViews */ = { isa = PBXGroup; children = ( @@ -1455,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 = ""; @@ -1478,6 +1496,7 @@ 0AD7EA5B1AC3ECD700617758 /* libPushSDK-1.8.3.a */, 0AD7EA511AC3EA6F00617758 /* JPushSDK.framework */, FD88F6095DB46DFAD41AB5DB /* Pods.framework */, + C3146F0F60F2A38BC6E0FA66 /* Pods_Yep.framework */, ); name = Frameworks; sourceTree = ""; @@ -1657,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 */ = { @@ -1672,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 */ = { @@ -1802,6 +1821,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 */, @@ -1971,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"; @@ -1998,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"; 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/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/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 00000000..3c73bd65 Binary files /dev/null and b/Yep/Images.xcassets/gradient_art.imageset/gradient_art.pdf differ 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 00000000..cd06a255 Binary files /dev/null and b/Yep/Images.xcassets/gradient_life.imageset/gradient_life.pdf differ 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 00000000..75146b31 Binary files /dev/null and b/Yep/Images.xcassets/gradient_sport.imageset/gradient_sport.pdf differ 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 00000000..91298276 Binary files /dev/null and b/Yep/Images.xcassets/gradient_tech.imageset/gradient_tech.pdf differ 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/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index f601d591..d284208a 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -109,6 +109,13 @@ class ConversationViewController: BaseViewController { @IBOutlet weak var takePhotoButton: MessageTypeButton! @IBOutlet weak var addLocationButton: MessageTypeButton! + var currentMenu: BubbleMenuView? + + func removeOldMenu() { + currentMenu?.hide() + currentMenu = nil + } + var originalNavigationControllerDelegate: UINavigationControllerDelegate? var waverView: YepWaverView! @@ -525,6 +532,8 @@ class ConversationViewController: BaseViewController { messageToolbar.stateTransitionAction = { [weak self] (messageToolbar, previousState, currentState) in + self?.removeOldMenu() + if let strongSelf = self { switch (previousState, currentState) { @@ -634,8 +643,6 @@ class ConversationViewController: BaseViewController { override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) - - conversationCollectionViewHasBeenMovedToBottomOnce = true FayeService.sharedManager.delegate = self @@ -668,6 +675,49 @@ class ConversationViewController: BaseViewController { self.navigationController?.setNavigationBarHidden(false, animated: true) self.setNeedsStatusBarAppearanceUpdate() + + + /* + // test menu + + if true { + + 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) + + 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 copyItem = BubbleMenuView.Item(title: "Copy") { + print("copy\n") + } + + let menu = BubbleMenuView(items: [copyItem]) + + 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) { @@ -700,6 +750,12 @@ class ConversationViewController: BaseViewController { } } + override func viewWillDisappear(animated: Bool) { + super.viewWillDisappear(animated) + + removeOldMenu() + } + override func viewDidDisappear(animated: Bool) { super.viewDidDisappear(animated) @@ -971,6 +1027,8 @@ class ConversationViewController: BaseViewController { func moreAction() { + removeOldMenu() + messageToolbar.state = .Default moreView.showProfileAction = { [weak self] in @@ -1802,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 @@ -1886,12 +1945,40 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.configureWithMessage(message, textContentLabelWidth: textContentLabelWidthOfMessage(message), collectionView: collectionView, indexPath: indexPath) + cell.longPressAction = { [weak self] cell in + + self?.removeOldMenu() + + if let strongSelf = self { + + let copyItem = BubbleMenuView.Item(type: .Normal, title: NSLocalizedString("Copy", comment: "")) { menu in + print("copy\n") + + UIPasteboard.generalPasteboard().string = cell.textContentTextView.text + + menu.hide() + self?.currentMenu = nil + } + + let bubbleFrame = cell.convertRect(cell.bubbleBodyImageView.frame, toView: strongSelf.view) + + let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(bubbleFrame) < YepConfig.Conversation.menuDirectionUpThreshold ? .Up : .Down + + let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem]) + + strongSelf.currentMenu = menu + + menu.showInView(strongSelf.view, withBubbleFrame: bubbleFrame) + } + } + return cell } } else { // from Me switch message.mediaType { + case MessageMediaType.Image.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightImageCellIdentifier, forIndexPath: indexPath) as! ChatRightImageCell @@ -2063,77 +2150,109 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } }, collectionView: collectionView, indexPath: indexPath) - cell.deleteMessageAction = { [weak self] in - dispatch_async(dispatch_get_main_queue()) { - if let strongSelf = self, realm = message.realm { + cell.longPressAction = { [weak self] cell in - var sectionDateMessage: Message? + self?.removeOldMenu() - if let currentMessageIndex = strongSelf.messages.indexOf(message) { + if let strongSelf = self { - let previousMessageIndex = currentMessageIndex - 1 + let copyItem = BubbleMenuView.Item(type: .Normal, title: NSLocalizedString("Copy", comment: "")) { menu in + print("copy\n") - if let previousMessage = strongSelf.messages[safe: previousMessageIndex] { + UIPasteboard.generalPasteboard().string = cell.textContentTextView.text - if previousMessage.mediaType == MessageMediaType.SectionDate.rawValue { - sectionDateMessage = previousMessage - } - } - } - - let currentIndexPath: NSIndexPath - if let index = strongSelf.messages.indexOf(message) { - currentIndexPath = NSIndexPath(forItem: index - strongSelf.displayedMessagesRange.location, inSection: indexPath.section) - } else { - currentIndexPath = indexPath - } - - if let sectionDateMessage = sectionDateMessage { - - var canDeleteTwoMessages = false // 考虑刚好的边界情况,例如消息为本束的最后一条,而 sectionDate 在上一束中 - if strongSelf.displayedMessagesRange.length >= 2 { - strongSelf.displayedMessagesRange.length -= 2 - canDeleteTwoMessages = true - - } else { - if strongSelf.displayedMessagesRange.location >= 1 { - strongSelf.displayedMessagesRange.location -= 1 - } - strongSelf.displayedMessagesRange.length -= 1 - } - - realm.write { - if let mediaMetaData = sectionDateMessage.mediaMetaData { - realm.delete(mediaMetaData) - } - if let mediaMetaData = message.mediaMetaData { - realm.delete(mediaMetaData) - } - realm.delete(sectionDateMessage) - realm.delete(message) - } - - if canDeleteTwoMessages { - let previousIndexPath = NSIndexPath(forItem: currentIndexPath.item - 1, inSection: currentIndexPath.section) - strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([previousIndexPath, currentIndexPath]) - } else { - strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) - } - - } else { - strongSelf.displayedMessagesRange.length -= 1 - realm.write { - if let mediaMetaData = message.mediaMetaData { - realm.delete(mediaMetaData) - } - realm.delete(message) - } - strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) - } - - // 必须更新,插入时需要 - strongSelf.lastTimeMessagesCount = strongSelf.messages.count + menu.hide() + self?.currentMenu = nil } + + let deleteItem = BubbleMenuView.Item(type: .Danger, title: NSLocalizedString("Delete", comment: "")) { menu in + print("delete\n") + + dispatch_async(dispatch_get_main_queue()) { + if let strongSelf = self, realm = message.realm { + + var sectionDateMessage: Message? + + if let currentMessageIndex = strongSelf.messages.indexOf(message) { + + let previousMessageIndex = currentMessageIndex - 1 + + if let previousMessage = strongSelf.messages[safe: previousMessageIndex] { + + if previousMessage.mediaType == MessageMediaType.SectionDate.rawValue { + sectionDateMessage = previousMessage + } + } + } + + let currentIndexPath: NSIndexPath + if let index = strongSelf.messages.indexOf(message) { + currentIndexPath = NSIndexPath(forItem: index - strongSelf.displayedMessagesRange.location, inSection: indexPath.section) + } else { + currentIndexPath = indexPath + } + + if let sectionDateMessage = sectionDateMessage { + + var canDeleteTwoMessages = false // 考虑刚好的边界情况,例如消息为本束的最后一条,而 sectionDate 在上一束中 + if strongSelf.displayedMessagesRange.length >= 2 { + strongSelf.displayedMessagesRange.length -= 2 + canDeleteTwoMessages = true + + } else { + if strongSelf.displayedMessagesRange.location >= 1 { + strongSelf.displayedMessagesRange.location -= 1 + } + strongSelf.displayedMessagesRange.length -= 1 + } + + realm.write { + if let mediaMetaData = sectionDateMessage.mediaMetaData { + realm.delete(mediaMetaData) + } + if let mediaMetaData = message.mediaMetaData { + realm.delete(mediaMetaData) + } + realm.delete(sectionDateMessage) + realm.delete(message) + } + + if canDeleteTwoMessages { + let previousIndexPath = NSIndexPath(forItem: currentIndexPath.item - 1, inSection: currentIndexPath.section) + strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([previousIndexPath, currentIndexPath]) + } else { + strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) + } + + } else { + strongSelf.displayedMessagesRange.length -= 1 + realm.write { + if let mediaMetaData = message.mediaMetaData { + realm.delete(mediaMetaData) + } + realm.delete(message) + } + strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) + } + + // 必须更新,插入时需要 + strongSelf.lastTimeMessagesCount = strongSelf.messages.count + } + } + + menu.hide() + self?.currentMenu = nil + } + + let bubbleFrame = cell.convertRect(cell.bubbleBodyImageView.frame, toView: strongSelf.view) + + 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, withBubbleFrame: bubbleFrame) } } @@ -2186,6 +2305,8 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi func scrollViewDidScroll(scrollView: UIScrollView) { pullToRefreshView.scrollViewDidScroll(scrollView) + + removeOldMenu() } func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { diff --git a/Yep/ViewControllers/Profile/ProfileViewController.swift b/Yep/ViewControllers/Profile/ProfileViewController.swift index a10dd43c..edfb5c71 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, category: skill.skillCategory) 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, category: userSkill.skillCategory) } } - 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, category: skill.skillCategory) 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, category: userSkill.skillCategory) } } - 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..9c487286 100644 --- a/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift +++ b/Yep/ViewControllers/SkillHome/SkillHomeViewController.swift @@ -31,19 +31,16 @@ class SkillHomeViewController: CustomNavigationBarViewController { return tempTableView; }() - var skillID: String? - - var skillLocalName: String? { + var skill: SkillCell.Skill? { willSet { - title = newValue + title = newValue?.localName + skillCoverURLString = newValue?.coverURLString } } var skillCoverURLString: String? { willSet { - if let coverURLString = newValue { - headerView?.skillCoverURLString = coverURLString - } + headerView?.skillCoverURLString = newValue } } @@ -102,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() @@ -124,7 +124,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 +242,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 +369,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/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift new file mode 100644 index 00000000..e4b1b322 --- /dev/null +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -0,0 +1,269 @@ +// +// BubbleMenuView.swift +// Yep +// +// Created by NIX on 15/7/22. +// Copyright (c) 2015年 Catch Inc. All rights reserved. +// + +import UIKit + +class BubbleMenuView: UIView { + + enum ArrowDirection { + case Up + case Down + } + + struct Item { + + enum Type { + case Normal + case Danger + } + let type: Type + + let title: String + + let action: BubbleMenuView -> Void + } + + var arrowDirection: ArrowDirection + var items: [Item] + + var buttons = [UIButton]() + + init(arrowDirection: ArrowDirection, items: [Item]) { + + self.arrowDirection = arrowDirection + self.items = items + + super.init(frame: CGRectZero) + + makeUI() + } + + required init(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: Actions + + func tapButton(button: UIButton) { + if let index = find(buttons, button) { + let action = items[index].action + action(self) + } + } + + func showInView(view: UIView, withBubbleFrame bubbleFrame: CGRect) { + + // position + + setTranslatesAutoresizingMaskIntoConstraints(false) + view.addSubview(self) + + var vConstant = CGRectGetMidY(bubbleFrame) - CGRectGetMidY(view.frame) + + let menuV: NSLayoutConstraint + + switch arrowDirection { + + case .Up: + vConstant += ceil(CGRectGetHeight(bubbleFrame) * 0.5) - offsetV + + menuV = NSLayoutConstraint(item: self, attribute: .Top, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: vConstant) + + case .Down: + vConstant -= ceil(CGRectGetHeight(bubbleFrame) * 0.5) - offsetV + + menuV = NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: vConstant) + } + + let centerXConstant = CGRectGetMidX(bubbleFrame) - CGRectGetMidX(view.frame) + + let menuCenterX = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) + + NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) + + + // animation + + transform = CGAffineTransformMakeScale(0.0001, 0.0001) + + UIView.animateWithDuration(0.25, delay: 0.0, usingSpringWithDamping: 0.65, initialSpringVelocity: 0.0, options: UIViewAnimationOptions(0), animations: { _ in + self.transform = CGAffineTransformMakeScale(1.0, 1.0) + }, completion: { finished in + self.transform = CGAffineTransformIdentity + }) + } + + func hide() { + + UIView.animateWithDuration(0.1, delay: 0.0, options: .CurveEaseInOut, animations: { _ in + self.transform = CGAffineTransformMakeScale(0.0001, 0.0001) + + }, completion: { finished in + self.removeFromSuperview() + }) + } + + // MARK: UI + + let arrowHeight: CGFloat = 8 + let buttonGap: CGFloat = 16 + let offsetV: CGFloat = -1 + + func makeUI() { + + backgroundColor = UIColor.clearColor() + + var format = "H:|" + + for (index, item) in enumerate(items) { + + let button = UIButton() + + switch item.type { + + case .Normal: + + button.setTitleColor(UIColor.whiteColor(), forState: .Normal) + button.setTitleColor(UIColor.lightGrayColor(), forState: .Highlighted) + + case .Danger: + + let dangerRed = UIColor(red: 1, green: 0.4, blue: 0.4, alpha: 1) + + button.setTitleColor(dangerRed, forState: .Normal) + button.setTitleColor(dangerRed.colorWithAlphaComponent(0.3), forState: .Highlighted) + } + + button.setTitle(item.title, forState: .Normal) + button.addTarget(self, action: "tapButton:", forControlEvents: .TouchUpInside) + + button.setTranslatesAutoresizingMaskIntoConstraints(false) + + addSubview(button) + + buttons.append(button) + + if index == 0 { + format += "-[button\(index)]" + } else { + format += "-(\(buttonGap))-[button\(index)(==button0)]" + } + } + + format += "-|" + + var views = [NSObject: AnyObject]() + + for (index, button) in enumerate(buttons) { + let key = "button\(index)" + views[key] = button + } + + let hConstraints = NSLayoutConstraint.constraintsWithVisualFormat(format, options: .AlignAllCenterY, metrics: nil, views: views) + + NSLayoutConstraint.activateConstraints(hConstraints) + + if let firstButton = buttons.first { + + let firstButtonTop = NSLayoutConstraint(item: firstButton, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0) + + switch arrowDirection { + + case .Up: + + let firstButtonTop = NSLayoutConstraint(item: firstButton, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: arrowHeight) + let firstButtonBottom = NSLayoutConstraint(item: firstButton, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: 0) + + NSLayoutConstraint.activateConstraints([firstButtonTop, firstButtonBottom]) + + case .Down: + + let firstButtonTop = NSLayoutConstraint(item: firstButton, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0) + let firstButtonBottom = NSLayoutConstraint(item: firstButton, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: -arrowHeight) + + NSLayoutConstraint.activateConstraints([firstButtonTop, firstButtonBottom]) + } + } + } + + override func drawRect(rect: CGRect) { + + UIColor.blackColor().colorWithAlphaComponent(0.6).setFill() + + // bubble + + var roundedRect = rect + + switch arrowDirection { + + case .Up: + roundedRect.origin.y += arrowHeight + roundedRect.size.height -= arrowHeight + + case .Down: + roundedRect.size.height -= arrowHeight + } + + let bubblePath = UIBezierPath(roundedRect: roundedRect, cornerRadius: 5) + bubblePath.fill() + + + // arrow + + switch arrowDirection { + + case .Up: + let topX = CGRectGetMidX(rect) + let topY = CGRectGetMinY(rect) + + let arrowPath = UIBezierPath() + arrowPath.moveToPoint(CGPointMake(topX, topY)) + arrowPath.addLineToPoint(CGPointMake(topX - (arrowHeight - 1), topY + arrowHeight)) + arrowPath.addLineToPoint(CGPointMake(topX + (arrowHeight - 1), topY + arrowHeight)) + arrowPath.closePath() + arrowPath.fill() + + case .Down: + let buttomX = CGRectGetMidX(rect) + let buttomY = CGRectGetMaxY(rect) + + let arrowPath = UIBezierPath() + arrowPath.moveToPoint(CGPointMake(buttomX, buttomY)) + arrowPath.addLineToPoint(CGPointMake(buttomX - (arrowHeight - 1), buttomY - arrowHeight)) + arrowPath.addLineToPoint(CGPointMake(buttomX + (arrowHeight - 1), buttomY - arrowHeight)) + arrowPath.closePath() + arrowPath.fill() + } + + + // lines + + UIColor.whiteColor().colorWithAlphaComponent(0.3).setStroke() + + for (index, button) in enumerate(buttons) { + if index > 0 { + let line = UIBezierPath() + + let x = CGRectGetMinX(button.frame) - buttonGap * 0.5 + let y = CGRectGetMaxY(rect) + + line.moveToPoint(CGPoint(x: x , y: 0)) + line.addLineToPoint(CGPoint(x: x, y: y)) + + line.lineWidth = 1 + + line.stroke() + } + } + } + +} + + + + diff --git a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift index de7f7919..9cb14931 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() @@ -38,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) @@ -59,13 +52,7 @@ 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) } } diff --git a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift index 15641756..66e9bf20 100644 --- a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift +++ b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift @@ -22,10 +22,11 @@ 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)? + override func awakeFromNib() { super.awakeFromNib() @@ -43,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) @@ -65,13 +60,7 @@ 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/Cells/Skill/SkillCell.swift b/Yep/Views/Cells/Skill/SkillCell.swift index 5b30ee77..8b8027bf 100644 --- a/Yep/Views/Cells/Skill/SkillCell.swift +++ b/Yep/Views/Cells/Skill/SkillCell.swift @@ -31,15 +31,47 @@ 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? + + enum Category: String { + case Art = "Art" + 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 + + init(ID: String, localName: String, coverURLString: String?, category: Category?) { + self.ID = ID + self.localName = localName + self.coverURLString = coverURLString + self.category = category ?? .Art } } - 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 +80,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) + } } } } diff --git a/Yep/Views/SkillHomeHeaderView/SkillHomeHeaderView.swift b/Yep/Views/SkillHomeHeaderView/SkillHomeHeaderView.swift index b0cc36dd..23ff21c9 100644 --- a/Yep/Views/SkillHomeHeaderView/SkillHomeHeaderView.swift +++ b/Yep/Views/SkillHomeHeaderView/SkillHomeHeaderView.swift @@ -11,10 +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 = skillCategory.gradientImage } } } diff --git a/Yep/Views/TextViews/ChatTextView.swift b/Yep/Views/TextViews/ChatTextView.swift index f81fcd8e..c9b44672 100644 --- a/Yep/Views/TextViews/ChatTextView.swift +++ b/Yep/Views/TextViews/ChatTextView.swift @@ -10,26 +10,7 @@ import UIKit 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:") - } + override func canBecomeFirstResponder() -> Bool { + return false } }