Browse Source

基础bug修复完成

南鑫林 5 years ago
parent
commit
1e722208c0
35 changed files with 2930 additions and 48 deletions
  1. 1 1
      RainbowPlanet/Podfile
  2. 1 1
      RainbowPlanet/Podfile.lock
  3. 102 2
      RainbowPlanet/RainbowPlanet.xcodeproj/project.pbxproj
  4. 7 0
      RainbowPlanet/RainbowPlanet/AppDelegate/AppDelegate+Window.swift
  5. 0 2
      RainbowPlanet/RainbowPlanet/Base/RootViewController/RootViewController.swift
  6. 1 1
      RainbowPlanet/RainbowPlanet/Manager/WebViewJavascriptBridgeManager/WebViewJavascriptBridgeManager.swift
  7. 2 0
      RainbowPlanet/RainbowPlanet/Model/CommunityModel/CommunityFollowFeedModel.swift
  8. 1 1
      RainbowPlanet/RainbowPlanet/Modules/CommunityModule/Community/View/Cell/FollowStatus/CommunityFollowStatusTableViewCell.swift
  9. 3 4
      RainbowPlanet/RainbowPlanet/Modules/CommunityModule/CommunityRecommendDetail/Controller/CommunityRecommendController.swift
  10. 11 13
      RainbowPlanet/RainbowPlanet/Modules/CommunityModule/CommunityVideoContent/View/CommunityVideoCoverCollectionCell.swift
  11. 124 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/ViewController/PublishMediaPickerViewController.swift
  12. 12 0
      RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishViewController.swift
  13. 1 1
      RainbowPlanet/RainbowPlanet/Modules/SearchModule/Search/View/SearchNavigationbarView.swift
  14. 7 17
      RainbowPlanet/RainbowPlanet/Modules/SearchModule/SearchContentList/View/SearchContentListCollectionCell.swift
  15. 3 3
      RainbowPlanet/RainbowPlanet/Modules/SearchModule/SearchContentList/ViewController/SearchContentListViewController.swift
  16. 1 1
      RainbowPlanet/RainbowPlanet/Modules/SearchModule/SearchResult/View/SearchResultNavigationbarView.swift
  17. 1 1
      RainbowPlanet/RainbowPlanet/Tools/CommentInputView/CommentReplyView.swift
  18. 39 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/PhotoPickerManager.swift
  19. 54 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/SynchronizedDictionary.swift
  20. 78 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLAlbumPopView.swift
  21. 68 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLAssetCollection+Extension.swift
  22. 370 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLAssetsCollection.swift
  23. 29 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLBundle.swift
  24. 22 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLCollectionTableViewCell.swift
  25. 179 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLPhotoCollectionViewCell.swift
  26. 274 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLPhotoLibrary.swift
  27. 86 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLPhotoPickerManager.swift
  28. 17 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLPhotopickerDataSourcesProtocol.swift
  29. 1012 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLPhotosPickerViewController.swift
  30. 58 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPickerResources/TLCollectionTableViewCell.xib
  31. 144 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPickerResources/TLPhotoCollectionViewCell.xib
  32. BIN
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPickerResources/TLPhotoPickerController.bundle/camera@3x.png
  33. BIN
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPickerResources/TLPhotoPickerController.bundle/insertPhotoMaterial@3x.png
  34. 221 0
      RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPickerResources/TLPhotosPickerViewController.xib
  35. 1 0
      RainbowPlanet/RainbowPlanet/ViewModel/Community/CommunityFollowUserViewModel.swift

+ 1 - 1
RainbowPlanet/Podfile

@@ -1,6 +1,6 @@
 #source 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git'
 # Uncomment the next line to define a global platform for your project
- platform :ios, '9.0'
+ platform :ios, '9.1'
 
 target 'RainbowPlanet' do
   # Comment the next line if you're not using Swift and don't want to use dynamic frameworks

+ 1 - 1
RainbowPlanet/Podfile.lock

@@ -250,6 +250,6 @@ SPEC CHECKSUMS:
   YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
   ZipArchive: e25a4373192673e3229ac8d6e9f64a3e5713c966
 
-PODFILE CHECKSUM: 810a7117534d7cc86fe6e12f6388571ac3b400f2
+PODFILE CHECKSUM: 3e7df9039ea1463b6287991998fd1bf590961a80
 
 COCOAPODS: 1.7.4

+ 102 - 2
RainbowPlanet/RainbowPlanet.xcodeproj/project.pbxproj

@@ -326,6 +326,23 @@
 		A7AA9F6322C62B270086498B /* CommunityRecommnendViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AA9F6222C62B270086498B /* CommunityRecommnendViewController.swift */; };
 		A7AA9F6522C63DCD0086498B /* CommunityFollowFeedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AA9F6422C63DCD0086498B /* CommunityFollowFeedModel.swift */; };
 		A7AA9F6722C640F10086498B /* CommunityRecommendFeedModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AA9F6622C640F10086498B /* CommunityRecommendFeedModel.swift */; };
+		A7AD2744230F88250099B3E0 /* PublishMediaPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AD2743230F88250099B3E0 /* PublishMediaPickerViewController.swift */; };
+		A7AD2756230F8D7D0099B3E0 /* TLCollectionTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A7AD2747230F8D7C0099B3E0 /* TLCollectionTableViewCell.xib */; };
+		A7AD2757230F8D7D0099B3E0 /* TLPhotoPickerController.bundle in Resources */ = {isa = PBXBuildFile; fileRef = A7AD2748230F8D7C0099B3E0 /* TLPhotoPickerController.bundle */; };
+		A7AD2758230F8D7D0099B3E0 /* TLPhotoCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = A7AD2749230F8D7C0099B3E0 /* TLPhotoCollectionViewCell.xib */; };
+		A7AD2759230F8D7D0099B3E0 /* TLPhotosPickerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A7AD274A230F8D7C0099B3E0 /* TLPhotosPickerViewController.xib */; };
+		A7AD275A230F8D7D0099B3E0 /* TLPhotoLibrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AD274C230F8D7C0099B3E0 /* TLPhotoLibrary.swift */; };
+		A7AD275B230F8D7D0099B3E0 /* TLPhotopickerDataSourcesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AD274D230F8D7C0099B3E0 /* TLPhotopickerDataSourcesProtocol.swift */; };
+		A7AD275C230F8D7D0099B3E0 /* TLCollectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AD274E230F8D7C0099B3E0 /* TLCollectionTableViewCell.swift */; };
+		A7AD275D230F8D7D0099B3E0 /* TLBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AD274F230F8D7C0099B3E0 /* TLBundle.swift */; };
+		A7AD275E230F8D7D0099B3E0 /* TLAlbumPopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AD2750230F8D7C0099B3E0 /* TLAlbumPopView.swift */; };
+		A7AD275F230F8D7D0099B3E0 /* TLPhotoCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AD2751230F8D7C0099B3E0 /* TLPhotoCollectionViewCell.swift */; };
+		A7AD2760230F8D7D0099B3E0 /* SynchronizedDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AD2752230F8D7C0099B3E0 /* SynchronizedDictionary.swift */; };
+		A7AD2761230F8D7D0099B3E0 /* TLAssetCollection+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AD2753230F8D7C0099B3E0 /* TLAssetCollection+Extension.swift */; };
+		A7AD2762230F8D7D0099B3E0 /* TLPhotosPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AD2754230F8D7C0099B3E0 /* TLPhotosPickerViewController.swift */; };
+		A7AD2763230F8D7D0099B3E0 /* TLAssetsCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AD2755230F8D7C0099B3E0 /* TLAssetsCollection.swift */; };
+		A7AD2765230F9A470099B3E0 /* TLPhotoPickerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AD2764230F9A470099B3E0 /* TLPhotoPickerManager.swift */; };
+		A7AD2768230F9C460099B3E0 /* PhotoPickerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7AD2767230F9C460099B3E0 /* PhotoPickerManager.swift */; };
 		A7B4E71F228131720012914A /* ProductSlidingLeftRightCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7B4E71E228131720012914A /* ProductSlidingLeftRightCollectionViewCell.swift */; };
 		A7B4E721228151F40012914A /* ProductFloorTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7B4E720228151F40012914A /* ProductFloorTitleView.swift */; };
 		A7B4E723228154750012914A /* ProductFloorBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7B4E722228154750012914A /* ProductFloorBannerView.swift */; };
@@ -1058,6 +1075,23 @@
 		A7AA9F6222C62B270086498B /* CommunityRecommnendViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommunityRecommnendViewController.swift; sourceTree = "<group>"; };
 		A7AA9F6422C63DCD0086498B /* CommunityFollowFeedModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommunityFollowFeedModel.swift; sourceTree = "<group>"; };
 		A7AA9F6622C640F10086498B /* CommunityRecommendFeedModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommunityRecommendFeedModel.swift; sourceTree = "<group>"; };
+		A7AD2743230F88250099B3E0 /* PublishMediaPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublishMediaPickerViewController.swift; sourceTree = "<group>"; };
+		A7AD2747230F8D7C0099B3E0 /* TLCollectionTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TLCollectionTableViewCell.xib; sourceTree = "<group>"; };
+		A7AD2748230F8D7C0099B3E0 /* TLPhotoPickerController.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TLPhotoPickerController.bundle; sourceTree = "<group>"; };
+		A7AD2749230F8D7C0099B3E0 /* TLPhotoCollectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TLPhotoCollectionViewCell.xib; sourceTree = "<group>"; };
+		A7AD274A230F8D7C0099B3E0 /* TLPhotosPickerViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TLPhotosPickerViewController.xib; sourceTree = "<group>"; };
+		A7AD274C230F8D7C0099B3E0 /* TLPhotoLibrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TLPhotoLibrary.swift; sourceTree = "<group>"; };
+		A7AD274D230F8D7C0099B3E0 /* TLPhotopickerDataSourcesProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TLPhotopickerDataSourcesProtocol.swift; sourceTree = "<group>"; };
+		A7AD274E230F8D7C0099B3E0 /* TLCollectionTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TLCollectionTableViewCell.swift; sourceTree = "<group>"; };
+		A7AD274F230F8D7C0099B3E0 /* TLBundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TLBundle.swift; sourceTree = "<group>"; };
+		A7AD2750230F8D7C0099B3E0 /* TLAlbumPopView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TLAlbumPopView.swift; sourceTree = "<group>"; };
+		A7AD2751230F8D7C0099B3E0 /* TLPhotoCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TLPhotoCollectionViewCell.swift; sourceTree = "<group>"; };
+		A7AD2752230F8D7C0099B3E0 /* SynchronizedDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizedDictionary.swift; sourceTree = "<group>"; };
+		A7AD2753230F8D7C0099B3E0 /* TLAssetCollection+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TLAssetCollection+Extension.swift"; sourceTree = "<group>"; };
+		A7AD2754230F8D7C0099B3E0 /* TLPhotosPickerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TLPhotosPickerViewController.swift; sourceTree = "<group>"; };
+		A7AD2755230F8D7C0099B3E0 /* TLAssetsCollection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TLAssetsCollection.swift; sourceTree = "<group>"; };
+		A7AD2764230F9A470099B3E0 /* TLPhotoPickerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TLPhotoPickerManager.swift; sourceTree = "<group>"; };
+		A7AD2767230F9C460099B3E0 /* PhotoPickerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerManager.swift; sourceTree = "<group>"; };
 		A7B4E71E228131720012914A /* ProductSlidingLeftRightCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductSlidingLeftRightCollectionViewCell.swift; sourceTree = "<group>"; };
 		A7B4E720228151F40012914A /* ProductFloorTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductFloorTitleView.swift; sourceTree = "<group>"; };
 		A7B4E722228154750012914A /* ProductFloorBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductFloorBannerView.swift; sourceTree = "<group>"; };
@@ -3380,6 +3414,7 @@
 		A77F2CBC2232022A001BD3F6 /* Tools */ = {
 			isa = PBXGroup;
 			children = (
+				A7AD2745230F8D7C0099B3E0 /* PhotoPicker */,
 				A7EE6E1323055A6000628D39 /* MemoryManager */,
 				A7EF3E112303EB6C001E4D26 /* GuidePageView */,
 				A76068F122E4B0ED008DF18F /* UImage+Gif */,
@@ -3744,6 +3779,53 @@
 			path = Router;
 			sourceTree = "<group>";
 		};
+		A7AD273D230F87E50099B3E0 /* ViewController */ = {
+			isa = PBXGroup;
+			children = (
+				A7AD2743230F88250099B3E0 /* PublishMediaPickerViewController.swift */,
+			);
+			path = ViewController;
+			sourceTree = "<group>";
+		};
+		A7AD2745230F8D7C0099B3E0 /* PhotoPicker */ = {
+			isa = PBXGroup;
+			children = (
+				A7AD2746230F8D7C0099B3E0 /* TLPhotoPickerResources */,
+				A7AD274B230F8D7C0099B3E0 /* TLPhotoPicker */,
+			);
+			path = PhotoPicker;
+			sourceTree = "<group>";
+		};
+		A7AD2746230F8D7C0099B3E0 /* TLPhotoPickerResources */ = {
+			isa = PBXGroup;
+			children = (
+				A7AD2747230F8D7C0099B3E0 /* TLCollectionTableViewCell.xib */,
+				A7AD2748230F8D7C0099B3E0 /* TLPhotoPickerController.bundle */,
+				A7AD2749230F8D7C0099B3E0 /* TLPhotoCollectionViewCell.xib */,
+				A7AD274A230F8D7C0099B3E0 /* TLPhotosPickerViewController.xib */,
+			);
+			path = TLPhotoPickerResources;
+			sourceTree = "<group>";
+		};
+		A7AD274B230F8D7C0099B3E0 /* TLPhotoPicker */ = {
+			isa = PBXGroup;
+			children = (
+				A7AD274C230F8D7C0099B3E0 /* TLPhotoLibrary.swift */,
+				A7AD274D230F8D7C0099B3E0 /* TLPhotopickerDataSourcesProtocol.swift */,
+				A7AD274E230F8D7C0099B3E0 /* TLCollectionTableViewCell.swift */,
+				A7AD274F230F8D7C0099B3E0 /* TLBundle.swift */,
+				A7AD2750230F8D7C0099B3E0 /* TLAlbumPopView.swift */,
+				A7AD2751230F8D7C0099B3E0 /* TLPhotoCollectionViewCell.swift */,
+				A7AD2752230F8D7C0099B3E0 /* SynchronizedDictionary.swift */,
+				A7AD2753230F8D7C0099B3E0 /* TLAssetCollection+Extension.swift */,
+				A7AD2754230F8D7C0099B3E0 /* TLPhotosPickerViewController.swift */,
+				A7AD2755230F8D7C0099B3E0 /* TLAssetsCollection.swift */,
+				A7AD2764230F9A470099B3E0 /* TLPhotoPickerManager.swift */,
+				A7AD2767230F9C460099B3E0 /* PhotoPickerManager.swift */,
+			);
+			path = TLPhotoPicker;
+			sourceTree = "<group>";
+		};
 		A7B4E71B22812D390012914A /* ShoppingMallSlidingLeftRight */ = {
 			isa = PBXGroup;
 			children = (
@@ -5010,6 +5092,7 @@
 		BD12B67222B4E99800AEB10B /* PublishMediaPicker */ = {
 			isa = PBXGroup;
 			children = (
+				A7AD273D230F87E50099B3E0 /* ViewController */,
 				BD12B68722B4F28F00AEB10B /* KSExtension.swift */,
 				BD12B67522B4ECE200AEB10B /* Controller */,
 				BD12B67622B4ED8800AEB10B /* Model */,
@@ -5965,7 +6048,9 @@
 				A75B787A22E07A51007B986A /* messageModuleTabbar.json in Resources */,
 				A78A5F7622FAA03800DD1764 /* share_iSpt.gif in Resources */,
 				BDD5483422C31752005BBE19 /* AlivcShortVideoImage.bundle in Resources */,
+				A7AD2759230F8D7D0099B3E0 /* TLPhotosPickerViewController.xib in Resources */,
 				A7CC74DE22703B4A003C4F38 /* MineModule.xcassets in Resources */,
+				A7AD2758230F8D7D0099B3E0 /* TLPhotoCollectionViewCell.xib in Resources */,
 				A7BF202422B392D600396DB3 /* CommunityModule.xcassets in Resources */,
 				A7EF3E102303DAEE001E4D26 /* Launch Screen.storyboard in Resources */,
 				BDD54A2522C31D5F005BBE19 /* music.json in Resources */,
@@ -5980,6 +6065,7 @@
 				A77F2C682231FB4A001BD3F6 /* Assets.xcassets in Resources */,
 				BDD54A2822C31D60005BBE19 /* LocalFilter.json in Resources */,
 				A75B787B22E07A51007B986A /* communityModuleTabbar.json in Resources */,
+				A7AD2756230F8D7D0099B3E0 /* TLCollectionTableViewCell.xib in Resources */,
 				A72C01232275404A0065E0C3 /* province_city_area.json in Resources */,
 				BDD54A2622C31D60005BBE19 /* watermark.png in Resources */,
 				BD108C9B22A60C3300837DAB /* HGImage.storyboard in Resources */,
@@ -5990,6 +6076,7 @@
 				A76068EB22E49BC1008DF18F /* collect.json in Resources */,
 				A7778C9922438F5D00C7C47A /* README.txt in Resources */,
 				BDD54A2922C31D60005BBE19 /* LocalMV.json in Resources */,
+				A7AD2757230F8D7D0099B3E0 /* TLPhotoPickerController.bundle in Resources */,
 				A7BF202722B3930100396DB3 /* MessageModule.xcassets in Resources */,
 				BDD54A2B22C31D78005BBE19 /* filter in Resources */,
 				BD108C9A22A60C3300837DAB /* HGImage.xcassets in Resources */,
@@ -6085,6 +6172,7 @@
 				A72A72BA22321DE000B21995 /* Extension+String.swift in Sources */,
 				BDAF83B222B3B67D0004BCC3 /* RecommendCommentFooter.swift in Sources */,
 				A7EE6E102305487700628D39 /* ThumbnailsManager.swift in Sources */,
+				A7AD2744230F88250099B3E0 /* PublishMediaPickerViewController.swift in Sources */,
 				A70B8430228FF6D400882BC5 /* ProductCartCountModel.swift in Sources */,
 				A770E5ED22D4298100CBD0A4 /* CommentReplyView.swift in Sources */,
 				A77F2CA02231FE45001BD3F6 /* BaseWebViewController.swift in Sources */,
@@ -6125,6 +6213,7 @@
 				BD13B6DB22BA03BC008BB323 /* PublishAddressPOIView.swift in Sources */,
 				A72A72BE22321DE000B21995 /* Extension+RxTimer.swift in Sources */,
 				BD61225F22C3561C00D3F513 /* AliyunMagicCameraView.m in Sources */,
+				A7AD2760230F8D7D0099B3E0 /* SynchronizedDictionary.swift in Sources */,
 				A770E61422D6625700CBD0A4 /* ShareCommunityView.swift in Sources */,
 				A7F2D6CB22B0E4270093000B /* CommunityRecommendFollowCollectionViewCell.swift in Sources */,
 				BDF47D7E22827C3F00941AB9 /* ProductSlidingTopBottomCollectionViewCell.swift in Sources */,
@@ -6188,6 +6277,7 @@
 				A7636AC52268139C00374F9E /* LocationViewController.swift in Sources */,
 				A73A56DB22DC9AB5004920FE /* UpdateVersionModel.swift in Sources */,
 				A7D46090227617D200A5A54E /* SQLModel.swift in Sources */,
+				A7AD275A230F8D7D0099B3E0 /* TLPhotoLibrary.swift in Sources */,
 				A790706522B9DFAD008CE279 /* TextLimitTool.m in Sources */,
 				A72C01222275404A0065E0C3 /* ProvinceCityAreaModel.swift in Sources */,
 				A7FF1579228C82CE00A85748 /* OrderDetailViewController.swift in Sources */,
@@ -6230,6 +6320,7 @@
 				A7F2D6DD22B2536F0093000B /* CardContentPicVideoCollectionViewCell.swift in Sources */,
 				A72623D922C2F8B100AEF875 /* MessageHomeOneCollectionViewCell.swift in Sources */,
 				A75B782822DEC708007B986A /* SepcialTwoTypeLayout.swift in Sources */,
+				A7AD275C230F8D7D0099B3E0 /* TLCollectionTableViewCell.swift in Sources */,
 				BD7AB83622841A8B0030646A /* ShoppingCartPayOrderItemCell.swift in Sources */,
 				A71AA519227219D7008FF1A5 /* EditExpressAddressViewController.swift in Sources */,
 				A7FF1568228C6E2300A85748 /* OrderDeliveryModeAndTimeTableViewCell.swift in Sources */,
@@ -6238,6 +6329,7 @@
 				A71738A822897E96000AEA6A /* SwiftMoyaNetWorkServiceShop.swift in Sources */,
 				BD20F1CD2283C51300677D8E /* OrderFinishPayController.swift in Sources */,
 				A729B5B022671310004AE098 /* MobileLoginView.swift in Sources */,
+				A7AD2768230F9C460099B3E0 /* PhotoPickerManager.swift in Sources */,
 				A71AA50C2272126A008FF1A5 /* EditAddressFooterView.swift in Sources */,
 				A70B2C35228815F700B2449F /* ProductDetailProductSkuLabelCollectionViewCell.swift in Sources */,
 				A70B2C60228870CE00B2449F /* ShopSectionHeaderView.swift in Sources */,
@@ -6255,6 +6347,7 @@
 				A7B4E721228151F40012914A /* ProductFloorTitleView.swift in Sources */,
 				A729B5AD2266FF45004AE098 /* BindPhoneNumberView.swift in Sources */,
 				A75C474E22938B3900139C0C /* OrderFreightTableViewCell.swift in Sources */,
+				A7AD2761230F8D7D0099B3E0 /* TLAssetCollection+Extension.swift in Sources */,
 				A7FF1592228C918100A85748 /* OrderRefunddetailsStatusTableViewCell.swift in Sources */,
 				BD12B67822B4ED9200AEB10B /* KSMediaPickerOutputModel.swift in Sources */,
 				A7CC74E62270628B003C4F38 /* DeliveryMethodTypeModel.swift in Sources */,
@@ -6284,6 +6377,7 @@
 				BD13B6DF22BA03BC008BB323 /* PublishTopicHeaderView.swift in Sources */,
 				A7778CB82244E97A00C7C47A /* BindPhoneNumberViewController.swift in Sources */,
 				A754150F224CACF9002480B5 /* SwiftSign.swift in Sources */,
+				A7AD275F230F8D7D0099B3E0 /* TLPhotoCollectionViewCell.swift in Sources */,
 				A71AF0BA226F00F8001730FE /* SearchResultView.swift in Sources */,
 				A77F2CB52232010F001BD3F6 /* ShoppingMallViewController.swift in Sources */,
 				A7D77DEB22DDC5900048D5F6 /* RedemptionAreaFSPagerViewCell.swift in Sources */,
@@ -6316,11 +6410,13 @@
 				A7A98E0B227EBD04005306E9 /* CategorySearchView.swift in Sources */,
 				A72A73142232475E00B21995 /* AlipayManager.swift in Sources */,
 				A7824B042271F10300ABA381 /* EditSelfMentionContactsView.swift in Sources */,
+				A7AD275D230F8D7D0099B3E0 /* TLBundle.swift in Sources */,
 				A7274C5B228EE636000E3A07 /* LBXScanViewController.swift in Sources */,
 				BD0FAA5322C4750A00DDFB37 /* AliyunCoverPickView.m in Sources */,
 				A7FF1566228C6DF200A85748 /* OrderShopAndStatusTableViewCell.swift in Sources */,
 				A7A98E332280272A005306E9 /* ShoppingMallBannerTableViewCell.swift in Sources */,
 				A790706122B9C294008CE279 /* ModifyDataNickNameSignView.swift in Sources */,
+				A7AD2763230F8D7D0099B3E0 /* TLAssetsCollection.swift in Sources */,
 				BD12204622AF997E0051C7C2 /* MessageListTableCell.swift in Sources */,
 				BDF862AA228E43A4000DEF84 /* OrderCommentTableViewCell.swift in Sources */,
 				A7B4E754228278320012914A /* ShoppingMallFloorTableViewCell.swift in Sources */,
@@ -6475,6 +6571,7 @@
 				A7BB685922696B9200AB07A2 /* SelfRecommendationCollectionViewCell.swift in Sources */,
 				BD61231522C3749800D3F513 /* AliyunPathManager.m in Sources */,
 				BD12B69A22B4FA8400AEB10B /* KSMediaPickerSelectIndicator.swift in Sources */,
+				A7AD2762230F8D7D0099B3E0 /* TLPhotosPickerViewController.swift in Sources */,
 				A7636AC822682BAF00374F9E /* LocationView.swift in Sources */,
 				BD61227C22C35C7F00D3F513 /* AliyunMediaConfig.m in Sources */,
 				A738D205225AF90D00EEE860 /* WeChatpayOrderModel.swift in Sources */,
@@ -6579,6 +6676,7 @@
 				A7274C5D228EE636000E3A07 /* LBXScanViewStyle.swift in Sources */,
 				A73911B3229ECE340033177E /* UICollectionViewLeftAlignedLayout.m in Sources */,
 				A7A98E1B227EEE49005306E9 /* SpecialView.swift in Sources */,
+				A7AD275B230F8D7D0099B3E0 /* TLPhotopickerDataSourcesProtocol.swift in Sources */,
 				BDF47D7A228271F600941AB9 /* ShoppingCartView.swift in Sources */,
 				A7824AFB2271EA2600ABA381 /* SelfMentionContactsListView.swift in Sources */,
 				A72A72AB22321DE000B21995 /* SwiftProgressHUD.swift in Sources */,
@@ -6607,6 +6705,7 @@
 				A7FF1560228C693D00A85748 /* OrderViewController.swift in Sources */,
 				A729B5B42267254B004AE098 /* PasswordLoginViewController.swift in Sources */,
 				A7B4E7582282897B0012914A /* ProductFloorLeftHeaderCollectionReusableView.swift in Sources */,
+				A7AD2765230F9A470099B3E0 /* TLPhotoPickerManager.swift in Sources */,
 				A7D4608E227616F800A5A54E /* SQLiteManager.swift in Sources */,
 				A78A5F7822FAC7F000DD1764 /* SetGenderModel.swift in Sources */,
 				A70B2C6B2288815300B2449F /* PickHeaderView.swift in Sources */,
@@ -6668,6 +6767,7 @@
 				A7D5F22922BB686200F8E9AF /* BaseJSWebBaseViewController.swift in Sources */,
 				BD20F1CB2283C12000677D8E /* ShoppingCartListNoneItemCell.swift in Sources */,
 				A7B4E756228281620012914A /* ShoppingMallSlidingLeftRightBgCollectionViewCell.swift in Sources */,
+				A7AD275E230F8D7D0099B3E0 /* TLAlbumPopView.swift in Sources */,
 				BD1FC18122B08D7A00D55081 /* CommunityMyFollowTopicCell.swift in Sources */,
 				A7C0FDE722B4A38500BC1E86 /* CardContentCommentListTableViewCell.swift in Sources */,
 				A757C92E22744ACE00226355 /* AddressManagerListModel.swift in Sources */,
@@ -6897,7 +6997,7 @@
 					"\"$(SRCROOT)/RainbowPlanet/Lib/AlipaySDK\"",
 				);
 				INFOPLIST_FILE = "$(SRCROOT)/RainbowPlanet/Supporting Files/Info.plist";
-				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.1;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",
@@ -7148,7 +7248,7 @@
 					"\"$(SRCROOT)/RainbowPlanet/Lib/AlipaySDK\"",
 				);
 				INFOPLIST_FILE = "$(SRCROOT)/RainbowPlanet/Supporting Files/Info.plist";
-				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+				IPHONEOS_DEPLOYMENT_TARGET = 9.1;
 				LD_RUNPATH_SEARCH_PATHS = (
 					"$(inherited)",
 					"@executable_path/Frameworks",

+ 7 - 0
RainbowPlanet/RainbowPlanet/AppDelegate/AppDelegate+Window.swift

@@ -16,6 +16,8 @@ extension AppDelegate {
     func initWindow(didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
         window = UIWindow.init(frame: UIScreen.main.bounds)
         window?.backgroundColor = UIColor.white
+        //版本更新
+        _ = UpdateVersionManager.shared
         let vc = RootViewController()
         vc.launchOptions = launchOptions
         window?.rootViewController = vc
@@ -23,6 +25,7 @@ extension AppDelegate {
         //基础配置
         DispatchQueue.global(qos: .default).async {
             [weak self] in
+            
             /// 设置全局的tabbar
             self?.setTabbarAppearence()
             /// 设置全局的navigation
@@ -120,6 +123,10 @@ extension AppDelegate {
         UITableView.appearance().estimatedSectionHeaderHeight = 0
         UITableView.appearance().estimatedSectionFooterHeight = 0
     }
+    
+    func setKingfisher() {
+       
+    }
 
     
     ///设置百度city转

+ 0 - 2
RainbowPlanet/RainbowPlanet/Base/RootViewController/RootViewController.swift

@@ -50,8 +50,6 @@ class RootViewController: BaseViewController {
             BaiduMapManager.shared.startLocation()
             //初始化友盟
             UMManager.shared.initUM(launchOptions: self?.launchOptions)
-            //版本更新
-            _ = UpdateVersionManager.shared
             //设置Tabbar
             kAppDelegate.setTabbarController()
             /// 引导页

+ 1 - 1
RainbowPlanet/RainbowPlanet/Manager/WebViewJavascriptBridgeManager/WebViewJavascriptBridgeManager.swift

@@ -135,7 +135,7 @@ class WebViewJavascriptBridgeManager: NSObject {
             
             // 去个人中心
             if wvjbModel?.params?.paramsModelPage == .user {
-                if wvjbModel?.params?.payload?.uid != nil {
+                if wvjbModel?.params?.payload?.uid != nil && wvjbModel?.params?.payload?.uid != UserModel.shared().getModel()?.uid {
                     Mediator.present(MineRouterModuleType.pushOtherPersonalCenter(uid: wvjbModel?.params?.payload?.uid ?? 0))
                 }
             }

+ 2 - 0
RainbowPlanet/RainbowPlanet/Model/CommunityModel/CommunityFollowFeedModel.swift

@@ -69,6 +69,7 @@ class CommunityFollowContentModel : NSObject, Mappable{
     var beans : Int?
     var postDesc : String?
     var commentDesc:String?
+    var postType:String?
     
     
     class func newInstance(map: Map) -> Mappable?{
@@ -82,6 +83,7 @@ class CommunityFollowContentModel : NSObject, Mappable{
         beans <- map["beans"]
         postDesc <- map["post_desc"]
         commentDesc <- map["comment_desc"]
+        postType <- map["post_type"]
         
     }
     

+ 1 - 1
RainbowPlanet/RainbowPlanet/Modules/CommunityModule/Community/View/Cell/FollowStatus/CommunityFollowStatusTableViewCell.swift

@@ -444,7 +444,7 @@ class CommunityFollowStatusTableViewCell: UITableViewCell {
     
     /// 内容详情页面
     @objc func contentDetail() {
-        if PostType(rawValue: communityFollowDataModel?.relateData?.type ?? "video") == .video {
+        if PostType(rawValue: communityFollowDataModel?.content?.postType ?? "video") == .video {
             NotificationCenter.default.post(name: NSNotification.Name(rawValue: "CommunityContentVideoClosure"), object: communityFollowDataModel?.relateId)
 
         }else {

+ 3 - 4
RainbowPlanet/RainbowPlanet/Modules/CommunityModule/CommunityRecommendDetail/Controller/CommunityRecommendController.swift

@@ -122,7 +122,6 @@ class CommunityRecommendController: BaseViewController {
         followButton.titleLabel?.font = kMediumFont13
         followButton.cornerRadius = 12
         followButton.masksToBounds = true
-        followButton.layer.borderWidth = 0.5
         followButton.alpha = 0
         return followButton
     }()
@@ -486,14 +485,14 @@ extension CommunityRecommendController {
                 //总间距
                 let spacingHeght : CGFloat = 35
                 
-                let str = communityPostDataModel.content?.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\r", with: "").prefix(13)
+                let str = communityPostDataModel.content?.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\r", with: "").prefix(20)
                 
                 if communityPostDataModel.title == "" || communityPostDataModel.title == nil  {
                     let content = "\(str ?? "")"
                     labelHeight = (content.heightForComment(font: kMediumFont13!, width: (((kScreenWidth - 15)/2) - 20)))
                 }else {
-                    let str = communityPostDataModel.title?.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\r", with: "")
-                    labelHeight = (str?.heightForComment(font: kMediumFont13!, width: (((kScreenWidth - 15)/2) - 20)))!
+                    let str = "\(communityPostDataModel.title?.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\r", with: "").prefix(20) ?? "")"
+                    labelHeight = (str.heightForComment(font: kMediumFont13!, width: (((kScreenWidth - 15)/2) - 20)))
                 }
                 
                 //button高度

+ 11 - 13
RainbowPlanet/RainbowPlanet/Modules/CommunityModule/CommunityVideoContent/View/CommunityVideoCoverCollectionCell.swift

@@ -441,7 +441,7 @@ class CommunityVideoCoverCollectionCell: UICollectionViewCell {
                 kAppDelegate.setLogin()
             }else {
                 if let shareClosure = self?.shareClosure {
-                    shareClosure(self!.videoItemMdl!)
+                    shareClosure((self?.videoItemMdl)!)
                 }
             }
 
@@ -529,20 +529,20 @@ class CommunityVideoCoverCollectionCell: UICollectionViewCell {
             if UserModel.isTokenNil() {
                 kAppDelegate.setLogin()
             }else {
-                collectBtn.isSelected = !collectBtn.isSelected
+                self?.collectBtn.isSelected = !collectBtn.isSelected
                 // 本地修改收藏数据
                 var collectCount = self?.videoItemMdl?.collectCount ?? 0
                 if self?.videoItemMdl?.isCollect == 0 {
-                    collectBtn.setTitle("\(collectCount)", for: .normal)
-                    collectBtn.setTitle("\(collectCount+1)", for: .selected)
                     self?.collectAnimationView.isHidden = false
                     self?.collectAnimationView.play(completion: { (_) in
                         self?.collectAnimationView.isHidden = true
                     })
+                    self?.videoItemMdl?.collectCount = collectCount + 1
                 } else {
-                    collectBtn.setTitle("\(collectCount)", for: .selected)
-                    collectBtn.setTitle("\(collectCount-1)", for: .normal)
+                    self?.videoItemMdl?.collectCount = collectCount - 1
                 }
+                self?.collectBtn.setTitle("\(self?.videoItemMdl?.collectCount ?? 0)", for: .normal)
+
                 // 点击回调
                 if let buttonClickClosure = self?.buttonClickClosure {
                     buttonClickClosure(videoBtnClickType.typeCollect, self?.videoItemMdl?.uid ?? 0, self?.videoItemMdl?.id ?? 0)
@@ -564,19 +564,17 @@ class CommunityVideoCoverCollectionCell: UICollectionViewCell {
             if UserModel.isTokenNil() {
                 kAppDelegate.setLogin()
             }else {
-                likeBtn.isSelected = !likeBtn.isSelected
+                self?.likeBtn.isSelected = !likeBtn.isSelected
                 // 本地修改点赞数据
                 var praiseCount = self?.videoItemMdl?.praiseCount ?? 0
                 if self?.videoItemMdl?.isLike == 0 {
-                    likeBtn.setTitle("\(praiseCount)", for: .normal)
-                    likeBtn.setTitle("\(praiseCount+1)", for: .selected)
+                    self?.likeBtn.setTitle("\(praiseCount+1)", for: .selected)
                     self?.praiseAnimationView.isHidden = false
                     self?.praiseAnimationView.play(completion: { (_) in
                         self?.praiseAnimationView.isHidden = true
                     })
                 } else {
-                    likeBtn.setTitle("\(praiseCount)", for: .selected)
-                    likeBtn.setTitle("\(praiseCount-1)", for: .normal)
+                    self?.likeBtn.setTitle("\(praiseCount-1)", for: .normal)
                 }
                 // 点击回调
                 if let buttonClickClosure = self?.buttonClickClosure {
@@ -881,8 +879,8 @@ class CommunityVideoCoverCollectionCell: UICollectionViewCell {
             // 评论
             commentBtn.setTitle("\(self.videoItemMdl?.commentCount ?? 0)", for: .normal)
             
-            collectBtn.isSelected = self.videoItemMdl?.isCollect == 0 ? false : true
-            likeBtn.isSelected = self.videoItemMdl?.isLike == 0 ? false : true
+            collectBtn.isSelected = (self.videoItemMdl?.isCollect == 0 ? false : true)
+            likeBtn.isSelected = (self.videoItemMdl?.isLike == 0 ? false : true)
             
             
             if self.videoItemMdl?.uid == UserModel.shared().getModel()?.uid {

+ 124 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishMediaPicker/ViewController/PublishMediaPickerViewController.swift

@@ -0,0 +1,124 @@
+//
+//  PublishMediaPickerViewController.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/8/23.
+//  Copyright © 2019 RainbowPlanet. All rights reserved.
+//
+
+import UIKit
+import JXSegmentedView
+import Photos
+import PhotosUI
+import MobileCoreServices
+
+//public protocol PublishMediaPickerViewControllerDelegate: class {
+//    func dismissPhotoPicker(withPHAssets: [PHAsset])
+//    func dismissPhotoPicker(withTLPHAssets: [TLPHAsset])
+//    func dismissComplete()
+//    func photoPickerDidCancel()
+//    func canSelectAsset(phAsset: PHAsset) -> Bool
+//    func didExceedMaximumNumberOfSelection(picker: PublishMediaPickerViewController)
+//    func handleNoAlbumPermissions(picker: PublishMediaPickerViewController)
+//    func handleNoCameraPermissions(picker: PublishMediaPickerViewController)
+//}
+//
+//extension PublishMediaPickerViewControllerDelegate {
+//    public func deninedAuthoization() { }
+//    public func dismissPhotoPicker(withPHAssets: [PHAsset]) { }
+//    public func dismissPhotoPicker(withTLPHAssets: [TLPHAsset]) { }
+//    public func dismissComplete() { }
+//    public func photoPickerDidCancel() { }
+//    public func canSelectAsset(phAsset: PHAsset) -> Bool { return true }
+//    public func didExceedMaximumNumberOfSelection(picker: PublishMediaPickerViewController) { }
+//    public func handleNoAlbumPermissions(picker: PublishMediaPickerViewController) { }
+//    public func handleNoCameraPermissions(picker: PublishMediaPickerViewController) { }
+//}
+//
+////for log
+//public protocol PublishMediaPickerLogDelegate: class {
+//    func selectedCameraCell(picker: PublishMediaPickerViewController)
+//    func deselectedPhoto(picker: PublishMediaPickerViewController, at: Int)
+//    func selectedPhoto(picker: PublishMediaPickerViewController, at: Int)
+//    func selectedAlbum(picker: PublishMediaPickerViewController, title: String, at: Int)
+//}
+//
+//extension PublishMediaPickerLogDelegate {
+//    func selectedCameraCell(picker: PublishMediaPickerViewController) { }
+//    func deselectedPhoto(picker: PublishMediaPickerViewController, at: Int) { }
+//    func selectedPhoto(picker: PublishMediaPickerViewController, at: Int) { }
+//    func selectedAlbum(picker: PublishMediaPickerViewController, collections: [TLAssetsCollection], at: Int) { }
+//}
+
+class PublishMediaPickerViewController: BaseViewController {
+    
+    deinit {
+        NXLLog("deinit")
+    }
+    
+    /// 最大视频个数
+    var maxVideoCount: UInt? = nil
+    /// 最大图片个数
+    var maxPictureCount: UInt? = nil
+    
+    /// 返回
+    typealias DismissClosure = () -> Void
+    var dismissClosure: DismissClosure?
+    
+    /// 完成
+    typealias CompleteClosure = () -> Void
+    var completeClosure: CompleteClosure?
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        setupViews()
+        setupLayouts()
+        setupData()
+    }
+    
+    override func setupViews() {
+        navigationBar.wr_setRightButton(title: "完成", titleColor: k999999Color)
+    }
+    
+    override func setupLayouts() {
+        
+    }
+    
+    override func setupData() {
+        /// 返回
+        navigationBar.onClickLeftButton = {
+            [weak self] in
+            if let dismissClosure = self?.dismissClosure {
+                dismissClosure()
+            }
+        }
+        /// 完成
+        navigationBar.onClickRightButton = {
+            [weak self] in
+            if let completeClosure = self?.completeClosure {
+                completeClosure()
+            }
+        }
+    }
+    
+//    lazy var <#property name#>: <#type name#> = {
+//        <#statements#>
+//        return <#value#>
+//    }()
+    
+    
+
+}
+
+// MARK: - JXSegmentedDelegate
+extension PublishMediaPickerViewController : JXSegmentedListContainerViewListDelegate {
+    public func listView() -> UIView {
+        return view
+    }
+    public func listDidAppear() {
+//        (view as! KSMediaPickerView).previewView.videoPlay()
+    }
+    public func listDidDisappear() {
+//        (view as! KSMediaPickerView).previewView.videoPause()
+    }
+}

+ 12 - 0
RainbowPlanet/RainbowPlanet/Modules/PublishModule/PublishViewController.swift

@@ -223,6 +223,18 @@ extension PublishViewController :JXSegmentedListContainerViewDataSource {
                 self?.navigationController?.pushViewController(pubVc, animated: true)
             }
             return mediaVc
+//            let publishMediaPickerVC = PublishMediaPickerViewController()
+//            publishMediaPickerVC.maxVideoCount = 1
+//            publishMediaPickerVC.maxPictureCount = 9
+//            publishMediaPickerVC.dismissClosure = {
+//                [weak self] in
+//                self?.dismiss(animated: true, completion: nil)
+//            }
+//            publishMediaPickerVC.completeClosure = {
+//
+//            }
+//
+//            return publishMediaPickerVC
         case 1:
             let videoVc = AliyunMagicCameraViewController()
             videoVc.quVideo = mediaConfig

+ 1 - 1
RainbowPlanet/RainbowPlanet/Modules/SearchModule/Search/View/SearchNavigationbarView.swift

@@ -110,7 +110,7 @@ extension SearchNavigationbarView : UITextFieldDelegate   {
     func textFieldShouldReturn(_ textField: UITextField) -> Bool {
         
         if self.searchTextField.text?.count ?? 0 > 0 {
-            self.searchTextField.becomeFirstResponder()
+            self.endEditing(true)
             
             var searchHistoryArray = Array<String>()
             

+ 7 - 17
RainbowPlanet/RainbowPlanet/Modules/SearchModule/SearchContentList/View/SearchContentListCollectionCell.swift

@@ -80,6 +80,7 @@ class SearchContentListCollectionCell: UICollectionViewCell {
             make.top.equalTo(contentImageView.snp_bottom).offset(15)
             make.left.equalTo(contentImageView.snp_left).offset(10)
             make.right.equalTo(contentImageView.snp_right).offset(-10)
+            make.height.lessThanOrEqualTo(37)
         }
         avatarButton.snp.makeConstraints { (make) in
             make.top.equalTo(titleLabel.snp_bottom).offset(10)
@@ -202,6 +203,7 @@ class SearchContentListCollectionCell: UICollectionViewCell {
         let likeLabel = UILabel()
         likeLabel.textColor = k999999Color
         likeLabel.font = kRegularFont12
+        likeLabel.sizeToFit()
         return likeLabel
     }()
     
@@ -225,10 +227,11 @@ class SearchContentListCollectionCell: UICollectionViewCell {
         didSet {
             contentImageView.kf.setImage(with: kURLThumbnailsImage(name: communityPostDataModel?.img ?? "",size: CGSize(width: self.size.width, height: (kScreenWidth-15)/2)), placeholder: kImage(name: "default_pic"))
             titleLabel.text = communityPostDataModel?.title
+            
             if communityPostDataModel?.title == "" || communityPostDataModel?.title == nil {
-                titleLabel.text = communityPostDataModel?.content?.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\r", with: "")
+                titleLabel.text = "\(communityPostDataModel?.content?.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\r", with: "").prefix(20) ?? "")"
             }else {
-                titleLabel.text = communityPostDataModel?.title?.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\r", with: "")
+                titleLabel.text = "\(communityPostDataModel?.title?.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\r", with: "").prefix(20) ?? "")"
             }
             avatarButton.kf.setImage(with: kURLThumbnailsImage(name: communityPostDataModel?.avatar ?? "", size: kSize18x18Image), for: UIControl.State.normal, placeholder: kImage(name: "default_avatar"))
             KingfisherManager.shared.cache.clearMemoryCache()
@@ -245,27 +248,14 @@ class SearchContentListCollectionCell: UICollectionViewCell {
             }else {
                 pauseImageView.isHidden = true
             }
-            
+            likeLabel.sizeToFit()
             nameButton.snp.remakeConstraints { (make) in
                 make.centerY.equalTo(avatarButton)
                 make.left.equalTo(avatarButton.snp_right).offset(5)
                 make.height.equalTo(18)
-                make.right.equalTo(likeBtn.snp_left).offset(-5)
-            }
-            
-            likeLabel.snp.remakeConstraints { (make) in
-                make.centerY.equalTo(avatarButton)
-                make.right.equalTo(-13)
-                make.left.equalTo(likeBtn.snp.right)
+                make.width.equalTo((((kScreenWidth - 15)/2) - 20)-18-likeLabel.width-13-28)
             }
             
-            likeBtn.snp.remakeConstraints { (make) in
-                make.centerY.equalTo(avatarButton)
-                make.right.equalTo(likeLabel.snp.left).offset(-3)
-                make.size.equalTo(18)
-            }
-            
-            
         }
     }
 }

+ 3 - 3
RainbowPlanet/RainbowPlanet/Modules/SearchModule/SearchContentList/ViewController/SearchContentListViewController.swift

@@ -129,14 +129,14 @@ extension SearchContentListViewController {
                 //总间距
                 let spacingHeght : CGFloat = 35
                 
-                let str = communityPostDataModel.content?.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\r", with: "").prefix(13)
+                let str = communityPostDataModel.content?.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\r", with: "").prefix(20)
                 
                 if communityPostDataModel.title == "" || communityPostDataModel.title == nil  {
                     let content = "\(str ?? "")"
                     labelHeight = (content.heightForComment(font: kMediumFont13!, width: (((kScreenWidth - 15)/2) - 20)))
                 }else {
-                    let str = communityPostDataModel.title?.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\r", with: "")
-                    labelHeight = (str?.heightForComment(font: kMediumFont13!, width: (((kScreenWidth - 15)/2) - 20)))!
+                    let str = "\(communityPostDataModel.title?.replacingOccurrences(of: "\n", with: "").replacingOccurrences(of: "\r", with: "").prefix(20) ?? "")"
+                    labelHeight = (str.heightForComment(font: kMediumFont13!, width: (((kScreenWidth - 15)/2) - 20)))
                 }
                 
                 //button高度

+ 1 - 1
RainbowPlanet/RainbowPlanet/Modules/SearchModule/SearchResult/View/SearchResultNavigationbarView.swift

@@ -116,7 +116,7 @@ extension SearchResultNavigationbarView : UITextFieldDelegate   {
         
         if self.searchTextField.text?.count ?? 0 > 0 {
             var searchHistoryArray = Array<String>()
-            self.searchTextField.becomeFirstResponder()
+            self.endEditing(true)
             if UserDefaults.standard.array(forKey: "SearchHistoryArray")?.isEmpty ?? true {
                 searchHistoryArray.append(self.searchTextField.text ?? "")
             } else {

+ 1 - 1
RainbowPlanet/RainbowPlanet/Tools/CommentInputView/CommentReplyView.swift

@@ -207,7 +207,7 @@ extension CommentReplyView {
         vProperty.popupViewEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
         vProperty.popupAnimationType = .frame
         vProperty.maskViewColor = UIColor(white: 0, alpha: 0.5)
-        vProperty.touchWildToHide = "0"
+        vProperty.touchWildToHide = "1"
         view.vProperty = vProperty
         view.replyButtonClosure = {
             [weak view] in

+ 39 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/PhotoPickerManager.swift

@@ -0,0 +1,39 @@
+//
+//  File.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/8/23.
+//  Copyright © 2019 RainbowPlanet. All rights reserved.
+//
+
+import Foundation
+
+public enum FetchCollectionType {
+    case assetCollections(PHAssetCollectionType)
+    case topLevelUserCollections
+}
+
+extension FetchCollectionType: Hashable {
+    private var identifier: String {
+        switch self {
+        case let .assetCollections(collectionType):
+            return "assetCollections\(collectionType.rawValue)"
+        case .topLevelUserCollections:
+            return "topLevelUserCollections"
+        }
+    }
+    
+    public func hash(into hasher: inout Hasher) {
+        hasher.combine(self.identifier)
+    }
+}
+
+public enum PopupConfigure {
+    case animation(TimeInterval)
+}
+
+public struct Platform {
+    public static var isSimulator: Bool {
+        return TARGET_OS_SIMULATOR != 0 // Use this line in Xcode 7 or newer
+    }
+}

+ 54 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/SynchronizedDictionary.swift

@@ -0,0 +1,54 @@
+//
+//  SynchronizedDictionary.swift
+//  TLPhotoPicker
+//
+//  Created by wade.hawk on 30/03/2019.
+//
+
+import Foundation
+
+public class SynchronizedDictionary<K:Hashable,V> {
+    private var dictionary: [K:V] = [:]
+    private let accessQueue = DispatchQueue(label: "SynchronizedDictionaryAccess",
+                                            attributes: .concurrent)
+    
+    deinit {
+        //print("deinit SynchronizedDictionary")
+    }
+    
+    public func removeAll() {
+        self.accessQueue.async(flags:.barrier) {
+            self.dictionary.removeAll()
+        }
+    }
+    
+    public func removeValue(forKey: K) {
+        self.accessQueue.async(flags:.barrier) {
+            self.dictionary.removeValue(forKey: forKey)
+        }
+    }
+    
+    public func forEach(_ closure: ((K,V) -> Void)) {
+        self.accessQueue.sync {
+            self.dictionary.forEach{ arg in
+                let (key, value) = arg
+                closure(key,value)
+            }
+        }
+    }
+    
+    public subscript(key: K) -> V? {
+        set {
+            self.accessQueue.async(flags:.barrier) {
+                self.dictionary[key] = newValue
+            }
+        }
+        get {
+            var element: V?
+            self.accessQueue.sync {
+                element = self.dictionary[key]
+            }
+            return element
+        }
+    }
+}

+ 78 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLAlbumPopView.swift

@@ -0,0 +1,78 @@
+//
+//  TLAlbumPopView.swift
+//  TLPhotosPicker
+//
+//  Created by wade.hawk on 2017. 4. 19..
+//  Copyright © 2017년 wade.hawk. All rights reserved.
+//
+
+import UIKit
+
+protocol PopupViewProtocol: class {
+    var bgView: UIView! { get set }
+    var popupView: UIView! { get set }
+    var originalFrame: CGRect { get set }
+    var show: Bool { get set }
+    func setupPopupFrame()
+}
+
+extension PopupViewProtocol where Self: UIView {
+    fileprivate func getFrame(scale: CGFloat) -> CGRect {
+        var frame = self.originalFrame
+        frame.size.width = frame.size.width * scale
+        frame.size.height = frame.size.height * scale
+        frame.origin.x = self.frame.width/2 - frame.width/2
+        return frame
+    }
+    func setupPopupFrame() {
+        if self.originalFrame != self.popupView.frame {
+            self.originalFrame = self.popupView.frame
+        }
+    }
+    func show(_ show: Bool, duration: TimeInterval = 0.1) {
+        guard self.show != show else { return }
+        self.layer.removeAllAnimations()
+        self.isHidden = false
+        self.popupView.frame = show ? getFrame(scale: 0.1) : self.popupView.frame
+        self.bgView.alpha = show ? 0 : 1
+        UIView.animate(withDuration: duration, animations: {
+            self.bgView.alpha = show ? 1 : 0
+            self.popupView.transform = show ? CGAffineTransform(scaleX: 1.05, y: 1.05) : CGAffineTransform(scaleX: 0.1, y: 0.1)
+            self.popupView.frame = show ? self.getFrame(scale: 1.05) : self.getFrame(scale: 0.1)
+        }) { _ in
+            self.isHidden = show ? false : true
+            UIView.animate(withDuration: duration) {
+                if show {
+                    self.popupView.transform = CGAffineTransform(scaleX: 1, y: 1)
+                    self.popupView.frame = self.originalFrame
+                }
+                self.show = show
+            }
+        }
+    }
+}
+
+open class TLAlbumPopView: UIView,PopupViewProtocol {
+    @IBOutlet open var bgView: UIView!
+    @IBOutlet open var popupView: UIView!
+    @IBOutlet var popupViewHeight: NSLayoutConstraint!
+    @IBOutlet open var tableView: UITableView!
+    @objc var originalFrame = CGRect.zero
+    @objc var show = false
+    
+    deinit {
+//        print("deinit TLAlbumPopView")
+    }
+    
+    override open func awakeFromNib() {
+        super.awakeFromNib()
+        self.popupView.layer.cornerRadius = 5.0
+        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapBgView))
+        self.bgView.addGestureRecognizer(tapGesture)
+        self.tableView.register(UINib(nibName: "TLCollectionTableViewCell", bundle: TLBundle.bundle()), forCellReuseIdentifier: "TLCollectionTableViewCell")
+    }
+    
+    @objc func tapBgView() {
+        self.show(false)
+    }
+}

+ 68 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLAssetCollection+Extension.swift

@@ -0,0 +1,68 @@
+//
+//  TLAssetCollection+Extension.swift
+//  TLPhotoPicker
+//
+//  Created by wade.hawk on 21/01/2019.
+//
+
+import Foundation
+import Photos
+
+public enum PHFetchedResultGroupedBy {
+    case year
+    case month
+    case week
+    case day
+    case hour
+    case custom(dateFormat: String)
+    var dateFormat: String {
+        switch self {
+        case .year:
+            return "yyyy"
+        case .month:
+            return "yyyyMM"
+        case .week:
+            return "yyyyMMW"
+        case .day:
+            return "yyyyMMdd"
+        case .hour:
+            return "yyyyMMddHH"
+        case let .custom(dateFormat):
+            return dateFormat
+        }
+    }
+}
+
+extension TLAssetsCollection {
+    func enumarateFetchResult(groupedBy: PHFetchedResultGroupedBy) -> Dictionary<String,[TLPHAsset]> {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = groupedBy.dateFormat
+        var assets = [PHAsset]()
+        assets.reserveCapacity(self.fetchResult?.count ?? 0)
+        self.fetchResult?.enumerateObjects({ (phAsset, idx, stop) in
+            if phAsset.creationDate != nil {
+                assets.append(phAsset)
+            }
+        })
+        let sections = Dictionary(grouping: assets.map{ TLPHAsset(asset: $0) }) { (element) -> String in
+            if let creationDate = element.phAsset?.creationDate {
+                let identifier = dateFormatter.string(from: creationDate)
+                return identifier
+            }
+            return ""
+        }
+        return sections
+    }
+
+    func section(groupedBy: PHFetchedResultGroupedBy) -> [(String,[TLPHAsset])] {
+        let dict = enumarateFetchResult(groupedBy: groupedBy)
+        var sections = [(String,[TLPHAsset])]()
+        let sortedKeys = dict.keys.sorted(by: >)
+        for key in sortedKeys {
+            if let array = dict[key] {
+                sections.append((key, array))
+            }
+        }
+        return sections
+    }
+}

+ 370 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLAssetsCollection.swift

@@ -0,0 +1,370 @@
+//
+//  TLAssetsCollection.swift
+//  TLPhotosPicker
+//
+//  Created by wade.hawk on 2017. 4. 18..
+//  Copyright © 2017년 wade.hawk. All rights reserved.
+//
+
+import Foundation
+import Photos
+import PhotosUI
+import MobileCoreServices
+
+public struct TLPHAsset {
+    enum CloudDownloadState {
+        case ready, progress, complete, failed
+    }
+    
+    public enum AssetType {
+        case photo, video, livePhoto
+    }
+    
+    public enum ImageExtType: String {
+        case png, jpg, gif, heic
+    }
+    
+    var state = CloudDownloadState.ready
+    public var phAsset: PHAsset? = nil
+    //Bool to check if TLPHAsset returned is created using camera.
+    public var isSelectedFromCamera = false
+    public var selectedOrder: Int = 0
+    public var type: AssetType {
+        get {
+            guard let phAsset = self.phAsset else { return .photo }
+            if phAsset.mediaSubtypes.contains(.photoLive) {
+                return .livePhoto
+            }else if phAsset.mediaType == .video {
+                return .video
+            }else {
+                return .photo
+            }
+        }
+    }
+    
+    public var fullResolutionImage: UIImage? {
+        get {
+            guard let phAsset = self.phAsset else { return nil }
+            return TLPhotoLibrary.fullResolutionImageData(asset: phAsset)
+        }
+    }
+    
+    public func extType() -> ImageExtType {
+        var ext = ImageExtType.png
+        if let fileName = self.originalFileName, let extention = URL(string: fileName)?.pathExtension.lowercased() {
+            ext = ImageExtType(rawValue: extention) ?? .png
+        }
+        return ext
+    }
+    
+    @discardableResult
+    public func cloudImageDownload(progressBlock: @escaping (Double) -> Void, completionBlock:@escaping (UIImage?)-> Void ) -> PHImageRequestID? {
+        guard let phAsset = self.phAsset else { return nil }
+        return TLPhotoLibrary.cloudImageDownload(asset: phAsset, progressBlock: progressBlock, completionBlock: completionBlock)
+    }
+    
+    public var originalFileName: String? {
+        get {
+            guard let phAsset = self.phAsset,let resource = PHAssetResource.assetResources(for: phAsset).first else { return nil }
+            return resource.originalFilename
+        }
+    }
+    
+    public func photoSize(options: PHImageRequestOptions? = nil ,completion: @escaping ((Int)->Void), livePhotoVideoSize: Bool = false) {
+        guard let phAsset = self.phAsset, self.type == .photo else { completion(-1); return }
+        var resource: PHAssetResource? = nil
+        if phAsset.mediaSubtypes.contains(.photoLive) == true, livePhotoVideoSize {
+            resource = PHAssetResource.assetResources(for: phAsset).filter { $0.type == .pairedVideo }.first
+        }else {
+            resource = PHAssetResource.assetResources(for: phAsset).filter { $0.type == .photo }.first
+        }
+        if let fileSize = resource?.value(forKey: "fileSize") as? Int {
+            completion(fileSize)
+        }else {
+            PHImageManager.default().requestImageData(for: phAsset, options: nil) { (data, uti, orientation, info) in
+                var fileSize = -1
+                if let data = data {
+                    let bcf = ByteCountFormatter()
+                    bcf.countStyle = .file
+                    fileSize = data.count
+                }
+                DispatchQueue.main.async {
+                    completion(fileSize)
+                }
+            }
+        }
+    }
+    
+    public func videoSize(options: PHVideoRequestOptions? = nil, completion: @escaping ((Int)->Void)) {
+        guard let phAsset = self.phAsset, self.type == .video else {  completion(-1); return }
+        let resource = PHAssetResource.assetResources(for: phAsset).filter { $0.type == .video }.first
+        if let fileSize = resource?.value(forKey: "fileSize") as? Int {
+            completion(fileSize)
+        }else {
+            PHImageManager.default().requestAVAsset(forVideo: phAsset, options: options) { (avasset, audioMix, info) in
+                func fileSize(_ url: URL?) -> Int? {
+                    do {
+                        guard let fileSize = try url?.resourceValues(forKeys: [.fileSizeKey]).fileSize else { return nil }
+                        return fileSize
+                    }catch { return nil }
+                }
+                var url: URL? = nil
+                if let urlAsset = avasset as? AVURLAsset {
+                    url = urlAsset.url
+                }else if let sandboxKeys = info?["PHImageFileSandboxExtensionTokenKey"] as? String, let path = sandboxKeys.components(separatedBy: ";").last {
+                    url = URL(fileURLWithPath: path)
+                }
+                let size = fileSize(url) ?? -1
+                DispatchQueue.main.async {
+                    completion(size)
+                }
+            }
+        }
+    }
+    
+    func MIMEType(_ url: URL?) -> String? {
+        guard let ext = url?.pathExtension else { return nil }
+        if !ext.isEmpty {
+            let UTIRef = UTTypeCreatePreferredIdentifierForTag("public.filename-extension" as CFString, ext as CFString, nil)
+            let UTI = UTIRef?.takeUnretainedValue()
+            UTIRef?.release()
+            if let UTI = UTI {
+                guard let MIMETypeRef = UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType) else { return nil }
+                let MIMEType = MIMETypeRef.takeUnretainedValue()
+                MIMETypeRef.release()
+                return MIMEType as String
+            }
+        }
+        return nil
+    }
+    
+    @discardableResult
+    //convertLivePhotosToJPG
+    // false : If you want mov file at live photos
+    // true  : If you want png file at live photos ( HEIC )
+    public func tempCopyMediaFile(videoRequestOptions: PHVideoRequestOptions? = nil, imageRequestOptions: PHImageRequestOptions? = nil, exportPreset: String = AVAssetExportPresetHighestQuality, convertLivePhotosToJPG: Bool = false, progressBlock:((Double) -> Void)? = nil, completionBlock:@escaping ((URL,String) -> Void)) -> PHImageRequestID? {
+        guard let phAsset = self.phAsset else { return nil }
+        var type: PHAssetResourceType? = nil
+        if phAsset.mediaSubtypes.contains(.photoLive) == true, convertLivePhotosToJPG == false {
+            type = .pairedVideo
+        }else {
+            type = phAsset.mediaType == .video ? .video : .photo
+        }
+        guard let resource = (PHAssetResource.assetResources(for: phAsset).filter{ $0.type == type }).first else { return nil }
+        let fileName = resource.originalFilename
+        var writeURL: URL? = nil
+        if #available(iOS 10.0, *) {
+            writeURL = FileManager.default.temporaryDirectory.appendingPathComponent("\(fileName)")
+        } else {
+            writeURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent("\(fileName)")
+        }
+        if (writeURL?.pathExtension.uppercased() == "HEIC" || writeURL?.pathExtension.uppercased() == "HEIF") && convertLivePhotosToJPG {
+            if let fileName2 = writeURL?.deletingPathExtension().lastPathComponent {
+                writeURL?.deleteLastPathComponent()
+                writeURL?.appendPathComponent("\(fileName2).jpg")
+            }
+        }
+        guard let localURL = writeURL,let mimetype = MIMEType(writeURL) else { return nil }
+        switch phAsset.mediaType {
+        case .video:
+            var requestOptions = PHVideoRequestOptions()
+            if let options = videoRequestOptions {
+                requestOptions = options
+            }else {
+                requestOptions.isNetworkAccessAllowed = true
+            }
+            //iCloud download progress
+            requestOptions.progressHandler = { (progress, error, stop, info) in
+                DispatchQueue.main.async {
+                    progressBlock?(progress)
+                }
+            }
+            return PHImageManager.default().requestExportSession(forVideo: phAsset, options: requestOptions, exportPreset: exportPreset) { (session, infoDict) in
+                session?.outputURL = localURL
+                session?.outputFileType = AVFileType.mov
+                session?.exportAsynchronously(completionHandler: {
+                    DispatchQueue.main.async {
+                        completionBlock(localURL, mimetype)
+                    }
+                })
+            }
+        case .image:
+            var requestOptions = PHImageRequestOptions()
+            if let options = imageRequestOptions {
+                requestOptions = options
+            }else {
+                requestOptions.isNetworkAccessAllowed = true
+            }
+            //iCloud download progress
+            requestOptions.progressHandler = { (progress, error, stop, info) in
+                DispatchQueue.main.async {
+                    progressBlock?(progress)
+                }
+            }
+            return PHImageManager.default().requestImageData(for: phAsset, options: requestOptions, resultHandler: { (data, uti, orientation, info) in
+                do {
+                    var data = data
+                    let needConvertLivePhotoToJPG = phAsset.mediaSubtypes.contains(.photoLive) == true && convertLivePhotosToJPG == true
+                    if needConvertLivePhotoToJPG, let imgData = data, let rawImage = UIImage(data: imgData)?.upOrientationImage() {
+                        data = rawImage.jpegData(compressionQuality: 1)
+                    }
+                    try data?.write(to: localURL)
+                    DispatchQueue.main.async {
+                        completionBlock(localURL, mimetype)
+                    }
+                }catch { }
+            })
+        default:
+            return nil
+        }
+    }
+    
+    private func videoFilename(phAsset: PHAsset) -> URL? {
+        guard let resource = (PHAssetResource.assetResources(for: phAsset).filter{ $0.type == .video }).first else {
+            return nil
+        }
+        var writeURL: URL?
+        let fileName = resource.originalFilename
+        if #available(iOS 10.0, *) {
+            writeURL = FileManager.default.temporaryDirectory.appendingPathComponent("\(fileName)")
+        } else {
+            writeURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent("\(fileName)")
+        }
+        return writeURL
+    }
+    
+    //Apparently, This is not the only way to export video.
+    //There is many way that export a video.
+    //This method was one of them.
+    public func exportVideoFile(options: PHVideoRequestOptions? = nil,
+                                outputURL: URL? = nil,
+                                outputFileType: AVFileType = .mov,
+                                progressBlock:((Double) -> Void)? = nil,
+                                completionBlock:@escaping ((URL,String) -> Void)) {
+        guard
+            let phAsset = self.phAsset,
+            phAsset.mediaType == .video,
+            let writeURL = outputURL ?? videoFilename(phAsset: phAsset),
+            let mimetype = MIMEType(writeURL)
+            else {
+                return
+        }
+        var requestOptions = PHVideoRequestOptions()
+        if let options = options {
+            requestOptions = options
+        }else {
+            requestOptions.isNetworkAccessAllowed = true
+        }
+        requestOptions.progressHandler = { (progress, error, stop, info) in
+            DispatchQueue.main.async {
+                progressBlock?(progress)
+            }
+        }
+        PHImageManager.default().requestAVAsset(forVideo: phAsset, options: requestOptions) { (avasset, avaudioMix, infoDict) in
+            guard let avasset = avasset else {
+                return
+            }
+            let exportSession = AVAssetExportSession.init(asset: avasset, presetName: AVAssetExportPresetHighestQuality)
+            exportSession?.outputURL = writeURL
+            exportSession?.outputFileType = outputFileType
+            exportSession?.exportAsynchronously(completionHandler: {
+                completionBlock(writeURL, mimetype)
+            })
+        }
+    }
+    
+    init(asset: PHAsset?) {
+        self.phAsset = asset
+    }
+
+    public static func asset(with localIdentifier: String) -> TLPHAsset? {
+        let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [localIdentifier], options: nil)
+        return TLPHAsset(asset: fetchResult.firstObject)
+    }
+}
+
+extension TLPHAsset: Equatable {
+    public static func ==(lhs: TLPHAsset, rhs: TLPHAsset) -> Bool {
+        guard let lphAsset = lhs.phAsset, let rphAsset = rhs.phAsset else { return false }
+        return lphAsset.localIdentifier == rphAsset.localIdentifier
+    }
+}
+
+extension Array {
+    subscript (safe index: Int) -> Element? {
+        return indices ~= index ? self[index] : nil
+    }
+}
+
+public struct TLAssetsCollection {
+    var phAssetCollection: PHAssetCollection? = nil
+    var fetchResult: PHFetchResult<PHAsset>? = nil
+    var useCameraButton: Bool = false
+    var recentPosition: CGPoint = CGPoint.zero
+    var title: String
+    var localIdentifier: String
+    public var sections: [(title: String, assets: [TLPHAsset])]? = nil
+    var count: Int {
+        get {
+            guard let count = self.fetchResult?.count, count > 0 else { return self.useCameraButton ? 1 : 0 }
+            return count + (self.useCameraButton ? 1 : 0)
+        }
+    }
+    
+    init(collection: PHAssetCollection) {
+        self.phAssetCollection = collection
+        self.title = collection.localizedTitle ?? ""
+        self.localIdentifier = collection.localIdentifier
+    }
+    
+    func getAsset(at index: Int) -> PHAsset? {
+        if self.useCameraButton && index == 0 { return nil }
+        let index = index - (self.useCameraButton ? 1 : 0)
+        guard let result = self.fetchResult, index < result.count else { return nil }
+        return result.object(at: max(index,0))
+    }
+    
+    func getTLAsset(at indexPath: IndexPath) -> TLPHAsset? {
+        let isCameraRow = self.useCameraButton && indexPath.section == 0 && indexPath.row == 0
+        if isCameraRow {
+            return nil
+        }
+        if let sections = self.sections {
+            let index = indexPath.row - ((self.useCameraButton && indexPath.section == 0) ? 1 : 0)
+            let result = sections[safe: indexPath.section]
+            return result?.assets[safe: index]
+        }else {
+            var index = indexPath.row
+            index = index - (self.useCameraButton ? 1 : 0)
+            guard let result = self.fetchResult, index < result.count else { return nil }
+            return TLPHAsset(asset: result.object(at: max(index,0)))
+        }
+    }
+    
+    mutating func reloadSection(groupedBy: PHFetchedResultGroupedBy) {
+        var groupedSections = self.section(groupedBy: groupedBy)
+        if self.useCameraButton {
+            groupedSections.insert(("camera",[TLPHAsset(asset: nil)]), at: 0)
+        }
+        self.sections = groupedSections
+    }
+    
+    static func ==(lhs: TLAssetsCollection, rhs: TLAssetsCollection) -> Bool {
+        return lhs.localIdentifier == rhs.localIdentifier
+    }
+}
+
+extension UIImage {
+    func upOrientationImage() -> UIImage? {
+        switch imageOrientation {
+        case .up:
+            return self
+        default:
+            UIGraphicsBeginImageContextWithOptions(size, false, scale)
+            draw(in: CGRect(origin: .zero, size: size))
+            let result = UIGraphicsGetImageFromCurrentImageContext()
+            UIGraphicsEndImageContext()
+            return result
+        }
+    }
+}

+ 29 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLBundle.swift

@@ -0,0 +1,29 @@
+//
+//  TLBundle.swift
+//  Pods
+//
+//  Created by wade.hawk on 2017. 5. 9..
+//
+//
+
+import Foundation
+
+open class TLBundle {
+    open class func podBundleImage(named: String) -> UIImage? {
+        let podBundle = Bundle(for: TLBundle.self)
+        if let url = podBundle.url(forResource: "TLPhotoPickerController", withExtension: "bundle") {
+            let bundle = Bundle(url: url)
+            return UIImage(named: named, in: bundle, compatibleWith: nil)!
+        }
+        return nil
+    }
+    
+    class func bundle() -> Bundle {
+        let podBundle = Bundle(for: TLBundle.self)
+        if let url = podBundle.url(forResource: "TLPhotoPicker", withExtension: "bundle") {
+            let bundle = Bundle(url: url)
+            return bundle ?? podBundle
+        }
+        return podBundle
+    }
+}

+ 22 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLCollectionTableViewCell.swift

@@ -0,0 +1,22 @@
+//
+//  TLCollectionTableViewCell.swift
+//  TLPhotosPicker
+//
+//  Created by wade.hawk on 2017. 5. 3..
+//  Copyright © 2017년 wade.hawk. All rights reserved.
+//
+
+import UIKit
+
+open class TLCollectionTableViewCell: UITableViewCell {
+    @IBOutlet open var thumbImageView: UIImageView!
+    @IBOutlet open var titleLabel: UILabel!
+    @IBOutlet open var subTitleLabel: UILabel!
+    
+    override open func awakeFromNib() {
+        super.awakeFromNib()   
+        if #available(iOS 11.0, *) {
+            self.thumbImageView.accessibilityIgnoresInvertColors = true
+        }
+    }
+}

+ 179 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLPhotoCollectionViewCell.swift

@@ -0,0 +1,179 @@
+//
+//  TLPhotoCollectionViewCell.swift
+//  TLPhotosPicker
+//
+//  Created by wade.hawk on 2017. 5. 3..
+//  Copyright © 2017년 wade.hawk. All rights reserved.
+//
+
+import UIKit
+import PhotosUI
+
+open class TLPlayerView: UIView {
+    @objc open var player: AVPlayer? {
+        get {
+            return playerLayer.player
+        }
+        set {
+            playerLayer.player = newValue
+        }
+    }
+    
+    @objc open var playerLayer: AVPlayerLayer {
+        return layer as! AVPlayerLayer
+    }
+    
+    // Override UIView property
+    override open class var layerClass: AnyClass {
+        return AVPlayerLayer.self
+    }
+}
+
+open class TLPhotoCollectionViewCell: UICollectionViewCell {
+    private var observer: NSObjectProtocol?
+    @IBOutlet open var imageView: UIImageView?
+    @IBOutlet open var playerView: TLPlayerView?
+    @IBOutlet open var livePhotoView: PHLivePhotoView?
+    @IBOutlet open var liveBadgeImageView: UIImageView?
+    @IBOutlet open var durationView: UIView?
+    @IBOutlet open var videoIconImageView: UIImageView?
+    @IBOutlet open var durationLabel: UILabel?
+    @IBOutlet open var indicator: UIActivityIndicatorView?
+    @IBOutlet open var selectedView: UIView?
+    @IBOutlet open var selectedHeight: NSLayoutConstraint?
+    @IBOutlet open var orderLabel: UILabel?
+    @IBOutlet open var orderBgView: UIView?
+    
+    var configure = TLPhotosPickerConfigure() {
+        didSet {
+            self.selectedView?.layer.borderColor = self.configure.selectedColor.cgColor
+            self.orderBgView?.backgroundColor = self.configure.selectedColor
+            self.videoIconImageView?.image = self.configure.videoIcon
+        }
+    }
+    
+    @objc open var isCameraCell = false
+    
+    open var duration: TimeInterval? {
+        didSet {
+            guard let duration = self.duration else { return }
+            self.selectedHeight?.constant = -10
+            self.durationLabel?.text = timeFormatted(timeInterval: duration)
+        }
+    }
+    
+    @objc open var player: AVPlayer? = nil {
+        didSet {
+            if self.configure.autoPlay == false { return }
+            if self.player == nil {
+                self.playerView?.playerLayer.player = nil
+                if let observer = self.observer {
+                    NotificationCenter.default.removeObserver(observer)
+                }
+            }else {
+                self.playerView?.playerLayer.player = self.player
+                self.observer = NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem, queue: nil, using: { [weak self] (_) in
+                    DispatchQueue.main.async {
+                        guard let `self` = self else { return }
+                        self.player?.seek(to: CMTime.zero)
+                        self.player?.play()
+                        self.player?.isMuted = self.configure.muteAudio
+                    }
+                })
+            }
+        }
+    }
+    
+    @objc open var selectedAsset: Bool = false {
+        willSet(newValue) {
+            self.selectedView?.isHidden = !newValue
+            self.durationView?.backgroundColor = newValue ? self.configure.selectedColor : UIColor(red: 0, green: 0, blue: 0, alpha: 0.6)
+            if !newValue {
+                self.orderLabel?.text = ""
+            }
+        }
+    }
+    
+    @objc open func timeFormatted(timeInterval: TimeInterval) -> String {
+        let seconds: Int = lround(timeInterval)
+        var hour: Int = 0
+        var minute: Int = Int(seconds/60)
+        let second: Int = seconds % 60
+        if minute > 59 {
+            hour = minute / 60
+            minute = minute % 60
+            return String(format: "%d:%d:%02d", hour, minute, second)
+        } else {
+            return String(format: "%d:%02d", minute, second)
+        }
+    }
+    
+    @objc open func popScaleAnim() {
+        UIView.animate(withDuration: 0.1, animations: {
+            self.transform = CGAffineTransform(scaleX: 1.05, y: 1.05)
+        }) { _ in
+            UIView.animate(withDuration: 0.1, animations: {
+                self.transform = CGAffineTransform(scaleX: 1, y: 1)
+            })
+        }
+    }
+    
+    @objc open func update(with phAsset: PHAsset) {
+        
+    }
+    
+    @objc open func selectedCell() {
+        
+    }
+    
+    @objc open func willDisplayCell() {
+        
+    }
+    
+    @objc open func endDisplayingCell() {
+        
+    }
+    
+    @objc func stopPlay() {
+        if let player = self.player {
+            player.pause()
+            self.player = nil
+        }
+        self.livePhotoView?.isHidden = true
+        self.livePhotoView?.stopPlayback()
+        self.livePhotoView?.delegate = nil
+    }
+    
+    deinit {
+//        print("deinit TLPhotoCollectionViewCell")
+    }
+    
+    override open func awakeFromNib() {
+        super.awakeFromNib()
+        self.playerView?.playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
+        self.livePhotoView?.isHidden = true
+        self.durationView?.isHidden = true
+        self.selectedView?.isHidden = true
+        self.selectedView?.layer.borderWidth = 10
+        self.selectedView?.layer.cornerRadius = 15
+        self.orderBgView?.layer.cornerRadius = 2
+        self.videoIconImageView?.image = self.configure.videoIcon
+        if #available(iOS 11.0, *) {
+            self.imageView?.accessibilityIgnoresInvertColors = true
+            self.playerView?.accessibilityIgnoresInvertColors = true
+            self.livePhotoView?.accessibilityIgnoresInvertColors = true
+            self.videoIconImageView?.accessibilityIgnoresInvertColors = true
+        }
+    }
+    
+    override open func prepareForReuse() {
+        super.prepareForReuse()
+        stopPlay()
+        self.livePhotoView?.isHidden = true
+        self.livePhotoView?.delegate = nil
+        self.durationView?.isHidden = true
+        self.durationView?.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.6)
+        self.selectedHeight?.constant = 10
+        self.selectedAsset = false
+    }
+}

+ 274 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLPhotoLibrary.swift

@@ -0,0 +1,274 @@
+//
+//  TLPhotoLibrary.swift
+//  TLPhotosPicker
+//
+//  Created by wade.hawk on 2017. 5. 3..
+//  Copyright © 2017년 wade.hawk. All rights reserved.
+//
+
+import Foundation
+import Photos
+
+protocol TLPhotoLibraryDelegate: class {
+    func loadCameraRollCollection(collection: TLAssetsCollection)
+    func loadCompleteAllCollection(collections: [TLAssetsCollection])
+}
+
+class TLPhotoLibrary {
+    
+    weak var delegate: TLPhotoLibraryDelegate? = nil
+    
+    lazy var imageManager: PHCachingImageManager = {
+        return PHCachingImageManager()
+    }()
+    
+    deinit {
+        NXLLog("deinit TLPhotoLibrary")
+    }
+    
+    @discardableResult
+    func livePhotoAsset(asset: PHAsset, size: CGSize = CGSize(width: 720, height: 1280), progressBlock: Photos.PHAssetImageProgressHandler? = nil, completionBlock:@escaping (PHLivePhoto,Bool)-> Void ) -> PHImageRequestID {
+        let options = PHLivePhotoRequestOptions()
+        options.deliveryMode = .opportunistic
+        options.isNetworkAccessAllowed = true
+        options.progressHandler = progressBlock
+        let scale = min(UIScreen.main.scale,2)
+        let targetSize = CGSize(width: size.width*scale, height: size.height*scale)
+        let requestID = self.imageManager.requestLivePhoto(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: options) { (livePhoto, info) in
+            let complete = (info?["PHImageResultIsDegradedKey"] as? Bool) == false
+            if let livePhoto = livePhoto {
+                completionBlock(livePhoto,complete)
+            }
+        }
+        return requestID
+    }
+    
+    @discardableResult
+    func videoAsset(asset: PHAsset, size: CGSize = CGSize(width: 720, height: 1280), progressBlock: Photos.PHAssetImageProgressHandler? = nil, completionBlock:@escaping (AVPlayerItem?, [AnyHashable : Any]?) -> Void ) -> PHImageRequestID {
+        let options = PHVideoRequestOptions()
+        options.isNetworkAccessAllowed = true
+        options.deliveryMode = .automatic
+        options.progressHandler = progressBlock
+        let requestID = self.imageManager.requestPlayerItem(forVideo: asset, options: options, resultHandler: { playerItem, info in
+            completionBlock(playerItem,info)
+        })
+        return requestID
+    }
+    
+    @discardableResult
+    func imageAsset(asset: PHAsset, size: CGSize = CGSize(width: 160, height: 160), options: PHImageRequestOptions? = nil, completionBlock:@escaping (UIImage,Bool)-> Void ) -> PHImageRequestID {
+        var options = options
+        if options == nil {
+            options = PHImageRequestOptions()
+            options?.isSynchronous = false
+            options?.resizeMode = .exact
+            options?.deliveryMode = .opportunistic
+            options?.isNetworkAccessAllowed = true
+        }
+        let scale = min(UIScreen.main.scale,2)
+        let targetSize = CGSize(width: size.width*scale, height: size.height*scale)
+        let requestID = self.imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: options) { image, info in
+            let complete = (info?["PHImageResultIsDegradedKey"] as? Bool) == false
+            if let image = image {
+                completionBlock(image,complete)
+            }
+        }
+        return requestID
+    }
+    
+    func cancelPHImageRequest(requestID: PHImageRequestID) {
+        self.imageManager.cancelImageRequest(requestID)
+    }
+    
+    @discardableResult
+    class func cloudImageDownload(asset: PHAsset, size: CGSize = PHImageManagerMaximumSize, progressBlock: @escaping (Double) -> Void, completionBlock:@escaping (UIImage?)-> Void ) -> PHImageRequestID {
+        let options = PHImageRequestOptions()
+        options.isSynchronous = false
+        options.isNetworkAccessAllowed = true
+        options.deliveryMode = .opportunistic
+        options.version = .current
+        options.resizeMode = .exact
+        options.progressHandler = { (progress,error,stop,info) in
+            progressBlock(progress)
+        }
+        let requestID = PHCachingImageManager().requestImageData(for: asset, options: options) { (imageData, dataUTI, orientation, info) in
+            if let data = imageData,let _ = info {
+                completionBlock(UIImage(data: data))
+            }else{
+                completionBlock(nil)//error
+            }
+        }
+        return requestID
+    }
+    
+    @discardableResult
+    class func fullResolutionImageData(asset: PHAsset) -> UIImage? {
+        let options = PHImageRequestOptions()
+        options.isSynchronous = true
+        options.resizeMode = .none
+        options.isNetworkAccessAllowed = false
+        options.version = .current
+        var image: UIImage? = nil
+        _ = PHCachingImageManager().requestImageData(for: asset, options: options) { (imageData, dataUTI, orientation, info) in
+            if let data = imageData {
+                image = UIImage(data: data)
+            }
+        }
+        return image
+    }
+}
+
+extension PHFetchOptions {
+    func merge(predicate: NSPredicate) {
+        if let storePredicate = self.predicate {
+            self.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [storePredicate, predicate])
+        }else {
+            self.predicate = predicate
+        }
+    }
+}
+
+//MARK: - Load Collection
+extension TLPhotoLibrary {
+    func getOption(configure: TLPhotosPickerConfigure) -> PHFetchOptions {
+        
+        let options = configure.fetchOption ?? PHFetchOptions()
+        options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
+        if let mediaType = configure.mediaType {
+            let mediaPredicate = NSPredicate(format: "mediaType = %i", mediaType.rawValue)
+            options.merge(predicate: mediaPredicate)
+        }
+        if configure.allowedVideo == false {
+            let notVideoPredicate = NSPredicate(format: "mediaType != %i", PHAssetMediaType.video.rawValue)
+            options.merge(predicate: notVideoPredicate)
+        }
+        if configure.allowedLivePhotos == false {
+            let notLivePhotoPredicate = NSPredicate(format: "NOT ((mediaSubtype & %d) != 0)", PHAssetMediaSubtype.photoLive.rawValue)
+            options.merge(predicate: notLivePhotoPredicate)
+        }
+        if let maxVideoDuration = configure.maxVideoDuration {
+            let durationPredicate = NSPredicate(format: "duration < %f", maxVideoDuration)
+            options.merge(predicate: durationPredicate)
+        }
+        return options
+    }
+    
+    func fetchResult(collection: TLAssetsCollection?, configure: TLPhotosPickerConfigure) -> PHFetchResult<PHAsset>? {
+        guard let phAssetCollection = collection?.phAssetCollection else { return nil }
+        let options = getOption(configure: configure)
+        return PHAsset.fetchAssets(in: phAssetCollection, options: options)
+    }
+    
+    func fetchCollection(configure: TLPhotosPickerConfigure) {
+        let useCameraButton = configure.usedCameraButton
+        let options = getOption(configure: configure)
+        let fetchCollectionOption = configure.fetchCollectionOption
+        
+        func getAlbum(subType: PHAssetCollectionSubtype, result: inout [TLAssetsCollection]) {
+            let collectionOption = fetchCollectionOption[.assetCollections(.album)]
+            let fetchCollection = PHAssetCollection.fetchAssetCollections(with: .album,
+                                                                          subtype: subType,
+                                                                          options: collectionOption)
+            var collections = [PHAssetCollection]()
+            fetchCollection.enumerateObjects { (collection, index, _) in 
+                if configure.allowedAlbumCloudShared == false && collection.assetCollectionSubtype == .albumCloudShared {
+                }else {
+                    collections.append(collection)
+                }
+            }
+            for collection in collections {
+                if !result.contains(where: { $0.localIdentifier == collection.localIdentifier }) {
+                    var assetsCollection = TLAssetsCollection(collection: collection)
+                    assetsCollection.fetchResult = PHAsset.fetchAssets(in: collection, options: options)
+                    if assetsCollection.count > 0 {
+                        result.append(assetsCollection)
+                    }
+                }
+            }
+        }
+        
+        @discardableResult
+        func getSmartAlbum(subType: PHAssetCollectionSubtype,
+                           useCameraButton: Bool = false,
+                           result: inout [TLAssetsCollection])
+            -> TLAssetsCollection?
+        {
+            let collectionOption = fetchCollectionOption[.assetCollections(.smartAlbum)]
+            let fetchCollection = PHAssetCollection.fetchAssetCollections(with: .smartAlbum,
+                                                                          subtype: subType,
+                                                                          options: collectionOption)
+            if
+                let collection = fetchCollection.firstObject,
+                result.contains(where: { $0.localIdentifier == collection.localIdentifier }) == false
+            {
+                var assetsCollection = TLAssetsCollection(collection: collection)
+                assetsCollection.fetchResult = PHAsset.fetchAssets(in: collection, options: options)
+                if assetsCollection.count > 0 || useCameraButton {
+                    result.append(assetsCollection)
+                    return assetsCollection
+                }
+            }
+            return nil
+        }
+        if let fetchCollectionTypes = configure.fetchCollectionTypes {
+            DispatchQueue.global(qos: .userInteractive).async { [weak self] in
+                var assetCollections = [TLAssetsCollection]()
+                for (type,subType) in fetchCollectionTypes {
+                    if type == .smartAlbum {
+                        getSmartAlbum(subType: subType, result: &assetCollections)
+                    }else {
+                        getAlbum(subType: subType, result: &assetCollections)
+                    }
+                }
+                DispatchQueue.main.async {
+                    self?.delegate?.loadCompleteAllCollection(collections: assetCollections)
+                }
+            }
+        }else {
+            DispatchQueue.global(qos: .userInteractive).async { [weak self] in
+                var assetCollections = [TLAssetsCollection]()
+                //Camera Roll
+                let camerarollCollection = getSmartAlbum(subType: .smartAlbumUserLibrary,
+                                                         useCameraButton: useCameraButton,
+                                                         result: &assetCollections)
+                if var cameraRoll = camerarollCollection {
+                    cameraRoll.useCameraButton = useCameraButton
+                    assetCollections[0] = cameraRoll
+                    DispatchQueue.main.async {
+                        self?.delegate?.loadCameraRollCollection(collection: cameraRoll)
+                    }
+                }
+                //Selfies
+                getSmartAlbum(subType: .smartAlbumSelfPortraits, result: &assetCollections)
+                //Panoramas
+                getSmartAlbum(subType: .smartAlbumPanoramas, result: &assetCollections)
+                //Favorites
+                getSmartAlbum(subType: .smartAlbumFavorites, result: &assetCollections)
+                //CloudShared
+                getSmartAlbum(subType: .albumCloudShared, result: &assetCollections)
+                //get all another albums
+                getAlbum(subType: .any, result: &assetCollections)
+                if configure.allowedVideo {
+                    //Videos
+                    getSmartAlbum(subType: .smartAlbumVideos, result: &assetCollections)
+                }
+                //Album
+                let collectionOption = fetchCollectionOption[.topLevelUserCollections]
+                let albumsResult = PHCollectionList.fetchTopLevelUserCollections(with: collectionOption)
+                albumsResult.enumerateObjects({ (collection, index, stop) -> Void in
+                    guard let collection = collection as? PHAssetCollection else { return }
+                    var assetsCollection = TLAssetsCollection(collection: collection)
+                    assetsCollection.fetchResult = PHAsset.fetchAssets(in: collection, options: options)
+                    if assetsCollection.count > 0, !assetCollections.contains(where: { $0.localIdentifier == collection.localIdentifier }) {
+                        assetCollections.append(assetsCollection)
+                    }
+                })
+                
+                DispatchQueue.main.async {
+                    self?.delegate?.loadCompleteAllCollection(collections: assetCollections)
+                }
+            }
+        }
+    }
+}
+

+ 86 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLPhotoPickerManager.swift

@@ -0,0 +1,86 @@
+//
+//  TLPhotoPickerManager.swift
+//  RainbowPlanet
+//
+//  Created by 南鑫林 on 2019/8/23.
+//  Copyright © 2019 RainbowPlanet. All rights reserved.
+//
+
+import UIKit
+
+public protocol TLPhotosPickerViewControllerDelegate: class {
+    func dismissPhotoPicker(withPHAssets: [PHAsset])
+    func dismissPhotoPicker(withTLPHAssets: [TLPHAsset])
+    func dismissComplete()
+    func photoPickerDidCancel()
+    func canSelectAsset(phAsset: PHAsset) -> Bool
+    func didExceedMaximumNumberOfSelection(picker: TLPhotosPickerViewController)
+    func handleNoAlbumPermissions(picker: TLPhotosPickerViewController)
+    func handleNoCameraPermissions(picker: TLPhotosPickerViewController)
+}
+
+extension TLPhotosPickerViewControllerDelegate {
+    public func deninedAuthoization() { }
+    public func dismissPhotoPicker(withPHAssets: [PHAsset]) { }
+    public func dismissPhotoPicker(withTLPHAssets: [TLPHAsset]) { }
+    public func dismissComplete() { }
+    public func photoPickerDidCancel() { }
+    public func canSelectAsset(phAsset: PHAsset) -> Bool { return true }
+    public func didExceedMaximumNumberOfSelection(picker: TLPhotosPickerViewController) { }
+    public func handleNoAlbumPermissions(picker: TLPhotosPickerViewController) { }
+    public func handleNoCameraPermissions(picker: TLPhotosPickerViewController) { }
+}
+
+//for log
+public protocol TLPhotosPickerLogDelegate: class {
+    func selectedCameraCell(picker: TLPhotosPickerViewController)
+    func deselectedPhoto(picker: TLPhotosPickerViewController, at: Int)
+    func selectedPhoto(picker: TLPhotosPickerViewController, at: Int)
+    func selectedAlbum(picker: TLPhotosPickerViewController, title: String, at: Int)
+}
+
+extension TLPhotosPickerLogDelegate {
+    func selectedCameraCell(picker: TLPhotosPickerViewController) { }
+    func deselectedPhoto(picker: TLPhotosPickerViewController, at: Int) { }
+    func selectedPhoto(picker: TLPhotosPickerViewController, at: Int) { }
+    func selectedAlbum(picker: TLPhotosPickerViewController, collections: [TLAssetsCollection], at: Int) { }
+}
+
+public struct TLPhotosPickerConfigure {
+    public var defaultCameraRollTitle = "Camera Roll"
+    public var tapHereToChange = "Tap here to change"
+    public var cancelTitle = "Cancel"
+    public var doneTitle = "Done"
+    public var emptyMessage = "No albums"
+    public var emptyImage: UIImage? = nil
+    public var usedCameraButton = true
+    public var usedPrefetch = false
+    public var allowedLivePhotos = true
+    public var allowedVideo = true
+    public var allowedAlbumCloudShared = false
+    public var allowedVideoRecording = true
+    public var recordingVideoQuality: UIImagePickerController.QualityType = .typeMedium
+    public var maxVideoDuration:TimeInterval? = nil
+    public var autoPlay = true
+    public var muteAudio = true
+    public var mediaType: PHAssetMediaType? = nil
+    public var numberOfColumn = 3
+    public var singleSelectedMode = false
+    public var maxSelectedAssets: Int? = nil
+    public var fetchOption: PHFetchOptions? = nil
+    public var fetchCollectionOption: [FetchCollectionType: PHFetchOptions] = [:]
+    public var selectedColor = UIColor(red: 88/255, green: 144/255, blue: 255/255, alpha: 1.0)
+    public var cameraBgColor = UIColor(red: 221/255, green: 223/255, blue: 226/255, alpha: 1)
+    public var cameraIcon = TLBundle.podBundleImage(named: "camera")
+    public var videoIcon = TLBundle.podBundleImage(named: "video")
+    public var placeholderIcon = TLBundle.podBundleImage(named: "insertPhotoMaterial")
+    public var nibSet: (nibName: String, bundle:Bundle)? = nil
+    public var cameraCellNibSet: (nibName: String, bundle:Bundle)? = nil
+    public var fetchCollectionTypes: [(PHAssetCollectionType,PHAssetCollectionSubtype)]? = nil
+    public var groupByFetch: PHFetchedResultGroupedBy? = nil
+    public var supportedInterfaceOrientations: UIInterfaceOrientationMask = .portrait
+    public var popup: [PopupConfigure] = []
+    public init() {
+        
+    }
+}

+ 17 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLPhotopickerDataSourcesProtocol.swift

@@ -0,0 +1,17 @@
+//
+//  TLPhotopickerDataSourcesProtocol.swift
+//  TLPhotoPicker
+//
+//  Created by wade.hawk on 21/01/2019.
+//
+
+import Foundation
+import Photos
+
+public protocol TLPhotopickerDataSourcesProtocol {
+    func headerReferenceSize() -> CGSize
+    func footerReferenceSize() -> CGSize
+    func registerSupplementView(collectionView: UICollectionView)
+    func supplementIdentifier(kind: String) -> String
+    func configure(supplement view: UICollectionReusableView, section: (title: String, assets: [TLPHAsset]))
+}

File diff suppressed because it is too large
+ 1012 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPicker/TLPhotosPickerViewController.swift


+ 58 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPickerResources/TLCollectionTableViewCell.xib

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16E195" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
+        <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="TLCollectionTableViewCell" id="9FY-S1-KKQ" customClass="TLCollectionTableViewCell" customModule="TLPhotoPicker" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="75"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="9FY-S1-KKQ" id="UUZ-nI-xH1">
+                <rect key="frame" x="0.0" y="0.0" width="375" height="74.5"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4Dk-kD-sMy">
+                        <rect key="frame" x="5" y="12.5" width="50" height="50"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                    </imageView>
+                    <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="7nv-2U-xMp">
+                        <rect key="frame" x="69" y="19" width="248" height="36.5"/>
+                        <subviews>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Camera Roll" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ES8-Tq-6Wz">
+                                <rect key="frame" x="0.0" y="0.0" width="248" height="17"/>
+                                <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
+                                <nil key="textColor"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="9999" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="NuJ-3w-ZAP">
+                                <rect key="frame" x="0.0" y="22" width="248" height="14.5"/>
+                                <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                                <color key="textColor" red="0.43137254901960786" green="0.43137254901960786" blue="0.43137254901960786" alpha="1" colorSpace="calibratedRGB"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                        </subviews>
+                    </stackView>
+                </subviews>
+                <constraints>
+                    <constraint firstItem="7nv-2U-xMp" firstAttribute="centerY" secondItem="UUZ-nI-xH1" secondAttribute="centerY" id="E6U-ch-GDV"/>
+                    <constraint firstItem="7nv-2U-xMp" firstAttribute="leading" secondItem="UUZ-nI-xH1" secondAttribute="leadingMargin" constant="61" id="Jsu-Hd-Sg3"/>
+                    <constraint firstAttribute="trailingMargin" secondItem="7nv-2U-xMp" secondAttribute="trailing" constant="50" id="T3U-hj-718"/>
+                </constraints>
+            </tableViewCellContentView>
+            <connections>
+                <outlet property="subTitleLabel" destination="NuJ-3w-ZAP" id="vlD-VJ-e5z"/>
+                <outlet property="thumbImageView" destination="4Dk-kD-sMy" id="f8b-VP-j8s"/>
+                <outlet property="titleLabel" destination="ES8-Tq-6Wz" id="sYW-0b-o03"/>
+            </connections>
+            <point key="canvasLocation" x="9.5" y="-83"/>
+        </tableViewCell>
+    </objects>
+</document>

+ 144 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPickerResources/TLPhotoCollectionViewCell.xib

@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16E195" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="TLPhotoCollectionViewCell" id="IF3-4e-v0j" customClass="TLPhotoCollectionViewCell" customModule="TLPhotoPicker" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
+                <rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="0cR-fZ-1bW">
+                        <rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
+                    </imageView>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vfk-Ao-TKR" customClass="PHLivePhotoView">
+                        <rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                    </view>
+                    <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="TGh-wt-hcR">
+                        <rect key="frame" x="70" y="70" width="25" height="25"/>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="width" constant="25" id="NMA-SI-Idt"/>
+                            <constraint firstAttribute="height" constant="25" id="XvY-Ee-EA2"/>
+                        </constraints>
+                    </imageView>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="apl-2Q-Hz7" customClass="TLPlayerView" customModule="TLPhotoPicker" customModuleProvider="target">
+                        <rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                    </view>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="d1a-KW-Ta4">
+                        <rect key="frame" x="-5" y="-5" width="110" height="110"/>
+                        <subviews>
+                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hbA-dR-I09">
+                                <rect key="frame" x="75" y="5" width="30" height="30"/>
+                                <subviews>
+                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="1" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Weu-ef-IZ5">
+                                        <rect key="frame" x="1.5" y="8" width="25" height="16"/>
+                                        <constraints>
+                                            <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="25" id="YMX-0Z-bfm"/>
+                                        </constraints>
+                                        <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="13"/>
+                                        <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                        <nil key="highlightedColor"/>
+                                    </label>
+                                </subviews>
+                                <color key="backgroundColor" red="0.27843137254901962" green="0.47058823529411764" blue="0.85098039215686272" alpha="1" colorSpace="calibratedRGB"/>
+                                <constraints>
+                                    <constraint firstAttribute="height" constant="30" id="8ln-g5-eHL"/>
+                                    <constraint firstItem="Weu-ef-IZ5" firstAttribute="leading" secondItem="hbA-dR-I09" secondAttribute="leading" constant="1.5" id="Yw3-zp-UZQ"/>
+                                    <constraint firstAttribute="trailing" secondItem="Weu-ef-IZ5" secondAttribute="trailing" constant="3.5" id="jsL-aw-IED"/>
+                                    <constraint firstItem="Weu-ef-IZ5" firstAttribute="centerY" secondItem="hbA-dR-I09" secondAttribute="centerY" constant="1" id="nUh-b3-s9s"/>
+                                </constraints>
+                            </view>
+                        </subviews>
+                        <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" secondItem="hbA-dR-I09" secondAttribute="trailing" constant="5" id="hjj-HC-A4B"/>
+                            <constraint firstItem="hbA-dR-I09" firstAttribute="top" secondItem="d1a-KW-Ta4" secondAttribute="top" constant="5" id="xJ1-j7-RX7"/>
+                        </constraints>
+                    </view>
+                    <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aju-ob-KlZ">
+                        <rect key="frame" x="0.0" y="75" width="100" height="25"/>
+                        <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Uzf-HJ-aUY">
+                                <rect key="frame" x="5" y="2.5" width="20" height="20"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                            </imageView>
+                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0:02" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zNx-FC-5V2">
+                                <rect key="frame" x="30" y="0.0" width="65" height="25"/>
+                                <constraints>
+                                    <constraint firstAttribute="width" constant="65" id="3hi-82-ovQ"/>
+                                </constraints>
+                                <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                                <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                <nil key="highlightedColor"/>
+                            </label>
+                        </subviews>
+                        <color key="backgroundColor" red="0.11109734326601028" green="0.57953345775604248" blue="0.96568840742111206" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="25" id="DzP-0j-1SD"/>
+                            <constraint firstItem="zNx-FC-5V2" firstAttribute="top" secondItem="aju-ob-KlZ" secondAttribute="top" id="Lim-xf-cbx"/>
+                            <constraint firstAttribute="bottom" secondItem="zNx-FC-5V2" secondAttribute="bottom" id="T0P-EH-uPu"/>
+                            <constraint firstAttribute="trailing" secondItem="zNx-FC-5V2" secondAttribute="trailing" constant="5" id="uhl-Y8-3g5"/>
+                        </constraints>
+                    </view>
+                    <activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="DZc-ag-e55">
+                        <rect key="frame" x="40" y="40" width="20" height="20"/>
+                    </activityIndicatorView>
+                </subviews>
+            </view>
+            <constraints>
+                <constraint firstAttribute="bottom" secondItem="vfk-Ao-TKR" secondAttribute="bottom" id="2gw-cO-5bN"/>
+                <constraint firstAttribute="bottom" secondItem="aju-ob-KlZ" secondAttribute="bottom" id="2wo-Ki-15d"/>
+                <constraint firstAttribute="trailing" secondItem="aju-ob-KlZ" secondAttribute="trailing" id="2zm-kD-GPn"/>
+                <constraint firstAttribute="bottom" secondItem="apl-2Q-Hz7" secondAttribute="bottom" id="3zu-V3-EAd"/>
+                <constraint firstAttribute="trailing" secondItem="0cR-fZ-1bW" secondAttribute="trailing" id="9sd-Ea-EBO"/>
+                <constraint firstAttribute="trailing" secondItem="vfk-Ao-TKR" secondAttribute="trailing" id="BZ0-ZG-uW5"/>
+                <constraint firstAttribute="bottom" secondItem="TGh-wt-hcR" secondAttribute="bottom" constant="5" id="Ba1-Z6-ypz"/>
+                <constraint firstItem="0cR-fZ-1bW" firstAttribute="leading" secondItem="IF3-4e-v0j" secondAttribute="leading" id="DXe-M9-mxX"/>
+                <constraint firstItem="aju-ob-KlZ" firstAttribute="leading" secondItem="IF3-4e-v0j" secondAttribute="leading" id="FDl-UE-XVM"/>
+                <constraint firstItem="apl-2Q-Hz7" firstAttribute="top" secondItem="IF3-4e-v0j" secondAttribute="top" id="JlA-ya-cf3"/>
+                <constraint firstAttribute="trailing" secondItem="apl-2Q-Hz7" secondAttribute="trailing" id="KZg-oh-B11"/>
+                <constraint firstAttribute="trailing" secondItem="TGh-wt-hcR" secondAttribute="trailing" constant="5" id="Meo-q5-HyZ"/>
+                <constraint firstItem="vfk-Ao-TKR" firstAttribute="leading" secondItem="IF3-4e-v0j" secondAttribute="leading" id="NOQ-KU-fHD"/>
+                <constraint firstItem="vfk-Ao-TKR" firstAttribute="top" secondItem="IF3-4e-v0j" secondAttribute="top" id="NrV-wc-c3q"/>
+                <constraint firstItem="d1a-KW-Ta4" firstAttribute="height" secondItem="IF3-4e-v0j" secondAttribute="height" constant="10" id="VMJ-Qp-D4N"/>
+                <constraint firstItem="apl-2Q-Hz7" firstAttribute="leading" secondItem="IF3-4e-v0j" secondAttribute="leading" id="bsL-0J-0Y5"/>
+                <constraint firstItem="d1a-KW-Ta4" firstAttribute="width" secondItem="IF3-4e-v0j" secondAttribute="width" constant="10" id="clS-DI-jvL"/>
+                <constraint firstItem="d1a-KW-Ta4" firstAttribute="top" secondItem="IF3-4e-v0j" secondAttribute="top" constant="-5" id="d3r-HZ-6We"/>
+                <constraint firstItem="DZc-ag-e55" firstAttribute="centerX" secondItem="IF3-4e-v0j" secondAttribute="centerX" id="fnn-1c-fSn"/>
+                <constraint firstItem="DZc-ag-e55" firstAttribute="centerY" secondItem="IF3-4e-v0j" secondAttribute="centerY" id="qZc-2h-nOx"/>
+                <constraint firstItem="d1a-KW-Ta4" firstAttribute="leading" secondItem="IF3-4e-v0j" secondAttribute="leading" constant="-5" id="sOj-ms-Oo3"/>
+                <constraint firstItem="0cR-fZ-1bW" firstAttribute="top" secondItem="IF3-4e-v0j" secondAttribute="top" id="sSC-fd-MoT"/>
+                <constraint firstAttribute="bottom" secondItem="0cR-fZ-1bW" secondAttribute="bottom" id="xzA-tS-EVK"/>
+            </constraints>
+            <connections>
+                <outlet property="durationLabel" destination="zNx-FC-5V2" id="5SU-lD-AGm"/>
+                <outlet property="durationView" destination="aju-ob-KlZ" id="hiP-Ze-cbc"/>
+                <outlet property="imageView" destination="0cR-fZ-1bW" id="N3f-v5-K9b"/>
+                <outlet property="indicator" destination="DZc-ag-e55" id="R3y-XL-0SY"/>
+                <outlet property="liveBadgeImageView" destination="TGh-wt-hcR" id="cry-3P-rLI"/>
+                <outlet property="livePhotoView" destination="vfk-Ao-TKR" id="uvj-l1-wcp"/>
+                <outlet property="orderBgView" destination="hbA-dR-I09" id="cQo-BP-xh1"/>
+                <outlet property="orderLabel" destination="Weu-ef-IZ5" id="B3t-X5-o3a"/>
+                <outlet property="playerView" destination="apl-2Q-Hz7" id="vTI-ie-mcV"/>
+                <outlet property="selectedHeight" destination="VMJ-Qp-D4N" id="uVe-tQ-4q5"/>
+                <outlet property="selectedView" destination="d1a-KW-Ta4" id="c31-4y-72g"/>
+                <outlet property="videoIconImageView" destination="Uzf-HJ-aUY" id="d7e-Bl-181"/>
+            </connections>
+            <point key="canvasLocation" x="32" y="-10"/>
+        </collectionViewCell>
+    </objects>
+</document>

BIN
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPickerResources/TLPhotoPickerController.bundle/camera@3x.png


BIN
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPickerResources/TLPhotoPickerController.bundle/insertPhotoMaterial@3x.png


+ 221 - 0
RainbowPlanet/RainbowPlanet/Tools/PhotoPicker/TLPhotoPickerResources/TLPhotosPickerViewController.xib

@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="TLPhotosPickerViewController" customModule="TLPhotoPicker" customModuleProvider="target">
+            <connections>
+                <outlet property="albumPopView" destination="Jcn-hC-Umh" id="c3n-m9-wfd"/>
+                <outlet property="cancelButton" destination="sqJ-Z7-zxj" id="J6u-hz-ePK"/>
+                <outlet property="collectionView" destination="4gR-Bn-quP" id="ZOF-qU-cpd"/>
+                <outlet property="customNavItem" destination="5CU-MZ-p1K" id="ih7-d3-nco"/>
+                <outlet property="doneButton" destination="daA-Ag-vVv" id="P53-fy-Sbh"/>
+                <outlet property="emptyImageView" destination="YDZ-o1-AXT" id="TVN-0v-aQc"/>
+                <outlet property="emptyMessageLabel" destination="7qj-q4-rHC" id="Bcp-Hu-lEY"/>
+                <outlet property="emptyView" destination="HPm-Vc-F86" id="4FT-XL-9ql"/>
+                <outlet property="indicator" destination="AEv-G6-dRI" id="coA-3n-07e"/>
+                <outlet property="navigationBar" destination="X8O-Gg-slz" id="Sp9-g1-r4y"/>
+                <outlet property="navigationBarTopConstraint" destination="IKp-hS-tTy" id="MFH-eP-0tb"/>
+                <outlet property="popArrowImageView" destination="5zn-je-qLx" id="6k9-cH-vcU"/>
+                <outlet property="subTitleArrowImageView" destination="b7w-7R-rco" id="IjY-7S-Zz1"/>
+                <outlet property="subTitleLabel" destination="DON-iU-Cox" id="ZyB-O9-EcR"/>
+                <outlet property="subTitleStackView" destination="kgt-Cn-AXg" id="Vcc-hP-iqe"/>
+                <outlet property="titleLabel" destination="xuG-bc-Oq9" id="2o0-aN-au6"/>
+                <outlet property="titleView" destination="VAz-Py-dsa" id="deY-US-9Jh"/>
+                <outlet property="view" destination="Zyk-dI-msE" id="dxK-gh-unF"/>
+            </connections>
+        </placeholder>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="Zyk-dI-msE">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <subviews>
+                <navigationBar contentMode="scaleToFill" translucent="NO" translatesAutoresizingMaskIntoConstraints="NO" id="X8O-Gg-slz">
+                    <rect key="frame" x="0.0" y="20" width="375" height="44"/>
+                    <items>
+                        <navigationItem id="5CU-MZ-p1K">
+                            <nil key="title"/>
+                            <barButtonItem key="leftBarButtonItem" title="Cancel" id="sqJ-Z7-zxj">
+                                <connections>
+                                    <action selector="cancelButtonTap" destination="-1" id="dm0-Ur-I5r"/>
+                                </connections>
+                            </barButtonItem>
+                            <view key="titleView" contentMode="scaleToFill" id="VAz-Py-dsa">
+                                <rect key="frame" x="87.5" y="0.0" width="200" height="44"/>
+                                <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                                <subviews>
+                                    <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="Ql8-7f-9Uk">
+                                        <rect key="frame" x="0.0" y="0.0" width="200" height="44"/>
+                                        <subviews>
+                                            <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xuG-bc-Oq9">
+                                                <rect key="frame" x="79.5" y="0.0" width="41.5" height="19.5"/>
+                                                <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
+                                                <nil key="textColor"/>
+                                                <nil key="highlightedColor"/>
+                                            </label>
+                                            <stackView opaque="NO" contentMode="scaleToFill" alignment="center" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="kgt-Cn-AXg">
+                                                <rect key="frame" x="78" y="19.5" width="44.5" height="24.5"/>
+                                                <subviews>
+                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="DON-iU-Cox">
+                                                        <rect key="frame" x="0.0" y="5.5" width="29.5" height="13.5"/>
+                                                        <fontDescription key="fontDescription" type="system" weight="medium" pointSize="11"/>
+                                                        <nil key="textColor"/>
+                                                        <nil key="highlightedColor"/>
+                                                    </label>
+                                                    <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="b7w-7R-rco">
+                                                        <rect key="frame" x="34.5" y="7.5" width="10" height="10"/>
+                                                        <constraints>
+                                                            <constraint firstAttribute="width" priority="999" constant="10" id="7bM-Da-Q8A"/>
+                                                            <constraint firstAttribute="height" priority="999" constant="10" id="OHz-gp-CQp"/>
+                                                        </constraints>
+                                                    </imageView>
+                                                </subviews>
+                                            </stackView>
+                                        </subviews>
+                                    </stackView>
+                                </subviews>
+                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                                <constraints>
+                                    <constraint firstAttribute="trailing" secondItem="Ql8-7f-9Uk" secondAttribute="trailing" id="Vv5-au-j7y"/>
+                                    <constraint firstAttribute="bottom" secondItem="Ql8-7f-9Uk" secondAttribute="bottom" id="XNk-yU-iZJ"/>
+                                    <constraint firstItem="Ql8-7f-9Uk" firstAttribute="top" secondItem="VAz-Py-dsa" secondAttribute="top" id="h9o-f1-oRa"/>
+                                    <constraint firstItem="Ql8-7f-9Uk" firstAttribute="leading" secondItem="VAz-Py-dsa" secondAttribute="leading" id="j8K-5o-bAh"/>
+                                </constraints>
+                            </view>
+                            <barButtonItem key="rightBarButtonItem" title="Done" id="daA-Ag-vVv">
+                                <connections>
+                                    <action selector="doneButtonTap" destination="-1" id="BzF-rn-rn4"/>
+                                </connections>
+                            </barButtonItem>
+                        </navigationItem>
+                    </items>
+                </navigationBar>
+                <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="4gR-Bn-quP">
+                    <rect key="frame" x="0.0" y="64" width="375" height="603"/>
+                    <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                    <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="5" minimumInteritemSpacing="5" id="VDa-Pp-VBq">
+                        <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>
+                    <connections>
+                        <outlet property="dataSource" destination="-1" id="6fE-SF-z6F"/>
+                        <outlet property="delegate" destination="-1" id="pjZ-sM-fyY"/>
+                    </connections>
+                </collectionView>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HPm-Vc-F86">
+                    <rect key="frame" x="0.0" y="64" width="375" height="603"/>
+                    <subviews>
+                        <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="gi6-Sw-3Zf">
+                            <rect key="frame" x="137.5" y="239" width="100" height="125.5"/>
+                            <subviews>
+                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="YDZ-o1-AXT">
+                                    <rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
+                                    <constraints>
+                                        <constraint firstAttribute="width" priority="999" constant="100" id="VUj-VB-7Kr"/>
+                                        <constraint firstAttribute="height" priority="999" constant="100" id="jBo-WN-gZr"/>
+                                    </constraints>
+                                </imageView>
+                                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7qj-q4-rHC">
+                                    <rect key="frame" x="29" y="105" width="42" height="20.5"/>
+                                    <fontDescription key="fontDescription" type="system" pointSize="17"/>
+                                    <nil key="textColor"/>
+                                    <nil key="highlightedColor"/>
+                                </label>
+                            </subviews>
+                        </stackView>
+                    </subviews>
+                    <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstItem="gi6-Sw-3Zf" firstAttribute="centerX" secondItem="HPm-Vc-F86" secondAttribute="centerX" id="FpA-96-esN"/>
+                        <constraint firstItem="gi6-Sw-3Zf" firstAttribute="centerY" secondItem="HPm-Vc-F86" secondAttribute="centerY" id="L0c-BG-65l"/>
+                    </constraints>
+                </view>
+                <activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="AEv-G6-dRI">
+                    <rect key="frame" x="177" y="323" width="20" height="20"/>
+                </activityIndicatorView>
+                <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Jcn-hC-Umh" customClass="TLAlbumPopView" customModule="TLPhotoPicker" customModuleProvider="target">
+                    <rect key="frame" x="0.0" y="64" width="375" height="603"/>
+                    <subviews>
+                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="GKD-We-AdT">
+                            <rect key="frame" x="0.0" y="0.0" width="375" height="603"/>
+                            <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.29999999999999999" colorSpace="calibratedRGB"/>
+                        </view>
+                        <view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="eL2-gJ-b87">
+                            <rect key="frame" x="1" y="17" width="373" height="130"/>
+                            <subviews>
+                                <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" style="plain" separatorStyle="default" rowHeight="75" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="grw-Nk-Sxr">
+                                    <rect key="frame" x="10" y="0.0" width="363" height="130"/>
+                                    <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                </tableView>
+                            </subviews>
+                            <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                            <constraints>
+                                <constraint firstItem="grw-Nk-Sxr" firstAttribute="top" secondItem="eL2-gJ-b87" secondAttribute="top" id="DAx-an-6Qt"/>
+                                <constraint firstAttribute="height" constant="130" id="cet-yf-3jU"/>
+                                <constraint firstAttribute="trailing" secondItem="grw-Nk-Sxr" secondAttribute="trailing" id="nM5-IG-MPJ"/>
+                                <constraint firstItem="grw-Nk-Sxr" firstAttribute="leading" secondItem="eL2-gJ-b87" secondAttribute="leading" constant="10" id="o4b-cS-L3T"/>
+                                <constraint firstAttribute="bottom" secondItem="grw-Nk-Sxr" secondAttribute="bottom" id="sPK-1G-qLo"/>
+                            </constraints>
+                        </view>
+                        <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="5zn-je-qLx">
+                            <rect key="frame" x="180" y="10" width="14" height="7"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="7" id="eZN-nB-EHu"/>
+                                <constraint firstAttribute="width" constant="14" id="hWo-ji-iBX"/>
+                            </constraints>
+                        </imageView>
+                    </subviews>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
+                    <constraints>
+                        <constraint firstItem="GKD-We-AdT" firstAttribute="top" secondItem="Jcn-hC-Umh" secondAttribute="top" id="83h-bg-tAJ"/>
+                        <constraint firstAttribute="trailing" secondItem="eL2-gJ-b87" secondAttribute="trailing" constant="1" id="IMh-Wh-897"/>
+                        <constraint firstItem="5zn-je-qLx" firstAttribute="centerX" secondItem="Jcn-hC-Umh" secondAttribute="centerX" id="LpE-mT-MxA"/>
+                        <constraint firstItem="eL2-gJ-b87" firstAttribute="top" secondItem="Jcn-hC-Umh" secondAttribute="top" constant="17" id="XtI-9R-CFm"/>
+                        <constraint firstItem="GKD-We-AdT" firstAttribute="leading" secondItem="Jcn-hC-Umh" secondAttribute="leading" id="krq-3L-sxU"/>
+                        <constraint firstItem="eL2-gJ-b87" firstAttribute="top" secondItem="5zn-je-qLx" secondAttribute="bottom" id="tM4-Tb-JsI"/>
+                        <constraint firstItem="eL2-gJ-b87" firstAttribute="leading" secondItem="Jcn-hC-Umh" secondAttribute="leading" constant="1" id="v5O-lt-eKe"/>
+                        <constraint firstAttribute="bottom" secondItem="GKD-We-AdT" secondAttribute="bottom" id="x4Q-bm-MrY"/>
+                        <constraint firstAttribute="trailing" secondItem="GKD-We-AdT" secondAttribute="trailing" id="xdF-2b-pOS"/>
+                    </constraints>
+                    <connections>
+                        <outlet property="bgView" destination="GKD-We-AdT" id="ymr-tp-YBW"/>
+                        <outlet property="popupView" destination="eL2-gJ-b87" id="xgf-xj-Rd4"/>
+                        <outlet property="popupViewHeight" destination="cet-yf-3jU" id="OS3-MZ-s9c"/>
+                        <outlet property="tableView" destination="grw-Nk-Sxr" id="Y3k-8m-iJp"/>
+                    </connections>
+                </view>
+            </subviews>
+            <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <constraints>
+                <constraint firstItem="HPm-Vc-F86" firstAttribute="bottom" secondItem="HLR-WT-D3I" secondAttribute="bottom" id="0AS-35-SWm"/>
+                <constraint firstItem="AEv-G6-dRI" firstAttribute="centerX" secondItem="Zyk-dI-msE" secondAttribute="centerX" id="44C-fd-MVc"/>
+                <constraint firstItem="X8O-Gg-slz" firstAttribute="leading" secondItem="Zyk-dI-msE" secondAttribute="leading" id="4Ud-fp-qD2"/>
+                <constraint firstItem="4gR-Bn-quP" firstAttribute="top" secondItem="X8O-Gg-slz" secondAttribute="bottom" id="CZx-xl-GLa"/>
+                <constraint firstItem="X8O-Gg-slz" firstAttribute="top" secondItem="HLR-WT-D3I" secondAttribute="top" id="IKp-hS-tTy"/>
+                <constraint firstItem="Jcn-hC-Umh" firstAttribute="top" secondItem="X8O-Gg-slz" secondAttribute="bottom" id="KdD-nT-6tf"/>
+                <constraint firstItem="HPm-Vc-F86" firstAttribute="leading" secondItem="HLR-WT-D3I" secondAttribute="leading" id="M3L-CU-HdQ"/>
+                <constraint firstAttribute="trailing" secondItem="4gR-Bn-quP" secondAttribute="trailing" id="M6b-2G-2m1"/>
+                <constraint firstAttribute="trailing" secondItem="Jcn-hC-Umh" secondAttribute="trailing" id="Njh-ZO-lnq"/>
+                <constraint firstAttribute="bottom" secondItem="Jcn-hC-Umh" secondAttribute="bottom" id="NxH-d8-b65"/>
+                <constraint firstItem="HPm-Vc-F86" firstAttribute="top" secondItem="X8O-Gg-slz" secondAttribute="bottom" id="YyG-QW-0ZP"/>
+                <constraint firstItem="AEv-G6-dRI" firstAttribute="centerY" secondItem="Zyk-dI-msE" secondAttribute="centerY" id="aLU-u9-ALA"/>
+                <constraint firstItem="Jcn-hC-Umh" firstAttribute="leading" secondItem="Zyk-dI-msE" secondAttribute="leading" id="aY7-Ml-cd3"/>
+                <constraint firstItem="HPm-Vc-F86" firstAttribute="trailing" secondItem="HLR-WT-D3I" secondAttribute="trailing" id="aoA-8G-xDA"/>
+                <constraint firstItem="4gR-Bn-quP" firstAttribute="leading" secondItem="Zyk-dI-msE" secondAttribute="leading" id="kb7-vy-yTu"/>
+                <constraint firstItem="4gR-Bn-quP" firstAttribute="bottom" secondItem="HLR-WT-D3I" secondAttribute="bottom" id="qqE-w2-Tsc"/>
+                <constraint firstAttribute="trailing" secondItem="X8O-Gg-slz" secondAttribute="trailing" id="yWV-L2-0f4"/>
+            </constraints>
+            <viewLayoutGuide key="safeArea" id="HLR-WT-D3I"/>
+            <point key="canvasLocation" x="33.5" y="53.5"/>
+        </view>
+    </objects>
+</document>

+ 1 - 0
RainbowPlanet/RainbowPlanet/ViewModel/Community/CommunityFollowUserViewModel.swift

@@ -148,6 +148,7 @@ class CommunityFollowUserViewModel: NSObject {
             followButton.layer.borderColor = kThemeColor.cgColor
             followButton.layer.borderWidth = 0.5
             followButton.setBackgroundImage(UIImage.imageWithColor(color: kThemeColor), for: UIControl.State.normal)
+            followButton.isHidden = false
             break
         case .alreadyFollow:
             followButton.setTitle("已关注", for: UIControl.State.normal)