w">
29
|
|
20
|
30
|
public var thumbupItems: Observable<[PhotoThumbupUserItem]> {
|
|
21
|
|
- return _thumbupItems.asObservable()
|
|
|
31
|
+ return itemViewModel.thumbupItems.asObservable()
|
|
22
|
32
|
}
|
|
23
|
33
|
|
|
24
|
34
|
public var commentItems: Observable<[AnimatableSectionModel<Int, PhotoCommentItem>]> {
|
|
25
|
|
- return _commentItems.map ({ model in
|
|
|
35
|
+ return itemViewModel.commentItems.map ({ model in
|
|
26
|
36
|
return [AnimatableSectionModel(model: 0, items: model)]
|
|
27
|
37
|
})
|
|
28
|
38
|
}
|
|
29
|
39
|
|
|
30
|
40
|
public var groupName: Observable<String> {
|
|
31
|
|
- return item.map({ v in
|
|
|
41
|
+ return itemViewModel.item.map({ v in
|
|
32
|
42
|
return v.group_name
|
|
33
|
43
|
})
|
|
34
|
44
|
}
|
|
35
|
45
|
|
|
36
|
46
|
public var groupAvatar: Observable<Int> {
|
|
37
|
|
- return item.map({ v in
|
|
|
47
|
+ return itemViewModel.item.map({ v in
|
|
38
|
48
|
return v.group_default_avatar
|
|
39
|
49
|
})
|
|
40
|
50
|
}
|
|
41
|
51
|
|
|
42
|
52
|
public var userName: Observable<String> {
|
|
43
|
|
- return item.map({ v in
|
|
|
53
|
+ return itemViewModel.item.map({ v in
|
|
44
|
54
|
return v.nickname
|
|
45
|
55
|
})
|
|
46
|
56
|
}
|
|
47
|
57
|
|
|
48
|
58
|
public var userAvatar: Observable<String> {
|
|
49
|
|
- return item.map({ v in
|
|
|
59
|
+ return itemViewModel.item.map({ v in
|
|
50
|
60
|
return v.avatar
|
|
51
|
61
|
})
|
|
52
|
62
|
}
|
|
53
|
63
|
|
|
54
|
64
|
public var photoTime: Observable<String> {
|
|
55
|
|
- return item.map({ v in
|
|
|
65
|
+ return itemViewModel.item.map({ v in
|
|
56
|
66
|
return v.create_at_time_interval
|
|
57
|
67
|
})
|
|
58
|
68
|
}
|
|
59
|
69
|
|
|
60
|
70
|
public var thumbupCount: Observable<String> {
|
|
61
|
|
- return _thumbupItems.map({ v in
|
|
|
71
|
+ return itemViewModel.thumbupItems.map({ v in
|
|
62
|
72
|
return "(\(v.count))"
|
|
63
|
73
|
})
|
|
64
|
74
|
}
|
|
65
|
75
|
|
|
66
|
76
|
public var commentCount: Observable<String> {
|
|
67
|
|
- return _commentItems.map({ v in
|
|
68
|
|
- return "(\(v.count))"
|
|
|
77
|
+ return itemViewModel.commentItems.map({ v in
|
|
|
78
|
+ return "(\(v.count))"
|
|
69
|
79
|
})
|
|
70
|
80
|
}
|
|
71
|
81
|
|
|
72
|
82
|
public var canBuy: Observable<Bool> {
|
|
73
|
|
- return item.map({ v in
|
|
|
83
|
+ return itemViewModel.item.map({ v in
|
|
74
|
84
|
return v.display_payment_btn > 0
|
|
75
|
85
|
})
|
|
76
|
86
|
}
|
|
77
|
87
|
|
|
|
88
|
+ public var watermarkImage: Observable<Bool> {
|
|
|
89
|
+ return _hasGetPrice.asObservable()
|
|
|
90
|
+ }
|
|
|
91
|
+
|
|
|
92
|
+ public var watermarkText: Observable<String> {
|
|
|
93
|
+ return _hasGetPrice.map ({ hasGetPrice in
|
|
|
94
|
+ return hasGetPrice ? "¥\(CGFloat(self.itemViewModel.item.value.nomark) / 100)" : "去除水印"
|
|
|
95
|
+ })
|
|
|
96
|
+ }
|
|
|
97
|
+
|
|
|
98
|
+ public var watermarkTextWithBought: Observable<String> {
|
|
|
99
|
+ return itemViewModel.item.map({ v in
|
|
|
100
|
+ return v.murl.isEmpty ? "去除水印" : "查看无水印照片"
|
|
|
101
|
+ })
|
|
|
102
|
+ }
|
|
|
103
|
+
|
|
|
104
|
+ public var watermarkImageWithBought: Observable<Bool> {
|
|
|
105
|
+ return itemViewModel.item.map({ v in
|
|
|
106
|
+ return !v.murl.isEmpty
|
|
|
107
|
+ })
|
|
|
108
|
+ }
|
|
|
109
|
+
|
|
78
|
110
|
public var isHiddenEnterGroupBtn = BehaviorRelay<Bool>(value: false)
|
|
79
|
111
|
|
|
80
|
112
|
public var viewWillAppear = BehaviorRelay<Void>(value: ())
|
|
81
|
113
|
public weak var delegate: PhotoDetailViewModelDelegate?
|
|
82
|
114
|
|
|
83
|
|
- private var item: BehaviorRelay<PhotoItem>
|
|
84
|
|
- private var _thumbupItems = BehaviorRelay<[PhotoThumbupUserItem]>(value: [])
|
|
85
|
|
- private var _commentItems = BehaviorRelay<[PhotoCommentItem]>(value: [])
|
|
86
|
|
-
|
|
87
|
|
- var repository: PhotoDetailRepository
|
|
|
115
|
+ public var content: Observable<[AnimatableSectionModel<Int, PhotoItem>]> {
|
|
|
116
|
+ return items.map({ model in
|
|
|
117
|
+ return [AnimatableSectionModel(model: 0, items: model)]
|
|
|
118
|
+ })
|
|
|
119
|
+ }
|
|
|
120
|
+
|
|
|
121
|
+ public init(items: [PhotoItem], currIndex: Int) {
|
|
|
122
|
+ self.items = BehaviorRelay<[PhotoItem]>(value: items)
|
|
|
123
|
+ self.currIndex = currIndex
|
|
|
124
|
+ self.itemViewModel = PhotoDetailItemViewModel(item: items[currIndex])
|
|
|
125
|
+ self.purchaseViewModel = PhotoPurchaseViewModel(item: items[currIndex])
|
|
|
126
|
+ }
|
|
88
|
127
|
|
|
89
|
|
- var disposeBag = DisposeBag()
|
|
90
|
|
-
|
|
91
|
|
- public init(item: PhotoItem) {
|
|
92
|
|
- self.item = BehaviorRelay<PhotoItem>(value: item)
|
|
93
|
|
- repository = PhotoDetailRepository(photoId: item.photo_id, groupId: item.group_id)
|
|
|
128
|
+ public func willShow(index: Int) {
|
|
|
129
|
+ currIndex = index
|
|
|
130
|
+ _hasGetPrice.accept(false)
|
|
|
131
|
+ itemViewModel.item.accept(items.value[index])
|
|
|
132
|
+ purchaseViewModel.switchItem(item: items.value[index])
|
|
94
|
133
|
|
|
95
|
|
- self.item.subscribe(onNext: {[unowned self] (photoItem) in
|
|
96
|
|
- self.repository = PhotoDetailRepository(photoId: photoItem.photo_id, groupId: photoItem.group_id)
|
|
97
|
|
- self.loadCommentItems()
|
|
98
|
|
- self.loadThumbupUserItems()
|
|
99
|
|
- }).disposed(by: disposeBag)
|
|
|
134
|
+ purchaseViewModel.notifyPhotoChanged.subscribe(onNext: payDidFinish(item:)).disposed(by: disposeBag)
|
|
100
|
135
|
}
|
|
101
|
136
|
|
|
102
|
|
- private func loadThumbupUserItems() {
|
|
103
|
|
- repository.loadThumbups().subscribe(onSuccess: { (items) in
|
|
104
|
|
- self._thumbupItems.accept(items)
|
|
105
|
|
- }).disposed(by: disposeBag)
|
|
|
137
|
+ public func submitThumbup() {
|
|
|
138
|
+ itemViewModel.submitThumbup()
|
|
106
|
139
|
}
|
|
107
|
140
|
|
|
108
|
|
- private func loadCommentItems() {
|
|
109
|
|
- repository.loadComments().subscribe(onSuccess: { (items) in
|
|
110
|
|
- self._commentItems.accept(items)
|
|
111
|
|
- }).disposed(by: disposeBag)
|
|
|
141
|
+ public func submitComment(text: String) {
|
|
|
142
|
+ itemViewModel.submitComment(text: text)
|
|
112
|
143
|
}
|
|
113
|
|
-
|
|
114
|
|
- public final func submitThumbup() {
|
|
115
|
|
- repository.submitThumbup().subscribe(onSuccess: { items in
|
|
116
|
|
- self._thumbupItems.accept(items)
|
|
117
|
|
- }).disposed(by: disposeBag)
|
|
|
144
|
+
|
|
|
145
|
+ public func purchase() {
|
|
|
146
|
+ if !itemViewModel.item.value.murl.isEmpty {
|
|
|
147
|
+ delegate?.didSelected()
|
|
|
148
|
+ return
|
|
|
149
|
+ }
|
|
|
150
|
+ if !_hasGetPrice.value {
|
|
|
151
|
+ _hasGetPrice.accept(true)
|
|
|
152
|
+ } else {
|
|
|
153
|
+ Toast.showActivity(message: "正在支付")
|
|
|
154
|
+ purchaseViewModel.purchase()
|
|
|
155
|
+ }
|
|
118
|
156
|
}
|
|
119
|
|
-
|
|
120
|
|
- public final func submitComment(text: String) {
|
|
121
|
|
- repository.submitComment(text: text).subscribe(onSuccess: { (items) in
|
|
122
|
|
- self._commentItems.accept(items)
|
|
123
|
|
- }).disposed(by: disposeBag)
|
|
|
157
|
+
|
|
|
158
|
+ public func payDidFinish(item: PhotoItem) {
|
|
|
159
|
+ var originItems = items.value
|
|
|
160
|
+ originItems[currIndex] = item
|
|
|
161
|
+ items.accept(originItems)
|
|
|
162
|
+ itemViewModel.item.accept(item)
|
|
124
|
163
|
}
|
|
125
|
164
|
|
|
126
|
165
|
public func navigateToGroup() {
|
|
127
|
|
- delegate?.navigateToGroup(GroupItem(json: item.value.toJSON() as [String : AnyObject]))
|
|
|
166
|
+ delegate?.navigateToGroup(GroupItem(json: items.value[currIndex].toJSON() as [String : AnyObject]))
|
|
128
|
167
|
}
|
|
129
|
|
-}
|
|
130
|
|
-
|
|
131
|
|
-extension PhotoDetailViewModel: PhotoDetailListViewModelSynchronization {
|
|
132
|
|
- public func willShow(_ item: PhotoItem) {
|
|
133
|
|
- self.item.accept(item)
|
|
|
168
|
+
|
|
|
169
|
+ public func didSelected() {
|
|
|
170
|
+ delegate?.didSelected()
|
|
134
|
171
|
}
|
|
135
|
172
|
}
|
|
|
|
@@ -7,116 +7,58 @@
|
|
7
|
7
|
//
|
|
8
|
8
|
|
|
9
|
9
|
import Foundation
|
|
|
10
|
+import RxSwift
|
|
|
11
|
+import RxCocoa
|
|
10
|
12
|
|
|
11
|
13
|
//wechat pay
|
|
12
|
|
-extension PhotoDetailViewModel {
|
|
13
|
|
- public final func handleResult(errorCode: Int, success: @escaping ((_ item: PhotoItem) -> Void)) {
|
|
14
|
|
- // func fetchOrderDetail() {
|
|
15
|
|
- // detailPageApi.post(param: ["order_id": orderId, "user_id": SharedUserInfo.userId] as [String: AnyObject], url: .orderDetail) { (result) in
|
|
16
|
|
- // guard let status = result["status"] as? Int, let data = result["data"] as? [String: AnyObject], let photoInfo = data["group_photo_info"] as? [String: AnyObject], status == 200 else {
|
|
17
|
|
- //// FFToastView.hideLoadingToast()
|
|
18
|
|
- //// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "")
|
|
19
|
|
- // return
|
|
20
|
|
- // }
|
|
21
|
|
- // let PhotoItem = PhotoItem(map: Map(mappingType: .fromJSON, JSON: photoInfo))
|
|
22
|
|
- // self.currentPhoto.murl = PhotoItem.murl
|
|
23
|
|
- // self.currentPhoto.rurl = PhotoItem.rurl
|
|
24
|
|
- // success(PhotoItem)
|
|
25
|
|
- //// FFToastView.hideLoadingToast()
|
|
26
|
|
- //// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "")
|
|
27
|
|
- //// PhotoLocalStorage.instance.updateLocalData(PhotoItem: PhotoItem)
|
|
28
|
|
- // }
|
|
29
|
|
- // }
|
|
30
|
|
- //// Delay(3) {
|
|
31
|
|
- // let orderQequest = StatusNetworkRequest(param: ["order_id": self.orderId as AnyObject], path: .orderQuery)
|
|
32
|
|
- // self.detailPageApi.post(request: orderQequest, handler: { (res) in
|
|
33
|
|
- // if res.status == 200 {
|
|
34
|
|
- // fetchOrderDetail()
|
|
35
|
|
- // } else {
|
|
36
|
|
- //// FFToastView.hideLoadingToast()
|
|
37
|
|
- //// FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "支付失败")
|
|
38
|
|
- // }
|
|
39
|
|
- // })
|
|
40
|
|
- //// }
|
|
|
14
|
+public class PhotoPurchaseViewModel {
|
|
|
15
|
+ private var purchaseAPI: PhotoPurchaseRemoteAPI
|
|
|
16
|
+ private var disposeBag = DisposeBag()
|
|
|
17
|
+ private var orderId: String = ""
|
|
|
18
|
+
|
|
|
19
|
+ public var notifyPhotoChanged = PublishSubject<PhotoItem>()
|
|
|
20
|
+
|
|
|
21
|
+ public init(item: PhotoItem) {
|
|
|
22
|
+ self.purchaseAPI = PhotoPurchaseRemoteAPI(item: item)
|
|
|
23
|
+
|
|
|
24
|
+ payDidFinish()
|
|
41
|
25
|
}
|
|
42
|
26
|
|
|
43
|
|
- public final func getHD(getPriceSuccess: ((_ isExist: Bool) -> Void)?) {
|
|
44
|
|
- // if !currentPhoto.rurl.isEmpty {
|
|
45
|
|
- // getPriceSuccess!(true)
|
|
46
|
|
- // return
|
|
47
|
|
- // } else {
|
|
48
|
|
- // if hdPrice != -0.01 {
|
|
49
|
|
- // payPrice(photoType: "origin")
|
|
50
|
|
- // } else {
|
|
51
|
|
- // getPrice(photoType: "origin", success: getPriceSuccess)
|
|
52
|
|
- // }
|
|
53
|
|
- // }
|
|
|
27
|
+ public func switchItem(item: PhotoItem) {
|
|
|
28
|
+ self.purchaseAPI = PhotoPurchaseRemoteAPI(item: item)
|
|
54
|
29
|
}
|
|
55
|
30
|
|
|
56
|
|
- public final func getWatermark(getPriceSuccess: ((_ isExist: Bool) -> Void)?) {
|
|
57
|
|
- // if !currentPhoto.murl.isEmpty {
|
|
58
|
|
- // getPriceSuccess!(true)
|
|
59
|
|
- // return
|
|
60
|
|
- // } else {
|
|
61
|
|
- // if watermarkPrice != -0.01 {
|
|
62
|
|
- // payPrice(photoType: "nomark")
|
|
63
|
|
- // } else {
|
|
64
|
|
- // getPrice(photoType: "nomark", success: getPriceSuccess)
|
|
65
|
|
- // }
|
|
66
|
|
- // }
|
|
|
31
|
+ public func purchase() {
|
|
|
32
|
+ purchaseAPI.purchase().subscribe(onSuccess: {[weak self] orderId in
|
|
|
33
|
+ guard let `self` = self else { return }
|
|
|
34
|
+ self.orderId = orderId
|
|
|
35
|
+ }).disposed(by: disposeBag)
|
|
67
|
36
|
}
|
|
68
|
37
|
|
|
69
|
|
- public final func payPrice(photoType: String) {
|
|
70
|
|
- //下单
|
|
71
|
|
- // let body = photoType == "origin" ? "获取高清照片" : "获取去水印照片"
|
|
72
|
|
- // let price = photoType == "origin" ? hdPrice : watermarkPrice
|
|
73
|
|
- // let params = ["user_id": SharedUserInfo.userId, "body": body, "total_fee": price, "trade_type": "APP", "group_id": currentPhoto.group_id, "photo_id": currentPhoto.photo_id, "photo_type": photoType] as [String: AnyObject]
|
|
74
|
|
- // detailPageApi.post(param: params, url: .wxorderCreat) { (result) in
|
|
75
|
|
- //// FFToastView.hideLoadingToast()
|
|
76
|
|
- // guard let status = result["status"] as? Int, let items = result["data"] as? [String: AnyObject], status == 200 else {
|
|
77
|
|
- // return
|
|
78
|
|
- // }
|
|
79
|
|
- // if let orderid = items["order_id"] as? String, let prepay_id = items["prepay_id"] as? String, let wxpay_params = items["wxpay_params"] as? [String: AnyObject], let appid = wxpay_params["appid"] as? String, let noncestr = wxpay_params["noncestr"] as? String, let package = wxpay_params["package"] as? String, let sign = wxpay_params["sign"] as? String, let partnerid = wxpay_params["partnerid"] as? String, let timestamp = wxpay_params["timestamp"] as? String {
|
|
80
|
|
- // //支付
|
|
81
|
|
- // self.orderId = orderid
|
|
82
|
|
- // #if !((arch(i386) || arch(x86_64)))
|
|
83
|
|
- // guard WXApi.isWXAppInstalled() else {
|
|
84
|
|
- // FFToastView.showToast(inView: UIApplication.shared.keyWindow!, withText: "尚未安装微信")
|
|
85
|
|
- // return
|
|
86
|
|
- // }
|
|
87
|
|
- //
|
|
88
|
|
- // WXApi.registerApp(appid)
|
|
89
|
|
- // let payRequest = PayReq()
|
|
90
|
|
- // payRequest.openID = appid
|
|
91
|
|
- // payRequest.partnerId = partnerid
|
|
92
|
|
- // payRequest.prepayId = prepay_id
|
|
93
|
|
- // payRequest.package = package
|
|
94
|
|
- // payRequest.nonceStr = noncestr
|
|
95
|
|
- // payRequest.timeStamp = UInt32(timestamp) ?? 0
|
|
96
|
|
- // payRequest.sign = sign
|
|
97
|
|
- // WXApi.send(payRequest)
|
|
98
|
|
- // #endif
|
|
99
|
|
- // }
|
|
100
|
|
- // }
|
|
|
38
|
+ private func payDidFinish() {
|
|
|
39
|
+ NotificationCenter.default.rx.notification(Notification.wxNotification.payDidFinish).subscribe(onNext: { (notification) in
|
|
|
40
|
+ guard let userInfo = notification.userInfo as? [String: Int],
|
|
|
41
|
+ let code = userInfo["code"] else {
|
|
|
42
|
+ Toast.show(message: "支付失败")
|
|
|
43
|
+ return
|
|
|
44
|
+ }
|
|
|
45
|
+
|
|
|
46
|
+ switch code {
|
|
|
47
|
+ case 0:
|
|
|
48
|
+ self.getOrderDetail()
|
|
|
49
|
+ break
|
|
|
50
|
+ case -2:
|
|
|
51
|
+ Toast.show(message: "取消支付")
|
|
|
52
|
+ break
|
|
|
53
|
+ default:
|
|
|
54
|
+ Toast.show(message: "发生未知错误")
|
|
|
55
|
+ }
|
|
|
56
|
+ }).disposed(by: disposeBag)
|
|
101
|
57
|
}
|
|
102
|
58
|
|
|
103
|
|
- public final func getPrice(photoType: String, success: ((_ isExist: Bool) -> Void)?) {
|
|
104
|
|
- // let params = ["user_id": SharedUserInfo.userId, "photo_id": currentPhoto.photo_id, "photo_type": photoType] as [String: AnyObject]
|
|
105
|
|
- // detailPageApi.post(param: params, url: .picPrice) {[weak self] (result) in
|
|
106
|
|
- // guard let status = result["status"] as? Int,
|
|
107
|
|
- // let items = result["data"] as? [String: AnyObject],
|
|
108
|
|
- // status == 200,
|
|
109
|
|
- // let weakself = self else {
|
|
110
|
|
- // return
|
|
111
|
|
- // }
|
|
112
|
|
- // if let price = items["price"] as? Double {
|
|
113
|
|
- // if photoType == "origin"{
|
|
114
|
|
- // weakself.hdPrice = price
|
|
115
|
|
- // } else {
|
|
116
|
|
- // weakself.watermarkPrice = price
|
|
117
|
|
- // }
|
|
118
|
|
- // success!(false)
|
|
119
|
|
- // }
|
|
120
|
|
- // }
|
|
|
59
|
+ private func getOrderDetail() {
|
|
|
60
|
+ purchaseAPI.getOrderDetail(orderId: orderId).subscribe(onSuccess: { item in
|
|
|
61
|
+ self.notifyPhotoChanged.onNext(item)
|
|
|
62
|
+ }).disposed(by: disposeBag)
|
|
121
|
63
|
}
|
|
122
|
64
|
}
|
|
|
|
@@ -77,7 +77,7 @@ public class UserInfoViewModel {
|
|
77
|
77
|
}
|
|
78
|
78
|
|
|
79
|
79
|
public func wxLogin() {
|
|
80
|
|
- repository.guestLogin().subscribe(onSuccess: { (userInfo) in
|
|
|
80
|
+ repository.wxLogin().subscribe(onSuccess: { (userInfo) in
|
|
81
|
81
|
self.shareUserInfo.accept(userInfo)
|
|
82
|
82
|
self._loginCompleted.onNext(())
|
|
83
|
83
|
}) { (error) in
|
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+//
|
|
|
2
|
+// Notification+wxPay.swift
|
|
|
3
|
+// PaiaiDataKit
|
|
|
4
|
+//
|
|
|
5
|
+// Created by ffib on 2019/4/1.
|
|
|
6
|
+// Copyright © 2019 yb. All rights reserved.
|
|
|
7
|
+//
|
|
|
8
|
+
|
|
|
9
|
+import Foundation
|
|
|
10
|
+
|
|
|
11
|
+public extension Notification {
|
|
|
12
|
+ struct wxNotification {
|
|
|
13
|
+ public static let payDidFinish = Notification.Name("WXPayDidFinishNotification")
|
|
|
14
|
+ }
|
|
|
15
|
+}
|
|
|
|
@@ -72,7 +72,7 @@ fileprivate extension AppCoordinator {
|
|
72
|
72
|
func makeMineCoordinator() -> MineCoordinator {
|
|
73
|
73
|
let mineVC = makeMineViewController()
|
|
74
|
74
|
mineVC.userInfoViewModel = shareUserInfoViewModel
|
|
75
|
|
- let mineCoordinator = MineCoordinator(mineVC, navigationController: navigationController)
|
|
|
75
|
+ let mineCoordinator = MineCoordinator(mineVC, navigationController: navigationController, mainViewController: containerViewController)
|
|
76
|
76
|
|
|
77
|
77
|
return mineCoordinator
|
|
78
|
78
|
}
|
|
|
|
@@ -35,11 +35,10 @@ extension GroupCoordinator: GroupViewModelDelegate {
|
|
35
|
35
|
|
|
36
|
36
|
func didSelect(_ items: [PhotoItem], currIndex: Int) {
|
|
37
|
37
|
let ctl = UIStoryboard.photoDetail.instantiateController(PhotoDetailViewController.self)
|
|
38
|
|
- let viewModel = PhotoDetailViewModel(item: items[currIndex])
|
|
|
38
|
+ let viewModel = PhotoDetailViewModel(items: items, currIndex: currIndex)
|
|
39
|
39
|
viewModel.isHiddenEnterGroupBtn.accept(true)
|
|
40
|
40
|
let coordinator = PhotoDetailCoordinator(ctl, nav: navigationController,
|
|
41
|
|
- viewModel: viewModel,
|
|
42
|
|
- listViewModel: PhotoDetailListViewModel(items: items, currIndex: currIndex))
|
|
|
41
|
+ viewModel: viewModel)
|
|
43
|
42
|
coordinators[.photoDetail] = coordinator
|
|
44
|
43
|
coordinator.start()
|
|
45
|
44
|
navigationController.pushViewController(coordinator.photoDetailViewController)
|
|
|
|
@@ -35,8 +35,7 @@ extension HomeCoordinator: HomeViewModelDelegate {
|
|
35
|
35
|
func didSelect(_ items: [PhotoItem], currIndex: Int) {
|
|
36
|
36
|
let ctl = UIStoryboard.photoDetail.instantiateController(PhotoDetailViewController.self)
|
|
37
|
37
|
let coordinator = PhotoDetailCoordinator(ctl, nav: navigationController,
|
|
38
|
|
- viewModel: PhotoDetailViewModel(item: items[currIndex]),
|
|
39
|
|
- listViewModel: PhotoDetailListViewModel(items: items, currIndex: currIndex))
|
|
|
38
|
+ viewModel: PhotoDetailViewModel(items: items, currIndex: currIndex))
|
|
40
|
39
|
coordinators[.photoDetail] = coordinator
|
|
41
|
40
|
coordinator.start()
|
|
42
|
41
|
navigationController.pushViewController(coordinator.photoDetailViewController)
|
|
|
|
@@ -1,11 +1,11 @@
|
|
1
|
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
|
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useSafeAreas="YES" colorMatched="YES">
|
|
|
2
|
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useSafeAreas="YES" colorMatched="YES">
|
|
3
|
3
|
<device id="retina4_7" orientation="portrait">
|
|
4
|
4
|
<adaptation id="fullscreen"/>
|
|
5
|
5
|
</device>
|
|
6
|
6
|
<dependencies>
|
|
7
|
7
|
<deployment identifier="iOS"/>
|
|
8
|
|
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
|
|
|
8
|
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
|
|
9
|
9
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
|
10
|
10
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
11
|
11
|
</dependencies>
|
|
|
|
@@ -43,7 +43,7 @@
|
|
43
|
43
|
</userDefinedRuntimeAttributes>
|
|
44
|
44
|
</imageView>
|
|
45
|
45
|
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="GAH-5d-ArA">
|
|
46
|
|
- <rect key="frame" x="339" y="12" width="24" height="36"/>
|
|
|
46
|
+ <rect key="frame" x="355" y="24" width="8" height="12"/>
|
|
47
|
47
|
</imageView>
|
|
48
|
48
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="群名称" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Bx9-cB-B0U">
|
|
49
|
49
|
<rect key="frame" x="70" y="6" width="49" height="19.5"/>
|
|
|
|
@@ -60,7 +60,7 @@
|
|
60
|
60
|
<nil key="highlightedColor"/>
|
|
61
|
61
|
</label>
|
|
62
|
62
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="有0张照片" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="aOD-P8-U4F">
|
|
63
|
|
- <rect key="frame" x="271" y="22" width="62" height="16"/>
|
|
|
63
|
+ <rect key="frame" x="287" y="22" width="62" height="16"/>
|
|
64
|
64
|
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
|
65
|
65
|
<color key="textColor" red="0.29411764709999999" green="0.29411764709999999" blue="0.29411764709999999" alpha="1" colorSpace="calibratedRGB"/>
|
|
66
|
66
|
<nil key="highlightedColor"/>
|
|
|
|
@@ -213,7 +213,7 @@
|
|
213
|
213
|
<nil key="highlightedColor"/>
|
|
214
|
214
|
</label>
|
|
215
|
215
|
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="MgR-ta-3jg">
|
|
216
|
|
- <rect key="frame" x="341" y="6" width="24" height="36"/>
|
|
|
216
|
+ <rect key="frame" x="357" y="18" width="8" height="12"/>
|
|
217
|
217
|
</imageView>
|
|
218
|
218
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="L1g-sb-a5F">
|
|
219
|
219
|
<rect key="frame" x="0.0" y="0.0" width="375" height="48"/>
|
|
|
|
@@ -248,7 +248,7 @@
|
|
248
|
248
|
<nil key="highlightedColor"/>
|
|
249
|
249
|
</label>
|
|
250
|
250
|
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="vLw-Zd-Mis">
|
|
251
|
|
- <rect key="frame" x="341" y="6" width="24" height="36"/>
|
|
|
251
|
+ <rect key="frame" x="357" y="18" width="8" height="12"/>
|
|
252
|
252
|
</imageView>
|
|
253
|
253
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FIE-jb-ZGu">
|
|
254
|
254
|
<rect key="frame" x="0.0" y="0.0" width="375" height="48"/>
|
|
|
|
@@ -283,7 +283,7 @@
|
|
283
|
283
|
<nil key="highlightedColor"/>
|
|
284
|
284
|
</label>
|
|
285
|
285
|
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="list-arrow" translatesAutoresizingMaskIntoConstraints="NO" id="mhJ-Uj-tdj">
|
|
286
|
|
- <rect key="frame" x="341" y="6" width="24" height="36"/>
|
|
|
286
|
+ <rect key="frame" x="357" y="18" width="8" height="12"/>
|
|
287
|
287
|
</imageView>
|
|
288
|
288
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="VGv-oO-leT">
|
|
289
|
289
|
<rect key="frame" x="0.0" y="0.0" width="375" height="48"/>
|
|
|
|
@@ -539,6 +539,9 @@
|
|
539
|
539
|
<state key="normal" title="登出" image="BTN-logout">
|
|
540
|
540
|
<color key="titleColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
|
541
|
541
|
</state>
|
|
|
542
|
+ <connections>
|
|
|
543
|
+ <action selector="loginOutAction:" destination="Kfp-Vc-gX5" eventType="touchUpInside" id="P1V-ug-XRT"/>
|
|
|
544
|
+ </connections>
|
|
542
|
545
|
</button>
|
|
543
|
546
|
</subviews>
|
|
544
|
547
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
|
|
|
@@ -577,7 +580,6 @@
|
|
577
|
580
|
</view>
|
|
578
|
581
|
<connections>
|
|
579
|
582
|
<outlet property="headerImageView" destination="diQ-B5-xB7" id="BrO-2N-Srv"/>
|
|
580
|
|
- <outlet property="logoutBtn" destination="uFJ-qP-CrW" id="VHg-fH-Znk"/>
|
|
581
|
583
|
<outlet property="mineView" destination="Jhj-pW-9Bq" id="DAA-ov-Pzt"/>
|
|
582
|
584
|
<outlet property="nickNameLabel" destination="59p-Cg-joQ" id="a4i-ff-np8"/>
|
|
583
|
585
|
<outlet property="tableView" destination="79F-2W-LpP" id="tPr-Iw-4MA"/>
|
|
|
|
@@ -589,14 +591,14 @@
|
|
589
|
591
|
</scene>
|
|
590
|
592
|
</scenes>
|
|
591
|
593
|
<resources>
|
|
592
|
|
- <image name="BTN-logout" width="32" height="32"/>
|
|
|
594
|
+ <image name="BTN-logout" width="48" height="48"/>
|
|
593
|
595
|
<image name="BTN-send" width="608" height="304"/>
|
|
594
|
596
|
<image name="about-contactUs" width="32" height="32"/>
|
|
595
|
597
|
<image name="about-score" width="32" height="32"/>
|
|
596
|
598
|
<image name="about-userAgreement" width="32" height="32"/>
|
|
597
|
|
- <image name="list-arrow" width="24" height="36"/>
|
|
|
599
|
+ <image name="list-arrow" width="8" height="12"/>
|
|
598
|
600
|
<image name="logo" width="140" height="140"/>
|
|
599
|
|
- <image name="navigation-background" width="12" height="132"/>
|
|
|
601
|
+ <image name="navigation-background" width="6" height="66"/>
|
|
600
|
602
|
<image name="默认头像" width="240" height="240"/>
|
|
601
|
603
|
</resources>
|
|
602
|
604
|
</document>
|
|
|
|
@@ -15,11 +15,13 @@ class MineCoordinator: Coordinator {
|
|
15
|
15
|
let mineViewController: MineViewController
|
|
16
|
16
|
let navigationController: UINavigationController
|
|
17
|
17
|
var childCoordinator = [CoordinatorKey: Coordinator]()
|
|
|
18
|
+ let mainViewController: ContainerViewController
|
|
18
|
19
|
// let shareUserInfoViewModel
|
|
19
|
20
|
|
|
20
|
|
- init(_ mineViewController: MineViewController, navigationController: UINavigationController) {
|
|
|
21
|
+ init(_ mineViewController: MineViewController, navigationController: UINavigationController, mainViewController: ContainerViewController) {
|
|
21
|
22
|
self.mineViewController = mineViewController
|
|
22
|
23
|
self.navigationController = navigationController
|
|
|
24
|
+ self.mainViewController = mainViewController
|
|
23
|
25
|
self.mineViewController.delegate = self
|
|
24
|
26
|
}
|
|
25
|
27
|
|
|
|
|
@@ -30,8 +32,11 @@ class MineCoordinator: Coordinator {
|
|
30
|
32
|
|
|
31
|
33
|
extension MineCoordinator: MineViewControllerDelegate {
|
|
32
|
34
|
func logout() {
|
|
|
35
|
+ mineViewController.dismissController()
|
|
|
36
|
+
|
|
33
|
37
|
let vc = makeLoginViewController()
|
|
34
|
|
- navigationController.presentController(vc)
|
|
|
38
|
+ vc.userInfoViewModel = mineViewController.userInfoViewModel
|
|
|
39
|
+ navigationController.addFullScreen(childViewController: vc)
|
|
35
|
40
|
}
|
|
36
|
41
|
|
|
37
|
42
|
func didSelect(_ item: MineItem) {
|
|
|
|
@@ -33,7 +33,6 @@ class MineViewController: SideViewController {
|
|
33
|
33
|
|
|
34
|
34
|
@IBOutlet weak var headerImageView: UIImageView!
|
|
35
|
35
|
@IBOutlet weak var nickNameLabel: UILabel!
|
|
36
|
|
- @IBOutlet weak var logoutBtn: UIButton!
|
|
37
|
36
|
@IBOutlet weak var tableView: UITableView!
|
|
38
|
37
|
@IBOutlet weak var mineView: UIView!
|
|
39
|
38
|
|
|
|
|
@@ -12,23 +12,19 @@ import PaiaiDataKit
|
|
12
|
12
|
final class PhotoDetailCoordinator: Coordinator {
|
|
13
|
13
|
let navigationController: UINavigationController
|
|
14
|
14
|
let photoDetailViewController: PhotoDetailViewController
|
|
15
|
|
- let shareListViewModel: PhotoDetailListViewModel
|
|
|
15
|
+ let shareViewModel: PhotoDetailViewModel
|
|
16
|
16
|
|
|
17
|
17
|
fileprivate var coordinators = [CoordinatorKey: Coordinator]()
|
|
18
|
18
|
|
|
19
|
19
|
init(_ photoDetailVC: PhotoDetailViewController,
|
|
20
|
20
|
nav: UINavigationController,
|
|
21
|
|
- viewModel: PhotoDetailViewModel,
|
|
22
|
|
- listViewModel: PhotoDetailListViewModel) {
|
|
|
21
|
+ viewModel: PhotoDetailViewModel) {
|
|
23
|
22
|
photoDetailViewController = photoDetailVC
|
|
24
|
|
- shareListViewModel = listViewModel
|
|
|
23
|
+ shareViewModel = viewModel
|
|
25
|
24
|
navigationController = nav
|
|
26
|
|
- photoDetailViewController.listViewModel = shareListViewModel
|
|
27
|
25
|
photoDetailViewController.viewModel = viewModel
|
|
28
|
26
|
|
|
29
|
27
|
viewModel.delegate = self
|
|
30
|
|
- shareListViewModel.synchronization = viewModel
|
|
31
|
|
- shareListViewModel.delegate = self
|
|
32
|
28
|
}
|
|
33
|
29
|
|
|
34
|
30
|
func start() {
|
|
|
|
@@ -46,12 +42,10 @@ extension PhotoDetailCoordinator: PhotoDetailViewModelDelegate {
|
|
46
|
42
|
|
|
47
|
43
|
navigationController.pushViewController(vc)
|
|
48
|
44
|
}
|
|
49
|
|
-}
|
|
50
|
|
-
|
|
51
|
|
-extension PhotoDetailCoordinator: PhotoDetailListViewModelDelegate {
|
|
|
45
|
+
|
|
52
|
46
|
func didSelected() {
|
|
53
|
47
|
let vc = UIStoryboard.photoDetail.instantiateController(PhotoPreviewViewController.self)
|
|
54
|
|
- vc.viewModel = shareListViewModel
|
|
|
48
|
+ vc.viewModel = shareViewModel
|
|
55
|
49
|
photoDetailViewController.presentController(vc)
|
|
56
|
50
|
}
|
|
57
|
51
|
}
|
|
|
|
@@ -13,9 +13,6 @@ import RxDataSources
|
|
13
|
13
|
import PaiaiDataKit
|
|
14
|
14
|
import PaiaiUIKit
|
|
15
|
15
|
|
|
16
|
|
-let kPhotographerMark = 1
|
|
17
|
|
-
|
|
18
|
|
-
|
|
19
|
16
|
final class PhotoDetailViewController: UIViewController {
|
|
20
|
17
|
|
|
21
|
18
|
@IBOutlet weak var enterGroupView: UIView!
|
|
|
|
@@ -50,7 +47,6 @@ final class PhotoDetailViewController: UIViewController {
|
|
50
|
47
|
|
|
51
|
48
|
// MARK: data property
|
|
52
|
49
|
var viewModel: PhotoDetailViewModel!
|
|
53
|
|
- var listViewModel: PhotoDetailListViewModel!
|
|
54
|
50
|
|
|
55
|
51
|
let disposeBag = DisposeBag()
|
|
56
|
52
|
|
|
|
|
@@ -90,11 +86,11 @@ extension PhotoDetailViewController {
|
|
90
|
86
|
}
|
|
91
|
87
|
|
|
92
|
88
|
@IBAction func purchase(_ sender: UITapGestureRecognizer) {
|
|
93
|
|
-
|
|
|
89
|
+ viewModel.purchase()
|
|
94
|
90
|
}
|
|
95
|
91
|
|
|
96
|
92
|
@IBAction func enterGroup(_ sender: UITapGestureRecognizer) {
|
|
97
|
|
- self.viewModel.navigateToGroup()
|
|
|
93
|
+ viewModel.navigateToGroup()
|
|
98
|
94
|
}
|
|
99
|
95
|
}
|
|
100
|
96
|
|
|
|
|
@@ -139,7 +135,7 @@ extension PhotoDetailViewController {
|
|
139
|
135
|
var photoCollectionViewDataSource: RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>> {
|
|
140
|
136
|
return RxCollectionViewSectionedAnimatedDataSource<AnimatableSectionModel<Int, PhotoItem>>(configureCell: { (dataSource, collectionView, indexPath, item) in
|
|
141
|
137
|
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoDetailImageCell", for: indexPath) as! PhotoDetailImageCell
|
|
142
|
|
- cell.imageView.setImage(item.photo_thumbnail2_url, placeholder: UIImage.photoPlaceholder)
|
|
|
138
|
+ cell.imageView.setImage(item.murl.isEmpty ? item.photo_thumbnail2_url : item.murl, placeholder: UIImage.photoPlaceholder)
|
|
143
|
139
|
return cell
|
|
144
|
140
|
})
|
|
145
|
141
|
}
|
|
|
|
@@ -168,6 +164,11 @@ extension PhotoDetailViewController {
|
|
168
|
164
|
bindCollectionViewToListViewModel()
|
|
169
|
165
|
bindListViewModelToCollectionView()
|
|
170
|
166
|
|
|
|
167
|
+ bindViewModelToWatermarkImage()
|
|
|
168
|
+ bindViewModelToWatermarkLabel()
|
|
|
169
|
+ bindViewModelToWatermarkImageWithBought()
|
|
|
170
|
+ bindViewModelToWatermarkLabelWithBought()
|
|
|
171
|
+
|
|
171
|
172
|
bindViewWillAppear()
|
|
172
|
173
|
|
|
173
|
174
|
monitorKeyboardWillShow()
|
|
|
|
@@ -244,7 +245,7 @@ extension PhotoDetailViewController {
|
|
244
|
245
|
}
|
|
245
|
246
|
|
|
246
|
247
|
func bindListViewModelToCollectionView() {
|
|
247
|
|
- listViewModel.content
|
|
|
248
|
+ viewModel.content
|
|
248
|
249
|
.bind(to: photoCollectionView.rx.items(dataSource: photoCollectionViewDataSource))
|
|
249
|
250
|
.disposed(by: disposeBag)
|
|
250
|
251
|
}
|
|
|
|
@@ -253,7 +254,7 @@ extension PhotoDetailViewController {
|
|
253
|
254
|
photoCollectionView.rx.willDisplayCell
|
|
254
|
255
|
.asDriver()
|
|
255
|
256
|
.drive(onNext: { [unowned self] in
|
|
256
|
|
- self.listViewModel.willShow(index: $0.at.row)
|
|
|
257
|
+ self.viewModel.willShow(index: $0.at.row)
|
|
257
|
258
|
})
|
|
258
|
259
|
.disposed(by: disposeBag)
|
|
259
|
260
|
}
|
|
|
|
@@ -261,15 +262,31 @@ extension PhotoDetailViewController {
|
|
261
|
262
|
func bindCollectionViewSelected() {
|
|
262
|
263
|
photoCollectionView.rx.itemSelected
|
|
263
|
264
|
.asDriver(onErrorJustReturn: IndexPath(item: 0, section: 0))
|
|
264
|
|
- .drive(onNext: { [unowned self] _ in self.listViewModel.didSelected() })
|
|
|
265
|
+ .drive(onNext: { [unowned self] _ in self.viewModel.didSelected() })
|
|
265
|
266
|
.disposed(by: disposeBag)
|
|
266
|
267
|
}
|
|
267
|
268
|
|
|
|
269
|
+ func bindViewModelToWatermarkImage() {
|
|
|
270
|
+ viewModel.watermarkImage.bind(to: waterMarkImage.rx.isHidden).disposed(by: disposeBag)
|
|
|
271
|
+ }
|
|
|
272
|
+
|
|
|
273
|
+ func bindViewModelToWatermarkLabel() {
|
|
|
274
|
+ viewModel.watermarkText.bind(to: waterMarkLabel.rx.text).disposed(by: disposeBag)
|
|
|
275
|
+ }
|
|
|
276
|
+
|
|
|
277
|
+ func bindViewModelToWatermarkImageWithBought() {
|
|
|
278
|
+ viewModel.watermarkImageWithBought.bind(to: waterMarkImage.rx.isHidden).disposed(by: disposeBag)
|
|
|
279
|
+ }
|
|
|
280
|
+
|
|
|
281
|
+ func bindViewModelToWatermarkLabelWithBought() {
|
|
|
282
|
+ viewModel.watermarkTextWithBought.bind(to: waterMarkLabel.rx.text).disposed(by: disposeBag)
|
|
|
283
|
+ }
|
|
|
284
|
+
|
|
268
|
285
|
func bindViewWillAppear() {
|
|
269
|
286
|
viewModel.viewWillAppear
|
|
270
|
287
|
.asDriver()
|
|
271
|
288
|
.drive(onNext: { [unowned self] _ in
|
|
272
|
|
- self.photoCollectionView.scrollToItem(at: IndexPath(item: self.listViewModel.currIndex, section: 0), at: .right, animated: false)
|
|
|
289
|
+ self.photoCollectionView.scrollToItem(at: IndexPath(item: self.viewModel.currIndex, section: 0), at: .right, animated: false)
|
|
273
|
290
|
})
|
|
274
|
291
|
.disposed(by: disposeBag)
|
|
275
|
292
|
}
|
|
|
|
@@ -17,7 +17,7 @@ final class PhotoPreviewViewController: UIViewController {
|
|
17
|
17
|
|
|
18
|
18
|
/// MARK: Storyboard property
|
|
19
|
19
|
@IBOutlet weak var collectionView: UICollectionView!
|
|
20
|
|
- var viewModel: PhotoDetailListViewModel!
|
|
|
20
|
+ var viewModel: PhotoDetailViewModel!
|
|
21
|
21
|
var disposeBag = DisposeBag()
|
|
22
|
22
|
|
|
23
|
23
|
override var prefersStatusBarHidden: Bool {
|
|
|
|
@@ -29,7 +29,6 @@ final class PhotoPreviewViewController: UIViewController {
|
|
29
|
29
|
binding()
|
|
30
|
30
|
scrollToSpecifiedImage()
|
|
31
|
31
|
navigationController?.setNavigationBarHidden(true, animated: true)
|
|
32
|
|
-
|
|
33
|
32
|
}
|
|
34
|
33
|
|
|
35
|
34
|
func scrollToSpecifiedImage() {
|