Merge branch 'develop' of https://github.com/CatchChat/Yep into develop

This commit is contained in:
kevinzhow
2015-12-19 17:17:45 +08:00
31 changed files with 1855 additions and 1125 deletions
+11 -11
View File
@@ -1,6 +1,6 @@
PODS:
- 1PasswordExtension (1.7)
- Alamofire (3.1.3)
- Alamofire (3.1.4)
- APAddressBook/Core (0.2.1)
- APAddressBook/Swift (0.2.1):
- APAddressBook/Core
@@ -8,7 +8,7 @@ PODS:
- Base64 (1.0.1)
- Crashlytics (3.4.1):
- Fabric (~> 1.6.0)
- DeviceGuru (1.3.2)
- DeviceGuru (1.3.3)
- Fabric (1.6.1)
- FXBlurView (1.6.4)
- JPush-iOS-SDK (1.8.8)
@@ -21,11 +21,11 @@ PODS:
- Navi (0.3.9)
- pop (1.0.8)
- Proposer (0.7.1)
- Realm (0.96.3):
- Realm/Headers (= 0.96.3)
- Realm/Headers (0.96.3)
- RealmSwift (0.96.3):
- Realm (= 0.96.3)
- Realm (0.97.0):
- Realm/Headers (= 0.97.0)
- Realm/Headers (0.97.0)
- RealmSwift (0.97.0):
- Realm (= 0.97.0)
- Ruler (0.6)
- SocketRocket (0.4.2)
- TPKeyboardAvoiding (1.2.11)
@@ -57,12 +57,12 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
1PasswordExtension: a22573ad528dd63bd79c1f3b3813b17c2f86b91b
Alamofire: 9f93b56389e48def9220dd57d1f44b1927229a5a
Alamofire: fbc829692f351fa1d8a31dd75fd7f7f56fea31fb
APAddressBook: 90c0fb07579a47e10ef1a2344e23cfd35f388bec
Appsee: 77f144701aa1a53d854d319a46667561849e8cf5
Base64: 4924bf3ca6fa559a5161ef717291bd450eb7bd1a
Crashlytics: 41574a245bc6ae10c55d57f385ebd2004e5bee05
DeviceGuru: bbc2660d73211dd5d868bc85a1c2ca9607d01153
DeviceGuru: 49c6178d77693f8459ace21cecaf4d1d26297d08
Fabric: bf0ceb04e7c924090efc5f8c55e4fbcca189e0a0
FXBlurView: db786c2561cb49a09ae98407f52460096ab8a44f
JPush-iOS-SDK: d4c097d8abbdd0837e24d44b41aacf64a6feddfd
@@ -73,8 +73,8 @@ SPEC CHECKSUMS:
Navi: 24f5c81aeb46b89d27168ec1d459581230ae2675
pop: bb773ae2c791ca2629de13b347e7a8b450fa6a57
Proposer: e9759ad71a6702fd94315a0bff1f8c116edf6f07
Realm: 145d3cdf78a03aee71bde5381ad7e542bd541720
RealmSwift: aab84968aad662f61f36473d1aea019f63481505
Realm: b498a6fb9d288b171ff98d0e2d4384c295be8990
RealmSwift: d014810dec75c9a3f1a33926d2dabfed855c582c
Ruler: b36ec3bbc5fc6c3b7f629a6052cc1c17ada4b280
SocketRocket: ffe08119b00ef982f6c37052a4705a057c8494ad
TPKeyboardAvoiding: e5ce146b313de063957bfa75a13f1e9b0ff18ab7
+37 -37
View File
@@ -60,9 +60,6 @@
501690181BFB18D20096C4F9 /* ChatLeftSocialWorkCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 501690161BFB18D20096C4F9 /* ChatLeftSocialWorkCell.swift */; };
501690191BFB18D20096C4F9 /* ChatLeftSocialWorkCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 501690171BFB18D20096C4F9 /* ChatLeftSocialWorkCell.xib */; };
5016901C1BFB22180096C4F9 /* SocialWorkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5016901B1BFB22180096C4F9 /* SocialWorkService.swift */; };
5016901F1BFDCECB0096C4F9 /* FeedSocialWorkCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5016901D1BFDCECB0096C4F9 /* FeedSocialWorkCell.swift */; };
501690201BFDCECB0096C4F9 /* FeedSocialWorkCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5016901E1BFDCECB0096C4F9 /* FeedSocialWorkCell.xib */; };
501690231BFEA6C30096C4F9 /* FeedBasicCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 501690221BFEA6C30096C4F9 /* FeedBasicCell.swift */; };
501813261BA07CED0025873C /* Activities.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 501813251BA07CED0025873C /* Activities.xcassets */; };
5018132C1BA3CFEF0025873C /* WeChatActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5018132B1BA3CFEF0025873C /* WeChatActivity.swift */; };
5019F6311B39BFE00000D993 /* ConversationMoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5019F6301B39BFE00000D993 /* ConversationMoreView.swift */; };
@@ -184,6 +181,8 @@
507F65F71B2EBC2700A35FDC /* MediaPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 507F65F61B2EBC2700A35FDC /* MediaPreviewView.swift */; };
5080EB1C1B93F43A006F3C2D /* PodsHelpYepViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5080EB1B1B93F43A006F3C2D /* PodsHelpYepViewController.swift */; };
5080EB1F1B93F932006F3C2D /* NSBundle+Yep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5080EB1E1B93F932006F3C2D /* NSBundle+Yep.swift */; };
50858EBB1C22487900EDE492 /* FeedBasicCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50858EBA1C22487900EDE492 /* FeedBasicCell.swift */; };
50858EBF1C224DA900EDE492 /* FeedBiggerImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50858EBE1C224DA900EDE492 /* FeedBiggerImageCell.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 */; };
@@ -302,6 +301,12 @@
50E3488E1B905C0100A8E699 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E3488D1B905C0100A8E699 /* AboutViewController.swift */; };
50E348921B9063A700A8E699 /* AboutCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E348901B9063A700A8E699 /* AboutCell.swift */; };
50E348931B9063A700A8E699 /* AboutCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 50E348911B9063A700A8E699 /* AboutCell.xib */; };
50E392BC1C22752C00C0CECB /* FeedNormalImagesCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E392BB1C22752C00C0CECB /* FeedNormalImagesCell.swift */; };
50E392BE1C228BF000C0CECB /* FeedCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E392BD1C228BF000C0CECB /* FeedCellLayout.swift */; };
50E392C01C22B30300C0CECB /* FeedGithubRepoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E392BF1C22B30300C0CECB /* FeedGithubRepoCell.swift */; };
50E392C21C22B9E400C0CECB /* FeedDribbbleShotCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E392C11C22B9E400C0CECB /* FeedDribbbleShotCell.swift */; };
50E392C41C22C0F600C0CECB /* FeedVoiceCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E392C31C22C0F600C0CECB /* FeedVoiceCell.swift */; };
50E392C61C22C82800C0CECB /* FeedLocationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E392C51C22C82800C0CECB /* FeedLocationCell.swift */; };
50E61CEB1AF1F69D00908A9D /* ConversationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E61CEA1AF1F69D00908A9D /* ConversationTitleView.swift */; };
50EB8C5E1AE78AB9001AC1EE /* YepAsset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50EB8C5D1AE78AB9001AC1EE /* YepAsset.swift */; };
50EB8CBF1AE89ED8001AC1EE /* ChatLeftVideoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50EB8CBD1AE89ED8001AC1EE /* ChatLeftVideoCell.swift */; };
@@ -315,8 +320,7 @@
50F5AF831BBA67060033C9BC /* NewFeedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50F5AF821BBA67060033C9BC /* NewFeedViewController.swift */; };
50F5AF861BBA676D0033C9BC /* NewFeed.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 50F5AF851BBA676D0033C9BC /* NewFeed.storyboard */; };
50F5AF881BBBB2AE0033C9BC /* HorizontalLineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50F5AF871BBBB2AE0033C9BC /* HorizontalLineView.swift */; };
50F5AF8C1BBBB64C0033C9BC /* FeedCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50F5AF8A1BBBB64C0033C9BC /* FeedCell.swift */; };
50F5AF8D1BBBB64C0033C9BC /* FeedCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 50F5AF8B1BBBB64C0033C9BC /* FeedCell.xib */; };
50F5AF8C1BBBB64C0033C9BC /* FeedAnyImagesCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50F5AF8A1BBBB64C0033C9BC /* FeedAnyImagesCell.swift */; };
50F5AF951BBBCDA30033C9BC /* FeedMediaAddCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50F5AF931BBBCDA30033C9BC /* FeedMediaAddCell.swift */; };
50F5AF961BBBCDA30033C9BC /* FeedMediaAddCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 50F5AF941BBBCDA30033C9BC /* FeedMediaAddCell.xib */; };
50F5AF991BBBD02A0033C9BC /* FeedMediaCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50F5AF971BBBD02A0033C9BC /* FeedMediaCell.swift */; };
@@ -423,9 +427,6 @@
501690161BFB18D20096C4F9 /* ChatLeftSocialWorkCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChatLeftSocialWorkCell.swift; path = Views/Cells/ChatLeftSocialWork/ChatLeftSocialWorkCell.swift; sourceTree = "<group>"; };
501690171BFB18D20096C4F9 /* ChatLeftSocialWorkCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ChatLeftSocialWorkCell.xib; path = Views/Cells/ChatLeftSocialWork/ChatLeftSocialWorkCell.xib; sourceTree = "<group>"; };
5016901B1BFB22180096C4F9 /* SocialWorkService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SocialWorkService.swift; path = Services/SocialWorkService.swift; sourceTree = "<group>"; };
5016901D1BFDCECB0096C4F9 /* FeedSocialWorkCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedSocialWorkCell.swift; path = Views/Cells/FeedSocialWork/FeedSocialWorkCell.swift; sourceTree = "<group>"; };
5016901E1BFDCECB0096C4F9 /* FeedSocialWorkCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = FeedSocialWorkCell.xib; path = Views/Cells/FeedSocialWork/FeedSocialWorkCell.xib; sourceTree = "<group>"; };
501690221BFEA6C30096C4F9 /* FeedBasicCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedBasicCell.swift; path = Views/Cells/FeedBasic/FeedBasicCell.swift; sourceTree = "<group>"; };
501813251BA07CED0025873C /* Activities.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Activities.xcassets; sourceTree = "<group>"; };
5018132B1BA3CFEF0025873C /* WeChatActivity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WeChatActivity.swift; path = Activities/WeChatActivity.swift; sourceTree = "<group>"; };
5019F6301B39BFE00000D993 /* ConversationMoreView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationMoreView.swift; path = Views/ConversationMore/ConversationMoreView.swift; sourceTree = "<group>"; };
@@ -548,6 +549,8 @@
507F65F61B2EBC2700A35FDC /* MediaPreviewView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MediaPreviewView.swift; path = Views/Media/MediaPreviewView.swift; sourceTree = "<group>"; };
5080EB1B1B93F43A006F3C2D /* PodsHelpYepViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PodsHelpYepViewController.swift; path = ViewControllers/PodsHelpYep/PodsHelpYepViewController.swift; sourceTree = "<group>"; };
5080EB1E1B93F932006F3C2D /* NSBundle+Yep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSBundle+Yep.swift"; path = "Extensions/NSBundle+Yep.swift"; sourceTree = "<group>"; };
50858EBA1C22487900EDE492 /* FeedBasicCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedBasicCell.swift; path = Views/Cells/Feed/FeedBasicCell.swift; sourceTree = "<group>"; };
50858EBE1C224DA900EDE492 /* FeedBiggerImageCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedBiggerImageCell.swift; path = Views/Cells/Feed/FeedBiggerImageCell.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>"; };
@@ -666,6 +669,12 @@
50E3488D1B905C0100A8E699 /* AboutViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AboutViewController.swift; path = ViewControllers/About/AboutViewController.swift; sourceTree = "<group>"; };
50E348901B9063A700A8E699 /* AboutCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AboutCell.swift; path = Views/Cells/About/AboutCell.swift; sourceTree = "<group>"; };
50E348911B9063A700A8E699 /* AboutCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = AboutCell.xib; path = Views/Cells/About/AboutCell.xib; sourceTree = "<group>"; };
50E392BB1C22752C00C0CECB /* FeedNormalImagesCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedNormalImagesCell.swift; path = Views/Cells/Feed/FeedNormalImagesCell.swift; sourceTree = "<group>"; };
50E392BD1C228BF000C0CECB /* FeedCellLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedCellLayout.swift; path = Views/Cells/Feed/FeedCellLayout.swift; sourceTree = "<group>"; };
50E392BF1C22B30300C0CECB /* FeedGithubRepoCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedGithubRepoCell.swift; path = Views/Cells/Feed/FeedGithubRepoCell.swift; sourceTree = "<group>"; };
50E392C11C22B9E400C0CECB /* FeedDribbbleShotCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedDribbbleShotCell.swift; path = Views/Cells/Feed/FeedDribbbleShotCell.swift; sourceTree = "<group>"; };
50E392C31C22C0F600C0CECB /* FeedVoiceCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedVoiceCell.swift; path = Views/Cells/Feed/FeedVoiceCell.swift; sourceTree = "<group>"; };
50E392C51C22C82800C0CECB /* FeedLocationCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedLocationCell.swift; path = Views/Cells/Feed/FeedLocationCell.swift; sourceTree = "<group>"; };
50E61CEA1AF1F69D00908A9D /* ConversationTitleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationTitleView.swift; path = Views/ConversationTitle/ConversationTitleView.swift; sourceTree = "<group>"; };
50EB8C5D1AE78AB9001AC1EE /* YepAsset.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = YepAsset.swift; path = Helpers/YepAsset.swift; sourceTree = "<group>"; };
50EB8CBD1AE89ED8001AC1EE /* ChatLeftVideoCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChatLeftVideoCell.swift; path = Views/Cells/ChatLeftVideo/ChatLeftVideoCell.swift; sourceTree = "<group>"; };
@@ -679,8 +688,7 @@
50F5AF821BBA67060033C9BC /* NewFeedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NewFeedViewController.swift; path = ViewControllers/NewFeed/NewFeedViewController.swift; sourceTree = "<group>"; };
50F5AF851BBA676D0033C9BC /* NewFeed.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = NewFeed.storyboard; path = ViewControllers/NewFeed/NewFeed.storyboard; sourceTree = "<group>"; };
50F5AF871BBBB2AE0033C9BC /* HorizontalLineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HorizontalLineView.swift; path = Views/HorizontalLine/HorizontalLineView.swift; sourceTree = "<group>"; };
50F5AF8A1BBBB64C0033C9BC /* FeedCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedCell.swift; path = Views/Cells/Feed/FeedCell.swift; sourceTree = "<group>"; };
50F5AF8B1BBBB64C0033C9BC /* FeedCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = FeedCell.xib; path = Views/Cells/Feed/FeedCell.xib; sourceTree = "<group>"; };
50F5AF8A1BBBB64C0033C9BC /* FeedAnyImagesCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedAnyImagesCell.swift; path = Views/Cells/Feed/FeedAnyImagesCell.swift; sourceTree = "<group>"; };
50F5AF931BBBCDA30033C9BC /* FeedMediaAddCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedMediaAddCell.swift; path = Views/Cells/FeedMediaAdd/FeedMediaAddCell.swift; sourceTree = "<group>"; };
50F5AF941BBBCDA30033C9BC /* FeedMediaAddCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = FeedMediaAddCell.xib; path = Views/Cells/FeedMediaAdd/FeedMediaAddCell.xib; sourceTree = "<group>"; };
50F5AF971BBBD02A0033C9BC /* FeedMediaCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FeedMediaCell.swift; path = Views/Cells/FeedMedia/FeedMediaCell.swift; sourceTree = "<group>"; };
@@ -991,23 +999,6 @@
name = ChatLeftSocialWork;
sourceTree = "<group>";
};
501690211BFDCED10096C4F9 /* FeedSocialWork */ = {
isa = PBXGroup;
children = (
5016901D1BFDCECB0096C4F9 /* FeedSocialWorkCell.swift */,
5016901E1BFDCECB0096C4F9 /* FeedSocialWorkCell.xib */,
);
name = FeedSocialWork;
sourceTree = "<group>";
};
501690241BFEA6CA0096C4F9 /* FeedBasic */ = {
isa = PBXGroup;
children = (
501690221BFEA6C30096C4F9 /* FeedBasicCell.swift */,
);
name = FeedBasic;
sourceTree = "<group>";
};
5019F62F1B39BFCB0000D993 /* ConversationMore */ = {
isa = PBXGroup;
children = (
@@ -1243,9 +1234,7 @@
5064F65B1B0B14470089FAD4 /* AddFriendMore */,
50E348941B9063AD00A8E699 /* About */,
503807251BDA180A0068345E /* FeedSkillUsers */,
501690241BFEA6CA0096C4F9 /* FeedBasic */,
50AFBF651BB4FC37007D19DA /* Feed */,
501690211BFDCED10096C4F9 /* FeedSocialWork */,
50F5AF921BBBCC960033C9BC /* FeedMediaAdd */,
50F5AF9B1BBBD0310033C9BC /* FeedMedia */,
6A5632901BC90A4900397B53 /* DiscoverCardUser */,
@@ -1979,8 +1968,15 @@
50AFBF651BB4FC37007D19DA /* Feed */ = {
isa = PBXGroup;
children = (
50F5AF8A1BBBB64C0033C9BC /* FeedCell.swift */,
50F5AF8B1BBBB64C0033C9BC /* FeedCell.xib */,
50E392BD1C228BF000C0CECB /* FeedCellLayout.swift */,
50858EBA1C22487900EDE492 /* FeedBasicCell.swift */,
50858EBE1C224DA900EDE492 /* FeedBiggerImageCell.swift */,
50E392BB1C22752C00C0CECB /* FeedNormalImagesCell.swift */,
50F5AF8A1BBBB64C0033C9BC /* FeedAnyImagesCell.swift */,
50E392BF1C22B30300C0CECB /* FeedGithubRepoCell.swift */,
50E392C11C22B9E400C0CECB /* FeedDribbbleShotCell.swift */,
50E392C31C22C0F600C0CECB /* FeedVoiceCell.swift */,
50E392C51C22C82800C0CECB /* FeedLocationCell.swift */,
);
name = Feed;
sourceTree = "<group>";
@@ -2435,7 +2431,6 @@
50E348931B9063A700A8E699 /* AboutCell.xib in Resources */,
5039594F1B05E6E000797A3E /* ProfileSocialAccountGithubCell.xib in Resources */,
502AE5591AB932D5005BD199 /* ProfileSectionHeaderReusableView.xib in Resources */,
50F5AF8D1BBBB64C0033C9BC /* FeedCell.xib in Resources */,
5056AD6F1B05CB92003F9359 /* ProfileSocialAccountImagesCell.xib in Resources */,
506BB7F61AE4E0A500C1A2A0 /* SkillAnnotationHeader.xib in Resources */,
50AFBF4E1BB3A594007D19DA /* bub3.caf in Resources */,
@@ -2485,7 +2480,6 @@
50CDBE431ACA9B4200459CE0 /* ChatRightImageCell.xib in Resources */,
50E1CE8B1BE0BC940025B933 /* MessageMedia.storyboard in Resources */,
50DEE0471BEA030900015741 /* PodsHelpYep.storyboard in Resources */,
501690201BFDCECB0096C4F9 /* FeedSocialWorkCell.xib in Resources */,
508C2AA51AD661B3002B8097 /* UserStateCell.xib in Resources */,
508F8FDF1B049ACF00461B0B /* InstagramMediaCell.xib in Resources */,
848806B11B789A2D000C5424 /* EditSkillCell.xib in Resources */,
@@ -2547,7 +2541,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Fabric/Fabric.framework/run\" 3030ba006e21bcf8eb4a2127b6a7931ea6667486 1b6549ac285402b232e4718eda293559d8ed8df039017af3fa9593518395eef0";
shellScript = "\"${PODS_ROOT}/Fabric/run\" 3030ba006e21bcf8eb4a2127b6a7931ea6667486 1b6549ac285402b232e4718eda293559d8ed8df039017af3fa9593518395eef0";
};
39615BAC5D2C17889BD12838 /* Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
@@ -2615,6 +2609,7 @@
500EED981BF07A3000C6BABC /* ConversationViewController+Feed.swift in Sources */,
508F8FDE1B049ACF00461B0B /* InstagramMediaCell.swift in Sources */,
502AE5211AB71C7E005BD199 /* BorderButton.swift in Sources */,
50858EBB1C22487900EDE492 /* FeedBasicCell.swift in Sources */,
84C959891B731FD20017D3ED /* ChatBaseCell.swift in Sources */,
502AE54E1AB93175005BD199 /* ProfileHeaderCell.swift in Sources */,
50A640E01B6F38CF0050E4A3 /* NotificationsViewController.swift in Sources */,
@@ -2664,6 +2659,7 @@
502C24831C1034000074A1BA /* UIImageView+Yep.swift in Sources */,
5080EB1C1B93F43A006F3C2D /* PodsHelpYepViewController.swift in Sources */,
0A1CAC731AFA526200826B45 /* SkillHomeSectionButton.swift in Sources */,
50E392BC1C22752C00C0CECB /* FeedNormalImagesCell.swift in Sources */,
50B38FCC1B6B37F00064C132 /* FeedbackViewController.swift in Sources */,
507F65F71B2EBC2700A35FDC /* MediaPreviewView.swift in Sources */,
501690181BFB18D20096C4F9 /* ChatLeftSocialWorkCell.swift in Sources */,
@@ -2703,6 +2699,7 @@
50DEE0411BE7626100015741 /* YepHelpers.swift in Sources */,
501138311BCB62A20055A014 /* FeedConversationCell.swift in Sources */,
502AE5401AB88862005BD199 /* SkillRankCell.swift in Sources */,
50E392C41C22C0F600C0CECB /* FeedVoiceCell.swift in Sources */,
50C090A01ADE391600CC6389 /* AddSkillsReusableView.swift in Sources */,
84385C4A1B85BE200071130D /* ShowStepMeetViewController.swift in Sources */,
5023DE2D1AB685ED00B3EE96 /* DiscoverViewController.swift in Sources */,
@@ -2725,6 +2722,7 @@
502280F81B1C3F2800E984EE /* FriendsInContactsViewController.swift in Sources */,
50E348921B9063A700A8E699 /* AboutCell.swift in Sources */,
508A08501C16B810000A3305 /* RecordButton.swift in Sources */,
50858EBF1C224DA900EDE492 /* FeedBiggerImageCell.swift in Sources */,
508D17401ACCD2740092D666 /* YepButton.swift in Sources */,
5019F6311B39BFE00000D993 /* ConversationMoreView.swift in Sources */,
506BB7F51AE4E0A500C1A2A0 /* SkillAnnotationHeader.swift in Sources */,
@@ -2752,21 +2750,23 @@
50DEE0311BE339B000015741 /* LoadMoreTableViewCell.swift in Sources */,
50DEE0361BE3720F00015741 /* LoadMoreCollectionViewCell.swift in Sources */,
504F41251ACE2D1D00FBB19A /* SampleView.swift in Sources */,
50E392C01C22B30300C0CECB /* FeedGithubRepoCell.swift in Sources */,
50A640EC1B6F4E420050E4A3 /* DoNotDisturbPeriodViewController.swift in Sources */,
502AE5291AB81076005BD199 /* YepService.swift in Sources */,
5016901F1BFDCECB0096C4F9 /* FeedSocialWorkCell.swift in Sources */,
50C090A41ADE46D500CC6389 /* RegisterSelectSkillsViewController.swift in Sources */,
50CC4FA21C1AC0EE00B6A263 /* UITableView+Yep.swift in Sources */,
50E392C61C22C82800C0CECB /* FeedLocationCell.swift in Sources */,
502AE51E1AB712D2005BD199 /* RegisterPickNameViewController.swift in Sources */,
50B8E6161B40F9E700C17EA1 /* YepDownloader.swift in Sources */,
50894D101AEE3C25000981AF /* YepHUD.swift in Sources */,
50EB8CCE1AEA1B38001AC1EE /* MessageMediaViewController.swift in Sources */,
50E114F91ABC137A00F13000 /* YepServiceSync.swift in Sources */,
50E392BE1C228BF000C0CECB /* FeedCellLayout.swift in Sources */,
506E241C1AE6254F00A33C1A /* MessageTypeButton.swift in Sources */,
505082351C212E9200643CEB /* FeedLocationContainerView.swift in Sources */,
0A3E60671ACCAECE003DC853 /* YepLocationService.swift in Sources */,
6A8215051BCBE5170011F36C /* MiniCardSkillLayout.swift in Sources */,
50F5AF8C1BBBB64C0033C9BC /* FeedCell.swift in Sources */,
50F5AF8C1BBBB64C0033C9BC /* FeedAnyImagesCell.swift in Sources */,
50894CF11AEA4726000981AF /* SettingsViewController.swift in Sources */,
5023DE2A1AB685BA00B3EE96 /* ContactsViewController.swift in Sources */,
50CDBE491ACBAD3200459CE0 /* ChatLeftImageCell.swift in Sources */,
@@ -2819,9 +2819,9 @@
840CD23C1B7B59D5000D2680 /* ShowStepViewController.swift in Sources */,
508F8FD01B01D04400461B0B /* GithubRepoCell.swift in Sources */,
50F2B97B1B2EEAF800F840CC /* NavigationTitleLabel.swift in Sources */,
501690231BFEA6C30096C4F9 /* FeedBasicCell.swift in Sources */,
50A820241B969B0F007CD30E /* NSTimeZone+Yep.swift in Sources */,
50FD753D1C1FB4AC0050A382 /* FPSLabel.swift in Sources */,
50E392C21C22B9E400C0CECB /* FeedDribbbleShotCell.swift in Sources */,
504F415A1AD5028200FBB19A /* SkillCell.swift in Sources */,
84385C481B85AC890071130D /* ShowStepMatchViewController.swift in Sources */,
0A0027D61B19CEC000AD4BE0 /* ConversationOperationQueue.swift in Sources */,
+1 -1
View File
@@ -94,7 +94,7 @@ class ImageCache {
let finalImage = storeImage.decodedImage()
println("Image Decode size \(storeImage.size)")
//println("Image Decode size \(storeImage.size)")
dispatch_async(dispatch_get_main_queue()) {
completion(url: attachmentURL, image: finalImage, cacheType: .None)
+12
View File
@@ -226,6 +226,18 @@ class YepConfig {
static let voiceTimeLengthTextAttributes:[String: NSObject] = [
NSFontAttributeName: UIFont.feedVoiceTimeLengthFont(),
]
static let bottomLabelsTextAttributes:[String: NSObject] = [
NSFontAttributeName: UIFont.feedBottomLabelsFont(),
]
}
struct FeedBiggerImageCell {
static let imageSize: CGSize = CGSize(width: 160, height: 160)
}
struct FeedNormalImagesCell {
static let imageSize: CGSize = CGSize(width: 80, height: 80)
}
struct FeedView {
+4
View File
@@ -49,6 +49,10 @@ extension UIFont {
return UIFont.systemFontOfSize(12)
}
class func feedBottomLabelsFont() -> UIFont {
return UIFont.systemFontOfSize(14)
}
class func feedVoiceTimeLengthFont() -> UIFont {
return UIFont.systemFontOfSize(15)
}
+7 -8
View File
@@ -83,7 +83,7 @@ extension UIImage {
let newHeight = pixelSideLength
let newWidth = (pixelSideLength / pixelHeight) * pixelWidth
newSize = CGSize(width: newWidth, height: newHeight)
newSize = CGSize(width: floor(newWidth), height: floor(newHeight))
} else {
@@ -93,16 +93,15 @@ extension UIImage {
let newWidth = pixelSideLength
let newHeight = (pixelSideLength / pixelWidth) * pixelHeight
newSize = CGSize(width: newWidth, height: newHeight)
newSize = CGSize(width: floor(newWidth), height: floor(newHeight))
}
if scale == UIScreen.mainScreen().scale {
let newSize = CGSize(width: newSize.width / scale, height: newSize.height / scale)
//println("newSize: \(newSize)")
let newSize = CGSize(width: floor(newSize.width / scale), height: floor(newSize.height / scale))
//println("A scaleToMinSideLength newSize: \(newSize)")
UIGraphicsBeginImageContextWithOptions(newSize, false, scale)
let rect = CGRectMake(0, 0, floor(newSize.width), floor(newSize.height))
let rect = CGRectMake(0, 0, newSize.width, newSize.height)
self.drawInRect(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
@@ -114,9 +113,9 @@ extension UIImage {
return self
} else {
//println("newSize: \(newSize)")
//println("B scaleToMinSideLength newSize: \(newSize)")
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
let rect = CGRectMake(0, 0, floor(newSize.width), floor(newSize.height))
let rect = CGRectMake(0, 0, newSize.width, newSize.height)
self.drawInRect(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
+12
View File
@@ -2743,6 +2743,18 @@ struct DiscoveredFeed: Hashable {
let attachment: Attachment?
var imageAttachments: [DiscoveredAttachment]? {
if let attachment = attachment, case let .Images(attachments) = attachment {
return attachments
}
return nil
}
var imageAttachmentsCount: Int {
return imageAttachments?.count ?? 0
}
let distance: Double?
let skill: Skill?
@@ -121,7 +121,7 @@ class ContactsViewController: BaseViewController {
}
#if DEBUG
view.addSubview(contactsFPSLabel)
// view.addSubview(contactsFPSLabel)
#endif
}
@@ -859,7 +859,7 @@ class ConversationViewController: BaseViewController {
}
#if DEBUG
view.addSubview(conversationFPSLabel)
// view.addSubview(conversationFPSLabel)
#endif
}
@@ -147,7 +147,7 @@ class ConversationsViewController: UIViewController {
}
#if DEBUG
view.addSubview(conversationsFPSLabel)
// view.addSubview(conversationsFPSLabel)
#endif
}
@@ -114,7 +114,7 @@ class DiscoverViewController: BaseViewController {
}
#if DEBUG
view.addSubview(discoverFPSLabel)
// view.addSubview(discoverFPSLabel)
#endif
}
@@ -14,6 +14,9 @@ import MapKit
class FeedsViewController: BaseViewController {
var skill: Skill?
var needShowSkill: Bool {
return (skill == nil) ? true : false
}
var profileUser: ProfileUser?
var preparedFeedsCount = 0
@@ -107,8 +110,14 @@ class FeedsViewController: BaseViewController {
#endif
private let feedSkillUsersCellID = "FeedSkillUsersCell"
private let feedCellID = "FeedCell"
private let feedSocialWorkCellID = "FeedSocialWorkCell"
private let feedBasicCellID = "FeedBasicCell"
private let feedBiggerImageCellID = "FeedBiggerImageCell"
private let feedNormalImagesCellID = "FeedNormalImagesCell"
private let feedAnyImagesCellID = "FeedAnyImagesCell"
private let feedGithubRepoCellID = "FeedGithubRepoCell"
private let feedDribbbleShotCellID = "FeedDribbbleShotCell"
private let feedVoiceCellID = "FeedVoiceCell"
private let feedLocationCellID = "FeedLocationCell"
private let loadMoreTableViewCellID = "LoadMoreTableViewCell"
private lazy var noFeedsFooterView: InfoView = InfoView(NSLocalizedString("No Feeds.", comment: ""))
@@ -145,7 +154,7 @@ class FeedsViewController: BaseViewController {
let indexPath = NSIndexPath(forRow: index, inSection: Section.Feed.rawValue)
if let cell = feedsTableView.cellForRowAtIndexPath(indexPath) as? FeedSocialWorkCell {
if let cell = feedsTableView.cellForRowAtIndexPath(indexPath) as? FeedVoiceCell {
cell.audioPlayedDuration = 0
}
@@ -176,33 +185,41 @@ class FeedsViewController: BaseViewController {
feedsTableView.tableFooterView = feeds.isEmpty ? noFeedsFooterView : UIView()
}
private var feedHeightHash = [String: CGFloat]()
private struct LayoutPool {
private func heightOfFeed(feed: DiscoveredFeed) -> CGFloat {
private var feedCellLayoutHash = [String: FeedCellLayout]()
let key = feed.id
private func feedCellLayoutOfFeed(feed: DiscoveredFeed) -> FeedCellLayout? {
let key = feed.id
if let height = feedHeightHash[key] {
return height
return feedCellLayoutHash[key]
}
} else {
private mutating func updateFeedCellLayout(layout: FeedCellLayout, forFeed feed: DiscoveredFeed) {
let height: CGFloat
switch feed.kind {
case .GithubRepo, .DribbbleShot, .Audio, .Location:
height = FeedSocialWorkCell.heightOfFeed(feed)
default:
height = FeedCell.heightOfFeed(feed)
}
let key = feed.id
if !key.isEmpty {
feedHeightHash[key] = height
feedCellLayoutHash[key] = layout
}
return height
//println("feedCellLayoutHash.count: \(feedCellLayoutHash.count)")
}
private mutating func heightOfFeed(feed: DiscoveredFeed) -> CGFloat {
if let layout = feedCellLayoutOfFeed(feed) {
return layout.height
} else {
let layout = FeedCellLayout(feed: feed)
updateFeedCellLayout(layout, forFeed: feed)
return layout.height
}
}
}
private static var layoutPool = LayoutPool()
private var feedSortStyle: FeedSortStyle = .Match {
didSet {
feeds = []
@@ -279,8 +296,16 @@ class FeedsViewController: BaseViewController {
feedsTableView.separatorColor = UIColor.yepCellSeparatorColor()
feedsTableView.registerNib(UINib(nibName: feedSkillUsersCellID, bundle: nil), forCellReuseIdentifier: feedSkillUsersCellID)
feedsTableView.registerNib(UINib(nibName: feedCellID, bundle: nil), forCellReuseIdentifier: feedCellID)
feedsTableView.registerNib(UINib(nibName: feedSocialWorkCellID, bundle: nil), forCellReuseIdentifier: feedSocialWorkCellID)
feedsTableView.registerClass(FeedBasicCell.self, forCellReuseIdentifier: feedBasicCellID)
feedsTableView.registerClass(FeedBiggerImageCell.self, forCellReuseIdentifier: feedBiggerImageCellID)
feedsTableView.registerClass(FeedNormalImagesCell.self, forCellReuseIdentifier: feedNormalImagesCellID)
feedsTableView.registerClass(FeedAnyImagesCell.self, forCellReuseIdentifier: feedAnyImagesCellID)
feedsTableView.registerClass(FeedGithubRepoCell.self, forCellReuseIdentifier: feedGithubRepoCellID)
feedsTableView.registerClass(FeedDribbbleShotCell.self, forCellReuseIdentifier: feedDribbbleShotCellID)
feedsTableView.registerClass(FeedVoiceCell.self, forCellReuseIdentifier: feedVoiceCellID)
feedsTableView.registerClass(FeedLocationCell.self, forCellReuseIdentifier: feedLocationCellID)
feedsTableView.registerNib(UINib(nibName: loadMoreTableViewCellID, bundle: nil), forCellReuseIdentifier: loadMoreTableViewCellID)
@@ -542,7 +567,7 @@ class FeedsViewController: BaseViewController {
let indexPath = NSIndexPath(forRow: index, inSection: Section.Feed.rawValue)
if let cell = feedsTableView.cellForRowAtIndexPath(indexPath) as? FeedSocialWorkCell {
if let cell = feedsTableView.cellForRowAtIndexPath(indexPath) as? FeedVoiceCell {
cell.audioPlayedDuration = currentTime
}
@@ -793,12 +818,42 @@ extension FeedsViewController: UITableViewDataSource, UITableViewDelegate {
switch feed.kind {
case .GithubRepo, .DribbbleShot, .Audio, .Location:
let cell = tableView.dequeueReusableCellWithIdentifier(feedSocialWorkCellID) as! FeedSocialWorkCell
case .Text:
let cell = tableView.dequeueReusableCellWithIdentifier(feedBasicCellID) as! FeedBasicCell
return cell
case .Image:
if feed.imageAttachmentsCount == 1 {
let cell = tableView.dequeueReusableCellWithIdentifier(feedBiggerImageCellID) as! FeedBiggerImageCell
return cell
} else if feed.imageAttachmentsCount <= 3 {
let cell = tableView.dequeueReusableCellWithIdentifier(feedNormalImagesCellID) as! FeedNormalImagesCell
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier(feedAnyImagesCellID) as! FeedAnyImagesCell
return cell
}
case .GithubRepo:
let cell = tableView.dequeueReusableCellWithIdentifier(feedGithubRepoCellID) as! FeedGithubRepoCell
return cell
case .DribbbleShot:
let cell = tableView.dequeueReusableCellWithIdentifier(feedDribbbleShotCellID) as! FeedDribbbleShotCell
return cell
case .Audio:
let cell = tableView.dequeueReusableCellWithIdentifier(feedVoiceCellID) as! FeedVoiceCell
return cell
case .Location:
let cell = tableView.dequeueReusableCellWithIdentifier(feedLocationCellID) as! FeedLocationCell
return cell
default:
let cell = tableView.dequeueReusableCellWithIdentifier(feedCellID) as! FeedCell
let cell = tableView.dequeueReusableCellWithIdentifier(feedBasicCellID) as! FeedBasicCell
return cell
}
@@ -867,22 +922,100 @@ extension FeedsViewController: UITableViewDataSource, UITableViewDelegate {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
let layout = FeedsViewController.layoutPool.feedCellLayoutOfFeed(feed)
let update: FeedCellLayout.Update = { newLayout in
FeedsViewController.layoutPool.updateFeedCellLayout(newLayout, forFeed: feed)
}
let layoutCache = (layout: layout, update: update)
switch feed.kind {
case .GithubRepo, .DribbbleShot, .Audio, .Location:
case .Text:
guard let cell = cell as? FeedSocialWorkCell else {
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
case .Image:
let tapMediaAction: FeedTapMediaAction = { [weak self] transitionView, image, attachments, index in
guard image != nil else {
return
}
let vc = UIStoryboard(name: "MediaPreview", bundle: nil).instantiateViewControllerWithIdentifier("MediaPreviewViewController") as! MediaPreviewViewController
vc.previewMedias = attachments.map({ PreviewMedia.AttachmentType(attachment: $0) })
vc.startIndex = index
let transitionView = transitionView
let frame = transitionView.convertRect(transitionView.bounds, toView: self?.view)
vc.previewImageViewInitalFrame = frame
vc.bottomPreviewImage = image
vc.transitionView = transitionView
delay(0) {
transitionView.alpha = 0 // Runloop
}
vc.afterDismissAction = { [weak self] in
transitionView.alpha = 1
self?.view.window?.makeKeyAndVisible()
}
mediaPreviewWindow.rootViewController = vc
mediaPreviewWindow.windowLevel = UIWindowLevelAlert - 1
mediaPreviewWindow.makeKeyAndVisible()
}
if feed.imageAttachmentsCount == 1 {
guard let cell = cell as? FeedBiggerImageCell else {
break
}
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
cell.tapMediaAction = tapMediaAction
} else if feed.imageAttachmentsCount <= 3 {
guard let cell = cell as? FeedNormalImagesCell else {
break
}
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
cell.tapMediaAction = tapMediaAction
} else {
guard let cell = cell as? FeedAnyImagesCell else {
break
}
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
cell.tapMediaAction = tapMediaAction
}
case .GithubRepo:
guard let cell = cell as? FeedGithubRepoCell else {
break
}
let feed = feeds[indexPath.item]
cell.configureWithFeed(feed, needShowSkill: (skill == nil) ? true : false)
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
cell.tapGithubRepoLinkAction = { [weak self] URL in
self?.yep_openURL(URL)
}
case .DribbbleShot:
guard let cell = cell as? FeedDribbbleShotCell else {
break
}
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
cell.tapDribbbleShotLinkAction = { [weak self] URL in
self?.yep_openURL(URL)
}
@@ -899,7 +1032,7 @@ extension FeedsViewController: UITableViewDataSource, UITableViewDelegate {
vc.startIndex = 0
let transitionView = transitionView
let frame = transitionView.convertRect(transitionView.frame, toView: self?.view)
let frame = transitionView.convertRect(transitionView.bounds, toView: self?.view)
vc.previewImageViewInitalFrame = frame
vc.bottomPreviewImage = image
@@ -916,6 +1049,14 @@ extension FeedsViewController: UITableViewDataSource, UITableViewDelegate {
mediaPreviewWindow.makeKeyAndVisible()
}
case .Audio:
guard let cell = cell as? FeedVoiceCell else {
break
}
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
cell.playOrPauseAudioAction = { [weak self] cell in
guard let realm = try? Realm(), feedAudio = FeedAudio.feedAudioWithFeedID(feed.id, inRealm: realm) else {
@@ -956,7 +1097,7 @@ extension FeedsViewController: UITableViewDataSource, UITableViewDelegate {
let indexPath = NSIndexPath(forRow: index, inSection: Section.Feed.rawValue)
if let cell = strongSelf.feedsTableView.cellForRowAtIndexPath(indexPath) as? FeedSocialWorkCell {
if let cell = strongSelf.feedsTableView.cellForRowAtIndexPath(indexPath) as? FeedVoiceCell {
cell.audioPlaying = false
}
@@ -977,6 +1118,14 @@ extension FeedsViewController: UITableViewDataSource, UITableViewDelegate {
}
}
case .Location:
guard let cell = cell as? FeedLocationCell else {
break
}
cell.configureWithFeed(feed, layoutCache: layoutCache, needShowSkill: needShowSkill)
cell.tapLocationAction = { locationName, locationCoordinate in
let mapItem = MKMapItem(placemark: MKPlacemark(coordinate: locationCoordinate, addressDictionary: nil))
@@ -986,54 +1135,7 @@ extension FeedsViewController: UITableViewDataSource, UITableViewDelegate {
}
default:
guard let cell = cell as? FeedCell else {
break
}
let feed = feeds[indexPath.item]
cell.configureWithFeed(feed, needShowSkill: (skill == nil) ? true : false)
cell.tapMediaAction = { [weak self] transitionView, image, attachments, index in
guard image != nil else {
return
}
let vc = UIStoryboard(name: "MediaPreview", bundle: nil).instantiateViewControllerWithIdentifier("MediaPreviewViewController") as! MediaPreviewViewController
vc.previewMedias = attachments.map({ PreviewMedia.AttachmentType(attachment: $0) })
vc.startIndex = index
let transitionView = transitionView
let frame = transitionView.convertRect(transitionView.frame, toView: self?.view)
vc.previewImageViewInitalFrame = frame
vc.bottomPreviewImage = image
vc.transitionView = transitionView
delay(0) {
transitionView.alpha = 0 // Runloop
}
vc.afterDismissAction = { [weak self] in
transitionView.alpha = 1
self?.view.window?.makeKeyAndVisible()
}
mediaPreviewWindow.rootViewController = vc
mediaPreviewWindow.windowLevel = UIWindowLevelAlert - 1
mediaPreviewWindow.makeKeyAndVisible()
/*
let info: [String: AnyObject] = [
"transitionView": transitionView,
"attachments": Box(value: attachments),
"index": index,
]
self?.performSegueWithIdentifier("showFeedMedia", sender: info)
*/
}
break
}
case Section.LoadMore.rawValue:
@@ -1066,7 +1168,7 @@ extension FeedsViewController: UITableViewDataSource, UITableViewDelegate {
case Section.Feed.rawValue:
let feed = feeds[indexPath.row]
return heightOfFeed(feed)
return FeedsViewController.layoutPool.heightOfFeed(feed)
case Section.LoadMore.rawValue:
return 60
@@ -558,7 +558,7 @@ class NewFeedViewController: UIViewController {
uploadState = .Uploading
let message = messageTextView.text
let message = messageTextView.text.trimming(.WhitespaceAndNewline)
let coordinate = YepLocationService.sharedManager.currentLocation?.coordinate
var kind: FeedKind = .Text
var mediaInfo: JSONDictionary?
@@ -793,7 +793,7 @@ class ProfileViewController: UIViewController {
}
#if DEBUG
view.addSubview(profileFPSLabel)
// view.addSubview(profileFPSLabel)
#endif
}
@@ -0,0 +1,165 @@
//
// FeedAnyImagesCell.swift
// Yep
//
// Created by nixzhu on 15/9/30.
// Copyright © 2015 Catch Inc. All rights reserved.
//
import UIKit
let feedAttachmentImageSize = YepConfig.FeedNormalImagesCell.imageSize
let feedAttachmentBiggerImageSize = YepConfig.FeedBiggerImageCell.imageSize
private let feedMediaCellID = "FeedMediaCell"
private let screenWidth: CGFloat = UIScreen.mainScreen().bounds.width
typealias FeedTapMediaAction = (transitionView: UIView, image: UIImage?, attachments: [DiscoveredAttachment], index: Int) -> Void
class FeedAnyImagesCell: FeedBasicCell {
lazy var mediaCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 5
layout.scrollDirection = .Horizontal
let collectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: layout)
collectionView.scrollsToTop = false
collectionView.contentInset = UIEdgeInsets(top: 0, left: 15 + 40 + 10, bottom: 0, right: 15)
collectionView.showsHorizontalScrollIndicator = false
collectionView.backgroundColor = UIColor.clearColor()
collectionView.registerNib(UINib(nibName: feedMediaCellID, bundle: nil), forCellWithReuseIdentifier: feedMediaCellID)
collectionView.dataSource = self
collectionView.delegate = self
let backgroundView = TouchClosuresView(frame: collectionView.bounds)
backgroundView.touchesBeganAction = { [weak self] in
if let strongSelf = self {
strongSelf.touchesBeganAction?(strongSelf)
}
}
backgroundView.touchesEndedAction = { [weak self] in
if let strongSelf = self {
if strongSelf.editing {
return
}
strongSelf.touchesEndedAction?(strongSelf)
}
}
backgroundView.touchesCancelledAction = { [weak self] in
if let strongSelf = self {
strongSelf.touchesCancelledAction?(strongSelf)
}
}
collectionView.backgroundView = backgroundView
return collectionView
}()
var tapMediaAction: FeedTapMediaAction?
var attachments = [DiscoveredAttachment]() {
didSet {
mediaCollectionView.reloadData()
}
}
override class func heightOfFeed(feed: DiscoveredFeed) -> CGFloat {
let height = super.heightOfFeed(feed) + feedAttachmentImageSize.height + 15
return ceil(height)
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(mediaCollectionView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareForReuse() {
super.prepareForReuse()
attachments = []
}
override func configureWithFeed(feed: DiscoveredFeed, layoutCache: FeedCellLayout.Cache, needShowSkill: Bool) {
var _newLayout: FeedCellLayout?
super.configureWithFeed(feed, layoutCache: (layout: layoutCache.layout, update: { newLayout in
_newLayout = newLayout
}), needShowSkill: needShowSkill)
if let anyImagesLayout = layoutCache.layout?.anyImagesLayout {
mediaCollectionView.frame = anyImagesLayout.mediaCollectionViewFrame
} else {
let y = messageTextView.frame.origin.y + messageTextView.frame.height + 15
let height = feedAttachmentImageSize.height
mediaCollectionView.frame = CGRect(x: 0, y: y, width: screenWidth, height: height)
}
if let attachment = feed.attachment, case let .Images(attachments) = attachment {
self.attachments = attachments
}
if layoutCache.layout == nil {
let anyImagesLayout = FeedCellLayout.AnyImagesLayout(mediaCollectionViewFrame: mediaCollectionView.frame)
_newLayout?.anyImagesLayout = anyImagesLayout
if let newLayout = _newLayout {
layoutCache.update(layout: newLayout)
}
}
}
}
extension FeedAnyImagesCell: UICollectionViewDataSource, UICollectionViewDelegate {
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return attachments.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(feedMediaCellID, forIndexPath: indexPath) as! FeedMediaCell
if let attachment = attachments[safe: indexPath.item] {
//println("attachment imageURL: \(imageURL)")
cell.configureWithAttachment(attachment, bigger: (attachments.count == 1))
}
return cell
}
func collectionView(collectionView: UICollectionView!, layout collectionViewLayout: UICollectionViewLayout!, sizeForItemAtIndexPath indexPath: NSIndexPath!) -> CGSize {
return feedAttachmentImageSize
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! FeedMediaCell
let transitionView = cell.imageView
tapMediaAction?(transitionView: transitionView, image: cell.imageView.image, attachments: attachments, index: indexPath.item)
}
}
+288
View File
@@ -0,0 +1,288 @@
//
// FeedBasicCell.swift
// Yep
//
// Created by nixzhu on 15/11/20.
// Copyright © 2015 Catch Inc. All rights reserved.
//
import UIKit
private let screenWidth: CGFloat = UIScreen.mainScreen().bounds.width
class FeedBasicCell: UITableViewCell {
lazy var avatarImageView: UIImageView = {
let imageView = UIImageView()
imageView.frame = CGRect(x: 15, y: 10, width: 40, height: 40)
imageView.contentMode = .ScaleAspectFit
let tapAvatar = UITapGestureRecognizer(target: self, action: "tapAvatar:")
imageView.userInteractionEnabled = true
imageView.addGestureRecognizer(tapAvatar)
return imageView
}()
lazy var nicknameLabel: UILabel = {
let label = UILabel()
label.textColor = UIColor.yepTintColor()
label.font = UIFont.systemFontOfSize(15)
label.frame = CGRect(x: 65, y: 21, width: 100, height: 18)
label.opaque = true
label.backgroundColor = UIColor.whiteColor()
label.clipsToBounds = true
return label
}()
lazy var skillButton: UIButton = {
let button = UIButton()
button.setBackgroundImage(UIImage(named: "skill_bubble_empty"), forState: .Normal)
button.setTitleColor(UIColor.yepTintColor(), forState: .Normal)
button.titleLabel?.font = UIFont.feedSkillFont()
let cellWidth = self.bounds.width
let width: CGFloat = 60
button.frame = CGRect(x: cellWidth - width - 15, y: 19, width: width, height: 22)
button.addTarget(self, action: "tapSkill:", forControlEvents: .TouchUpInside)
return button
}()
lazy var messageTextView: FeedTextView = {
let textView = FeedTextView()
textView.textColor = UIColor.yepMessageColor()
textView.font = UIFont.feedMessageFont()
textView.textContainer.lineFragmentPadding = 0
textView.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
textView.editable = false
textView.scrollEnabled = false
textView.showsHorizontalScrollIndicator = false
textView.showsVerticalScrollIndicator = false
textView.dataDetectorTypes = [.Link, .CalendarEvent]
textView.frame = CGRect(x: 65, y: 54, width: screenWidth - 65 - 15, height: 26)
textView.opaque = true
textView.backgroundColor = UIColor.whiteColor()
textView.touchesBeganAction = { [weak self] in
if let strongSelf = self {
strongSelf.touchesBeganAction?(strongSelf)
}
}
textView.touchesEndedAction = { [weak self] in
if let strongSelf = self {
if strongSelf.editing {
return
}
strongSelf.touchesEndedAction?(strongSelf)
}
}
textView.touchesCancelledAction = { [weak self] in
if let strongSelf = self {
strongSelf.touchesCancelledAction?(strongSelf)
}
}
return textView
}()
lazy var leftBottomLabel: UILabel = {
let label = UILabel()
label.textColor = UIColor.grayColor()
label.font = UIFont.feedBottomLabelsFont()
label.frame = CGRect(x: 65, y: 0, width: 200, height: 17)
label.opaque = true
label.backgroundColor = UIColor.whiteColor()
label.clipsToBounds = true
return label
}()
lazy var messageCountLabel: UILabel = {
let label = UILabel()
label.textColor = UIColor.yepTintColor()
label.font = UIFont.feedBottomLabelsFont()
label.frame = CGRect(x: 65, y: 0, width: 200, height: 17)
label.opaque = true
label.backgroundColor = UIColor.whiteColor()
label.clipsToBounds = true
return label
}()
lazy var discussionImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "icon_discussion")
return imageView
}()
var feed: DiscoveredFeed?
var tapAvatarAction: (UITableViewCell -> Void)?
var tapSkillAction: (UITableViewCell -> Void)?
var touchesBeganAction: (UITableViewCell -> Void)?
var touchesEndedAction: (UITableViewCell -> Void)?
var touchesCancelledAction: (UITableViewCell -> Void)?
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
separatorInset = UIEdgeInsets(top: 0, left: 65, bottom: 0, right: 0)
contentView.addSubview(avatarImageView)
contentView.addSubview(nicknameLabel)
contentView.addSubview(skillButton)
contentView.addSubview(messageTextView)
contentView.addSubview(leftBottomLabel)
contentView.addSubview(messageCountLabel)
contentView.addSubview(discussionImageView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
static let messageTextViewMaxWidth: CGFloat = {
let maxWidth = UIScreen.mainScreen().bounds.width - (15 + 40 + 10 + 15)
return maxWidth
}()
class func heightOfFeed(feed: DiscoveredFeed) -> CGFloat {
let rect = feed.body.boundingRectWithSize(CGSize(width: FeedBasicCell.messageTextViewMaxWidth, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.textAttributes, context: nil)
let height: CGFloat = ceil(rect.height) + 10 + 40 + 4 + 15 + 17 + 15
return ceil(height)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func prepareForReuse() {
super.prepareForReuse()
feed = nil
messageTextView.text = nil
messageTextView.attributedText = nil
}
private func calHeightOfMessageTextView() {
let rect = messageTextView.text.boundingRectWithSize(CGSize(width: FeedBasicCell.messageTextViewMaxWidth, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.textAttributes, context: nil)
messageTextView.frame.size.height = ceil(rect.height)
}
func configureWithFeed(feed: DiscoveredFeed, layoutCache: FeedCellLayout.Cache, needShowSkill: Bool) {
self.feed = feed
let layout = layoutCache.layout
messageTextView.text = "\u{200B}\(feed.body)" // ref http://stackoverflow.com/a/25994821
//println("messageTextView.text: >>>\(messageTextView.text)<<<")
if let basicLayout = layout?.basicLayout {
messageTextView.frame = basicLayout.messageTextViewFrame
} else {
calHeightOfMessageTextView()
}
if needShowSkill, let skill = feed.skill {
skillButton.setTitle(skill.localName, forState: .Normal)
skillButton.hidden = false
if let basicLayout = layout?.basicLayout {
skillButton.frame = basicLayout.skillButtonFrame
nicknameLabel.frame = basicLayout.nicknameLabelFrameWhen(hasLogo: false, hasSkill: true)
} else {
let rect = skill.localName.boundingRectWithSize(CGSize(width: 320, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.skillTextAttributes, context: nil)
let skillButtonWidth = ceil(rect.width) + 20
skillButton.frame = CGRect(x: screenWidth - skillButtonWidth - 15, y: 19, width: skillButtonWidth, height: 22)
nicknameLabel.frame.size.width = screenWidth - 65 - skillButtonWidth - 20 - 10 - 15
}
} else {
skillButton.hidden = true
if let basicLayout = layout?.basicLayout {
nicknameLabel.frame = basicLayout.nicknameLabelFrameWhen(hasLogo: false, hasSkill: false)
} else {
nicknameLabel.frame.size.width = screenWidth - 65 - 15
}
}
let plainAvatar = PlainAvatar(avatarURLString: feed.creator.avatarURLString, avatarStyle: nanoAvatarStyle)
avatarImageView.navi_setAvatar(plainAvatar, withFadeTransitionDuration: avatarFadeTransitionDuration)
nicknameLabel.text = feed.creator.nickname
leftBottomLabel.text = feed.timeAndDistanceString
let messagesCountString = "\(feed.messagesCount)"
messageCountLabel.text = messagesCountString
messageCountLabel.hidden = (feed.messagesCount == 0)
if let basicLayout = layout?.basicLayout {
leftBottomLabel.frame = basicLayout.leftBottomLabelFrame
messageCountLabel.frame = basicLayout.messageCountLabelFrame
discussionImageView.frame = basicLayout.discussionImageViewFrame
} else {
leftBottomLabel.frame.origin.y = contentView.bounds.height - leftBottomLabel.frame.height - 10
let rect = messagesCountString.boundingRectWithSize(CGSize(width: 320, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.bottomLabelsTextAttributes, context: nil)
let width = ceil(rect.width)
messageCountLabel.frame = CGRect(x: screenWidth - width - 45 - 8, y: leftBottomLabel.frame.origin.y, width: width, height: 19)
discussionImageView.frame = CGRect(x: screenWidth - 30 - 15, y: leftBottomLabel.frame.origin.y - 1, width: 30, height: 19)
}
if layoutCache.layout == nil {
var nicknameLabelFrame = nicknameLabel.frame
nicknameLabelFrame.size.width = screenWidth - 65 - 15
let basicLayout = FeedCellLayout.BasicLayout(avatarImageViewFrame: avatarImageView.frame, nicknameLabelFrame: nicknameLabelFrame, skillButtonFrame: skillButton.frame, messageTextViewFrame: messageTextView.frame, leftBottomLabelFrame: leftBottomLabel.frame, messageCountLabelFrame: messageCountLabel.frame, discussionImageViewFrame: discussionImageView.frame)
let newLayout = FeedCellLayout(height: contentView.bounds.height, basicLayout: basicLayout)
layoutCache.update(layout: newLayout)
}
}
// MARK: Actions
func tapAvatar(sender: UITapGestureRecognizer) {
tapAvatarAction?(self)
}
func tapSkill(sender: AnyObject) {
tapSkillAction?(self)
}
}
@@ -0,0 +1,96 @@
//
// FeedBiggerImageCell.swift
// Yep
//
// Created by nixzhu on 15/12/17.
// Copyright © 2015 Catch Inc. All rights reserved.
//
import UIKit
class FeedBiggerImageCell: FeedBasicCell {
var tapMediaAction: FeedTapMediaAction?
lazy var biggerImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .ScaleAspectFill
imageView.clipsToBounds = true
imageView.frame = CGRect(origin: CGPoint(x: 65, y: 0), size: YepConfig.FeedBiggerImageCell.imageSize)
imageView.layer.borderColor = UIColor.yepBorderColor().CGColor
imageView.layer.borderWidth = 1
imageView.userInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: "tap:")
imageView.addGestureRecognizer(tap)
return imageView
}()
override class func heightOfFeed(feed: DiscoveredFeed) -> CGFloat {
let height = super.heightOfFeed(feed) + YepConfig.FeedBiggerImageCell.imageSize.height + 15
return ceil(height)
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(biggerImageView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func prepareForReuse() {
super.prepareForReuse()
biggerImageView.image = nil
}
override func configureWithFeed(feed: DiscoveredFeed, layoutCache: FeedCellLayout.Cache, needShowSkill: Bool) {
var _newLayout: FeedCellLayout?
super.configureWithFeed(feed, layoutCache: (layout: layoutCache.layout, update: { newLayout in
_newLayout = newLayout
}), needShowSkill: needShowSkill)
if let biggerImageLayout = layoutCache.layout?.biggerImageLayout {
biggerImageView.frame = biggerImageLayout.biggerImageViewFrame
} else {
biggerImageView.frame.origin.y = messageTextView.frame.origin.y + messageTextView.frame.height + 15
}
if let onlyAttachment = feed.imageAttachments?.first {
biggerImageView.yep_showActivityIndicatorWhenLoading = true
biggerImageView.yep_setImageOfAttachment(onlyAttachment, withSize: YepConfig.FeedBiggerImageCell.imageSize)
}
if layoutCache.layout == nil {
let biggerImageLayout = FeedCellLayout.BiggerImageLayout(biggerImageViewFrame: biggerImageView.frame)
_newLayout?.biggerImageLayout = biggerImageLayout
if let newLayout = _newLayout {
layoutCache.update(layout: newLayout)
}
}
}
@objc private func tap(sender: UITapGestureRecognizer) {
if let attachments = feed?.imageAttachments {
tapMediaAction?(transitionView: biggerImageView, image: biggerImageView.image, attachments: attachments, index: 0)
}
}
}
-172
View File
@@ -1,172 +0,0 @@
//
// FeedCell.swift
// Yep
//
// Created by nixzhu on 15/9/30.
// Copyright © 2015 Catch Inc. All rights reserved.
//
import UIKit
let feedAttachmentImageSize = CGSize(width: 80, height: 80)
let feedAttachmentBiggerImageSize = CGSize(width: 160, height: 160)
class FeedCell: FeedBasicCell {
@IBOutlet weak var mediaCollectionView: UICollectionView!
@IBOutlet weak var collectionViewHeight: NSLayoutConstraint!
@IBOutlet weak var leftBottomLabelTopConstraint: NSLayoutConstraint!
var tapMediaAction: ((transitionView: UIView, image: UIImage?, attachments: [DiscoveredAttachment], index: Int) -> Void)?
var attachments = [DiscoveredAttachment]() {
didSet {
let oldHeight = collectionViewHeight.constant
let newHeight: CGFloat
if attachments.count == 1 {
newHeight = feedAttachmentBiggerImageSize.height
} else {
newHeight = feedAttachmentImageSize.height
}
if newHeight != oldHeight {
collectionViewHeight.constant = newHeight
}
mediaCollectionView.reloadData()
}
}
static let messageTextViewMaxWidth: CGFloat = {
let maxWidth = UIScreen.mainScreen().bounds.width - (15 + 40 + 10 + 15)
return maxWidth
}()
let feedMediaCellID = "FeedMediaCell"
class func heightOfFeed(feed: DiscoveredFeed) -> CGFloat {
let rect = feed.body.boundingRectWithSize(CGSize(width: FeedCell.messageTextViewMaxWidth, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.textAttributes, context: nil)
var height: CGFloat = ceil(rect.height) + 10 + 40 + 4 + 15 + 17 + 15
if let attachment = feed.attachment {
if case let .Images(attachments) = attachment {
let imageHeight: CGFloat = attachments.count == 1 ? feedAttachmentBiggerImageSize.height : feedAttachmentImageSize.height
height += (imageHeight + 15)
}
}
return ceil(height)
}
override func awakeFromNib() {
super.awakeFromNib()
mediaCollectionView.scrollsToTop = false
mediaCollectionView.contentInset = UIEdgeInsets(top: 0, left: 15 + 40 + 10, bottom: 0, right: 15)
mediaCollectionView.showsHorizontalScrollIndicator = false
mediaCollectionView.backgroundColor = UIColor.clearColor()
mediaCollectionView.registerNib(UINib(nibName: feedMediaCellID, bundle: nil), forCellWithReuseIdentifier: feedMediaCellID)
mediaCollectionView.dataSource = self
mediaCollectionView.delegate = self
let backgroundView = TouchClosuresView(frame: mediaCollectionView.bounds)
backgroundView.touchesBeganAction = { [weak self] in
if let strongSelf = self {
strongSelf.touchesBeganAction?(strongSelf)
}
}
backgroundView.touchesEndedAction = { [weak self] in
if let strongSelf = self {
if strongSelf.editing {
return
}
strongSelf.touchesEndedAction?(strongSelf)
}
}
backgroundView.touchesCancelledAction = { [weak self] in
if let strongSelf = self {
strongSelf.touchesCancelledAction?(strongSelf)
}
}
mediaCollectionView.backgroundView = backgroundView
}
override func prepareForReuse() {
super.prepareForReuse()
attachments = []
}
override func configureWithFeed(feed: DiscoveredFeed, needShowSkill: Bool) {
super.configureWithFeed(feed, needShowSkill: needShowSkill)
var hasMedia = false
if let attachment = feed.attachment {
if case let .Images(attachments) = attachment {
hasMedia = !attachments.isEmpty
self.attachments = attachments
}
}
if attachments.count > 1 {
leftBottomLabelTopConstraint.constant = hasMedia ? (15 + feedAttachmentImageSize.height + 15) : 15
} else {
leftBottomLabelTopConstraint.constant = hasMedia ? (15 + feedAttachmentBiggerImageSize.height + 15) : 15
}
mediaCollectionView.hidden = hasMedia ? false : true
}
}
extension FeedCell: UICollectionViewDataSource, UICollectionViewDelegate {
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return attachments.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(feedMediaCellID, forIndexPath: indexPath) as! FeedMediaCell
if let attachment = attachments[safe: indexPath.item] {
//println("attachment imageURL: \(imageURL)")
cell.configureWithAttachment(attachment, bigger: (attachments.count == 1))
}
return cell
}
func collectionView(collectionView: UICollectionView!, layout collectionViewLayout: UICollectionViewLayout!, sizeForItemAtIndexPath indexPath: NSIndexPath!) -> CGSize {
if attachments.count > 1 {
return feedAttachmentImageSize
} else {
return feedAttachmentBiggerImageSize
}
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let cell = collectionView.cellForItemAtIndexPath(indexPath) as! FeedMediaCell
let transitionView = cell.imageView
tapMediaAction?(transitionView: transitionView, image: cell.imageView.image, attachments: attachments, index: indexPath.item)
}
}
-121
View File
@@ -1,121 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" horizontalHuggingPriority="251" selectionStyle="default" indentationWidth="10" reuseIdentifier="FeedCell" rowHeight="217" id="KGk-i7-Jjw" customClass="FeedCell" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="381" height="217"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="381" height="216.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2 hours ago ∙ 1.2 km" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yFm-kf-Ghp" userLabel="Time Label">
<rect key="frame" x="65" y="183" width="127.5" height="17"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="14"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="COt-7F-KVK">
<rect key="frame" x="0.0" y="95" width="381" height="80"/>
<constraints>
<constraint firstAttribute="height" constant="80" id="6PE-QR-i1C"/>
</constraints>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="5" minimumInteritemSpacing="0.0" id="sxC-Ge-mF8">
<size key="itemSize" width="50" height="50"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
</collectionView>
<label clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="NIX" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="d97-mK-bJE" userLabel="Nickname Label">
<rect key="frame" x="65" y="21" width="232" height="18"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_discussion" translatesAutoresizingMaskIntoConstraints="NO" id="B9B-Nc-h8k">
<rect key="frame" x="336" y="182" width="30" height="19"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="GRs-kP-Ugk" userLabel="Avatar Image View">
<rect key="frame" x="15" y="10" width="40" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="iWz-Lj-rIE"/>
</constraints>
</imageView>
<label clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="42" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6k9-TF-Ftd" userLabel="Message Count Label">
<rect key="frame" x="311" y="183" width="17" height="17"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="14"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<textView multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" editable="NO" text="How do you do?" translatesAutoresizingMaskIntoConstraints="NO" id="XYv-cX-YOQ" customClass="FeedTextView" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="65" y="54" width="301" height="26"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="height" constant="26" id="DpP-3J-Ftw"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<dataDetectorType key="dataDetectorTypes" phoneNumber="YES" link="YES" address="YES" calendarEvent="YES"/>
</textView>
<button contentMode="scaleToFill" horizontalHuggingPriority="251" horizontalCompressionResistancePriority="751" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="w50-SA-ZeZ">
<rect key="frame" x="305" y="19" width="61" height="22"/>
<inset key="contentEdgeInsets" minX="10" minY="0.0" maxX="10" maxY="0.0"/>
<state key="normal" title="Swift" backgroundImage="skill_bubble_empty">
<color key="titleColor" red="0.0" green="0.50196081400000003" blue="1" alpha="1" colorSpace="calibratedRGB"/>
</state>
</button>
</subviews>
<constraints>
<constraint firstItem="yFm-kf-Ghp" firstAttribute="leading" secondItem="d97-mK-bJE" secondAttribute="leading" id="4dw-W2-nT9"/>
<constraint firstAttribute="trailing" secondItem="B9B-Nc-h8k" secondAttribute="trailing" constant="15" id="5um-0R-Amw"/>
<constraint firstItem="COt-7F-KVK" firstAttribute="top" secondItem="XYv-cX-YOQ" secondAttribute="bottom" constant="15" id="9J9-YH-c9Y"/>
<constraint firstAttribute="trailing" secondItem="COt-7F-KVK" secondAttribute="trailing" id="AfO-Hm-djL"/>
<constraint firstItem="XYv-cX-YOQ" firstAttribute="top" secondItem="GRs-kP-Ugk" secondAttribute="bottom" constant="4" id="ISv-4s-Llp"/>
<constraint firstItem="XYv-cX-YOQ" firstAttribute="leading" secondItem="d97-mK-bJE" secondAttribute="leading" id="IxD-gR-ma8"/>
<constraint firstItem="B9B-Nc-h8k" firstAttribute="leading" secondItem="6k9-TF-Ftd" secondAttribute="trailing" constant="8" id="JkX-QS-ZmS"/>
<constraint firstAttribute="trailing" secondItem="XYv-cX-YOQ" secondAttribute="trailing" constant="15" id="MkQ-lA-NHH"/>
<constraint firstItem="d97-mK-bJE" firstAttribute="leading" secondItem="GRs-kP-Ugk" secondAttribute="trailing" constant="10" id="QXo-33-0ak"/>
<constraint firstItem="B9B-Nc-h8k" firstAttribute="centerY" secondItem="yFm-kf-Ghp" secondAttribute="centerY" id="RQK-md-Cni"/>
<constraint firstItem="6k9-TF-Ftd" firstAttribute="centerY" secondItem="B9B-Nc-h8k" secondAttribute="centerY" id="Sk6-jV-ssD"/>
<constraint firstItem="d97-mK-bJE" firstAttribute="centerY" secondItem="GRs-kP-Ugk" secondAttribute="centerY" id="XVe-o1-zRc"/>
<constraint firstItem="w50-SA-ZeZ" firstAttribute="leading" secondItem="d97-mK-bJE" secondAttribute="trailing" constant="8" id="cNw-hl-wur"/>
<constraint firstItem="GRs-kP-Ugk" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="10" id="cna-DW-PPM"/>
<constraint firstItem="GRs-kP-Ugk" firstAttribute="width" secondItem="GRs-kP-Ugk" secondAttribute="height" multiplier="1:1" id="eSL-Jv-LjB"/>
<constraint firstItem="w50-SA-ZeZ" firstAttribute="centerY" secondItem="d97-mK-bJE" secondAttribute="centerY" id="hiS-rM-P2a"/>
<constraint firstAttribute="trailing" secondItem="w50-SA-ZeZ" secondAttribute="trailing" constant="15" id="o7n-fb-1OH"/>
<constraint firstItem="yFm-kf-Ghp" firstAttribute="top" secondItem="XYv-cX-YOQ" secondAttribute="bottom" constant="103" id="sKd-JT-Af9"/>
<constraint firstItem="GRs-kP-Ugk" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="15" id="tIk-7d-Ux7"/>
<constraint firstItem="COt-7F-KVK" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" id="uDa-ob-a5U"/>
</constraints>
</tableViewCellContentView>
<inset key="separatorInset" minX="60" minY="0.0" maxX="0.0" maxY="0.0"/>
<connections>
<outlet property="avatarImageView" destination="GRs-kP-Ugk" id="Rch-2A-tIe"/>
<outlet property="collectionViewHeight" destination="6PE-QR-i1C" id="dys-gS-hg4"/>
<outlet property="leftBottomLabel" destination="yFm-kf-Ghp" id="DJi-XF-E6C"/>
<outlet property="leftBottomLabelTopConstraint" destination="sKd-JT-Af9" id="UUi-Ex-7Oc"/>
<outlet property="mediaCollectionView" destination="COt-7F-KVK" id="ldA-nK-8V3"/>
<outlet property="messageCountLabel" destination="6k9-TF-Ftd" id="GNB-Qx-e2z"/>
<outlet property="messageTextView" destination="XYv-cX-YOQ" id="2mS-ke-PoR"/>
<outlet property="messageTextViewHeightConstraint" destination="DpP-3J-Ftw" id="nSl-a2-gRm"/>
<outlet property="nicknameLabel" destination="d97-mK-bJE" id="xcQ-hs-iRs"/>
<outlet property="skillButton" destination="w50-SA-ZeZ" id="iQw-6p-3rX"/>
</connections>
<point key="canvasLocation" x="322.5" y="383.5"/>
</tableViewCell>
</objects>
<resources>
<image name="icon_discussion" width="30" height="19"/>
<image name="skill_bubble_empty" width="23" height="22"/>
</resources>
</document>
+301
View File
@@ -0,0 +1,301 @@
//
// FeedCellLayout.swift
// Yep
//
// Created by nixzhu on 15/12/17.
// Copyright © 2015 Catch Inc. All rights reserved.
//
import UIKit
private let screenWidth: CGFloat = UIScreen.mainScreen().bounds.width
struct FeedCellLayout {
typealias Update = (layout: FeedCellLayout) -> Void
typealias Cache = (layout: FeedCellLayout?, update: Update)
let height: CGFloat
struct BasicLayout {
func nicknameLabelFrameWhen(hasLogo hasLogo: Bool, hasSkill: Bool) -> CGRect {
var frame = nicknameLabelFrame
frame.size.width -= hasLogo ? (18 + 10) : 0
frame.size.width -= hasSkill ? (skillButtonFrame.width + 10) : 0
return frame
}
let avatarImageViewFrame: CGRect
private let nicknameLabelFrame: CGRect
let skillButtonFrame: CGRect
let messageTextViewFrame: CGRect
let leftBottomLabelFrame: CGRect
let messageCountLabelFrame: CGRect
let discussionImageViewFrame: CGRect
init(avatarImageViewFrame: CGRect,
nicknameLabelFrame: CGRect,
skillButtonFrame: CGRect,
messageTextViewFrame: CGRect,
leftBottomLabelFrame: CGRect,
messageCountLabelFrame: CGRect,
discussionImageViewFrame: CGRect) {
self.avatarImageViewFrame = avatarImageViewFrame
self.nicknameLabelFrame = nicknameLabelFrame
self.skillButtonFrame = skillButtonFrame
self.messageTextViewFrame = messageTextViewFrame
self.leftBottomLabelFrame = leftBottomLabelFrame
self.messageCountLabelFrame = messageCountLabelFrame
self.discussionImageViewFrame = discussionImageViewFrame
}
}
let basicLayout: BasicLayout
struct BiggerImageLayout {
let biggerImageViewFrame: CGRect
init(biggerImageViewFrame: CGRect) {
self.biggerImageViewFrame = biggerImageViewFrame
}
}
var biggerImageLayout: BiggerImageLayout?
struct NormalImagesLayout {
let imageView1Frame: CGRect
let imageView2Frame: CGRect
let imageView3Frame: CGRect
init(imageView1Frame: CGRect, imageView2Frame: CGRect, imageView3Frame: CGRect) {
self.imageView1Frame = imageView1Frame
self.imageView2Frame = imageView2Frame
self.imageView3Frame = imageView3Frame
}
}
var normalImagesLayout: NormalImagesLayout?
struct AnyImagesLayout {
let mediaCollectionViewFrame: CGRect
init(mediaCollectionViewFrame: CGRect) {
self.mediaCollectionViewFrame = mediaCollectionViewFrame
}
}
var anyImagesLayout: AnyImagesLayout?
struct GithubRepoLayout {
let githubRepoContainerViewFrame: CGRect
}
var githubRepoLayout: GithubRepoLayout?
struct DribbbleShotLayout {
let dribbbleShotContainerViewFrame: CGRect
}
var dribbbleShotLayout: DribbbleShotLayout?
struct AudioLayout {
let voiceContainerViewFrame: CGRect
}
var audioLayout: AudioLayout?
struct LocationLayout {
let locationContainerViewFrame: CGRect
}
var locationLayout: LocationLayout?
// MARK: - Init
init(height: CGFloat, basicLayout: BasicLayout) {
self.height = height
self.basicLayout = basicLayout
}
init(feed: DiscoveredFeed) {
let height: CGFloat
switch feed.kind {
case .Text:
height = FeedBasicCell.heightOfFeed(feed)
case .Image:
if feed.imageAttachmentsCount == 1 {
height = FeedBiggerImageCell.heightOfFeed(feed)
} else if feed.imageAttachmentsCount <= 3 {
height = FeedNormalImagesCell.heightOfFeed(feed)
} else {
height = FeedAnyImagesCell.heightOfFeed(feed)
}
case .GithubRepo:
height = FeedGithubRepoCell.heightOfFeed(feed)
case .DribbbleShot:
height = FeedDribbbleShotCell.heightOfFeed(feed)
case .Audio:
height = FeedVoiceCell.heightOfFeed(feed)
case .Location:
height = FeedLocationCell.heightOfFeed(feed)
default:
height = FeedBasicCell.heightOfFeed(feed)
}
self.height = height
let avatarImageViewFrame = CGRect(x: 15, y: 10, width: 40, height: 40)
let nicknameLabelFrame: CGRect
let skillButtonFrame: CGRect
if let skill = feed.skill {
let rect = skill.localName.boundingRectWithSize(CGSize(width: 320, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.skillTextAttributes, context: nil)
let skillButtonWidth = ceil(rect.width) + 20
skillButtonFrame = CGRect(x: screenWidth - skillButtonWidth - 15, y: 19, width: skillButtonWidth, height: 22)
let nicknameLabelWidth = screenWidth - 65 - 15
nicknameLabelFrame = CGRect(x: 65, y: 21, width: nicknameLabelWidth, height: 18)
} else {
let nicknameLabelWidth = screenWidth - 65 - 15
nicknameLabelFrame = CGRect(x: 65, y: 21, width: nicknameLabelWidth, height: 18)
skillButtonFrame = CGRectZero
}
let _rect1 = feed.body.boundingRectWithSize(CGSize(width: FeedBasicCell.messageTextViewMaxWidth, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.textAttributes, context: nil)
let messageTextViewHeight = ceil(_rect1.height)
let messageTextViewFrame = CGRect(x: 65, y: 54, width: screenWidth - 65 - 15, height: messageTextViewHeight)
let leftBottomLabelOriginY = height - 17 - 10
let leftBottomLabelFrame = CGRect(x: 65, y: leftBottomLabelOriginY, width: 200, height: 17)
let messagesCountString = "\(feed.messagesCount)"
let _rect2 = messagesCountString.boundingRectWithSize(CGSize(width: 320, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.bottomLabelsTextAttributes, context: nil)
let _width = ceil(_rect2.width)
let messageCountLabelFrame = CGRect(x: screenWidth - _width - 45 - 8, y: leftBottomLabelOriginY, width: _width, height: 19)
let discussionImageViewFrame = CGRect(x: screenWidth - 30 - 15, y: leftBottomLabelOriginY - 1, width: 30, height: 19)
let basicLayout = FeedCellLayout.BasicLayout(
avatarImageViewFrame: avatarImageViewFrame,
nicknameLabelFrame: nicknameLabelFrame,
skillButtonFrame: skillButtonFrame,
messageTextViewFrame: messageTextViewFrame,
leftBottomLabelFrame: leftBottomLabelFrame,
messageCountLabelFrame: messageCountLabelFrame,
discussionImageViewFrame: discussionImageViewFrame
)
self.basicLayout = basicLayout
let beginY = messageTextViewFrame.origin.y + messageTextViewFrame.height + 15
switch feed.kind {
case .Text:
break
case .Image:
if feed.imageAttachmentsCount == 1 {
let biggerImageViewFrame = CGRect(origin: CGPoint(x: 65, y: beginY), size: YepConfig.FeedBiggerImageCell.imageSize)
let biggerImageLayout = FeedCellLayout.BiggerImageLayout(biggerImageViewFrame: biggerImageViewFrame)
self.biggerImageLayout = biggerImageLayout
} else if feed.imageAttachmentsCount <= 3 {
let x1 = 65 + (YepConfig.FeedNormalImagesCell.imageSize.width + 5) * 0
let imageView1Frame = CGRect(origin: CGPoint(x: x1, y: beginY), size: YepConfig.FeedNormalImagesCell.imageSize)
let x2 = 65 + (YepConfig.FeedNormalImagesCell.imageSize.width + 5) * 1
let imageView2Frame = CGRect(origin: CGPoint(x: x2, y: beginY), size: YepConfig.FeedNormalImagesCell.imageSize)
let x3 = 65 + (YepConfig.FeedNormalImagesCell.imageSize.width + 5) * 2
let imageView3Frame = CGRect(origin: CGPoint(x: x3, y: beginY), size: YepConfig.FeedNormalImagesCell.imageSize)
let normalImagesLayout = FeedCellLayout.NormalImagesLayout(imageView1Frame: imageView1Frame, imageView2Frame: imageView2Frame, imageView3Frame: imageView3Frame)
self.normalImagesLayout = normalImagesLayout
} else {
let height = feedAttachmentImageSize.height
let mediaCollectionViewFrame = CGRect(x: 0, y: beginY, width: screenWidth, height: height)
let anyImagesLayout = FeedCellLayout.AnyImagesLayout(mediaCollectionViewFrame: mediaCollectionViewFrame)
self.anyImagesLayout = anyImagesLayout
}
case .GithubRepo:
let height: CGFloat = leftBottomLabelFrame.origin.y - beginY - 15
let githubRepoContainerViewFrame = CGRect(x: 65, y: beginY, width: screenWidth - 65 - 60, height: height)
let githubRepoLayout = FeedCellLayout.GithubRepoLayout(githubRepoContainerViewFrame: githubRepoContainerViewFrame)
self.githubRepoLayout = githubRepoLayout
case .DribbbleShot:
let height: CGFloat = leftBottomLabelFrame.origin.y - beginY - 15
let dribbbleShotContainerViewFrame = CGRect(x: 65, y: beginY, width: screenWidth - 65 - 60, height: height)
let dribbbleShotLayout = FeedCellLayout.DribbbleShotLayout(dribbbleShotContainerViewFrame: dribbbleShotContainerViewFrame)
self.dribbbleShotLayout = dribbbleShotLayout
case .Audio:
if let attachment = feed.attachment {
if case let .Audio(audioInfo) = attachment {
let timeLengthString = String(format: "%.1f\"", audioInfo.duration)
let rect = timeLengthString.boundingRectWithSize(CGSize(width: 320, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.voiceTimeLengthTextAttributes, context: nil)
let width = 7 + 30 + 5 + CGFloat(audioInfo.sampleValues.count) * 3 + 5 + rect.width + 5
let y = beginY + 2
let voiceContainerViewFrame = CGRect(x: 65, y: y, width: width, height: 40)
let audioLayout = FeedCellLayout.AudioLayout(voiceContainerViewFrame: voiceContainerViewFrame)
self.audioLayout = audioLayout
}
}
case .Location:
let height: CGFloat = leftBottomLabelFrame.origin.y - beginY - 15
let locationContainerViewFrame = CGRect(x: 65, y: beginY, width: screenWidth - 65 - 60, height: height)
let locationLayout = FeedCellLayout.LocationLayout(locationContainerViewFrame: locationContainerViewFrame)
self.locationLayout = locationLayout
default:
break
}
}
}
@@ -0,0 +1,156 @@
//
// FeedDribbbleShotCell.swift
// Yep
//
// Created by nixzhu on 15/12/17.
// Copyright © 2015 Catch Inc. All rights reserved.
//
import UIKit
import Ruler
private let screenWidth: CGFloat = UIScreen.mainScreen().bounds.width
private let dribbbleShotHeight: CGFloat = Ruler.iPhoneHorizontal(160, 200, 220).value
class FeedDribbbleShotCell: FeedBasicCell {
var tapDribbbleShotLinkAction: (NSURL -> Void)?
var tapDribbbleShotMediaAction: ((transitionView: UIView, image: UIImage?, imageURL: NSURL, linkURL: NSURL) -> Void)?
lazy var logoImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: SocialAccount.Dribbble.iconName)
imageView.frame = CGRect(x: 0, y: 0, width: 18, height: 18)
imageView.tintColor = SocialAccount.Dribbble.tintColor
return imageView
}()
lazy var mediaContainerView: FeedMediaContainerView = {
let view = FeedMediaContainerView()
view.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
return view
}()
lazy var socialWorkBorderImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "social_work_border")
return imageView
}()
lazy var halfMaskImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "social_media_image_mask"))
return imageView
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(logoImageView)
contentView.addSubview(mediaContainerView)
contentView.addSubview(socialWorkBorderImageView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override class func heightOfFeed(feed: DiscoveredFeed) -> CGFloat {
let height = super.heightOfFeed(feed) + (dribbbleShotHeight + 15)
return ceil(height)
}
override func prepareForReuse() {
super.prepareForReuse()
mediaContainerView.mediaImageView.image = nil
}
override func configureWithFeed(feed: DiscoveredFeed, layoutCache: FeedCellLayout.Cache, needShowSkill: Bool) {
var _newLayout: FeedCellLayout?
super.configureWithFeed(feed, layoutCache: (layout: layoutCache.layout, update: { newLayout in
_newLayout = newLayout
}), needShowSkill: needShowSkill)
if needShowSkill, let _ = feed.skill {
logoImageView.frame.origin.x = skillButton.frame.origin.x - 10 - 18
logoImageView.frame.origin.y = nicknameLabel.frame.origin.y
} else {
logoImageView.frame.origin.x = screenWidth - 18 - 15
logoImageView.frame.origin.y = nicknameLabel.frame.origin.y
}
nicknameLabel.frame.size.width -= logoImageView.bounds.width + 10
if let attachment = feed.attachment {
if case let .Dribbble(dribbbleShot) = attachment {
if let URL = NSURL(string: dribbbleShot.imageURLString) {
mediaContainerView.mediaImageView.kf_showIndicatorWhenLoading = true
mediaContainerView.mediaImageView.kf_setImageWithURL(URL, placeholderImage: nil, optionsInfo: MediaOptionsInfos)
}
mediaContainerView.linkContainerView.textLabel.text = dribbbleShot.title
}
}
mediaContainerView.tapMediaAction = { [weak self] mediaImageView in
guard let attachment = feed.attachment else {
return
}
if case .DribbbleShot = feed.kind {
if case let .Dribbble(shot) = attachment, let imageURL = NSURL(string: shot.imageURLString), let linkURL = NSURL(string: shot.htmlURLString) {
self?.tapDribbbleShotMediaAction?(transitionView: mediaImageView, image: mediaImageView.image, imageURL: imageURL, linkURL: linkURL)
}
}
}
mediaContainerView.linkContainerView.tapAction = { [weak self] in
guard let attachment = feed.attachment else {
return
}
if case .DribbbleShot = feed.kind {
if case let .Dribbble(shot) = attachment, let URL = NSURL(string: shot.htmlURLString) {
self?.tapDribbbleShotLinkAction?(URL)
}
}
}
if let dribbbleShotLayout = layoutCache.layout?.dribbbleShotLayout {
mediaContainerView.frame = dribbbleShotLayout.dribbbleShotContainerViewFrame
socialWorkBorderImageView.frame = mediaContainerView.frame
} else {
let y = messageTextView.frame.origin.y + messageTextView.frame.height + 15
let height: CGFloat = leftBottomLabel.frame.origin.y - y - 15
mediaContainerView.frame = CGRect(x: 65, y: y, width: screenWidth - 65 - 60, height: height)
socialWorkBorderImageView.frame = mediaContainerView.frame
}
mediaContainerView.layoutIfNeeded()
halfMaskImageView.frame = mediaContainerView.mediaImageView.bounds
mediaContainerView.mediaImageView.maskView = halfMaskImageView
if layoutCache.layout == nil {
let dribbbleShotLayout = FeedCellLayout.DribbbleShotLayout(dribbbleShotContainerViewFrame: mediaContainerView.frame)
_newLayout?.dribbbleShotLayout = dribbbleShotLayout
if let newLayout = _newLayout {
layoutCache.update(layout: newLayout)
}
}
}
}
@@ -0,0 +1,121 @@
//
// FeedGithubRepoCell.swift
// Yep
//
// Created by nixzhu on 15/12/17.
// Copyright © 2015 Catch Inc. All rights reserved.
//
import UIKit
private let screenWidth: CGFloat = UIScreen.mainScreen().bounds.width
class FeedGithubRepoCell: FeedBasicCell {
var tapGithubRepoLinkAction: (NSURL -> Void)?
lazy var logoImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: SocialAccount.Github.iconName)
imageView.frame = CGRect(x: 0, y: 0, width: 18, height: 18)
imageView.tintColor = SocialAccount.Github.tintColor
return imageView
}()
lazy var githubRepoContainerView: FeedGithubRepoContainerView = {
let view = FeedGithubRepoContainerView()
view.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
return view
}()
lazy var socialWorkBorderImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "social_work_border")
return imageView
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(logoImageView)
contentView.addSubview(githubRepoContainerView)
contentView.addSubview(socialWorkBorderImageView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override class func heightOfFeed(feed: DiscoveredFeed) -> CGFloat {
let height = super.heightOfFeed(feed) + (80 + 15)
return ceil(height)
}
override func configureWithFeed(feed: DiscoveredFeed, layoutCache: FeedCellLayout.Cache, needShowSkill: Bool) {
var _newLayout: FeedCellLayout?
super.configureWithFeed(feed, layoutCache: (layout: layoutCache.layout, update: { newLayout in
_newLayout = newLayout
}), needShowSkill: needShowSkill)
if needShowSkill, let _ = feed.skill {
logoImageView.frame.origin.x = skillButton.frame.origin.x - 10 - 18
logoImageView.frame.origin.y = nicknameLabel.frame.origin.y
} else {
logoImageView.frame.origin.x = screenWidth - 18 - 15
logoImageView.frame.origin.y = nicknameLabel.frame.origin.y
}
nicknameLabel.frame.size.width -= logoImageView.bounds.width + 10
if let attachment = feed.attachment {
if case let .Github(githubRepo) = attachment {
githubRepoContainerView.nameLabel.text = githubRepo.name
githubRepoContainerView.descriptionLabel.text = githubRepo.description
}
}
githubRepoContainerView.tapAction = { [weak self] in
guard let attachment = feed.attachment else {
return
}
if case .GithubRepo = feed.kind {
if case let .Github(repo) = attachment, let URL = NSURL(string: repo.URLString) {
self?.tapGithubRepoLinkAction?(URL)
}
}
}
if let githubRepoLayout = layoutCache.layout?.githubRepoLayout {
githubRepoContainerView.frame = githubRepoLayout.githubRepoContainerViewFrame
socialWorkBorderImageView.frame = githubRepoContainerView.frame
} else {
let y = messageTextView.frame.origin.y + messageTextView.frame.height + 15
let height: CGFloat = leftBottomLabel.frame.origin.y - y - 15
githubRepoContainerView.frame = CGRect(x: 65, y: y, width: screenWidth - 65 - 60, height: height)
socialWorkBorderImageView.frame = githubRepoContainerView.frame
}
if layoutCache.layout == nil {
let githubRepoLayout = FeedCellLayout.GithubRepoLayout(githubRepoContainerViewFrame: githubRepoContainerView.frame)
_newLayout?.githubRepoLayout = githubRepoLayout
if let newLayout = _newLayout {
layoutCache.update(layout: newLayout)
}
}
}
}
+129
View File
@@ -0,0 +1,129 @@
//
// FeedLocationCell.swift
// Yep
//
// Created by nixzhu on 15/12/17.
// Copyright © 2015 Catch Inc. All rights reserved.
//
import UIKit
import MapKit
private let screenWidth: CGFloat = UIScreen.mainScreen().bounds.width
class FeedLocationCell: FeedBasicCell {
var tapLocationAction: ((locationName: String, locationCoordinate: CLLocationCoordinate2D) -> Void)?
lazy var locationContainerView: FeedLocationContainerView = {
let view = FeedLocationContainerView()
view.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
return view
}()
lazy var socialWorkBorderImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "social_work_border")
return imageView
}()
lazy var halfMaskImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "social_media_image_mask"))
return imageView
}()
override func prepareForReuse() {
super.prepareForReuse()
locationContainerView.mapImageView.image = nil
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(locationContainerView)
contentView.addSubview(socialWorkBorderImageView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override class func heightOfFeed(feed: DiscoveredFeed) -> CGFloat {
let height = super.heightOfFeed(feed) + (110 + 15)
return ceil(height)
}
override func configureWithFeed(feed: DiscoveredFeed, layoutCache: FeedCellLayout.Cache, needShowSkill: Bool) {
var _newLayout: FeedCellLayout?
super.configureWithFeed(feed, layoutCache: (layout: layoutCache.layout, update: { newLayout in
_newLayout = newLayout
}), needShowSkill: needShowSkill)
if let attachment = feed.attachment {
if case let .Location(locationInfo) = attachment {
let location = CLLocation(latitude: locationInfo.latitude, longitude: locationInfo.longitude)
let size = CGSize(width: UIScreen.mainScreen().bounds.width - 65 - 60, height: 110 - locationContainerView.nameLabel.bounds.height)
locationContainerView.mapImageView.yep_showActivityIndicatorWhenLoading = true
locationContainerView.mapImageView.yep_setImageOfLocation(location, withSize: size)
if locationInfo.name.isEmpty {
locationContainerView.nameLabel.text = NSLocalizedString("Unknown location", comment: "")
} else {
locationContainerView.nameLabel.text = locationInfo.name
}
}
}
locationContainerView.mapImageView.maskView = halfMaskImageView
locationContainerView.tapAction = { [weak self] in
guard let attachment = feed.attachment else {
return
}
if case .Location = feed.kind {
if case let .Location(locationInfo) = attachment {
self?.tapLocationAction?(locationName: locationInfo.name, locationCoordinate: locationInfo.coordinate)
}
}
}
if let locationLayout = layoutCache.layout?.locationLayout {
locationContainerView.frame = locationLayout.locationContainerViewFrame
socialWorkBorderImageView.frame = locationContainerView.frame
} else {
let y = messageTextView.frame.origin.y + messageTextView.frame.height + 15
let height: CGFloat = leftBottomLabel.frame.origin.y - y - 15
locationContainerView.frame = CGRect(x: 65, y: y, width: screenWidth - 65 - 60, height: height)
socialWorkBorderImageView.frame = locationContainerView.frame
}
locationContainerView.layoutIfNeeded()
halfMaskImageView.frame = locationContainerView.mapImageView.bounds
locationContainerView.mapImageView.maskView = halfMaskImageView
if layoutCache.layout == nil {
let locationLayout = FeedCellLayout.LocationLayout(locationContainerViewFrame: locationContainerView.frame)
_newLayout?.locationLayout = locationLayout
if let newLayout = _newLayout {
layoutCache.update(layout: newLayout)
}
}
}
}
@@ -0,0 +1,147 @@
//
// FeedNormalImagesCell.swift
// Yep
//
// Created by nixzhu on 15/12/17.
// Copyright © 2015 Catch Inc. All rights reserved.
//
import UIKit
class FeedNormalImagesCell: FeedBasicCell {
var tapMediaAction: FeedTapMediaAction?
private func createImageViewWithFrame(frame: CGRect) -> UIImageView {
let imageView = UIImageView()
imageView.contentMode = .ScaleAspectFill
imageView.clipsToBounds = true
imageView.frame = CGRect(origin: CGPoint(x: 65, y: 0), size: YepConfig.FeedNormalImagesCell.imageSize)
imageView.frame = frame
imageView.layer.borderColor = UIColor.yepBorderColor().CGColor
imageView.layer.borderWidth = 1
imageView.userInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: "tap:")
imageView.addGestureRecognizer(tap)
return imageView
}
lazy var imageView1: UIImageView = {
let x = 65
let frame = CGRect(origin: CGPoint(x: x, y: 0), size: YepConfig.FeedNormalImagesCell.imageSize)
let imageView = self.createImageViewWithFrame(frame)
return imageView
}()
lazy var imageView2: UIImageView = {
let x = 65 + (YepConfig.FeedNormalImagesCell.imageSize.width + 5)
let frame = CGRect(origin: CGPoint(x: x, y: 0), size: YepConfig.FeedNormalImagesCell.imageSize)
let imageView = self.createImageViewWithFrame(frame)
return imageView
}()
lazy var imageView3: UIImageView = {
let x = 65 + (YepConfig.FeedNormalImagesCell.imageSize.width + 5) * 2
let frame = CGRect(origin: CGPoint(x: x, y: 0), size: YepConfig.FeedNormalImagesCell.imageSize)
let imageView = self.createImageViewWithFrame(frame)
return imageView
}()
override class func heightOfFeed(feed: DiscoveredFeed) -> CGFloat {
let height = super.heightOfFeed(feed) + YepConfig.FeedNormalImagesCell.imageSize.height + 15
return ceil(height)
}
var imageViews: [UIImageView] = []
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(imageView1)
contentView.addSubview(imageView2)
contentView.addSubview(imageView3)
imageViews = [imageView1, imageView2, imageView3]
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override func prepareForReuse() {
super.prepareForReuse()
imageView1.image = nil
imageView2.image = nil
imageView3.image = nil
}
override func configureWithFeed(feed: DiscoveredFeed, layoutCache: FeedCellLayout.Cache, needShowSkill: Bool) {
var _newLayout: FeedCellLayout?
super.configureWithFeed(feed, layoutCache: (layout: layoutCache.layout, update: { newLayout in
_newLayout = newLayout
}), needShowSkill: needShowSkill)
if let normalImagesLayout = layoutCache.layout?.normalImagesLayout {
imageView1.frame = normalImagesLayout.imageView1Frame
imageView2.frame = normalImagesLayout.imageView2Frame
imageView3.frame = normalImagesLayout.imageView3Frame
} else {
imageViews.forEach({
$0.frame.origin.y = messageTextView.frame.origin.y + messageTextView.frame.height + 15
})
}
if let attachments = feed.imageAttachments {
for i in 0..<imageViews.count {
if let attachment = attachments[safe: i] {
imageViews[i].yep_showActivityIndicatorWhenLoading = true
imageViews[i].yep_setImageOfAttachment(attachment, withSize: YepConfig.FeedNormalImagesCell.imageSize)
imageViews[i].hidden = false
} else {
imageViews[i].hidden = true
}
}
}
if layoutCache.layout == nil {
let normalImagesLayout = FeedCellLayout.NormalImagesLayout(imageView1Frame: imageView1.frame, imageView2Frame: imageView2.frame, imageView3Frame: imageView3.frame)
_newLayout?.normalImagesLayout = normalImagesLayout
if let newLayout = _newLayout {
layoutCache.update(layout: newLayout)
}
}
}
@objc private func tap(sender: UITapGestureRecognizer) {
if let imageView = sender.view as? UIImageView, index = imageViews.indexOf(imageView) {
if let attachments = feed?.imageAttachments {
tapMediaAction?(transitionView: imageView, image: imageView.image, attachments: attachments, index: index)
}
}
}
}
+173
View File
@@ -0,0 +1,173 @@
//
// FeedVoiceCell.swift
// Yep
//
// Created by nixzhu on 15/12/17.
// Copyright © 2015 Catch Inc. All rights reserved.
//
import UIKit
import RealmSwift
class FeedVoiceCell: FeedBasicCell {
lazy var voiceContainerView: FeedVoiceContainerView = {
let view = FeedVoiceContainerView()
view.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
return view
}()
var audioPlaying: Bool = false {
willSet {
voiceContainerView.audioPlaying = newValue
}
}
var playOrPauseAudioAction: (FeedVoiceCell -> Void)?
var audioPlayedDuration: NSTimeInterval = 0 {
willSet {
updateVoiceContainerView()
}
}
private func updateVoiceContainerView() {
guard let feed = feed, realm = try? Realm(), feedAudio = FeedAudio.feedAudioWithFeedID(feed.id, inRealm: realm) else {
return
}
if let (audioDuration, audioSamples) = feedAudio.audioMetaInfo {
voiceContainerView.voiceSampleView.samples = audioSamples
voiceContainerView.voiceSampleView.progress = CGFloat(audioPlayedDuration / audioDuration)
}
if let playingFeedAudio = YepAudioService.sharedManager.playingFeedAudio where playingFeedAudio.feedID == feedAudio.feedID, let audioPlayer = YepAudioService.sharedManager.audioPlayer where audioPlayer.playing {
audioPlaying = true
} else {
audioPlaying = false
}
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(voiceContainerView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override class func heightOfFeed(feed: DiscoveredFeed) -> CGFloat {
let height = super.heightOfFeed(feed) + (44 + 15)
return ceil(height)
}
override func configureWithFeed(feed: DiscoveredFeed, layoutCache: FeedCellLayout.Cache, needShowSkill: Bool) {
var _newLayout: FeedCellLayout?
super.configureWithFeed(feed, layoutCache: (layout: layoutCache.layout, update: { newLayout in
_newLayout = newLayout
}), needShowSkill: needShowSkill)
if let attachment = feed.attachment {
if case let .Audio(audioInfo) = attachment {
voiceContainerView.voiceSampleView.sampleColor = UIColor.leftWaveColor()
voiceContainerView.voiceSampleView.samples = audioInfo.sampleValues
let timeLengthString = String(format: "%.1f\"", audioInfo.duration)
voiceContainerView.timeLengthLabel.text = timeLengthString
if let audioLayout = layoutCache.layout?.audioLayout {
voiceContainerView.frame = audioLayout.voiceContainerViewFrame
} else {
let rect = timeLengthString.boundingRectWithSize(CGSize(width: 320, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.voiceTimeLengthTextAttributes, context: nil)
let width = 7 + 30 + 5 + CGFloat(audioInfo.sampleValues.count) * 3 + 5 + rect.width + 5
let y = messageTextView.frame.origin.y + messageTextView.frame.height + 15 + 2
voiceContainerView.frame = CGRect(x: 65, y: y, width: width, height: 40)
}
if let realm = try? Realm() {
let feedAudio = FeedAudio.feedAudioWithFeedID(audioInfo.feedID, inRealm: realm)
if let feedAudio = feedAudio, playingFeedAudio = YepAudioService.sharedManager.playingFeedAudio, audioPlayer = YepAudioService.sharedManager.audioPlayer {
audioPlaying = (feedAudio.feedID == playingFeedAudio.feedID) && audioPlayer.playing
} else {
audioPlaying = false
}
let needDownload = (feedAudio == nil) || (feedAudio?.fileName ?? "").isEmpty
if needDownload {
if let URL = NSURL(string: audioInfo.URLString) {
YepDownloader.downloadDataFromURL(URL, reportProgress: { progress in
println("audio progress: \(progress)")
}, finishedAction: { data in
println("audio finish: \(data.length)")
dispatch_async(dispatch_get_main_queue()) {
if let realm = try? Realm() {
var feedAudio = FeedAudio.feedAudioWithFeedID(audioInfo.feedID, inRealm: realm)
if feedAudio == nil {
let newFeedAudio = FeedAudio()
newFeedAudio.feedID = audioInfo.feedID
newFeedAudio.URLString = audioInfo.URLString
newFeedAudio.metadata = audioInfo.metaData
let _ = try? realm.write {
realm.add(newFeedAudio)
}
feedAudio = newFeedAudio
}
if let feedAudio = feedAudio where feedAudio.fileName.isEmpty {
let fileName = NSUUID().UUIDString
if let _ = NSFileManager.saveMessageAudioData(data, withName: fileName) {
let _ = try? realm.write {
feedAudio.fileName = fileName
}
}
}
}
}
})
}
}
voiceContainerView.playOrPauseAudioAction = { [weak self] in
if let strongSelf = self {
strongSelf.playOrPauseAudioAction?(strongSelf)
}
}
}
}
}
if layoutCache.layout == nil {
let audioLayout = FeedCellLayout.AudioLayout(voiceContainerViewFrame: voiceContainerView.frame)
_newLayout?.audioLayout = audioLayout
if let newLayout = _newLayout {
layoutCache.update(layout: newLayout)
}
}
}
}
@@ -1,130 +0,0 @@
//
// FeedBasicCell.swift
// Yep
//
// Created by nixzhu on 15/11/20.
// Copyright © 2015 Catch Inc. All rights reserved.
//
import UIKit
class FeedBasicCell: UITableViewCell {
@IBOutlet weak var avatarImageView: UIImageView!
@IBOutlet weak var nicknameLabel: UILabel!
@IBOutlet weak var skillButton: UIButton!
@IBOutlet weak var messageTextView: FeedTextView!
@IBOutlet weak var messageTextViewHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var leftBottomLabel: UILabel!
@IBOutlet weak var messageCountLabel: UILabel!
var tapAvatarAction: (UITableViewCell -> Void)?
var tapSkillAction: (UITableViewCell -> Void)?
var touchesBeganAction: (UITableViewCell -> Void)?
var touchesEndedAction: (UITableViewCell -> Void)?
var touchesCancelledAction: (UITableViewCell -> Void)?
override func prepareForReuse() {
super.prepareForReuse()
messageTextView.text = nil
messageTextView.attributedText = nil
}
override func awakeFromNib() {
super.awakeFromNib()
nicknameLabel.textColor = UIColor.yepTintColor()
messageTextView.textColor = UIColor.yepMessageColor()
leftBottomLabel.textColor = UIColor.grayColor()
messageCountLabel.textColor = UIColor.yepTintColor()
skillButton.setTitleColor(UIColor.yepTintColor(), forState: .Normal)
messageTextView.font = UIFont.feedMessageFont()
messageTextView.textContainer.lineFragmentPadding = 0
messageTextView.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
messageTextView.dataDetectorTypes = .Link
skillButton.titleLabel?.font = UIFont.feedSkillFont()
let tapAvatar = UITapGestureRecognizer(target: self, action: "tapAvatar:")
avatarImageView.userInteractionEnabled = true
avatarImageView.addGestureRecognizer(tapAvatar)
skillButton.addTarget(self, action: "tapSkill:", forControlEvents: .TouchUpInside)
messageTextView.touchesBeganAction = { [weak self] in
if let strongSelf = self {
strongSelf.touchesBeganAction?(strongSelf)
}
}
messageTextView.touchesEndedAction = { [weak self] in
if let strongSelf = self {
if strongSelf.editing {
return
}
strongSelf.touchesEndedAction?(strongSelf)
}
}
messageTextView.touchesCancelledAction = { [weak self] in
if let strongSelf = self {
strongSelf.touchesCancelledAction?(strongSelf)
}
}
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
private func calHeightOfMessageTextView() {
let rect = messageTextView.text.boundingRectWithSize(CGSize(width: FeedCell.messageTextViewMaxWidth, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.textAttributes, context: nil)
messageTextViewHeightConstraint.constant = ceil(rect.height)
}
func configureWithFeed(feed: DiscoveredFeed, needShowSkill: Bool) {
messageTextView.text = "\u{200B}\(feed.body)" // ref http://stackoverflow.com/a/25994821
calHeightOfMessageTextView()
if needShowSkill, let skill = feed.skill {
skillButton.setTitle(skill.localName, forState: .Normal)
skillButton.hidden = false
} else {
skillButton.hidden = true
}
let plainAvatar = PlainAvatar(avatarURLString: feed.creator.avatarURLString, avatarStyle: nanoAvatarStyle)
avatarImageView.navi_setAvatar(plainAvatar, withFadeTransitionDuration: avatarFadeTransitionDuration)
nicknameLabel.text = feed.creator.nickname
leftBottomLabel.text = feed.timeAndDistanceString
messageCountLabel.text = "\(feed.messagesCount)"
messageCountLabel.hidden = (feed.messagesCount == 0)
}
// MARK: Actions
func tapAvatar(sender: UITapGestureRecognizer) {
tapAvatarAction?(self)
}
func tapSkill(sender: AnyObject) {
tapSkillAction?(self)
}
}
@@ -19,7 +19,7 @@ class FeedMediaCell: UICollectionViewCell {
super.awakeFromNib()
imageView.backgroundColor = YepConfig.FeedMedia.backgroundColor
imageView.layer.minificationFilter = kCAFilterLinear
// imageView.layer.minificationFilter = kCAFilterLinear
contentView.backgroundColor = UIColor.clearColor()
}
@@ -1,374 +0,0 @@
//
// FeedSocialWorkCell.swift
// Yep
//
// Created by nixzhu on 15/11/19.
// Copyright © 2015 Catch Inc. All rights reserved.
//
import UIKit
import Kingfisher
import Ruler
import RealmSwift
import MapKit
private let dribbbleShotHeight: CGFloat = Ruler.iPhoneHorizontal(160, 200, 220).value
class FeedSocialWorkCell: FeedBasicCell {
@IBOutlet weak var logoImageView: UIImageView!
@IBOutlet weak var logoImageViewTrailingConstraint: NSLayoutConstraint!
@IBOutlet weak var socialWorkContainerView: UIView!
@IBOutlet weak var mediaContainerView: FeedMediaContainerView!
@IBOutlet weak var githubRepoContainerView: FeedGithubRepoContainerView!
@IBOutlet weak var voiceContainerView: FeedVoiceContainerView!
@IBOutlet weak var voiceContainerViewWidthConstraint: NSLayoutConstraint!
@IBOutlet weak var locationContainerView: FeedLocationContainerView!
@IBOutlet weak var socialWorkBorderImageView: UIImageView!
@IBOutlet weak var socialWorkContainerViewHeightConstraint: NSLayoutConstraint!
lazy var halfMaskImageView: UIImageView = {
let imageView = UIImageView(image: UIImage(named: "social_media_image_mask"))
return imageView
}()
var feed: DiscoveredFeed?
var tapGithubRepoLinkAction: (NSURL -> Void)?
var tapDribbbleShotLinkAction: (NSURL -> Void)?
var tapDribbbleShotMediaAction: ((transitionView: UIView, image: UIImage?, imageURL: NSURL, linkURL: NSURL) -> Void)?
var tapLocationAction: ((locationName: String, locationCoordinate: CLLocationCoordinate2D) -> Void)?
var audioPlaying: Bool = false {
willSet {
voiceContainerView.audioPlaying = newValue
}
}
var playOrPauseAudioAction: (FeedSocialWorkCell -> Void)?
var audioPlayedDuration: NSTimeInterval = 0 {
willSet {
updateVoiceContainerView()
}
}
private func updateVoiceContainerView() {
guard let feed = feed, realm = try? Realm(), feedAudio = FeedAudio.feedAudioWithFeedID(feed.id, inRealm: realm) else {
return
}
if let (audioDuration, audioSamples) = feedAudio.audioMetaInfo {
voiceContainerView.voiceSampleView.samples = audioSamples
voiceContainerView.voiceSampleView.progress = CGFloat(audioPlayedDuration / audioDuration)
}
if let playingFeedAudio = YepAudioService.sharedManager.playingFeedAudio where playingFeedAudio.feedID == feedAudio.feedID, let audioPlayer = YepAudioService.sharedManager.audioPlayer where audioPlayer.playing {
audioPlaying = true
} else {
audioPlaying = false
}
}
static let messageTextViewMaxWidth: CGFloat = {
let maxWidth = UIScreen.mainScreen().bounds.width - (15 + 40 + 10 + 15)
return maxWidth
}()
override func layoutSubviews() {
super.layoutSubviews()
if feed?.hasSocialImage ?? false {
halfMaskImageView.frame = mediaContainerView.mediaImageView.bounds
}
if feed?.hasMapImage ?? false {
halfMaskImageView.frame = locationContainerView.mapImageView.bounds
}
}
override func prepareForReuse() {
super.prepareForReuse()
mediaContainerView.mediaImageView.image = nil
locationContainerView.mapImageView.image = nil
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
class func heightOfFeed(feed: DiscoveredFeed) -> CGFloat {
let rect = feed.body.boundingRectWithSize(CGSize(width: FeedSocialWorkCell.messageTextViewMaxWidth, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.textAttributes, context: nil)
var height: CGFloat = ceil(rect.height) + 10 + 40 + 4 + 15 + 17 + 15
switch feed.kind {
case .GithubRepo:
height += (80 + 15)
case .DribbbleShot:
height += (dribbbleShotHeight + 15)
case .Audio:
height += (44 + 15)
case .Location:
height += (110 + 15)
default:
break
}
return ceil(height)
}
override func configureWithFeed(feed: DiscoveredFeed, needShowSkill: Bool) {
super.configureWithFeed(feed, needShowSkill: needShowSkill)
self.feed = feed
if needShowSkill, let skill = feed.skill {
let rect = skill.localName.boundingRectWithSize(CGSize(width: 320, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.skillTextAttributes, context: nil)
logoImageViewTrailingConstraint.constant = 8 + (10 + rect.width + 10) + 15
} else {
logoImageViewTrailingConstraint.constant = 15
}
if let
accountName = feed.kind.accountName,
socialAccount = SocialAccount(rawValue: accountName) {
logoImageView.image = UIImage(named: socialAccount.iconName)
logoImageView.tintColor = socialAccount.tintColor
logoImageView.hidden = false
} else {
logoImageView.hidden = true
}
var socialWorkImageURL: NSURL?
switch feed.kind {
case .GithubRepo:
mediaContainerView.hidden = true
githubRepoContainerView.hidden = false
voiceContainerView.hidden = true
locationContainerView.hidden = true
socialWorkBorderImageView.hidden = false
if let attachment = feed.attachment {
if case let .Github(githubRepo) = attachment {
githubRepoContainerView.nameLabel.text = githubRepo.name
githubRepoContainerView.descriptionLabel.text = githubRepo.description
}
}
githubRepoContainerView.tapAction = { [weak self] in
guard let attachment = feed.attachment else {
return
}
if case .GithubRepo = feed.kind {
if case let .Github(repo) = attachment, let URL = NSURL(string: repo.URLString) {
self?.tapGithubRepoLinkAction?(URL)
}
}
}
socialWorkContainerViewHeightConstraint.constant = 80
case .DribbbleShot:
mediaContainerView.hidden = false
githubRepoContainerView.hidden = true
voiceContainerView.hidden = true
locationContainerView.hidden = true
socialWorkBorderImageView.hidden = false
if let attachment = feed.attachment {
if case let .Dribbble(dribbbleShot) = attachment {
socialWorkImageURL = NSURL(string: dribbbleShot.imageURLString)
mediaContainerView.linkContainerView.textLabel.text = dribbbleShot.title
}
}
mediaContainerView.tapMediaAction = { [weak self] mediaImageView in
guard let attachment = feed.attachment else {
return
}
if case .DribbbleShot = feed.kind {
if case let .Dribbble(shot) = attachment, let imageURL = NSURL(string: shot.imageURLString), let linkURL = NSURL(string: shot.htmlURLString) {
self?.tapDribbbleShotMediaAction?(transitionView: mediaImageView, image: mediaImageView.image, imageURL: imageURL, linkURL: linkURL)
}
}
}
mediaContainerView.linkContainerView.tapAction = { [weak self] in
guard let attachment = feed.attachment else {
return
}
if case .DribbbleShot = feed.kind {
if case let .Dribbble(shot) = attachment, let URL = NSURL(string: shot.htmlURLString) {
self?.tapDribbbleShotLinkAction?(URL)
}
}
}
mediaContainerView.mediaImageView.maskView = halfMaskImageView
socialWorkContainerViewHeightConstraint.constant = dribbbleShotHeight
contentView.layoutIfNeeded()
case .Audio:
mediaContainerView.hidden = true
githubRepoContainerView.hidden = true
voiceContainerView.hidden = false
locationContainerView.hidden = true
socialWorkBorderImageView.hidden = true
if let attachment = feed.attachment {
if case let .Audio(audioInfo) = attachment {
voiceContainerView.voiceSampleView.sampleColor = UIColor.leftWaveColor()
voiceContainerView.voiceSampleView.samples = audioInfo.sampleValues
let timeLengthString = String(format: "%.1f\"", audioInfo.duration)
voiceContainerView.timeLengthLabel.text = timeLengthString
let rect = timeLengthString.boundingRectWithSize(CGSize(width: 320, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.FeedBasicCell.voiceTimeLengthTextAttributes, context: nil)
voiceContainerViewWidthConstraint.constant = 7 + 30 + 5 + CGFloat(audioInfo.sampleValues.count) * 3 + 5 + rect.width + 5
if let realm = try? Realm() {
let feedAudio = FeedAudio.feedAudioWithFeedID(audioInfo.feedID, inRealm: realm)
if let feedAudio = feedAudio, playingFeedAudio = YepAudioService.sharedManager.playingFeedAudio, audioPlayer = YepAudioService.sharedManager.audioPlayer {
audioPlaying = (feedAudio.feedID == playingFeedAudio.feedID) && audioPlayer.playing
} else {
audioPlaying = false
}
let needDownload = (feedAudio == nil) || (feedAudio?.fileName ?? "").isEmpty
if needDownload {
if let URL = NSURL(string: audioInfo.URLString) {
YepDownloader.downloadDataFromURL(URL, reportProgress: { progress in
println("audio progress: \(progress)")
}, finishedAction: { data in
println("audio finish: \(data.length)")
dispatch_async(dispatch_get_main_queue()) {
if let realm = try? Realm() {
var feedAudio = FeedAudio.feedAudioWithFeedID(audioInfo.feedID, inRealm: realm)
if feedAudio == nil {
let newFeedAudio = FeedAudio()
newFeedAudio.feedID = audioInfo.feedID
newFeedAudio.URLString = audioInfo.URLString
newFeedAudio.metadata = audioInfo.metaData
let _ = try? realm.write {
realm.add(newFeedAudio)
}
feedAudio = newFeedAudio
}
if let feedAudio = feedAudio where feedAudio.fileName.isEmpty {
let fileName = NSUUID().UUIDString
if let _ = NSFileManager.saveMessageAudioData(data, withName: fileName) {
let _ = try? realm.write {
feedAudio.fileName = fileName
}
}
}
}
}
})
}
}
voiceContainerView.playOrPauseAudioAction = { [weak self] in
if let strongSelf = self {
strongSelf.playOrPauseAudioAction?(strongSelf)
}
}
}
}
}
socialWorkContainerViewHeightConstraint.constant = 44
case .Location:
mediaContainerView.hidden = true
githubRepoContainerView.hidden = true
voiceContainerView.hidden = true
locationContainerView.hidden = false
socialWorkBorderImageView.hidden = false
if let attachment = feed.attachment {
if case let .Location(locationInfo) = attachment {
let location = CLLocation(latitude: locationInfo.latitude, longitude: locationInfo.longitude)
let size = CGSize(width: UIScreen.mainScreen().bounds.width - 65 - 60, height: 110 - locationContainerView.nameLabel.bounds.height)
locationContainerView.mapImageView.yep_showActivityIndicatorWhenLoading = true
locationContainerView.mapImageView.yep_setImageOfLocation(location, withSize: size)
if locationInfo.name.isEmpty {
locationContainerView.nameLabel.text = NSLocalizedString("Unknown location", comment: "")
} else {
locationContainerView.nameLabel.text = locationInfo.name
}
}
}
locationContainerView.mapImageView.maskView = halfMaskImageView
locationContainerView.tapAction = { [weak self] in
guard let attachment = feed.attachment else {
return
}
if case .Location = feed.kind {
if case let .Location(locationInfo) = attachment {
self?.tapLocationAction?(locationName: locationInfo.name, locationCoordinate: locationInfo.coordinate)
}
}
}
socialWorkContainerViewHeightConstraint.constant = 110
contentView.layoutIfNeeded()
default:
break
}
if let URL = socialWorkImageURL {
// ref https://github.com/onevcat/Kingfisher/pull/171
mediaContainerView.mediaImageView.kf_showIndicatorWhenLoading = true
mediaContainerView.mediaImageView.kf_setImageWithURL(URL, placeholderImage: nil, optionsInfo: MediaOptionsInfos)
}
}
}
@@ -1,178 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="9531" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="352" id="KGk-i7-Jjw" customClass="FeedSocialWorkCell" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="402" height="352"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="402" height="351.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2 hours ago ∙ 1.2 km" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9CZ-zE-b9N" userLabel="Time Label">
<rect key="frame" x="65" y="310" width="127.5" height="17"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="14"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="NIX" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="viF-na-QGX" userLabel="Nickname Label">
<rect key="frame" x="65" y="21" width="227" height="18"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="15"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_discussion" translatesAutoresizingMaskIntoConstraints="NO" id="fqI-ij-1Pj">
<rect key="frame" x="357" y="309" width="30" height="19"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="lyg-eU-J2p" userLabel="Avatar Image View">
<rect key="frame" x="15" y="10" width="40" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="40" id="1S1-Ds-KZn"/>
</constraints>
</imageView>
<label clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="42" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dhp-xa-CcY" userLabel="Message Count Label">
<rect key="frame" x="332" y="310" width="17" height="17"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" weight="light" pointSize="14"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<textView multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" editable="NO" text="How do you do?" translatesAutoresizingMaskIntoConstraints="NO" id="Xeg-hl-49c" customClass="FeedTextView" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="65" y="54" width="322" height="26"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="height" constant="26" id="NbJ-It-NNH"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<dataDetectorType key="dataDetectorTypes" phoneNumber="YES" link="YES" address="YES" calendarEvent="YES"/>
</textView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eHY-0K-bDQ">
<rect key="frame" x="65" y="95" width="277" height="200"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="FZd-l0-SQA" customClass="FeedMediaContainerView" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="277" height="200"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tpD-68-XCp" customClass="FeedGithubRepoContainerView" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="277" height="200"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bIi-Kx-Rnj" customClass="FeedLocationContainerView" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="277" height="200"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0Oq-0T-2Oh" customClass="FeedVoiceContainerView" customModule="Yep" customModuleProvider="target">
<rect key="frame" x="0.0" y="80" width="200" height="40"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="width" constant="200" id="V3t-3y-aAc"/>
<constraint firstAttribute="height" constant="40" id="fpI-SW-8tc"/>
</constraints>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="social_work_border" translatesAutoresizingMaskIntoConstraints="NO" id="Iob-TA-bgf">
<rect key="frame" x="0.0" y="0.0" width="277" height="200"/>
</imageView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="FZd-l0-SQA" secondAttribute="trailing" id="5cP-Qk-6n7"/>
<constraint firstAttribute="bottom" secondItem="bIi-Kx-Rnj" secondAttribute="bottom" id="GuF-Eu-SIk"/>
<constraint firstItem="tpD-68-XCp" firstAttribute="leading" secondItem="eHY-0K-bDQ" secondAttribute="leading" id="HY2-aO-Wcm"/>
<constraint firstAttribute="trailing" secondItem="tpD-68-XCp" secondAttribute="trailing" id="HZ0-ON-v4A"/>
<constraint firstAttribute="trailing" secondItem="bIi-Kx-Rnj" secondAttribute="trailing" id="InX-V8-eVD"/>
<constraint firstItem="Iob-TA-bgf" firstAttribute="leading" secondItem="eHY-0K-bDQ" secondAttribute="leading" id="MvN-Gi-duP"/>
<constraint firstAttribute="height" constant="200" id="Ogh-S5-nei"/>
<constraint firstItem="Iob-TA-bgf" firstAttribute="top" secondItem="eHY-0K-bDQ" secondAttribute="top" id="P4P-tA-MrO"/>
<constraint firstAttribute="trailing" secondItem="Iob-TA-bgf" secondAttribute="trailing" id="Rgw-iN-KuX"/>
<constraint firstItem="FZd-l0-SQA" firstAttribute="leading" secondItem="eHY-0K-bDQ" secondAttribute="leading" id="SWR-pV-OIA"/>
<constraint firstItem="tpD-68-XCp" firstAttribute="top" secondItem="eHY-0K-bDQ" secondAttribute="top" id="ZvG-hQ-rUk"/>
<constraint firstAttribute="bottom" secondItem="Iob-TA-bgf" secondAttribute="bottom" id="bDt-as-dcI"/>
<constraint firstItem="tpD-68-XCp" firstAttribute="centerY" secondItem="eHY-0K-bDQ" secondAttribute="centerY" id="gyI-Ik-drE"/>
<constraint firstAttribute="bottom" secondItem="FZd-l0-SQA" secondAttribute="bottom" id="iP0-Zu-Uz9"/>
<constraint firstItem="bIi-Kx-Rnj" firstAttribute="top" secondItem="eHY-0K-bDQ" secondAttribute="top" id="kj1-hJ-1ss"/>
<constraint firstAttribute="bottom" secondItem="tpD-68-XCp" secondAttribute="bottom" id="o2b-Jg-uOq"/>
<constraint firstItem="0Oq-0T-2Oh" firstAttribute="centerY" secondItem="eHY-0K-bDQ" secondAttribute="centerY" id="rYu-PP-sfQ"/>
<constraint firstItem="0Oq-0T-2Oh" firstAttribute="leading" secondItem="eHY-0K-bDQ" secondAttribute="leading" id="tv0-Al-JXT"/>
<constraint firstItem="bIi-Kx-Rnj" firstAttribute="leading" secondItem="eHY-0K-bDQ" secondAttribute="leading" id="wju-Wp-354"/>
<constraint firstItem="FZd-l0-SQA" firstAttribute="top" secondItem="eHY-0K-bDQ" secondAttribute="top" id="yNJ-XO-rA1"/>
</constraints>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_github" translatesAutoresizingMaskIntoConstraints="NO" id="Tlc-MI-H1b">
<rect key="frame" x="300" y="21" width="18" height="18"/>
<constraints>
<constraint firstAttribute="width" constant="18" id="UaS-K6-jBs"/>
<constraint firstAttribute="height" constant="18" id="Y99-oD-aJp"/>
</constraints>
</imageView>
<button contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WSp-ar-Z5j">
<rect key="frame" x="326" y="19" width="61" height="22"/>
<inset key="contentEdgeInsets" minX="10" minY="0.0" maxX="10" maxY="0.0"/>
<state key="normal" title="Swift" backgroundImage="skill_bubble_empty">
<color key="titleColor" red="0.0" green="0.50196081400000003" blue="1" alpha="1" colorSpace="calibratedRGB"/>
</state>
</button>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="Tlc-MI-H1b" secondAttribute="trailing" constant="84" id="0Ef-zJ-e9x"/>
<constraint firstItem="viF-na-QGX" firstAttribute="centerY" secondItem="lyg-eU-J2p" secondAttribute="centerY" id="5So-sI-oYv"/>
<constraint firstItem="lyg-eU-J2p" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="15" id="6cS-RN-NhO"/>
<constraint firstItem="lyg-eU-J2p" firstAttribute="width" secondItem="lyg-eU-J2p" secondAttribute="height" multiplier="1:1" id="Cil-Iy-8VS"/>
<constraint firstItem="fqI-ij-1Pj" firstAttribute="leading" secondItem="dhp-xa-CcY" secondAttribute="trailing" constant="8" id="Kot-8P-yc1"/>
<constraint firstItem="Xeg-hl-49c" firstAttribute="top" secondItem="lyg-eU-J2p" secondAttribute="bottom" constant="4" id="KvD-q8-C6x"/>
<constraint firstItem="Tlc-MI-H1b" firstAttribute="centerY" secondItem="viF-na-QGX" secondAttribute="centerY" id="M6V-9K-GkW"/>
<constraint firstItem="9CZ-zE-b9N" firstAttribute="leading" secondItem="viF-na-QGX" secondAttribute="leading" id="QwI-Mp-xqY"/>
<constraint firstItem="dhp-xa-CcY" firstAttribute="centerY" secondItem="fqI-ij-1Pj" secondAttribute="centerY" id="ZRm-Fq-eqi"/>
<constraint firstItem="viF-na-QGX" firstAttribute="leading" secondItem="lyg-eU-J2p" secondAttribute="trailing" constant="10" id="cLu-0m-Gh0"/>
<constraint firstItem="eHY-0K-bDQ" firstAttribute="top" secondItem="Xeg-hl-49c" secondAttribute="bottom" constant="15" id="eze-0p-5Oc"/>
<constraint firstItem="lyg-eU-J2p" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" constant="10" id="f4R-YP-lhh"/>
<constraint firstAttribute="trailing" secondItem="eHY-0K-bDQ" secondAttribute="trailing" constant="60" id="gQL-VB-nuG"/>
<constraint firstItem="eHY-0K-bDQ" firstAttribute="leading" secondItem="Xeg-hl-49c" secondAttribute="leading" id="i5x-ip-Wth"/>
<constraint firstAttribute="trailing" secondItem="fqI-ij-1Pj" secondAttribute="trailing" constant="15" id="lcj-5f-hIP"/>
<constraint firstItem="9CZ-zE-b9N" firstAttribute="top" secondItem="eHY-0K-bDQ" secondAttribute="bottom" constant="15" id="mAw-uy-sHw"/>
<constraint firstAttribute="trailing" secondItem="Xeg-hl-49c" secondAttribute="trailing" constant="15" id="pcn-VC-2BM"/>
<constraint firstItem="Tlc-MI-H1b" firstAttribute="leading" secondItem="viF-na-QGX" secondAttribute="trailing" constant="8" id="rvc-zs-SGL"/>
<constraint firstAttribute="trailing" secondItem="WSp-ar-Z5j" secondAttribute="trailing" constant="15" id="siL-Yx-xKW"/>
<constraint firstItem="fqI-ij-1Pj" firstAttribute="centerY" secondItem="9CZ-zE-b9N" secondAttribute="centerY" id="tnO-T5-MBo"/>
<constraint firstItem="WSp-ar-Z5j" firstAttribute="centerY" secondItem="Tlc-MI-H1b" secondAttribute="centerY" id="xl5-mP-DM0"/>
<constraint firstItem="Xeg-hl-49c" firstAttribute="leading" secondItem="viF-na-QGX" secondAttribute="leading" id="ygU-tt-O9Y"/>
</constraints>
</tableViewCellContentView>
<inset key="separatorInset" minX="60" minY="0.0" maxX="0.0" maxY="0.0"/>
<connections>
<outlet property="avatarImageView" destination="lyg-eU-J2p" id="o1o-7n-PKc"/>
<outlet property="githubRepoContainerView" destination="tpD-68-XCp" id="M47-oR-QPU"/>
<outlet property="leftBottomLabel" destination="9CZ-zE-b9N" id="JGf-RX-sTu"/>
<outlet property="locationContainerView" destination="bIi-Kx-Rnj" id="7Of-HK-npZ"/>
<outlet property="logoImageView" destination="Tlc-MI-H1b" id="awx-yd-g5F"/>
<outlet property="logoImageViewTrailingConstraint" destination="0Ef-zJ-e9x" id="uKa-Bv-9Cf"/>
<outlet property="mediaContainerView" destination="FZd-l0-SQA" id="LCU-HU-fxL"/>
<outlet property="messageCountLabel" destination="dhp-xa-CcY" id="GAv-oY-UAJ"/>
<outlet property="messageTextView" destination="Xeg-hl-49c" id="qAM-BL-3xN"/>
<outlet property="messageTextViewHeightConstraint" destination="NbJ-It-NNH" id="1h3-eZ-hg4"/>
<outlet property="nicknameLabel" destination="viF-na-QGX" id="xWf-rc-8Ij"/>
<outlet property="skillButton" destination="WSp-ar-Z5j" id="BEY-ce-WjV"/>
<outlet property="socialWorkBorderImageView" destination="Iob-TA-bgf" id="iSW-Sk-rMC"/>
<outlet property="socialWorkContainerView" destination="eHY-0K-bDQ" id="XmX-Qj-xlW"/>
<outlet property="socialWorkContainerViewHeightConstraint" destination="Ogh-S5-nei" id="56b-gu-LFP"/>
<outlet property="voiceContainerView" destination="0Oq-0T-2Oh" id="R3x-bT-4xb"/>
<outlet property="voiceContainerViewWidthConstraint" destination="V3t-3y-aAc" id="xvN-Lt-8rL"/>
</connections>
<point key="canvasLocation" x="260" y="304"/>
</tableViewCell>
</objects>
<resources>
<image name="icon_discussion" width="30" height="19"/>
<image name="icon_github" width="24" height="23"/>
<image name="skill_bubble_empty" width="23" height="22"/>
<image name="social_work_border" width="11" height="11"/>
</resources>
</document>
@@ -68,11 +68,14 @@ class FeedGithubRepoContainerView: UIView {
"accessoryImageView": accessoryImageView,
]
let constraintsH = NSLayoutConstraint.constraintsWithVisualFormat("H:|-10-[iconImageView]-10-[nameLabel]-5-[accessoryImageView]-10-|", options: [], metrics: nil, views: views)
let constraintsH = NSLayoutConstraint.constraintsWithVisualFormat("H:|-10-[iconImageView(16)]-10-[nameLabel]-5-[accessoryImageView(8)]-10-|", options: [], metrics: nil, views: views)
iconImageView.setContentHuggingPriority(UILayoutPriorityDefaultHigh, forAxis: .Horizontal)
accessoryImageView.setContentHuggingPriority(UILayoutPriorityDefaultHigh, forAxis: .Horizontal)
iconImageView.setContentCompressionResistancePriority(UILayoutPriorityDefaultHigh, forAxis: .Horizontal)
accessoryImageView.setContentCompressionResistancePriority(UILayoutPriorityDefaultHigh, forAxis: .Horizontal)
let constraintsV = NSLayoutConstraint.constraintsWithVisualFormat("V:[nameLabel]-3-[descriptionLabel]", options: [.AlignAllLeading, .AlignAllTrailing], metrics: nil, views: views)
let iconImageViewCenterY = NSLayoutConstraint(item: iconImageView, attribute: .CenterY, relatedBy: .Equal, toItem: nameLabel, attribute: .CenterY, multiplier: 1.0, constant: 0)
@@ -58,10 +58,7 @@ class LinkContainerView: UIView {
"accessoryImageView": accessoryImageView,
]
let constraintsH = NSLayoutConstraint.constraintsWithVisualFormat("H:|-10-[iconImageView]-10-[textLabel]-5-[accessoryImageView]-10-|", options: [.AlignAllCenterY], metrics: nil, views: views)
iconImageView.setContentHuggingPriority(UILayoutPriorityDefaultHigh, forAxis: .Horizontal)
accessoryImageView.setContentHuggingPriority(UILayoutPriorityDefaultHigh, forAxis: .Horizontal)
let constraintsH = NSLayoutConstraint.constraintsWithVisualFormat("H:|-10-[iconImageView(20)]-10-[textLabel]-5-[accessoryImageView(8)]-10-|", options: [.AlignAllCenterY], metrics: nil, views: views)
let iconImageViewCenterY = NSLayoutConstraint(item: iconImageView, attribute: .CenterY, relatedBy: .Equal, toItem: self, attribute: .CenterY, multiplier: 1.0, constant: 0)