mirror of
https://github.com/wahyd4/Yep.git
synced 2026-08-24 20:26:02 +10:00
Merge branch 'feature/better_message_preview' into develop
This commit is contained in:
@@ -103,6 +103,7 @@
|
||||
506E241E1AE6391A00A33C1A /* TouchZoomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506E241D1AE6391A00A33C1A /* TouchZoomButton.swift */; };
|
||||
506EC20A1AC95BFC00CE42B3 /* UIFont+Yep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 506EC2091AC95BFC00CE42B3 /* UIFont+Yep.swift */; };
|
||||
5076C56A1AC46B9F00B22952 /* FayeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5076C5691AC46B9F00B22952 /* FayeService.swift */; };
|
||||
5076FC5A1AF9DF6B00D7381A /* ConversationMessagePreviewTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5076FC591AF9DF6B00D7381A /* ConversationMessagePreviewTransitionManager.swift */; };
|
||||
50894CF11AEA4726000981AF /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50894CF01AEA4726000981AF /* SettingsViewController.swift */; };
|
||||
50894CF51AEA4A01000981AF /* SettingsUserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50894CF31AEA4A01000981AF /* SettingsUserCell.swift */; };
|
||||
50894CF61AEA4A01000981AF /* SettingsUserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 50894CF41AEA4A01000981AF /* SettingsUserCell.xib */; };
|
||||
@@ -143,6 +144,7 @@
|
||||
50CDBE461ACA9F2200459CE0 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CDBE451ACA9F2200459CE0 /* ImageCache.swift */; };
|
||||
50CDBE491ACBAD3200459CE0 /* ChatLeftImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50CDBE471ACBAD3200459CE0 /* ChatLeftImageCell.swift */; };
|
||||
50CDBE4A1ACBAD3200459CE0 /* ChatLeftImageCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 50CDBE481ACBAD3200459CE0 /* ChatLeftImageCell.xib */; };
|
||||
50D4D0DB1AFA825B005AEB6F /* MediaControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50D4D0DA1AFA825B005AEB6F /* MediaControlView.swift */; };
|
||||
50E114F41ABBF9CC00F13000 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E114F31ABBF9CC00F13000 /* Models.swift */; };
|
||||
50E114F71ABBFA7000F13000 /* RLMSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E114F61ABBFA7000F13000 /* RLMSupport.swift */; };
|
||||
50E114F91ABC137A00F13000 /* YepServiceSync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E114F81ABC137A00F13000 /* YepServiceSync.swift */; };
|
||||
@@ -273,6 +275,7 @@
|
||||
506E241D1AE6391A00A33C1A /* TouchZoomButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TouchZoomButton.swift; path = Views/Buttons/TouchZoomButton.swift; sourceTree = "<group>"; };
|
||||
506EC2091AC95BFC00CE42B3 /* UIFont+Yep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIFont+Yep.swift"; path = "Extensions/UIFont+Yep.swift"; sourceTree = "<group>"; };
|
||||
5076C5691AC46B9F00B22952 /* FayeService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FayeService.swift; path = Services/FayeService.swift; sourceTree = "<group>"; };
|
||||
5076FC591AF9DF6B00D7381A /* ConversationMessagePreviewTransitionManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationMessagePreviewTransitionManager.swift; path = ViewControllers/Conversation/ConversationMessagePreviewTransitionManager.swift; sourceTree = "<group>"; };
|
||||
50894CF01AEA4726000981AF /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SettingsViewController.swift; path = ViewControllers/Settings/SettingsViewController.swift; sourceTree = "<group>"; };
|
||||
50894CF31AEA4A01000981AF /* SettingsUserCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SettingsUserCell.swift; path = Views/Cells/SettingsUser/SettingsUserCell.swift; sourceTree = "<group>"; };
|
||||
50894CF41AEA4A01000981AF /* SettingsUserCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = SettingsUserCell.xib; path = Views/Cells/SettingsUser/SettingsUserCell.xib; sourceTree = "<group>"; };
|
||||
@@ -313,6 +316,7 @@
|
||||
50CDBE451ACA9F2200459CE0 /* ImageCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageCache.swift; path = Caches/ImageCache.swift; sourceTree = "<group>"; };
|
||||
50CDBE471ACBAD3200459CE0 /* ChatLeftImageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChatLeftImageCell.swift; path = Views/Cells/ChatLeftImage/ChatLeftImageCell.swift; sourceTree = "<group>"; };
|
||||
50CDBE481ACBAD3200459CE0 /* ChatLeftImageCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ChatLeftImageCell.xib; path = Views/Cells/ChatLeftImage/ChatLeftImageCell.xib; sourceTree = "<group>"; };
|
||||
50D4D0DA1AFA825B005AEB6F /* MediaControlView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MediaControlView.swift; path = Views/Media/MediaControlView.swift; sourceTree = "<group>"; };
|
||||
50E114F31ABBF9CC00F13000 /* Models.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Models.swift; path = Realm/Models.swift; sourceTree = "<group>"; };
|
||||
50E114F61ABBFA7000F13000 /* RLMSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RLMSupport.swift; path = Realm/RLMSupport.swift; sourceTree = "<group>"; };
|
||||
50E114F81ABC137A00F13000 /* YepServiceSync.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = YepServiceSync.swift; path = Services/YepServiceSync.swift; sourceTree = "<group>"; };
|
||||
@@ -769,6 +773,7 @@
|
||||
children = (
|
||||
503CAB421AC00CB100DFE830 /* ConversationViewController.swift */,
|
||||
50165C441AC2860900C7AEBE /* ConversationLayout.swift */,
|
||||
5076FC591AF9DF6B00D7381A /* ConversationMessagePreviewTransitionManager.swift */,
|
||||
);
|
||||
name = Conversation;
|
||||
sourceTree = "<group>";
|
||||
@@ -1060,6 +1065,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
50EB8CCA1AEA1AC0001AC1EE /* MediaView.swift */,
|
||||
50D4D0DA1AFA825B005AEB6F /* MediaControlView.swift */,
|
||||
);
|
||||
name = Media;
|
||||
sourceTree = "<group>";
|
||||
@@ -1327,6 +1333,7 @@
|
||||
508D174C1ACCF49B0092D666 /* ChatRightAudioCell.swift in Sources */,
|
||||
502AE53D1AB87C0D005BD199 /* YepUserDefaults.swift in Sources */,
|
||||
50EB8CC41AE89F12001AC1EE /* ChatRightVideoCell.swift in Sources */,
|
||||
50D4D0DB1AFA825B005AEB6F /* MediaControlView.swift in Sources */,
|
||||
508D17471ACCF4710092D666 /* ChatLeftAudioCell.swift in Sources */,
|
||||
50894D021AEA6433000981AF /* EditProfileLessInfoCell.swift in Sources */,
|
||||
50894CFA1AEA54BA000981AF /* SettingsMoreCell.swift in Sources */,
|
||||
@@ -1362,6 +1369,7 @@
|
||||
506EC20A1AC95BFC00CE42B3 /* UIFont+Yep.swift in Sources */,
|
||||
0A0A11821AE389380008772C /* RegisterSkillsLayout.swift in Sources */,
|
||||
50C0909B1ADE234F00CC6389 /* RegisterPickSkillsViewController.swift in Sources */,
|
||||
5076FC5A1AF9DF6B00D7381A /* ConversationMessagePreviewTransitionManager.swift in Sources */,
|
||||
508D16BD1ADCAF0400270E3F /* PullToRefreshView.swift in Sources */,
|
||||
508D17441ACCDC9F0092D666 /* VoiceRecordButton.swift in Sources */,
|
||||
502AE5271AB72D06005BD199 /* YepNetworking.swift in Sources */,
|
||||
|
||||
@@ -71,15 +71,15 @@
|
||||
<outlet property="delegate" destination="la3-6z-2aH" id="zOV-zM-2KH"/>
|
||||
</connections>
|
||||
</collectionView>
|
||||
<toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Q0w-sM-iIR" customClass="MessageToolbar" customModule="Yep" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="250" width="600" height="50"/>
|
||||
<toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Q0w-sM-iIR" customClass="MessageToolbar" customModule="Yep" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="396" width="600" height="44"/>
|
||||
<items/>
|
||||
</toolbar>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="g11-Ob-rEy" userLabel="More Message Types View">
|
||||
<rect key="frame" x="0.0" y="300" width="600" height="300"/>
|
||||
<rect key="frame" x="0.0" y="440" width="600" height="300"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="avI-im-eEZ" userLabel="Choose Photo Button" customClass="MessageTypeButton" customModule="Yep" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="20" width="173" height="120"/>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="avI-im-eEZ" userLabel="Choose Photo Button" customClass="MessageTypeButton" customModule="Yep" customModuleProvider="target">
|
||||
<rect key="frame" x="20" y="20" width="173" height="260"/>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
@@ -88,8 +88,8 @@
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="title" value="Choose photo"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="HcA-7v-16m" userLabel="Take Photo Button" customClass="MessageTypeButton" customModule="Yep" customModuleProvider="target">
|
||||
<rect key="frame" x="213" y="20" width="174" height="120"/>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="HcA-7v-16m" userLabel="Take Photo Button" customClass="MessageTypeButton" customModule="Yep" customModuleProvider="target">
|
||||
<rect key="frame" x="213" y="20" width="174" height="260"/>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
@@ -98,8 +98,8 @@
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="title" value="Take photo"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Hg3-Ss-sqD" userLabel="Add Location Button" customClass="MessageTypeButton" customModule="Yep" customModuleProvider="target">
|
||||
<rect key="frame" x="407" y="20" width="173" height="120"/>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Hg3-Ss-sqD" userLabel="Add Location Button" customClass="MessageTypeButton" customModule="Yep" customModuleProvider="target">
|
||||
<rect key="frame" x="407" y="20" width="173" height="260"/>
|
||||
<state key="normal">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
@@ -120,6 +120,7 @@
|
||||
<constraint firstItem="avI-im-eEZ" firstAttribute="height" secondItem="HcA-7v-16m" secondAttribute="height" id="apZ-ns-N9S"/>
|
||||
<constraint firstItem="avI-im-eEZ" firstAttribute="top" secondItem="g11-Ob-rEy" secondAttribute="top" constant="20" id="b4S-GW-ghP"/>
|
||||
<constraint firstAttribute="height" constant="300" id="faf-Xw-b0H"/>
|
||||
<constraint firstAttribute="bottom" secondItem="avI-im-eEZ" secondAttribute="bottom" constant="20" id="sv1-0R-BYO"/>
|
||||
<constraint firstItem="Hg3-Ss-sqD" firstAttribute="leading" secondItem="HcA-7v-16m" secondAttribute="trailing" constant="20" id="uSu-cr-saV"/>
|
||||
<constraint firstItem="avI-im-eEZ" firstAttribute="leading" secondItem="g11-Ob-rEy" secondAttribute="leading" constant="20" id="uke-uY-P5h"/>
|
||||
<constraint firstItem="Hg3-Ss-sqD" firstAttribute="height" secondItem="HcA-7v-16m" secondAttribute="height" id="xWM-E0-CPp"/>
|
||||
@@ -133,7 +134,7 @@
|
||||
<constraint firstItem="g11-Ob-rEy" firstAttribute="leading" secondItem="P6X-OT-hT5" secondAttribute="leading" id="B04-LV-qWQ"/>
|
||||
<constraint firstItem="Q0w-sM-iIR" firstAttribute="leading" secondItem="P6X-OT-hT5" secondAttribute="leading" id="BYY-lE-CF8"/>
|
||||
<constraint firstItem="o5R-dM-KPW" firstAttribute="leading" secondItem="P6X-OT-hT5" secondAttribute="leading" id="BjN-8c-WjM"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Q0w-sM-iIR" secondAttribute="bottom" constant="300" id="Sf8-1u-t01"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Q0w-sM-iIR" secondAttribute="bottom" constant="160" id="Sf8-1u-t01"/>
|
||||
<constraint firstItem="g11-Ob-rEy" firstAttribute="top" secondItem="Q0w-sM-iIR" secondAttribute="bottom" id="UC0-RV-osX"/>
|
||||
<constraint firstAttribute="trailing" secondItem="g11-Ob-rEy" secondAttribute="trailing" id="cB1-tg-2P7"/>
|
||||
<constraint firstItem="o5R-dM-KPW" firstAttribute="top" secondItem="P6X-OT-hT5" secondAttribute="top" id="d3q-cT-PCM"/>
|
||||
@@ -243,12 +244,22 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="2Cb-zQ-dUZ" customClass="MediaControlView" customModule="Yep" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="540" width="600" height="60"/>
|
||||
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="60" id="2CO-oT-53G"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<gestureRecognizers/>
|
||||
<constraints>
|
||||
<constraint firstItem="eW6-5y-wrX" firstAttribute="top" secondItem="k4j-Ub-3bn" secondAttribute="bottom" id="SD4-Rb-R2n"/>
|
||||
<constraint firstItem="k4j-Ub-3bn" firstAttribute="top" secondItem="aNq-7S-JK2" secondAttribute="top" id="Zbg-wi-X7W"/>
|
||||
<constraint firstAttribute="trailing" secondItem="2Cb-zQ-dUZ" secondAttribute="trailing" id="gVX-Fl-qnR"/>
|
||||
<constraint firstItem="2Cb-zQ-dUZ" firstAttribute="leading" secondItem="aNq-7S-JK2" secondAttribute="leading" id="lDq-Nl-fPd"/>
|
||||
<constraint firstItem="eW6-5y-wrX" firstAttribute="top" secondItem="2Cb-zQ-dUZ" secondAttribute="bottom" id="o3u-xh-Qwa"/>
|
||||
<constraint firstItem="k4j-Ub-3bn" firstAttribute="leading" secondItem="aNq-7S-JK2" secondAttribute="leading" id="xJR-ze-vBa"/>
|
||||
<constraint firstAttribute="trailing" secondItem="k4j-Ub-3bn" secondAttribute="trailing" id="xvH-sO-9MX"/>
|
||||
</constraints>
|
||||
@@ -257,6 +268,7 @@
|
||||
</connections>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="mediaControlView" destination="2Cb-zQ-dUZ" id="x2S-Ga-6sm"/>
|
||||
<outlet property="mediaView" destination="k4j-Ub-3bn" id="RmJ-k6-aF2"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
|
||||
@@ -1081,15 +1081,25 @@ func sendMessageWithMediaType(mediaType: MessageMediaType, inFilePath filePath:
|
||||
thumbnailData = UIImageJPEGRepresentation(image, YepConfig.messageImageCompressionQuality())
|
||||
}
|
||||
|
||||
s3PrivateUploadParams(failureHandler: nil) { s3UploadParams in
|
||||
uploadFileToS3(inFilePath: nil, orFileData: thumbnailData, mimeType: MessageMediaType.Image.mineType(), s3UploadParams: s3UploadParams) { (result, error) in
|
||||
s3PrivateUploadParams(failureHandler: nil) { thumbnailS3UploadParams in
|
||||
uploadFileToS3(inFilePath: nil, orFileData: thumbnailData, mimeType: MessageMediaType.Image.mineType(), s3UploadParams: thumbnailS3UploadParams) { (result, error) in
|
||||
|
||||
if let metaData = metaData {
|
||||
let attachments = ["video": [["file": s3UploadParams.key, "metadata": metaData]], "thumbnail": [["file": s3UploadParams.key]]]
|
||||
let attachments = [
|
||||
"video": [
|
||||
["file": s3UploadParams.key, "metadata": metaData]
|
||||
],
|
||||
"thumbnail": [["file": thumbnailS3UploadParams.key]]
|
||||
]
|
||||
messageInfo["attachments"] = attachments
|
||||
|
||||
} else {
|
||||
let attachments = ["video": [["file": s3UploadParams.key]], "thumbnail": [["file": s3UploadParams.key]]]
|
||||
let attachments = [
|
||||
"video": [
|
||||
["file": s3UploadParams.key]
|
||||
],
|
||||
"thumbnail": [["file": thumbnailS3UploadParams.key]]
|
||||
]
|
||||
messageInfo["attachments"] = attachments
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ func downloadAttachmentOfMessage(message: Message) {
|
||||
let thumbnailURLString = message.thumbnailURLString
|
||||
|
||||
if !thumbnailURLString.isEmpty && message.localThumbnailName.isEmpty {
|
||||
if let url = NSURL(string: attachmentURLString) {
|
||||
if let url = NSURL(string: thumbnailURLString) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
|
||||
let data = NSData(contentsOfURL: url)
|
||||
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
//
|
||||
// ConversationMessagePreviewTransitionManager.swift
|
||||
// Yep
|
||||
//
|
||||
// Created by NIX on 15/5/6.
|
||||
// Copyright (c) 2015年 Catch Inc. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class ConversationMessagePreviewTransitionManager: NSObject, UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning {
|
||||
|
||||
var frame = CGRectZero
|
||||
var transitionView: UIView? {
|
||||
didSet {
|
||||
if let transitionView = transitionView {
|
||||
transitionViewSnapshot = transitionView.snapshotViewAfterScreenUpdates(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
var transitionViewSnapshot: UIView?
|
||||
|
||||
|
||||
var isPresentation = false
|
||||
|
||||
var transitionContext: UIViewControllerContextTransitioning?
|
||||
|
||||
// MARK: UIViewControllerTransitioningDelegate
|
||||
|
||||
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||
isPresentation = true
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||
isPresentation = false
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
// MARK: UIViewControllerAnimatedTransitioning
|
||||
|
||||
func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval {
|
||||
return isPresentation ? 0.5 : 0.5
|
||||
}
|
||||
|
||||
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
|
||||
|
||||
self.transitionContext = transitionContext
|
||||
|
||||
if isPresentation {
|
||||
presentTransition(transitionContext)
|
||||
} else {
|
||||
dismissTransition(transitionContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let largerOffset: CGFloat = 80
|
||||
|
||||
func presentTransition(transitionContext: UIViewControllerContextTransitioning) {
|
||||
let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as? ConversationsViewController
|
||||
let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) as? MessageMediaViewController
|
||||
|
||||
let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)
|
||||
let toView = transitionContext.viewForKey(UITransitionContextToViewKey)
|
||||
|
||||
let containerView = transitionContext.containerView()
|
||||
|
||||
containerView.addSubview(toView!)
|
||||
|
||||
let animatingVC = toVC!
|
||||
let animatingView = toView!
|
||||
|
||||
if let transitionViewSnapshot = transitionViewSnapshot {
|
||||
|
||||
animatingView.addSubview(transitionViewSnapshot)
|
||||
transitionViewSnapshot.frame = frame
|
||||
|
||||
animatingVC.view.backgroundColor = UIColor.clearColor()
|
||||
animatingVC.mediaView.alpha = 0
|
||||
animatingVC.mediaControlView.alpha = 0
|
||||
|
||||
let fullDuration = transitionDuration(transitionContext)
|
||||
|
||||
UIView.animateKeyframesWithDuration(fullDuration, delay: 0.0, options: .CalculationModeCubic, animations: { () -> Void in
|
||||
|
||||
UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.2, animations: { () -> Void in
|
||||
animatingVC.view.backgroundColor = UIColor.whiteColor()
|
||||
})
|
||||
|
||||
UIView.addKeyframeWithRelativeStartTime(0.2, relativeDuration: 0.5, animations: { () -> Void in
|
||||
transitionViewSnapshot.center = animatingView.center
|
||||
})
|
||||
|
||||
|
||||
UIView.addKeyframeWithRelativeStartTime(0.7, relativeDuration: 0.2, animations: { () -> Void in
|
||||
let targetWidth = animatingView.bounds.width + self.largerOffset
|
||||
|
||||
let dw = targetWidth - transitionViewSnapshot.bounds.width
|
||||
let ratio = targetWidth / transitionViewSnapshot.bounds.width
|
||||
let height = ratio * transitionViewSnapshot.bounds.height
|
||||
let dh = height - transitionViewSnapshot.bounds.height
|
||||
|
||||
let frame = CGRectInset(transitionViewSnapshot.frame, -dw * 0.5, -dh * 0.5)
|
||||
|
||||
transitionViewSnapshot.frame = frame
|
||||
})
|
||||
|
||||
UIView.addKeyframeWithRelativeStartTime(0.9, relativeDuration: 0.0, animations: { () -> Void in
|
||||
let ratio = (animatingView.bounds.width + self.largerOffset) / animatingView.bounds.width
|
||||
animatingVC.mediaView.transform = CGAffineTransformMakeScale(ratio, ratio)
|
||||
animatingVC.mediaView.alpha = 1
|
||||
animatingVC.mediaControlView.alpha = 1
|
||||
|
||||
transitionViewSnapshot.alpha = 0
|
||||
})
|
||||
|
||||
UIView.addKeyframeWithRelativeStartTime(0.9, relativeDuration: 0.1, animations: { () -> Void in
|
||||
animatingVC.mediaView.transform = CGAffineTransformMakeScale(1.0, 1.0)
|
||||
})
|
||||
|
||||
}, completion: { (finished) -> Void in
|
||||
transitionViewSnapshot.removeFromSuperview()
|
||||
|
||||
transitionContext.completeTransition(true)
|
||||
})
|
||||
|
||||
} else {
|
||||
transitionContext.completeTransition(false)
|
||||
}
|
||||
}
|
||||
|
||||
func dismissTransition(transitionContext: UIViewControllerContextTransitioning) {
|
||||
let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as? MessageMediaViewController
|
||||
|
||||
let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)
|
||||
|
||||
let animatingVC = fromVC!
|
||||
let animatingView = fromView!
|
||||
|
||||
let fullDuration = transitionDuration(transitionContext)
|
||||
|
||||
if let transitionViewSnapshot = transitionViewSnapshot {
|
||||
|
||||
if let transitionView = self.transitionView {
|
||||
transitionView.alpha = 0
|
||||
}
|
||||
|
||||
UIView.animateKeyframesWithDuration(fullDuration, delay: 0.0, options: .CalculationModeCubic, animations: { () -> Void in
|
||||
|
||||
UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.2, animations: { () -> Void in
|
||||
let ratio = (animatingView.bounds.width + self.largerOffset) / animatingView.bounds.width
|
||||
animatingVC.mediaView.transform = CGAffineTransformMakeScale(ratio, ratio)
|
||||
animatingVC.mediaControlView.alpha = 0
|
||||
})
|
||||
|
||||
UIView.addKeyframeWithRelativeStartTime(0.2, relativeDuration: 0.0, animations: { () -> Void in
|
||||
animatingView.addSubview(transitionViewSnapshot)
|
||||
transitionViewSnapshot.center = animatingView.center
|
||||
transitionViewSnapshot.alpha = 1
|
||||
|
||||
animatingVC.mediaView.alpha = 0
|
||||
})
|
||||
|
||||
UIView.addKeyframeWithRelativeStartTime(0.2, relativeDuration: 0.6, animations: { () -> Void in
|
||||
transitionViewSnapshot.frame = self.frame
|
||||
})
|
||||
|
||||
UIView.addKeyframeWithRelativeStartTime(0.8, relativeDuration: 0.2, animations: { () -> Void in
|
||||
animatingVC.view.backgroundColor = UIColor.clearColor()
|
||||
})
|
||||
|
||||
}, completion: { (finished) -> Void in
|
||||
|
||||
if let transitionView = self.transitionView {
|
||||
transitionView.alpha = 1
|
||||
}
|
||||
|
||||
transitionViewSnapshot.removeFromSuperview()
|
||||
|
||||
transitionContext.completeTransition(true)
|
||||
})
|
||||
|
||||
} else {
|
||||
transitionContext.completeTransition(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,8 @@ class ConversationViewController: UIViewController {
|
||||
return dateFormatter
|
||||
}()
|
||||
|
||||
var messagePreviewTransitionManager: ConversationMessagePreviewTransitionManager?
|
||||
|
||||
|
||||
var conversationCollectionViewHasBeenMovedToBottomOnce = false
|
||||
|
||||
@@ -898,11 +900,82 @@ class ConversationViewController: UIViewController {
|
||||
// MARK: Navigation
|
||||
|
||||
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
|
||||
|
||||
if segue.identifier == "presentMessageMedia" {
|
||||
|
||||
let vc = segue.destinationViewController as! MessageMediaViewController
|
||||
vc.message = sender as? Message
|
||||
|
||||
if let message = sender as? Message {
|
||||
vc.message = message
|
||||
|
||||
let indexPath = NSIndexPath(forRow: Int(messages.indexOfObject(message)) - displayedMessagesRange.location , inSection: 0)
|
||||
|
||||
if let cell = conversationCollectionView.cellForItemAtIndexPath(indexPath) {
|
||||
|
||||
var frame = CGRectZero
|
||||
var transitionView: UIView?
|
||||
|
||||
if let sender = message.fromFriend {
|
||||
if sender.friendState != UserFriendState.Me.rawValue {
|
||||
switch message.mediaType {
|
||||
|
||||
case MessageMediaType.Image.rawValue:
|
||||
let cell = cell as! ChatLeftImageCell
|
||||
transitionView = cell.messageImageView
|
||||
frame = cell.convertRect(cell.messageImageView.frame, toView: view)
|
||||
|
||||
case MessageMediaType.Video.rawValue:
|
||||
let cell = cell as! ChatLeftVideoCell
|
||||
transitionView = cell.thumbnailImageView
|
||||
frame = cell.convertRect(cell.thumbnailImageView.frame, toView: view)
|
||||
|
||||
case MessageMediaType.Location.rawValue:
|
||||
let cell = cell as! ChatLeftLocationCell
|
||||
transitionView = cell.mapImageView
|
||||
frame = cell.convertRect(cell.mapImageView.frame, toView: view)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
} else {
|
||||
switch message.mediaType {
|
||||
|
||||
case MessageMediaType.Image.rawValue:
|
||||
let cell = cell as! ChatRightImageCell
|
||||
transitionView = cell.messageImageView
|
||||
frame = cell.convertRect(cell.messageImageView.frame, toView: view)
|
||||
|
||||
case MessageMediaType.Video.rawValue:
|
||||
let cell = cell as! ChatRightVideoCell
|
||||
transitionView = cell.thumbnailImageView
|
||||
frame = cell.convertRect(cell.thumbnailImageView.frame, toView: view)
|
||||
|
||||
case MessageMediaType.Location.rawValue:
|
||||
let cell = cell as! ChatRightLocationCell
|
||||
transitionView = cell.mapImageView
|
||||
frame = cell.convertRect(cell.mapImageView.frame, toView: view)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vc.modalPresentationStyle = UIModalPresentationStyle.Custom
|
||||
|
||||
let transitionManager = ConversationMessagePreviewTransitionManager()
|
||||
transitionManager.frame = frame
|
||||
transitionManager.transitionView = transitionView
|
||||
|
||||
vc.transitioningDelegate = transitionManager
|
||||
|
||||
messagePreviewTransitionManager = transitionManager
|
||||
}
|
||||
}
|
||||
|
||||
} else if segue.identifier == "presentPickLocation" {
|
||||
|
||||
let nvc = segue.destinationViewController as! UINavigationController
|
||||
let vc = nvc.topViewController as! PickLocationViewController
|
||||
|
||||
|
||||
@@ -15,6 +15,12 @@ class MessageMediaViewController: UIViewController {
|
||||
|
||||
@IBOutlet weak var mediaView: MediaView!
|
||||
|
||||
@IBOutlet weak var mediaControlView: MediaControlView!
|
||||
|
||||
deinit {
|
||||
NSNotificationCenter.defaultCenter().removeObserver(self)
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
@@ -23,13 +29,33 @@ class MessageMediaViewController: UIViewController {
|
||||
switch message.mediaType {
|
||||
|
||||
case MessageMediaType.Image.rawValue:
|
||||
|
||||
mediaControlView.type = .Image
|
||||
|
||||
if
|
||||
let imageFileURL = NSFileManager.yepMessageImageURLWithName(message.localAttachmentName),
|
||||
let image = UIImage(contentsOfFile: imageFileURL.path!) {
|
||||
mediaView.imageView.image = image
|
||||
|
||||
mediaControlView.shareAction = {
|
||||
let presentingViewController = self.presentingViewController
|
||||
|
||||
self.dismissViewControllerAnimated(true, completion: { () -> Void in
|
||||
|
||||
let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil)
|
||||
|
||||
presentingViewController?.presentViewController(activityViewController, animated: true, completion: { () -> Void in
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
case MessageMediaType.Video.rawValue:
|
||||
|
||||
mediaControlView.type = .Video
|
||||
mediaControlView.playState = .Playing
|
||||
|
||||
if
|
||||
let videoFileURL = NSFileManager.yepMessageVideoURLWithName(message.localAttachmentName),
|
||||
let asset = AVURLAsset(URL: videoFileURL, options: [:]),
|
||||
@@ -37,15 +63,56 @@ class MessageMediaViewController: UIViewController {
|
||||
|
||||
let x = NSFileManager.defaultManager().fileExistsAtPath(videoFileURL.path!)
|
||||
|
||||
mediaView.videoPlayerLayer.frame = mediaView.bounds
|
||||
playerItem.seekToTime(kCMTimeZero)
|
||||
//mediaView.videoPlayerLayer.player.replaceCurrentItemWithPlayerItem(playerItem)
|
||||
mediaView.videoPlayerLayer.player = AVPlayer(playerItem: playerItem)
|
||||
let player = AVPlayer(playerItem: playerItem)
|
||||
|
||||
mediaControlView.timeLabel.text = ""
|
||||
|
||||
player.addPeriodicTimeObserverForInterval(CMTimeMakeWithSeconds(0.1, Int32(NSEC_PER_SEC)), queue: nil, usingBlock: { time in
|
||||
|
||||
if player.currentItem.status == .ReadyToPlay {
|
||||
let durationSeconds = CMTimeGetSeconds(player.currentItem.duration)
|
||||
let currentSeconds = CMTimeGetSeconds(time)
|
||||
let coundDownTime = Double(Int((durationSeconds - currentSeconds) * 10)) / 10
|
||||
self.mediaControlView.timeLabel.text = "\(coundDownTime)"
|
||||
}
|
||||
})
|
||||
|
||||
NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerItemDidReachEnd:", name: AVPlayerItemDidPlayToEndTimeNotification, object: player.currentItem)
|
||||
|
||||
mediaControlView.playAction = { mediaControlView in
|
||||
player.play()
|
||||
|
||||
mediaControlView.playState = .Playing
|
||||
}
|
||||
|
||||
mediaControlView.pauseAction = { mediaControlView in
|
||||
player.pause()
|
||||
|
||||
mediaControlView.playState = .Pause
|
||||
}
|
||||
|
||||
mediaView.videoPlayerLayer.player = player
|
||||
|
||||
mediaView.videoPlayerLayer.player.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions(0), context: nil)
|
||||
|
||||
//mediaView.videoPlayerLayer.player.play()
|
||||
mediaView.imageView.removeFromSuperview()
|
||||
|
||||
|
||||
mediaControlView.shareAction = {
|
||||
let presentingViewController = self.presentingViewController
|
||||
|
||||
self.dismissViewControllerAnimated(true, completion: { () -> Void in
|
||||
|
||||
let activityViewController = UIActivityViewController(activityItems: [videoFileURL], applicationActivities: nil)
|
||||
|
||||
presentingViewController?.presentViewController(activityViewController, animated: true, completion: { () -> Void in
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -54,6 +121,12 @@ class MessageMediaViewController: UIViewController {
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillDisappear(animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
|
||||
mediaView.videoPlayerLayer.player.pause()
|
||||
}
|
||||
|
||||
@IBAction func swipeDown(sender: UISwipeGestureRecognizer) {
|
||||
|
||||
if let message = message {
|
||||
@@ -67,16 +140,21 @@ class MessageMediaViewController: UIViewController {
|
||||
|
||||
override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
|
||||
if let player = object as? AVPlayer {
|
||||
|
||||
if player == mediaView.videoPlayerLayer.player {
|
||||
|
||||
if keyPath == "status" {
|
||||
switch player.status {
|
||||
|
||||
case AVPlayerStatus.Failed:
|
||||
println("Failed")
|
||||
|
||||
case AVPlayerStatus.ReadyToPlay:
|
||||
println("ReadyToPlay")
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
self.mediaView.videoPlayerLayer.player.play()
|
||||
}
|
||||
|
||||
case AVPlayerStatus.Unknown:
|
||||
println("Unknown")
|
||||
}
|
||||
@@ -84,4 +162,12 @@ class MessageMediaViewController: UIViewController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func playerItemDidReachEnd(notification: NSNotification) {
|
||||
mediaControlView.playState = .Pause
|
||||
|
||||
if let playerItem = notification.object as? AVPlayerItem {
|
||||
playerItem.seekToTime(kCMTimeZero)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// MediaControlView.swift
|
||||
// Yep
|
||||
//
|
||||
// Created by NIX on 15/5/7.
|
||||
// Copyright (c) 2015年 Catch Inc. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
//@IBDesignable
|
||||
class MediaControlView: UIView {
|
||||
|
||||
enum Type {
|
||||
case Image
|
||||
case Video
|
||||
}
|
||||
|
||||
var type: Type = .Video {
|
||||
didSet {
|
||||
switch type {
|
||||
|
||||
case .Image:
|
||||
timeLabel.hidden = true
|
||||
playButton.hidden = true
|
||||
|
||||
case .Video:
|
||||
timeLabel.hidden = false
|
||||
playButton.hidden = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum PlayState {
|
||||
case Playing
|
||||
case Pause
|
||||
}
|
||||
|
||||
var playState: PlayState = .Pause {
|
||||
didSet {
|
||||
switch playState {
|
||||
case .Playing:
|
||||
playButton.setImage(UIImage(named: "icon_pause"), forState: .Normal)
|
||||
case .Pause:
|
||||
playButton.setImage(UIImage(named: "icon_play"), forState: .Normal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var playAction: (MediaControlView -> Void)?
|
||||
var pauseAction: (MediaControlView -> Void)?
|
||||
|
||||
var shareAction: (() -> Void)?
|
||||
|
||||
lazy var timeLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.textAlignment = .Center
|
||||
label.font = UIFont(name: "HelveticaNeue-Light", size: 14)
|
||||
label.textColor = UIColor.whiteColor()
|
||||
label.text = "00:42"
|
||||
return label
|
||||
}()
|
||||
|
||||
lazy var playButton: UIButton = {
|
||||
let button = UIButton()
|
||||
button.setImage(UIImage(named: "icon_play"), forState: .Normal)
|
||||
button.tintColor = UIColor.whiteColor()
|
||||
button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
|
||||
button.addTarget(self, action: "playOrPause", forControlEvents: UIControlEvents.TouchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
lazy var shareButton: UIButton = {
|
||||
let button = UIButton()
|
||||
button.setImage(UIImage(named: "icon_more"), forState: .Normal)
|
||||
button.tintColor = UIColor.whiteColor()
|
||||
button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
|
||||
button.addTarget(self, action: "share", forControlEvents: UIControlEvents.TouchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
|
||||
override func didMoveToSuperview() {
|
||||
super.didMoveToSuperview()
|
||||
|
||||
makeUI()
|
||||
}
|
||||
|
||||
func makeUI() {
|
||||
addSubview(timeLabel)
|
||||
addSubview(playButton)
|
||||
addSubview(shareButton)
|
||||
|
||||
timeLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
|
||||
playButton.setTranslatesAutoresizingMaskIntoConstraints(false)
|
||||
shareButton.setTranslatesAutoresizingMaskIntoConstraints(false)
|
||||
|
||||
let viewsDictionary = [
|
||||
"timeLable": timeLabel,
|
||||
"playButton": playButton,
|
||||
"shareButton": shareButton,
|
||||
]
|
||||
|
||||
let constraintsV = NSLayoutConstraint.constraintsWithVisualFormat("V:|[timeLable]|", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary)
|
||||
|
||||
let constraintsH = NSLayoutConstraint.constraintsWithVisualFormat("H:|-20-[timeLable]-(>=0)-[playButton]-(>=0)-[shareButton]|", options: .AlignAllCenterY | .AlignAllTop | .AlignAllBottom, metrics: nil, views: viewsDictionary)
|
||||
|
||||
NSLayoutConstraint.activateConstraints(constraintsV)
|
||||
NSLayoutConstraint.activateConstraints(constraintsH)
|
||||
|
||||
let playButtonConstraintCenterX = NSLayoutConstraint(item: playButton, attribute: .CenterX, relatedBy: .Equal, toItem: self, attribute: .CenterX, multiplier: 1.0, constant: 0)
|
||||
|
||||
NSLayoutConstraint.activateConstraints([playButtonConstraintCenterX])
|
||||
}
|
||||
|
||||
// MARK: Actions
|
||||
|
||||
func playOrPause() {
|
||||
|
||||
switch playState {
|
||||
|
||||
case .Playing:
|
||||
if let action = pauseAction {
|
||||
action(self)
|
||||
}
|
||||
|
||||
case .Pause:
|
||||
if let action = playAction {
|
||||
action(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func share() {
|
||||
if let action = shareAction {
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,14 +13,14 @@ class MediaView: UIView {
|
||||
|
||||
lazy var imageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.contentMode = .ScaleAspectFill
|
||||
imageView.contentMode = .ScaleAspectFit
|
||||
return imageView
|
||||
}()
|
||||
|
||||
lazy var videoPlayerLayer: AVPlayerLayer = {
|
||||
let player = AVPlayer()
|
||||
let playerLayer = AVPlayerLayer(player: player)
|
||||
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
|
||||
playerLayer.videoGravity = AVLayerVideoGravityResizeAspect
|
||||
//playerLayer.backgroundColor = UIColor.darkGrayColor().CGColor
|
||||
return playerLayer
|
||||
}()
|
||||
@@ -31,7 +31,14 @@ class MediaView: UIView {
|
||||
makeUI()
|
||||
|
||||
layer.addSublayer(videoPlayerLayer)
|
||||
videoPlayerLayer.frame = bounds
|
||||
|
||||
println("videoPlayerLayer.frame: \(videoPlayerLayer.frame)")
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
videoPlayerLayer.frame = UIScreen.mainScreen().bounds
|
||||
}
|
||||
|
||||
func makeUI() {
|
||||
|
||||
Reference in New Issue
Block a user