es-num lines-num-new"> 681
<subviews>
- <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" indicatorStyle="white" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="cvI-jg-TrD">
- <rect key="frame" x="0.0" y="20" width="395" height="647"/>
+ <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" indicatorStyle="white" dataMode="prototypes" prefetchingEnabled="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cvI-jg-TrD">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="0.0" minimumInteritemSpacing="0.0" id="nE7-Ce-1KB">
<size key="itemSize" width="237.5" height="357"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
@@ -830,7 +689,7 @@
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="imageCell" id="PAU-eQ-c9k" customClass="ImageCell" customModule="Paiai_iOS" customModuleProvider="target">
- <rect key="frame" x="0.0" y="145" width="237.5" height="357"/>
+ <rect key="frame" x="0.0" y="155" width="237.5" height="357"/>
<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="237.5" height="357"/>
@@ -856,35 +715,31 @@
</connections>
</collectionViewCell>
</cells>
- <connections>
- <outlet property="dataSource" destination="p3y-A2-QU1" id="gOQ-91-JoU"/>
- <outlet property="delegate" destination="p3y-A2-QU1" id="Woc-UQ-V73"/>
- </connections>
</collectionView>
- <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BRP-J0-WGF">
+ <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BRP-J0-WGF" userLabel="button group">
<rect key="frame" x="0.0" y="623" width="375" height="44"/>
<subviews>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Q90-2h-mGx">
- <rect key="frame" x="231" y="-26" width="96" height="96"/>
- <state key="normal" image="大图模式-下载"/>
- <connections>
- <action selector="load" destination="p3y-A2-QU1" eventType="touchUpInside" id="tC2-9R-1be"/>
- </connections>
- </button>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2r6-s1-9be">
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2r6-s1-9be" userLabel="back">
<rect key="frame" x="43.5" y="-26" width="96" height="96"/>
- <state key="normal" image="back"/>
+ <state key="normal" image="navigation-back"/>
<connections>
<action selector="back" destination="p3y-A2-QU1" eventType="touchUpInside" id="xKk-c3-Iub"/>
</connections>
</button>
- <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aOC-mu-785">
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aOC-mu-785" userLabel="rotate">
<rect key="frame" x="139.5" y="-26" width="96" height="96"/>
- <state key="normal" image="旋转"/>
+ <state key="normal" image="BTN-rotate"/>
<connections>
<action selector="rotateTheImage:" destination="p3y-A2-QU1" eventType="touchUpInside" id="LiB-TG-UYL"/>
</connections>
</button>
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Q90-2h-mGx" userLabel="download">
+ <rect key="frame" x="231" y="-26" width="96" height="96"/>
+ <state key="normal" image="BTN-download"/>
+ <connections>
+ <action selector="download:" destination="p3y-A2-QU1" eventType="touchUpInside" id="cEE-Yt-FWf"/>
+ </connections>
+ </button>
</subviews>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.5" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
@@ -902,14 +757,15 @@
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
- <constraint firstItem="uHN-Ad-PoZ" firstAttribute="top" secondItem="cvI-jg-TrD" secondAttribute="bottom" id="F0H-Mg-CBe"/>
- <constraint firstItem="uHN-Ad-PoZ" firstAttribute="top" secondItem="BRP-J0-WGF" secondAttribute="bottom" id="HMX-tH-TKt"/>
- <constraint firstItem="cvI-jg-TrD" firstAttribute="top" secondItem="MdC-Fu-zFL" secondAttribute="topMargin" id="bET-rg-QJH"/>
- <constraint firstItem="cvI-jg-TrD" firstAttribute="leading" secondItem="MdC-Fu-zFL" secondAttribute="leading" id="bxo-Ri-B7l"/>
- <constraint firstAttribute="trailing" secondItem="BRP-J0-WGF" secondAttribute="trailing" id="es7-Qg-qLl"/>
- <constraint firstItem="BRP-J0-WGF" firstAttribute="leading" secondItem="MdC-Fu-zFL" secondAttribute="leading" id="nES-ms-zxG"/>
- <constraint firstAttribute="trailing" secondItem="cvI-jg-TrD" secondAttribute="trailing" constant="-20" id="y4O-SP-QE3"/>
+ <constraint firstAttribute="bottom" secondItem="cvI-jg-TrD" secondAttribute="bottom" id="F0H-Mg-CBe"/>
+ <constraint firstItem="pxb-BY-KAJ" firstAttribute="bottom" secondItem="BRP-J0-WGF" secondAttribute="bottom" id="HMX-tH-TKt"/>
+ <constraint firstItem="cvI-jg-TrD" firstAttribute="top" secondItem="MdC-Fu-zFL" secondAttribute="top" id="bET-rg-QJH"/>
+ <constraint firstItem="cvI-jg-TrD" firstAttribute="leading" secondItem="pxb-BY-KAJ" secondAttribute="leading" id="bxo-Ri-B7l"/>
+ <constraint firstItem="pxb-BY-KAJ" firstAttribute="trailing" secondItem="BRP-J0-WGF" secondAttribute="trailing" id="es7-Qg-qLl"/>
+ <constraint firstItem="BRP-J0-WGF" firstAttribute="leading" secondItem="pxb-BY-KAJ" secondAttribute="leading" id="nES-ms-zxG"/>
+ <constraint firstItem="pxb-BY-KAJ" firstAttribute="trailing" secondItem="cvI-jg-TrD" secondAttribute="trailing" id="y4O-SP-QE3"/>
</constraints>
+ <viewLayoutGuide key="safeArea" id="pxb-BY-KAJ"/>
</view>
<connections>
<outlet property="collectionView" destination="cvI-jg-TrD" id="1eT-ax-Cma"/>
@@ -921,23 +777,22 @@
</scene>
</scenes>
<resources>
- <image name="BTN-分享" width="138" height="138"/>
- <image name="BTN-评论" width="138" height="138"/>
- <image name="Oval 491" width="192" height="192"/>
- <image name="back" width="36" height="72"/>
- <image name="icon-记录" width="36" height="36"/>
- <image name="icon-评论" width="36" height="36"/>
- <image name="icon-赞" width="36" height="36"/>
- <image name="list-arrow" width="16" height="16"/>
+ <image name="BTN-comment" width="138" height="138"/>
+ <image name="BTN-download" width="96" height="96"/>
+ <image name="BTN-rotate" width="96" height="96"/>
+ <image name="BTN-share" width="138" height="138"/>
+ <image name="BTN-thumbup" width="192" height="192"/>
+ <image name="defaultAvatar" width="240" height="240"/>
+ <image name="icon-comment" width="36" height="36"/>
+ <image name="icon-thumbup" width="36" height="36"/>
+ <image name="icon-time" width="36" height="36"/>
+ <image name="list-arrow" width="24" height="36"/>
+ <image name="navigation-back" width="36" height="72"/>
<image name="分享-QQ" width="162" height="162"/>
<image name="分享-微信好友" width="162" height="162"/>
<image name="分享-微博" width="162" height="162"/>
<image name="分享-朋友圈" width="162" height="162"/>
- <image name="去除水印" width="8" height="144"/>
- <image name="大图模式-下载" width="96" height="96"/>
- <image name="旋转" width="96" height="96"/>
<image name="购买-去水印" width="96" height="96"/>
<image name="进入群" width="114" height="60"/>
- <image name="默认头像" width="80" height="80"/>
</resources>
</document>
@@ -1,5 +1,5 @@ |
||
| 1 | 1 |
// |
| 2 |
-// DetailCommentCell.swift |
|
| 2 |
+// PhotoDetailCommentCell.swift |
|
| 3 | 3 |
// PaiAi |
| 4 | 4 |
// |
| 5 | 5 |
// Created by zhengjianfei on 16/4/8. |
@@ -10,7 +10,7 @@ import UIKit |
||
| 10 | 10 |
import PaiaiDataKit |
| 11 | 11 |
import PaiaiUIKit |
| 12 | 12 |
|
| 13 |
-class DetailCommentCell: UITableViewCell {
|
|
| 13 |
+class PhotoDetailCommentCell: UITableViewCell {
|
|
| 14 | 14 |
|
| 15 | 15 |
// MARK: Storyboard property |
| 16 | 16 |
@IBOutlet weak var headImage: UIImageView! |
@@ -7,9 +7,57 @@ |
||
| 7 | 7 |
// |
| 8 | 8 |
|
| 9 | 9 |
import Foundation |
| 10 |
+import PaiaiDataKit |
|
| 11 |
+ |
|
| 12 |
+final class PhotoDetailCoordinator: Coordinator {
|
|
| 13 |
+ let navigationController: UINavigationController |
|
| 14 |
+ let photoDetailViewController: PhotoDetailViewController |
|
| 15 |
+ let shareListViewModel: PhotoDetailListViewModel |
|
| 16 |
+ |
|
| 17 |
+ fileprivate var coordinators = [String: Coordinator]() |
|
| 18 |
+ |
|
| 19 |
+ init(_ photoDetailVC: PhotoDetailViewController, |
|
| 20 |
+ nav: UINavigationController, |
|
| 21 |
+ viewModel: PhotoDetailViewModel, |
|
| 22 |
+ listViewModel: PhotoDetailListViewModel) {
|
|
| 23 |
+ photoDetailViewController = photoDetailVC |
|
| 24 |
+ shareListViewModel = listViewModel |
|
| 25 |
+ navigationController = nav |
|
| 26 |
+ photoDetailViewController.listViewModel = shareListViewModel |
|
| 27 |
+ photoDetailViewController.viewModel = viewModel |
|
| 28 |
+ |
|
| 29 |
+ viewModel.delegate = self |
|
| 30 |
+ shareListViewModel.synchronization = viewModel |
|
| 31 |
+ shareListViewModel.delegate = self |
|
| 32 |
+ } |
|
| 33 |
+ |
|
| 34 |
+ func start() {
|
|
| 35 |
+ |
|
| 36 |
+ } |
|
| 37 |
+} |
|
| 38 |
+ |
|
| 39 |
+extension PhotoDetailCoordinator: PhotoDetailViewModelDelegate {
|
|
| 40 |
+ func navigateToGroup(_ item: GroupItem) {
|
|
| 41 |
+ let vc = GroupViewController.instantiate() |
|
| 42 |
+ vc.viewModel = GroupViewModel(groupItem: item) |
|
| 43 |
+ let coordinator = GroupCoordinator(vc, |
|
| 44 |
+ navigationController: navigationController) |
|
| 45 |
+ coordinators["group"] = coordinator |
|
| 46 |
+ |
|
| 47 |
+ navigationController.pushViewController(vc) |
|
| 48 |
+ } |
|
| 49 |
+} |
|
| 50 |
+ |
|
| 51 |
+extension PhotoDetailCoordinator: PhotoDetailListViewModelDelegate {
|
|
| 52 |
+ func didSelected() {
|
|
| 53 |
+ let vc = UIStoryboard.photoDetail.instantiateController(PhotoPreviewViewController.self) |
|
| 54 |
+ vc.viewModel = shareListViewModel |
|
| 55 |
+ navigationController.pushViewController(vc, animated: true) |
|
| 56 |
+ } |
|
| 57 |
+} |
|
| 10 | 58 |
|
| 11 | 59 |
extension UIStoryboard {
|
| 12 | 60 |
static var photoDetail: UIStoryboard {
|
| 13 |
- return UIStoryboard(name: "Detail", bundle: Bundle(identifier: "com.Paiai-iOS")) |
|
| 61 |
+ return UIStoryboard(name: "PhotoDetail", bundle: Bundle(identifier: "com.Paiai-iOS")) |
|
| 14 | 62 |
} |
| 15 | 63 |
} |
@@ -9,5 +9,5 @@ |
||
| 9 | 9 |
import UIKit |
| 10 | 10 |
|
| 11 | 11 |
class PhotoDetailImageCell: UICollectionViewCell {
|
| 12 |
- |
|
| 12 |
+ @IBOutlet weak var imageView: UIImageView! |
|
| 13 | 13 |
} |
@@ -9,6 +9,7 @@ |
||
| 9 | 9 |
import UIKit |
| 10 | 10 |
import RxSwift |
| 11 | 11 |
import RxCocoa |
| 12 |
+import RxDataSources |
|
| 12 | 13 |
import PaiaiDataKit |
| 13 | 14 |
import PaiaiUIKit |
| 14 | 15 |
|
@@ -17,6 +18,7 @@ let kPhotographerMark = 1 |
||
| 17 | 18 |
|
| 18 | 19 |
final class PhotoDetailViewController: UIViewController {
|
| 19 | 20 |
|
| 21 |
+ @IBOutlet weak var enterGroupView: UIView! |
|
| 20 | 22 |
@IBOutlet weak var groupAvatar: UIImageView! |
| 21 | 23 |
@IBOutlet weak var groupName: UILabel! |
| 22 | 24 |
|
@@ -30,409 +32,333 @@ final class PhotoDetailViewController: UIViewController {
|
||
| 30 | 32 |
@IBOutlet weak var thumbupView: UIView! |
| 31 | 33 |
|
| 32 | 34 |
@IBOutlet weak var commentCount: UILabel! |
| 33 |
- @IBOutlet weak var tableView: UITableView! |
|
| 35 |
+ @IBOutlet weak var commentTableView: UITableView! |
|
| 34 | 36 |
|
| 35 |
- @IBOutlet weak var commentView: UIView! |
|
| 37 |
+ @IBOutlet weak var commentEditingView: UIView! |
|
| 36 | 38 |
@IBOutlet weak var commentHeight: NSLayoutConstraint! |
| 37 | 39 |
@IBOutlet weak var commentTextField: UITextField! |
| 38 | 40 |
@IBOutlet weak var sendBtn: UIButton! |
| 39 | 41 |
|
| 40 | 42 |
@IBOutlet weak var buyView: UIView! |
| 43 |
+ @IBOutlet weak var waterMarkView: UIView! |
|
| 41 | 44 |
@IBOutlet weak var waterMarkImage: UIImageView! |
| 42 | 45 |
@IBOutlet weak var waterMarkLabel: UILabel! |
| 43 |
- |
|
| 46 |
+ |
|
| 47 |
+ @IBOutlet weak var thumbupViewHeightConstraint: NSLayoutConstraint! |
|
| 48 |
+ @IBOutlet weak var commentEditYConstraint: NSLayoutConstraint! |
|
| 49 |
+ |
|
| 44 | 50 |
// MARK: data property |
| 45 | 51 |
var viewModel: PhotoDetailViewModel! |
| 46 |
- lazy var datas = [PhotoItem]() |
|
| 47 |
- lazy var currentPhotoIndex = 0 |
|
| 48 |
- var isHiddenEnterView = false |
|
| 52 |
+ var listViewModel: PhotoDetailListViewModel! |
|
| 53 |
+ |
|
| 49 | 54 |
let disposeBag = DisposeBag() |
| 50 |
- static let storyboardCtl = UIStoryboard.photoDetail.instantiateInitialViewController() as! PhotoDetailViewController |
|
| 51 | 55 |
|
| 52 | 56 |
// MARK: view function |
| 53 | 57 |
override func viewDidLoad() {
|
| 54 | 58 |
super.viewDidLoad() |
| 55 |
-// detailPageViewModel.tipDelegate = self |
|
| 56 |
-// tableView.tableFooterView = UIView() |
|
| 57 |
- configureNotification() |
|
| 58 |
- |
|
| 59 |
- commentTextField.rx.text |
|
| 60 |
- .map {!($0?.isEmpty)!}
|
|
| 61 |
- .bind(to: sendBtn.rx.isEnabled) |
|
| 62 |
- .disposed(by: disposeBag) |
|
| 59 |
+ binding() |
|
| 60 |
+ setup() |
|
| 61 |
+ } |
|
| 62 |
+ |
|
| 63 |
+ func setup() {
|
|
| 64 |
+ setupCommentTextField() |
|
| 65 |
+ setupWaterMarkView() |
|
| 63 | 66 |
} |
| 64 | 67 |
|
| 65 | 68 |
func setupCommentTextField() {
|
| 66 | 69 |
commentTextField.addLeftPadding(7) |
| 67 | 70 |
} |
| 71 |
+ |
|
| 72 |
+ func setupWaterMarkView() {
|
|
| 73 |
+ guard let image = UIImage.PhotoDetail.purchaseBackground else { return }
|
|
| 74 |
+ waterMarkView.backgroundColor = UIColor(patternImage: image) |
|
| 75 |
+ } |
|
| 68 | 76 |
|
| 69 | 77 |
override func viewWillAppear(_ animated: Bool) {
|
| 70 | 78 |
super.viewWillAppear(true) |
| 71 |
-// titleWithbackBar = "详情" |
|
| 72 |
- navigationController?.isNavigationBarHidden = false |
|
| 73 |
-// refreshUI(index: currentPhotoIndex) |
|
| 74 |
- } |
|
| 75 |
- |
|
| 76 |
-// override func backToController() {
|
|
| 77 |
-// navigationController?.popViewController(animated: true) |
|
| 78 |
-// if let last = navigationController?.viewControllers[(navigationController?.viewControllers.count)! - 1] as? HomeViewController {
|
|
| 79 |
-//// last.mainViewModel.models.value = datas |
|
| 80 |
-// } |
|
| 81 |
-// |
|
| 82 |
-// if let last = navigationController?.viewControllers[(navigationController?.viewControllers.count)! - 1] as? GroupViewController {
|
|
| 83 |
-//// last.MineGroupViewModel.models.value = datas |
|
| 84 |
-// } |
|
| 85 |
-// } |
|
| 86 |
- |
|
| 87 |
- func configureNotification() {
|
|
| 88 |
- do {
|
|
| 89 |
-// NotificationCenter.default.rx.notification(Notification.Name(rawValue: WXPayDidFinishNotification)).asObservable().subscribe { (notification) in
|
|
| 90 |
-// FFToastView.showLoadingToast(inView: UIApplication.shared.keyWindow!, blockSuperView: true) |
|
| 91 |
-// self.detailPageViewModel.handleResult(errorCode: 0, success: {[weak self](PhotoItem) in
|
|
| 92 |
-// if let weakself = self {
|
|
| 93 |
-// weakself.datas[weakself.currentPhotoIndex].murl = PhotoItem.murl |
|
| 94 |
-// weakself.datas[weakself.currentPhotoIndex].rurl = PhotoItem.rurl |
|
| 95 |
-//// weakself.showBuyView() |
|
| 96 |
-// weakself.tableView.reloadRows(at: [IndexPath(item: 0, section: 1)], with: .none) |
|
| 97 |
-// let fullPicCtl = UIStoryboard.detailBoard.instantiateController(ShowFullPicController.self) |
|
| 98 |
-// fullPicCtl.datas = weakself.datas |
|
| 99 |
-// fullPicCtl.currentPhotoIndex = weakself.currentPhotoIndex |
|
| 100 |
-// fullPicCtl.showNomark = weakself.detailPageViewModel.watermarkPrice != -1 |
|
| 101 |
-// fullPicCtl.showHD = weakself.detailPageViewModel.hdPrice != -1 |
|
| 102 |
-// weakself.navigationController?.pushViewController(fullPicCtl, animated: true) |
|
| 103 |
-// } |
|
| 104 |
-// }) |
|
| 105 |
-// }.disposed(by: disposeBag) |
|
| 106 |
- } |
|
| 107 |
- do {
|
|
| 108 |
-// NotificationCenter.default.rx.notification(Notification.Name.UIKeyboardWillShow) |
|
| 109 |
-// .asObservable() |
|
| 110 |
-// .subscribe({ (notification) in
|
|
| 111 |
-// guard let info = notification.element?.userInfo, let avalue = info[UIKeyboardFrameEndUserInfoKey] else {
|
|
| 112 |
-// return |
|
| 113 |
-// } |
|
| 114 |
-// |
|
| 115 |
-// let height = (avalue as AnyObject).cgRectValue.size.height |
|
| 116 |
-// self.returnKeyboarAction(notification.element!, height: height) |
|
| 117 |
-// }).disposed(by: disposeBag) |
|
| 118 |
- } |
|
| 119 |
- |
|
| 120 |
- do {
|
|
| 121 |
- NotificationCenter.default.rx.notification(UIResponder.keyboardWillHideNotification) |
|
| 122 |
- .asObservable() |
|
| 123 |
- .subscribe({ (notification) in
|
|
| 124 |
- self.returnKeyboarAction(notification.element!, height: 0) |
|
| 125 |
- }).disposed(by: disposeBag) |
|
| 126 |
- } |
|
| 127 |
- |
|
| 79 |
+ viewModel.viewWillAppear.accept(()) |
|
| 128 | 80 |
} |
| 81 |
+} |
|
| 129 | 82 |
|
| 130 |
- // MARK: refresh interface |
|
| 131 |
- func refreshUI(index: Int) {
|
|
| 132 |
- currentPhotoIndex = index |
|
| 133 |
-// detailPageViewModel.currentPhoto = datas[index] |
|
| 134 |
- |
|
| 135 |
-// detailPageViewModel.fetchThumbup(success: {[weak self] in
|
|
| 136 |
-// if let weakself = self {
|
|
| 137 |
-// var model = weakself.datas[index] |
|
| 138 |
-// model.thumbup_num = weakself.detailPageViewModel.thumbups.count |
|
| 139 |
-// weakself.datas[index] = model |
|
| 140 |
-//// PhotoLocalStorage.instance.updateLocalData(PhotoItem: model) |
|
| 141 |
-// weakself.reloadSection(inter: 3) |
|
| 142 |
-// } |
|
| 143 |
-// }) |
|
| 144 |
-// detailPageViewModel.fetchComment(success: {[weak self] in
|
|
| 145 |
-// if let weakself = self {
|
|
| 146 |
-// |
|
| 147 |
-// var model = weakself.datas[index] |
|
| 148 |
-// model.comment_num = weakself.detailPageViewModel.comments.count |
|
| 149 |
-// weakself.datas[index] = model |
|
| 150 |
-//// PhotoLocalStorage.instance.updateLocalData(PhotoItem: model) |
|
| 151 |
-// weakself.reloadSection(inter: 4) |
|
| 152 |
-// } |
|
| 153 |
-// }) |
|
| 83 |
+//MARK textField delegate |
|
| 84 |
+extension PhotoDetailViewController: UIGestureRecognizerDelegate {
|
|
| 85 |
+ // MARK: textField |
|
| 154 | 86 |
|
| 155 |
-// reloadSection(inter: 0) |
|
| 156 |
-// reloadSection(inter: 2) |
|
| 157 |
- showBuyView() |
|
| 87 |
+ func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
|
|
| 88 |
+ return commentTextField.isFirstResponder |
|
| 158 | 89 |
} |
| 90 |
+ |
|
| 91 |
+} |
|
| 159 | 92 |
|
| 160 |
- func showBuyView() {
|
|
| 161 |
-// if detailPageViewModel.currentPhoto.photo_from == kPhotographerMark && detailPageViewModel.currentPhoto.display_payment_btn == 1 {
|
|
| 162 |
-// buyView.isHidden = false |
|
| 163 |
-// detailPageViewModel.hdPrice = -0.01 |
|
| 164 |
-// detailPageViewModel.watermarkPrice = -0.01 |
|
| 165 |
-// shuiyinLabel.text = !detailPageViewModel.currentPhoto.murl.isEmpty ? "查看无水印图" : "去除水印" |
|
| 166 |
-// shuiyinImage.isHidden = false |
|
| 167 |
-// } else {
|
|
| 168 |
-// buyView.isHidden = true |
|
| 169 |
-// } |
|
| 170 |
- } |
|
| 171 | 93 |
|
| 172 |
- // MARK: Storyboard button function |
|
| 173 |
- @IBAction func HDPay(_ sender: UIButton) {
|
|
| 174 |
-// detailPageViewModel.getHD (getPriceSuccess: { [weak self] (isExist) in
|
|
| 175 |
-// if let weakself = self {
|
|
| 176 |
-// if isExist {
|
|
| 177 |
-// let fullPicCtl = UIStoryboard(name: "Detail", bundle: nil).instantiateController(ShowFullPicController.self) |
|
| 178 |
-// fullPicCtl.datas = [weakself.datas[weakself.currentPhotoIndex]] |
|
| 179 |
-// fullPicCtl.showNomark = true |
|
| 180 |
-// fullPicCtl.currentPhotoIndex = weakself.currentPhotoIndex |
|
| 181 |
-// weakself.navigationController?.pushViewController(fullPicCtl, animated: true) |
|
| 182 |
-// } else {
|
|
| 183 |
-// } |
|
| 184 |
-// } |
|
| 185 |
-// }) |
|
| 94 |
+/// bind storyboard gesture action |
|
| 95 |
+extension PhotoDetailViewController {
|
|
| 96 |
+ @IBAction func purchase(_ sender: UITapGestureRecognizer) {
|
|
| 97 |
+ |
|
| 186 | 98 |
} |
| 187 |
- |
|
| 188 |
- @IBAction func waterMarkPay(_ sender: UIButton) {
|
|
| 189 |
- |
|
| 190 |
-// detailPageViewModel.getWatermark (getPriceSuccess: { [weak self] (isExist) in
|
|
| 191 |
-// if let weakself = self {
|
|
| 192 |
-// if isExist {
|
|
| 193 |
-// let fullPicCtl = UIStoryboard(name: "Detail", bundle: nil).instantiateController(ShowFullPicController.self) |
|
| 194 |
-// fullPicCtl.datas = weakself.datas |
|
| 195 |
-// fullPicCtl.showNomark = true |
|
| 196 |
-// fullPicCtl.currentPhotoIndex = weakself.currentPhotoIndex |
|
| 197 |
-// weakself.navigationController?.pushViewController(fullPicCtl, animated: true) |
|
| 198 |
-// } else {
|
|
| 199 |
-// weakself.shuiyinImage.isHidden = true |
|
| 200 |
-// weakself.shuiyinLabel.text = "¥\((weakself.detailPageViewModel.watermarkPrice/100))" |
|
| 201 |
-// } |
|
| 202 |
-// } |
|
| 203 |
-// }) |
|
| 99 |
+ |
|
| 100 |
+ @IBAction func enterGroup(_ sender: UITapGestureRecognizer) {
|
|
| 101 |
+ self.viewModel.navigateToGroup() |
|
| 204 | 102 |
} |
| 103 |
+} |
|
| 205 | 104 |
|
| 105 |
+/// bind storyboard button action |
|
| 106 |
+extension PhotoDetailViewController {
|
|
| 206 | 107 |
@IBAction func share() {
|
| 207 | 108 |
let ctl = UIStoryboard.photoDetail.instantiateController(ShareController.self) |
| 208 | 109 |
ctl.shareContent = "我使用拍爱分享了一张美图,你也快来试试吧" |
| 209 |
- ctl.shareImgUrlThumb = datas[currentPhotoIndex].photo_thumbnail_url |
|
| 210 |
- ctl.shareUrl = datas[currentPhotoIndex].photo_share_url |
|
| 110 |
+ // ctl.shareImgUrlThumb = datas[currentPhotoIndex].photo_thumbnail_url |
|
| 111 |
+ // ctl.shareUrl = datas[currentPhotoIndex].photo_share_url |
|
| 211 | 112 |
presentController(ctl) |
| 212 | 113 |
} |
| 213 |
- |
|
| 114 |
+ |
|
| 214 | 115 |
@IBAction func comment() {
|
| 215 |
- commentView.isHidden = false |
|
| 216 | 116 |
commentTextField.becomeFirstResponder() |
| 117 |
+ |
|
| 217 | 118 |
} |
| 218 |
- |
|
| 119 |
+ |
|
| 219 | 120 |
@IBAction func sendComment() {
|
| 220 |
- guard let text = commentTextField.text else {
|
|
| 221 |
- return |
|
| 222 |
- } |
|
| 223 |
-// detailPageViewModel.sendComment(content: text, success: { [weak self] in
|
|
| 224 |
-// if let weakself = self {
|
|
| 225 |
-// weakself.commentTextField.text = "" |
|
| 226 |
-// weakself.commentTextField.resignFirstResponder() |
|
| 227 |
-// weakself.commentView.isHidden = true |
|
| 228 |
-// weakself.refreshUI(index: weakself.currentPhotoIndex) |
|
| 229 |
-// } |
|
| 230 |
-// }) |
|
| 121 |
+ guard let text = commentTextField.text else { return }
|
|
| 122 |
+ |
|
| 123 |
+ viewModel.submitComment(text: text) |
|
| 124 |
+ commentTextField.resignFirstResponder() |
|
| 231 | 125 |
} |
| 232 |
- |
|
| 126 |
+ |
|
| 233 | 127 |
@IBAction func thumbup() {
|
| 234 |
-// detailPageViewModel.sendThumbup(success: {[weak self] in
|
|
| 235 |
-// if let weakself = self {
|
|
| 236 |
-// weakself.refreshUI(index: weakself.currentPhotoIndex) |
|
| 237 |
-// } |
|
| 238 |
-// |
|
| 239 |
-// }) |
|
| 128 |
+ viewModel.submitThumbup() |
|
| 240 | 129 |
} |
| 130 |
+} |
|
| 241 | 131 |
|
| 242 |
- // MARK: custom function |
|
| 243 |
- func reloadSection(inter: Int) {
|
|
| 244 |
- tableView.beginUpdates() |
|
| 245 |
- let indexSet = IndexSet(integer: inter) |
|
| 246 |
- tableView.reloadSections(indexSet, with: .none) |
|
| 247 |
- tableView.endUpdates() |
|
| 132 |
+/// bind rx |
|
| 133 |
+extension PhotoDetailViewController {
|
|
| 134 |
+ |
|
| 135 |
+ var commentTableViewDataSource: RxTableViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoCommentItem>> {
|
|
| 136 |
+ return RxTableViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoCommentItem>>(configureCell: { (dataSource, tableView, indexPath, item) in
|
|
| 137 |
+ let cell = tableView.dequeueReusableCell(withIdentifier: "photoDetailCommentCell", for: indexPath) as! PhotoDetailCommentCell |
|
| 138 |
+ cell.setInfo(item) |
|
| 139 |
+ return cell |
|
| 140 |
+ }) |
|
| 248 | 141 |
} |
| 249 |
- |
|
| 250 |
- @objc func showThumps() {
|
|
| 251 |
-// if detailPageViewModel.thumbupsCount > 0 {
|
|
| 252 |
-// detailPageViewModel.thumbupsCount = 0 |
|
| 253 |
-// } else {
|
|
| 254 |
-// detailPageViewModel.thumbupsCount = detailPageViewModel.thumbups.count |
|
| 255 |
-// } |
|
| 256 |
- reloadSection(inter: 3) |
|
| 257 |
- } |
|
| 258 |
- @objc func showComments() {
|
|
| 259 |
-// if detailPageViewModel.commentsCount > 0 {
|
|
| 260 |
-// detailPageViewModel.commentsCount = 0 |
|
| 261 |
-// } else {
|
|
| 262 |
-// detailPageViewModel.commentsCount = detailPageViewModel.comments.count |
|
| 263 |
-// } |
|
| 264 |
- reloadSection(inter: 4) |
|
| 142 |
+ |
|
| 143 |
+ var photoCollectionViewDataSource: RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>> {
|
|
| 144 |
+ return RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>>(configureCell: { (dataSource, collectionView, indexPath, item) in
|
|
| 145 |
+ let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoDetailImageCell", for: indexPath) as! PhotoDetailImageCell |
|
| 146 |
+ cell.imageView.setImage(item.photo_thumbnail2_url, placeholder: UIImage.photoPlaceholder) |
|
| 147 |
+ return cell |
|
| 148 |
+ }) |
|
| 265 | 149 |
} |
| 266 |
- |
|
| 267 |
- @objc func loadReportController() {
|
|
| 268 |
-// let ctl = UIStoryboard.photoDetail.instantiateController(ReportController.self) |
|
| 269 |
-// presentController(ctl) |
|
| 150 |
+ |
|
| 151 |
+ func binding() {
|
|
| 152 |
+ bindEnterGroupViewHiddenState() |
|
| 153 |
+ bindViewModelToGroupName() |
|
| 154 |
+ bindViewModelToGroupAvatar() |
|
| 155 |
+ |
|
| 156 |
+ bindViewModelToUserName() |
|
| 157 |
+ bindgingViewModelToUserAvatar() |
|
| 158 |
+ |
|
| 159 |
+ bindViewModelToThumbupCount() |
|
| 160 |
+ bindViewModelToThumbupView() |
|
| 161 |
+ |
|
| 162 |
+ bindViewModelToCommentCount() |
|
| 163 |
+ bindViewModelToCommentTableView() |
|
| 164 |
+ |
|
| 165 |
+ bindBuyViewIsVisiable() |
|
| 166 |
+ |
|
| 167 |
+ bindCommentTextFieldToSendBtn() |
|
| 168 |
+ |
|
| 169 |
+ bindCollectionViewDelegate() |
|
| 170 |
+ bindCollectionViewSelected() |
|
| 171 |
+ bindCollectionViewToListViewModel() |
|
| 172 |
+ bindListViewModelToCollectionView() |
|
| 173 |
+ |
|
| 174 |
+ bindViewWillAppear() |
|
| 175 |
+ |
|
| 176 |
+ monitorKeyboardWillShow() |
|
| 177 |
+ monitorKeyboardWillHide() |
|
| 270 | 178 |
} |
| 271 |
- |
|
| 272 |
- func returnKeyboarAction(_ notification: Notification, height: CGFloat) {
|
|
| 273 |
- guard let info = (notification as NSNotification).userInfo, let duration = info[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval else {
|
|
| 274 |
- return |
|
| 275 |
- } |
|
| 276 |
- |
|
| 277 |
- UIView.animate(withDuration: duration, animations: {() -> Void in
|
|
| 278 |
- self.commentHeight.constant = height |
|
| 279 |
- self.commentView.superview!.layoutIfNeeded() |
|
| 280 |
- }) |
|
| 179 |
+ |
|
| 180 |
+ func bindEnterGroupViewHiddenState() {
|
|
| 181 |
+ viewModel.isHiddenEnterGroupBtn.bind(to: enterGroupView.rx.isHidden).disposed(by: disposeBag) |
|
| 281 | 182 |
} |
| 282 |
- |
|
| 283 |
- // MARK: deinit |
|
| 284 |
- deinit {
|
|
| 285 |
- NotificationCenter.default.removeObserver(self) |
|
| 183 |
+ |
|
| 184 |
+ func bindViewModelToGroupName() {
|
|
| 185 |
+ viewModel.groupName.bind(to: groupName.rx.text).disposed(by: disposeBag) |
|
| 286 | 186 |
} |
| 287 |
- |
|
| 288 |
-} |
|
| 289 |
- |
|
| 290 |
-// MARK: custom delegate function |
|
| 291 |
-extension PhotoDetailViewController: CellDelegate {
|
|
| 292 |
- func selectIndex(indexpath: IndexPath) {
|
|
| 293 |
- let ctl = UIStoryboard.photoDetail.instantiateController(ShowFullPicController.self) |
|
| 294 |
- ctl.datas = datas |
|
| 295 |
- ctl.currentPhotoIndex = currentPhotoIndex |
|
| 296 |
- show(ctl, sender: nil) |
|
| 187 |
+ |
|
| 188 |
+ func bindViewModelToGroupAvatar() {
|
|
| 189 |
+ viewModel.groupAvatar |
|
| 190 |
+ .subscribe(onNext: {[weak self] (avatar) in
|
|
| 191 |
+ guard let `self` = self else { return }
|
|
| 192 |
+ self.groupAvatar.setImage(avatar) |
|
| 193 |
+ }).disposed(by: disposeBag) |
|
| 297 | 194 |
} |
| 298 |
- |
|
| 299 |
- func returnCurrentIndex(index: Int) {
|
|
| 300 |
- refreshUI(index: index) |
|
| 195 |
+ |
|
| 196 |
+ func bindgingViewModelToUserAvatar() {
|
|
| 197 |
+ viewModel.userAvatar |
|
| 198 |
+ .subscribe(onNext: {[weak self] (avatar) in
|
|
| 199 |
+ guard let `self` = self else { return }
|
|
| 200 |
+ self.userAvatar.setImage(avatar) |
|
| 201 |
+ }).disposed(by: disposeBag) |
|
| 301 | 202 |
} |
| 302 |
- |
|
| 303 |
- func pushNext() {
|
|
| 304 |
- let ctl = UIStoryboard.main.instantiateController(GroupViewController.self) |
|
| 305 |
- |
|
| 306 |
-// ctl.groupModel = GroupModel(map: Map(mappingType: .fromJSON, JSON: datas[currentPhotoIndex].toJSON())) |
|
| 307 |
- show(ctl, sender: nil) |
|
| 203 |
+ |
|
| 204 |
+ func bindViewModelToUserName() {
|
|
| 205 |
+ viewModel.groupName.bind(to: userName.rx.text).disposed(by: disposeBag) |
|
| 308 | 206 |
} |
| 309 |
-} |
|
| 310 |
- |
|
| 311 |
-//MARK textField delegate |
|
| 312 |
-extension PhotoDetailViewController: UIGestureRecognizerDelegate {
|
|
| 313 |
- // MARK: textField |
|
| 314 |
- |
|
| 315 |
- func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
|
|
| 316 |
- return commentTextField.isFirstResponder |
|
| 207 |
+ |
|
| 208 |
+ func bindViewModelToPhotoTime() {
|
|
| 209 |
+ viewModel.photoTime.bind(to: photoTime.rx.text).disposed(by: disposeBag) |
|
| 317 | 210 |
} |
| 318 |
- |
|
| 319 |
- @IBAction func ReturnKeyboard(_ sender: UITapGestureRecognizer) {
|
|
| 320 |
- if !commentView.isHidden {
|
|
| 321 |
- commentTextField.resignFirstResponder() |
|
| 322 |
- commentView.isHidden = true |
|
| 323 |
- } |
|
| 211 |
+ |
|
| 212 |
+ func bindViewModelToThumbupCount() {
|
|
| 213 |
+ viewModel.thumbupCount.bind(to: thumbupCount.rx.text).disposed(by: disposeBag) |
|
| 324 | 214 |
} |
| 325 |
- |
|
| 326 |
-} |
|
| 327 |
- |
|
| 328 |
-// MARK: UITableView delegate |
|
| 329 |
-extension PhotoDetailViewController: UITableViewDataSource, UITableViewDelegate {
|
|
| 330 |
- |
|
| 331 |
- func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
|
| 332 |
- if section == 3 {
|
|
| 333 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "thumbupHeadCell") |
|
| 334 |
- if let label = cell?.viewWithTag(1001) as? UILabel {
|
|
| 335 |
-// label.text = "(\(detailPageViewModel.thumbups.count))" |
|
| 336 |
- } |
|
| 337 |
- if let button = cell?.viewWithTag(1011) as? UIButton {
|
|
| 338 |
- button.addTarget(self, action: #selector(showThumps), for: .touchUpInside) |
|
| 339 |
- } |
|
| 340 |
- if let imageView = cell?.viewWithTag(1008) as? UIImageView {
|
|
| 341 |
-// let imageName = detailPageViewModel.thumbupsCount <= 0 ? "收起" : "list-arrow" |
|
| 342 |
-// imageView.image = UIImage(named : imageName) |
|
| 343 |
- } |
|
| 344 |
- return cell?.contentView |
|
| 345 |
- } else if section == 4 {
|
|
| 346 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "comentHeadCell") |
|
| 347 |
- if let label = cell?.viewWithTag(1002) as? UILabel {
|
|
| 348 |
-// label.text = "(\(detailPageViewModel.comments.count))" |
|
| 349 |
- } |
|
| 350 |
- if let button = cell?.viewWithTag(1012) as? UIButton {
|
|
| 351 |
- button.addTarget(self, action: #selector(showComments), for: .touchUpInside) |
|
| 352 |
- } |
|
| 353 |
- if let imageView = cell?.viewWithTag(1009) as? UIImageView {
|
|
| 354 |
-// let imageName = detailPageViewModel.commentsCount <= 0 ? "收起" : "list-arrow" |
|
| 355 |
-// imageView.image = UIImage(named : imageName) |
|
| 356 |
- } |
|
| 357 |
- return cell?.contentView |
|
| 358 |
- } |
|
| 359 |
- return nil |
|
| 215 |
+ |
|
| 216 |
+ func bindViewModelToThumbupView() {
|
|
| 217 |
+ viewModel.thumbupItems |
|
| 218 |
+ .asDriver(onErrorJustReturn: []) |
|
| 219 |
+ .drive(onNext: { [weak self] (items) in
|
|
| 220 |
+ self?.setupThumbupView(items: items) |
|
| 221 |
+ }).disposed(by: disposeBag) |
|
| 360 | 222 |
} |
| 361 |
- |
|
| 362 |
- func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
|
|
| 363 |
- if section == 3 || section == 4 {
|
|
| 364 |
- return 44 |
|
| 365 |
- } |
|
| 366 |
- return 0 |
|
| 223 |
+ |
|
| 224 |
+ func bindViewModelToCommentCount() {
|
|
| 225 |
+ viewModel.commentCount.bind(to: commentCount.rx.text).disposed(by: disposeBag) |
|
| 367 | 226 |
} |
| 368 |
- |
|
| 369 |
- func numberOfSections(in tableView: UITableView) -> Int {
|
|
| 370 |
- return 0 |
|
| 227 |
+ |
|
| 228 |
+ func bindViewModelToCommentTableView() {
|
|
| 229 |
+ viewModel.commentItems |
|
| 230 |
+ .bind(to: commentTableView.rx.items(dataSource: commentTableViewDataSource)) |
|
| 231 |
+ .disposed(by: disposeBag) |
|
| 371 | 232 |
} |
| 372 |
- |
|
| 373 |
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
| 374 |
-// if section == 3 {
|
|
| 375 |
-// return detailPageViewModel.thumbupsCount > 0 ? 1 : 0 |
|
| 376 |
-// } else if section == 4 {
|
|
| 377 |
-// return detailPageViewModel.commentsCount |
|
| 378 |
-// } |
|
| 379 |
- return 0 |
|
| 233 |
+ |
|
| 234 |
+ func bindBuyViewIsVisiable() {
|
|
| 235 |
+ viewModel.canBuy.map { !$0 }.bind(to: buyView.rx.isHidden).disposed(by: disposeBag)
|
|
| 380 | 236 |
} |
| 381 |
- |
|
| 382 |
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
| 383 |
- if indexPath.section == 0 {
|
|
| 384 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "headCell", for: indexPath) as! DetailPageHeadCell |
|
| 385 |
- cell.enterView.isHidden = isHiddenEnterView |
|
| 386 |
-// cell.setInfo(datas[currentPhotoIndex]) |
|
| 387 |
- cell.delegate = self |
|
| 388 |
- if let reportBtn = cell.viewWithTag(40001) as? UIButton {
|
|
| 389 |
- |
|
| 390 |
- reportBtn.addTarget(self, action: #selector(loadReportController), for: .touchUpInside) |
|
| 391 |
-// reportBtn.isHidden = !(UserDefaults.Account.bool(forKey: .isAudit)) |
|
| 392 |
- } |
|
| 393 |
- return cell |
|
| 394 |
- } else if indexPath.section == 1 {
|
|
| 395 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "detailPagePhotoCell", for: indexPath) as! DetailPagePhotoCell |
|
| 396 |
-// cell.datas = datas |
|
| 397 |
-// cell.currentPhotoIndex = currentPhotoIndex |
|
| 398 |
- cell.delegate = self |
|
| 399 |
- cell.first = true |
|
| 400 |
- cell.collectionView.reloadData() |
|
| 401 |
- return cell |
|
| 402 |
- } else if indexPath.section == 2 {
|
|
| 403 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "nameCell", for: indexPath) as! DetailPageNameCell |
|
| 404 |
-// cell.setInfo(datas[currentPhotoIndex]) |
|
| 405 |
- return cell |
|
| 406 |
- } else if indexPath.section == 3 {
|
|
| 407 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "thumbupCell", for: indexPath) as! DetailthumbupImagesCell |
|
| 408 |
-// if detailPageViewModel.thumbups.count > 0 {
|
|
| 409 |
-// let headers = detailPageViewModel.thumbups.map {$0.avatar}
|
|
| 410 |
-// cell.setInfo(content: headers) |
|
| 411 |
-// } |
|
| 412 |
- return cell |
|
| 413 |
- } else {
|
|
| 414 |
- let cell = tableView.dequeueReusableCell(withIdentifier: "comentCell", for: indexPath) as! DetailCommentCell |
|
| 415 |
-// cell.setInfo(detailPageViewModel.comments[indexPath.row]) |
|
| 416 |
- return cell |
|
| 417 |
- } |
|
| 237 |
+ |
|
| 238 |
+ func bindCommentTextFieldToSendBtn() {
|
|
| 239 |
+ commentTextField.rx.text |
|
| 240 |
+ .map { !($0?.isEmpty)! }
|
|
| 241 |
+ .bind(to: sendBtn.rx.isEnabled) |
|
| 242 |
+ .disposed(by: disposeBag) |
|
| 243 |
+ } |
|
| 244 |
+ |
|
| 245 |
+ func bindCollectionViewDelegate() {
|
|
| 246 |
+ photoCollectionView.rx.setDelegate(self).disposed(by: disposeBag) |
|
| 247 |
+ |
|
| 248 |
+ } |
|
| 249 |
+ |
|
| 250 |
+ func bindListViewModelToCollectionView() {
|
|
| 251 |
+ listViewModel.content |
|
| 252 |
+ .bind(to: photoCollectionView.rx.items(dataSource: photoCollectionViewDataSource)) |
|
| 253 |
+ .disposed(by: disposeBag) |
|
| 254 |
+ } |
|
| 255 |
+ |
|
| 256 |
+ func bindCollectionViewToListViewModel() {
|
|
| 257 |
+ photoCollectionView.rx.willDisplayCell |
|
| 258 |
+ .asDriver() |
|
| 259 |
+ .drive(onNext: { [unowned self] in
|
|
| 260 |
+ self.listViewModel.willShow(index: $0.at.row) |
|
| 261 |
+ }) |
|
| 262 |
+ .disposed(by: disposeBag) |
|
| 263 |
+ } |
|
| 264 |
+ |
|
| 265 |
+ func bindCollectionViewSelected() {
|
|
| 266 |
+ photoCollectionView.rx.itemSelected |
|
| 267 |
+ .asDriver(onErrorJustReturn: IndexPath(item: 0, section: 0)) |
|
| 268 |
+ .drive(onNext: { [unowned self] _ in self.listViewModel.didSelected() })
|
|
| 269 |
+ .disposed(by: disposeBag) |
|
| 270 |
+ } |
|
| 271 |
+ |
|
| 272 |
+ func bindViewWillAppear() {
|
|
| 273 |
+ viewModel.viewWillAppear |
|
| 274 |
+ .asDriver() |
|
| 275 |
+ .drive(onNext: { [unowned self] _ in
|
|
| 276 |
+ self.photoCollectionView.scrollToItem(at: IndexPath(item: self.listViewModel.currIndex, section: 0), at: .right, animated: false) |
|
| 277 |
+ }) |
|
| 278 |
+ .disposed(by: disposeBag) |
|
| 418 | 279 |
} |
| 280 |
+ |
|
| 281 |
+ func monitorKeyboardWillShow() {
|
|
| 282 |
+ NotificationCenter.default.rx |
|
| 283 |
+ .notification(UIResponder.keyboardWillShowNotification) |
|
| 284 |
+ .takeUntil(self.rx.deallocated) |
|
| 285 |
+ .subscribe { [unowned self] notification in
|
|
| 286 |
+ guard let userInfo = notification.element?.userInfo, |
|
| 287 |
+ let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect, |
|
| 288 |
+ let timeInterval = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval, |
|
| 289 |
+ let curve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int |
|
| 290 |
+ else { return }
|
|
| 291 |
+ UIView.setAnimationCurve(UIView.AnimationCurve(rawValue: curve) ?? .linear) |
|
| 292 |
+ UIView.animate(withDuration: timeInterval, animations: {
|
|
| 293 |
+ self.commentEditYConstraint.constant = keyboardFrame.height |
|
| 294 |
+ self.view.layoutIfNeeded() |
|
| 295 |
+ }) |
|
| 296 |
+ }.disposed(by: disposeBag) |
|
| 297 |
+ } |
|
| 298 |
+ |
|
| 299 |
+ func monitorKeyboardWillHide() {
|
|
| 300 |
+ NotificationCenter.default.rx |
|
| 301 |
+ .notification(UIResponder.keyboardWillHideNotification) |
|
| 302 |
+ .takeUntil(self.rx.deallocated) |
|
| 303 |
+ .subscribe { [unowned self] notification in
|
|
| 304 |
+ guard let userInfo = notification.element?.userInfo, |
|
| 305 |
+ let timeInterval = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval, |
|
| 306 |
+ let curve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int |
|
| 307 |
+ else { return }
|
|
| 308 |
+ UIView.setAnimationCurve(UIView.AnimationCurve(rawValue: curve) ?? .linear) |
|
| 309 |
+ UIView.animate(withDuration: timeInterval, animations: {
|
|
| 310 |
+ self.commentEditYConstraint.constant = -56 |
|
| 311 |
+ self.view.layoutIfNeeded() |
|
| 312 |
+ }) |
|
| 313 |
+ self.commentTextField.clear() |
|
| 314 |
+ }.disposed(by: disposeBag) |
|
| 315 |
+ } |
|
| 316 |
+} |
|
| 419 | 317 |
|
| 420 |
- func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
|
|
| 421 |
- if indexPath.section == 0 {
|
|
| 422 |
- return 48 |
|
| 423 |
- } else if indexPath.section == 1 {
|
|
| 424 |
- return 360 |
|
| 425 |
- } else if indexPath.section == 2 {
|
|
| 426 |
- return 36 |
|
| 427 |
- } else if indexPath.section == 3 {
|
|
| 428 |
- return 40 |
|
| 429 |
- } else {
|
|
| 430 |
-// return 40 + detailPageViewModel.comments[indexPath.row].cellHeigth |
|
| 431 |
- return 40 |
|
| 318 |
+extension PhotoDetailViewController {
|
|
| 319 |
+ func setupThumbupView(items: [PhotoThumbupUserItem]) {
|
|
| 320 |
+ thumbupView.subviews.forEach { $0.removeFromSuperview() }
|
|
| 321 |
+ |
|
| 322 |
+ let row = (Int(kScreenWidth) - 6) / 34 |
|
| 323 |
+ var topConstraint: CGFloat = 6 |
|
| 324 |
+ var last: UIImageView? |
|
| 325 |
+ |
|
| 326 |
+ for (index, item) in items.enumerated() {
|
|
| 327 |
+ let imageView = UIImageView() |
|
| 328 |
+ imageView.cornerRadius = 5 |
|
| 329 |
+ imageView.translatesAutoresizingMaskIntoConstraints = false |
|
| 330 |
+ imageView.setImage(item.avatar, placeholder: UIImage.defaultAvatar) |
|
| 331 |
+ thumbupView.addSubview(imageView) |
|
| 332 |
+ |
|
| 333 |
+ if index % row == 0 && index != 0 {
|
|
| 334 |
+ topConstraint += 28 + 6 |
|
| 335 |
+ last = nil |
|
| 336 |
+ } |
|
| 337 |
+ |
|
| 338 |
+ NSLayoutConstraint.activate([ |
|
| 339 |
+ imageView.widthAnchor.constraint(equalToConstant: 28), |
|
| 340 |
+ imageView.heightAnchor.constraint(equalToConstant: 28), |
|
| 341 |
+ imageView.topAnchor.constraint(equalTo: thumbupView.topAnchor, constant: topConstraint), |
|
| 342 |
+ imageView.leadingAnchor.constraint(equalTo: last?.trailingAnchor ?? thumbupView.leadingAnchor, constant: 6) |
|
| 343 |
+ ]) |
|
| 344 |
+ |
|
| 345 |
+ last = imageView |
|
| 432 | 346 |
} |
| 347 |
+ thumbupViewHeightConstraint.constant = items.isEmpty ? 1 : topConstraint + 34 |
|
| 348 |
+ commentTableView.tableHeaderView?.height = 532 + thumbupViewHeightConstraint.constant |
|
| 433 | 349 |
} |
| 434 | 350 |
} |
| 435 | 351 |
|
| 436 |
-extension PhotoDetailViewController {
|
|
| 352 |
+extension PhotoDetailViewController: UICollectionViewDelegateFlowLayout {
|
|
| 353 |
+ func collectionView(_ collectionView: UICollectionView, |
|
| 354 |
+ layout collectionViewLayout: UICollectionViewLayout, |
|
| 355 |
+ sizeForItemAt indexPath: IndexPath) -> CGSize {
|
|
| 356 |
+ return CGSize(width: kScreenWidth, height: 359) |
|
| 357 |
+ } |
|
| 437 | 358 |
|
| 359 |
+ func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
|
|
| 360 |
+ return 0 |
|
| 361 |
+ } |
|
| 438 | 362 |
} |
| 363 |
+ |
|
| 364 |
+extension PhotoDetailViewController: NavigationBackViewController {}
|
@@ -1,5 +1,5 @@ |
||
| 1 | 1 |
// |
| 2 |
-// ShowFullPicController.swift |
|
| 2 |
+// PhotoPreviewViewController.swift |
|
| 3 | 3 |
// PaiAi |
| 4 | 4 |
// |
| 5 | 5 |
// Created by zhengjianfei on 16/4/9. |
@@ -9,49 +9,104 @@ |
||
| 9 | 9 |
import UIKit |
| 10 | 10 |
import PaiaiDataKit |
| 11 | 11 |
import PaiaiUIKit |
| 12 |
+import RxCocoa |
|
| 13 |
+import RxSwift |
|
| 14 |
+import RxDataSources |
|
| 12 | 15 |
|
| 13 |
-final class ShowFullPicController: UIViewController {
|
|
| 16 |
+final class PhotoPreviewViewController: UIViewController {
|
|
| 14 | 17 |
|
| 15 |
- // MARK: Storyboard property |
|
| 18 |
+ /// MARK: Storyboard property |
|
| 16 | 19 |
@IBOutlet weak var collectionView: UICollectionView! |
| 17 |
-// @IBOutlet weak var progressView: FFProgress! |
|
| 18 |
- // MARK: parameter property |
|
| 19 |
- lazy var datas = [PhotoItem]() |
|
| 20 |
- lazy var currentPhotoIndex = 0 |
|
| 21 |
- lazy var firstLayout = true |
|
| 22 |
- lazy var currentPageIndex = 0 |
|
| 23 |
- lazy var showNomark = false |
|
| 24 |
- lazy var showHD = false |
|
| 25 |
- |
|
| 26 |
- var shufflingImage = [String]() |
|
| 27 |
- |
|
| 28 |
- // MARK: Controller fucntion |
|
| 20 |
+ var viewModel: PhotoDetailListViewModel! |
|
| 21 |
+ var disposeBag = DisposeBag() |
|
| 22 |
+ |
|
| 23 |
+ override var prefersStatusBarHidden: Bool {
|
|
| 24 |
+ return true |
|
| 25 |
+ } |
|
| 26 |
+ |
|
| 29 | 27 |
override func viewDidLoad() {
|
| 30 | 28 |
super.viewDidLoad() |
| 31 |
- navigationController?.isNavigationBarHidden = true |
|
| 32 |
-// titleWithbackBar = "" |
|
| 33 |
- |
|
| 34 |
- } |
|
| 35 |
- |
|
| 36 |
- override func viewDidLayoutSubviews() {
|
|
| 37 |
- if firstLayout {
|
|
| 38 |
- collectionView.contentOffset = CGPoint(x: (CGFloat(currentPhotoIndex) * (collectionView.width)), y: 0) |
|
| 39 |
- firstLayout = false |
|
| 29 |
+ binding() |
|
| 30 |
+ scrollToSpecifiedImage() |
|
| 31 |
+ navigationController?.setNavigationBarHidden(true, animated: true) |
|
| 32 |
+ |
|
| 33 |
+ } |
|
| 34 |
+ |
|
| 35 |
+ func scrollToSpecifiedImage() {
|
|
| 36 |
+ collectionView.layoutIfNeeded() |
|
| 37 |
+ collectionView.scrollToItem(at: IndexPath(item: viewModel.currIndex, section: 0), at: .right, animated: false) |
|
| 38 |
+ } |
|
| 39 |
+ |
|
| 40 |
+ override func viewDidAppear(_ animated: Bool) {
|
|
| 41 |
+ super.viewWillAppear(animated) |
|
| 42 |
+ bindCollectionViewToViewModel() |
|
| 43 |
+ } |
|
| 44 |
+ |
|
| 45 |
+ override func viewWillDisappear(_ animated: Bool) {
|
|
| 46 |
+ super.viewWillDisappear(animated) |
|
| 47 |
+ navigationController?.setNavigationBarHidden(false, animated: true) |
|
| 48 |
+ } |
|
| 49 |
+ |
|
| 50 |
+ @IBAction func download(_ sender: UIButton) {
|
|
| 51 |
+ guard let cell = collectionView.cellForItem(at: IndexPath(item: viewModel.currIndex, section: 0)) as? ImageCell, |
|
| 52 |
+ let image = cell.photoImage.image else {
|
|
| 53 |
+ // FFToastView.showToast(inView: view, withText: "未检测到图片") |
|
| 54 |
+ return |
|
| 40 | 55 |
} |
| 41 |
- super.viewDidLayoutSubviews() |
|
| 56 |
+ |
|
| 57 |
+ UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil) |
|
| 42 | 58 |
} |
| 59 |
+ |
|
| 60 |
+ @objc func image(_ image: UIImage?, didFinishSavingWithError error: NSError?, contextInfo info: UnsafeMutableRawPointer) {
|
|
| 61 |
+ if error != nil {
|
|
| 62 |
+ // FFToastView.showToast(inView: view, withText: "保存图片失败") |
|
| 63 |
+ } else {
|
|
| 64 |
+ // FFToastView.showImageToast(inView: view, withText: "已保存图片到相册", withImage: "提示弹窗-勾") |
|
| 65 |
+ } |
|
| 66 |
+ } |
|
| 67 |
+} |
|
| 68 |
+ |
|
| 69 |
+/// binding |
|
| 70 |
+extension PhotoPreviewViewController {
|
|
| 71 |
+ |
|
| 72 |
+ var dataSource: RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>> {
|
|
| 73 |
+ return RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>>(configureCell: { (dataSource, collectionView, indexPath, item) in
|
|
| 74 |
+ let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! ImageCell |
|
| 75 |
+ cell.setModel(url: item.murl.isEmpty ? item.photo_url : item.murl) |
|
| 76 |
+ return cell |
|
| 77 |
+ }) |
|
| 78 |
+ } |
|
| 79 |
+ |
|
| 80 |
+ func binding() {
|
|
| 81 |
+ bindViewModelToCollectionView() |
|
| 82 |
+ bindCollectionViewDelegate() |
|
| 83 |
+ } |
|
| 84 |
+ |
|
| 85 |
+ func bindViewModelToCollectionView() {
|
|
| 86 |
+ viewModel.content |
|
| 87 |
+ .bind(to: collectionView.rx.items(dataSource: dataSource)) |
|
| 88 |
+ .disposed(by: disposeBag) |
|
| 89 |
+ } |
|
| 90 |
+ |
|
| 91 |
+ func bindCollectionViewDelegate() {
|
|
| 92 |
+ collectionView.rx.setDelegate(self).disposed(by: disposeBag) |
|
| 93 |
+ } |
|
| 94 |
+ |
|
| 95 |
+ func bindCollectionViewToViewModel() {
|
|
| 96 |
+ collectionView.rx.willDisplayCell |
|
| 97 |
+ .asDriver() |
|
| 98 |
+ .drive(onNext: { [unowned self] in self.viewModel.willShow(index: $0.at.row) })
|
|
| 99 |
+ .disposed(by: disposeBag) |
|
| 100 |
+ } |
|
| 101 |
+} |
|
| 43 | 102 |
|
| 44 |
- // MARK: Storyboard button function |
|
| 103 |
+/// storyboard button action |
|
| 104 |
+extension PhotoPreviewViewController {
|
|
| 45 | 105 |
@IBAction func back() {
|
| 46 |
- _ = navigationController?.popViewController(animated: true) |
|
| 47 |
- guard let ctl = navigationController?.viewControllers.last as? PhotoDetailViewController else {
|
|
| 48 |
- return |
|
| 49 |
- } |
|
| 50 |
-// ctl.currentPhotoIndex = currentPageIndex |
|
| 51 |
-// ctl.tableView.reloadData() |
|
| 106 |
+ navigationController?.popViewController(animated: true) |
|
| 52 | 107 |
} |
| 53 | 108 |
@IBAction func rotateTheImage(_ sender: UIButton) {
|
| 54 |
- guard let cell = collectionView.cellForItem(at: IndexPath(item: currentPageIndex, section: 0)) as? ImageCell else {
|
|
| 109 |
+ guard let cell = collectionView.cellForItem(at: IndexPath(item: viewModel.currIndex, section: 0)) as? ImageCell else {
|
|
| 55 | 110 |
return |
| 56 | 111 |
} |
| 57 | 112 |
UIView.beginAnimations("image.rotate", context: nil)
|
@@ -71,54 +126,14 @@ final class ShowFullPicController: UIViewController {
|
||
| 71 | 126 |
} |
| 72 | 127 |
} |
| 73 | 128 |
} |
| 129 |
+ |
|
| 74 | 130 |
|
| 75 |
- @IBAction func load() {
|
|
| 76 |
- guard let cell = collectionView.cellForItem(at: IndexPath(item: currentPageIndex, section: 0)) as? ImageCell else {
|
|
| 77 |
-// FFToastView.showToast(inView: view, withText: "未检测到图片") |
|
| 78 |
- return |
|
| 79 |
- } |
|
| 80 |
- guard let image = cell.photoImage.image else {
|
|
| 81 |
-// FFToastView.showToast(inView: view, withText: "未检测到图片") |
|
| 82 |
- return |
|
| 83 |
- } |
|
| 84 |
- UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil) |
|
| 85 |
- } |
|
| 86 |
- |
|
| 87 |
- @objc func image(_ image: UIImage?, didFinishSavingWithError error: NSError?, contextInfo info: UnsafeMutableRawPointer) {
|
|
| 88 |
- if error != nil {
|
|
| 89 |
-// FFToastView.showToast(inView: view, withText: "保存图片失败") |
|
| 90 |
- } else {
|
|
| 91 |
-// FFToastView.showImageToast(inView: view, withText: "已保存图片到相册", withImage: "提示弹窗-勾") |
|
| 92 |
- } |
|
| 93 |
- |
|
| 94 |
- } |
|
| 95 | 131 |
} |
| 96 | 132 |
|
| 97 | 133 |
// MARK: UICollectionView delegate |
| 98 |
-extension ShowFullPicController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
|
| 99 |
- |
|
| 100 |
- func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
|
| 101 |
- return shufflingImage.count > datas.count ? shufflingImage.count : datas.count |
|
| 102 |
- } |
|
| 103 |
- |
|
| 104 |
- func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
|
| 105 |
- let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! ImageCell |
|
| 106 |
- if shufflingImage.count <= 0 {
|
|
| 107 |
- let data = datas[indexPath.item] |
|
| 108 |
- let urlStr = data.murl.isEmpty ? data.photo_url : data.murl |
|
| 109 |
- cell.setModel(url: urlStr) |
|
| 110 |
- } else {
|
|
| 111 |
- cell.setModel(url: shufflingImage[indexPath.row]) |
|
| 112 |
- } |
|
| 113 |
- return cell |
|
| 114 |
- } |
|
| 134 |
+extension PhotoPreviewViewController: UICollectionViewDelegateFlowLayout {
|
|
| 115 | 135 |
|
| 116 | 136 |
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
|
| 117 | 137 |
return CGSize(width: collectionView.width, height: collectionView.height - 20) |
| 118 | 138 |
} |
| 119 |
- |
|
| 120 |
- func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
|
| 121 |
- let page = Int(scrollView.contentOffset.x / (collectionView.width)) |
|
| 122 |
- currentPageIndex = page |
|
| 123 |
- } |
|
| 124 | 139 |
} |
@@ -9,13 +9,21 @@ |
||
| 9 | 9 |
import UIKit |
| 10 | 10 |
|
| 11 | 11 |
class ShareView: UIView {
|
| 12 |
+ |
|
| 13 |
+} |
|
| 14 |
+ |
|
| 12 | 15 |
|
| 13 |
- /* |
|
| 14 |
- // Only override draw() if you perform custom drawing. |
|
| 15 |
- // An empty implementation adversely affects performance during animation. |
|
| 16 |
- override func draw(_ rect: CGRect) {
|
|
| 17 |
- // Drawing code |
|
| 18 |
- } |
|
| 19 |
- */ |
|
| 20 | 16 |
|
| 17 |
+extension ShareView {
|
|
| 18 |
+ |
|
| 19 |
+ func activateConstraints() {
|
|
| 20 |
+ |
|
| 21 |
+ } |
|
| 22 |
+ |
|
| 23 |
+ func activateConstraintsShareView() {
|
|
| 24 |
+ guard let superView = superview else { return }
|
|
| 25 |
+ |
|
| 26 |
+ self.translatesAutoresizingMaskIntoConstraints = false |
|
| 27 |
+ |
|
| 28 |
+ } |
|
| 21 | 29 |
} |
@@ -1,15 +0,0 @@ |
||
| 1 |
-#!/bin/bash |
|
| 2 |
- |
|
| 3 |
-xcrun simctl shutdown all |
|
| 4 |
- |
|
| 5 |
-path=$(find ~/Library/Developer/Xcode/DerivedData/Paiai-*/Build/Products/Debug-iphonesimulator -name "Paiai.app" | head -n 1) |
|
| 6 |
-echo "${path}"
|
|
| 7 |
- |
|
| 8 |
-filename=MultiSimConfig.txt |
|
| 9 |
-grep -v '^#' $filename | while read -r line |
|
| 10 |
-do |
|
| 11 |
- echo $line |
|
| 12 |
- xcrun instruments -w "$line" |
|
| 13 |
- xcrun simctl install booted $path |
|
| 14 |
- xcrun simctl launch booted com.Paiai.Paiai |
|
| 15 |
-done |