Skip to content

Commit a461854

Browse files
committed
Merge branch 'develop' into issue/1988-image-uplad-product-id
# Conflicts: # WooCommerce/Classes/ViewRelated/Products/Media/ProductImageActionHandler.swift
2 parents d365fae + d7328be commit a461854

File tree

26 files changed

+846
-200
lines changed

26 files changed

+846
-200
lines changed

Gemfile.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
GIT
22
remote: https://github.com/wordpress-mobile/release-toolkit
3-
revision: d00351ee4e04d8a5f3305116dab017b2c389b1cf
4-
tag: 0.9.1
3+
revision: e426345db3afc839ee463ec1ce8432f584880957
4+
tag: 0.9.2
55
specs:
6-
fastlane-plugin-wpmreleasetoolkit (0.9.1)
6+
fastlane-plugin-wpmreleasetoolkit (0.9.2)
77
activesupport (~> 4)
88
chroma (= 0.2.0)
99
diffy (~> 3.3)
@@ -198,7 +198,7 @@ GEM
198198
octokit (4.18.0)
199199
faraday (>= 0.9)
200200
sawyer (~> 0.8.0, >= 0.5.3)
201-
oj (3.10.5)
201+
oj (3.10.6)
202202
optimist (3.0.0)
203203
options (2.3.2)
204204
os (1.0.1)

Networking/Networking/Model/Product/Product.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ public struct Product: Codable {
460460
try container.encode(featured, forKey: .featured)
461461
try container.encode(catalogVisibilityKey, forKey: .catalogVisibilityKey)
462462
try container.encode(slug, forKey: .slug)
463+
try container.encode(purchaseNote, forKey: .purchaseNote)
463464
}
464465
}
465466

Podfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ target 'WooCommerce' do
3131

3232
pod 'Gridicons', '~> 1.0'
3333

34-
pod 'WordPressAuthenticator', '~> 1.12.0'
34+
pod 'WordPressAuthenticator', '~> 1.13.0-beta.4'
3535
# To allow pod to pick up beta versions use -beta. E.g., 1.1.7-beta.1
36-
#pod 'WordPressAuthenticator', :git => 'https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git', :branch => ''
37-
#pod 'WordPressAuthenticator', :git => 'https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git', :commit => ''
36+
# pod 'WordPressAuthenticator', :git => 'https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git', :branch => ''
37+
# pod 'WordPressAuthenticator', :git => 'https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git', :commit => ''
3838

3939
# pod 'WordPressShared', :git => 'https://github.com/wordpress-mobile/WordPress-iOS-Shared.git', :branch => ''
4040
pod 'WordPressShared', '~> 1.8.16'

Podfile.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ PODS:
4949
- WordPress-Aztec-iOS (1.11.0)
5050
- WordPress-Editor-iOS (1.11.0):
5151
- WordPress-Aztec-iOS (= 1.11.0)
52-
- WordPressAuthenticator (1.12.0):
52+
- WordPressAuthenticator (1.13.0-beta.4):
5353
- 1PasswordExtension (= 1.8.6)
5454
- Alamofire (= 4.8)
5555
- CocoaLumberjack (~> 3.5)
@@ -101,7 +101,7 @@ DEPENDENCIES:
101101
- KeychainAccess (~> 3.2)
102102
- Kingfisher (~> 5.11.0)
103103
- WordPress-Editor-iOS (~> 1.11.0)
104-
- WordPressAuthenticator (~> 1.12.0)
104+
- WordPressAuthenticator (~> 1.13.0-beta.4)
105105
- WordPressShared (~> 1.8.16)
106106
- WordPressUI (~> 1.5.2)
107107
- Wormholy (~> 1.5.2)
@@ -172,7 +172,7 @@ SPEC CHECKSUMS:
172172
UIDeviceIdentifier: 44f805037d21b94394821828f4fcaba34b38c2d0
173173
WordPress-Aztec-iOS: 050b34d4c3adfb7c60363849049b13d60683b348
174174
WordPress-Editor-iOS: 304098424f1051cb271546c99f906aac296b1b81
175-
WordPressAuthenticator: 593bbdad097e4752cc464ac1c6ef460e1a9801a8
175+
WordPressAuthenticator: d55a86bb181478bb536b3fc8a9dd4eaa7f6bc3e0
176176
WordPressKit: 0602e8188245b3267269570d3d78c138e64a4eba
177177
WordPressShared: 1bc316ed162f42af4e0fa2869437e9e28b532b01
178178
WordPressUI: 70cc58a253c352330b23cd8fa6dd6a2021570e18
@@ -188,6 +188,6 @@ SPEC CHECKSUMS:
188188
ZendeskSupportProvidersSDK: e183d32abac888c448469e2005c4a5a8c3ed73f0
189189
ZendeskSupportSDK: e52f37fa8bcba91f024b81025869fe5a2860f741
190190

191-
PODFILE CHECKSUM: ea2d66e1c363926ebf17e44164fd4f687a973e0c
191+
PODFILE CHECKSUM: 1fdc82d9f06d4aef1372b814f6a800315cf8d526
192192

193193
COCOAPODS: 1.9.1

WooCommerce/Classes/ViewRelated/Orders/Order Details/Order Notes Section/Add Order Note/NewNoteViewController.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ private extension NewNoteViewController {
140140
NSLocalizedString("Private note",
141141
comment: "Spoken accessibility label for an icon image that indicates it's a private note and is not seen by the customer.")
142142

143-
cell.onTextChange = { [weak self] (text) in
143+
cell.noteTextView.onTextChange = { [weak self] (text) in
144144
self?.navigationItem.rightBarButtonItem?.isEnabled = !text.isEmpty
145145
self?.noteText = text
146146
}

WooCommerce/Classes/ViewRelated/Orders/OrdersViewController.swift

Lines changed: 21 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class OrdersViewController: UIViewController {
2222

2323
weak var delegate: OrdersViewControllerDelegate?
2424

25-
private lazy var viewModel = OrdersViewModel()
25+
private let viewModel: OrdersViewModel
2626

2727
/// Main TableView.
2828
///
@@ -46,15 +46,6 @@ class OrdersViewController: UIViewController {
4646
return FooterSpinnerView(tableViewStyle: tableView.style)
4747
}()
4848

49-
/// ResultsController: Surrounds us. Binds the galaxy together. And also, keeps the UITableView <> (Stored) Orders in sync.
50-
///
51-
private lazy var resultsController: ResultsController<StorageOrder> = {
52-
let storageManager = ServiceLocator.storageManager
53-
let descriptor = NSSortDescriptor(keyPath: \StorageOrder.dateCreated, ascending: false)
54-
55-
return ResultsController<StorageOrder>(storageManager: storageManager, sectionNameKeyPath: "normalizedAgeAsString", sortedBy: [descriptor])
56-
}()
57-
5849
/// Used for looking up the `OrderStatus` to show in the `OrderTableViewCell`.
5950
///
6051
/// The `OrderStatus` data is fetched from the API by `OrdersMasterViewModel`.
@@ -70,28 +61,12 @@ class OrdersViewController: UIViewController {
7061
///
7162
private let syncingCoordinator = SyncingCoordinator()
7263

73-
/// OrderStatus that must be matched by retrieved orders.
74-
///
75-
private let statusFilter: OrderStatus?
76-
7764
/// The current list of order statuses for the default site
7865
///
7966
private var currentSiteStatuses: [OrderStatus] {
8067
return statusResultsController.fetchedObjects
8168
}
8269

83-
/// Indicates if there are no results onscreen.
84-
///
85-
private var isEmpty: Bool {
86-
return resultsController.isEmpty
87-
}
88-
89-
/// Indicates if there's a filter being applied.
90-
///
91-
private var isFiltered: Bool {
92-
return statusFilter != nil
93-
}
94-
9570
/// UI Active State
9671
///
9772
private var state: State = .results {
@@ -112,7 +87,7 @@ class OrdersViewController: UIViewController {
11287
/// - Parameter statusFilter The filter to use.
11388
///
11489
init(title: String, statusFilter: OrderStatus? = nil) {
115-
self.statusFilter = statusFilter
90+
viewModel = OrdersViewModel(statusFilter: statusFilter)
11691

11792
super.init(nibName: Self.nibName, bundle: nil)
11893

@@ -126,7 +101,6 @@ class OrdersViewController: UIViewController {
126101
override func viewDidLoad() {
127102
super.viewDidLoad()
128103

129-
refreshResultsPredicate()
130104
refreshStatusPredicate()
131105
registerTableViewHeadersAndCells()
132106

@@ -135,6 +109,8 @@ class OrdersViewController: UIViewController {
135109
configureGhostableTableView()
136110
configureResultsControllers()
137111

112+
configureViewModel()
113+
138114
startListeningToNotifications()
139115
}
140116

@@ -153,24 +129,10 @@ class OrdersViewController: UIViewController {
153129
// MARK: - User Interface Initialization
154130
//
155131
private extension OrdersViewController {
156-
/// Setup: Order filtering
132+
/// Initialize ViewModel operations
157133
///
158-
func refreshResultsPredicate() {
159-
resultsController.predicate = {
160-
let excludeSearchCache = NSPredicate(format: "exclusiveForSearch = false")
161-
let excludeNonMatchingStatus = statusFilter.map { NSPredicate(format: "statusKey = %@", $0.slug) }
162-
163-
var predicates = [ excludeSearchCache, excludeNonMatchingStatus ].compactMap { $0 }
164-
if let tomorrow = Date.tomorrow() {
165-
let dateSubPredicate = NSPredicate(format: "dateCreated < %@", tomorrow as NSDate)
166-
predicates.append(dateSubPredicate)
167-
}
168-
169-
return NSCompoundPredicate(andPredicateWithSubpredicates: predicates)
170-
}()
171-
172-
tableView.setContentOffset(.zero, animated: false)
173-
tableView.reloadData()
134+
func configureViewModel() {
135+
viewModel.activateAndForwardUpdates(to: tableView)
174136
}
175137

176138
/// Setup: Order status predicate
@@ -192,10 +154,6 @@ private extension OrdersViewController {
192154
/// Setup: Results Controller
193155
///
194156
func configureResultsControllers() {
195-
// Orders FRC
196-
resultsController.startForwardingEvents(to: tableView)
197-
try? resultsController.performFetch()
198-
199157
// Order status FRC
200158
try? statusResultsController.performFetch()
201159
}
@@ -302,7 +260,6 @@ extension OrdersViewController: SyncingCoordinatorDelegate {
302260

303261
let action = viewModel.synchronizationAction(
304262
siteID: siteID,
305-
statusKey: statusFilter?.slug,
306263
pageNumber: pageNumber,
307264
pageSize: pageSize,
308265
reason: SyncReason(rawValue: reason ?? "")) { [weak self] error in
@@ -314,7 +271,8 @@ extension OrdersViewController: SyncingCoordinatorDelegate {
314271
DDLogError("⛔️ Error synchronizing orders: \(error)")
315272
self.displaySyncingErrorNotice(pageNumber: pageNumber, pageSize: pageSize, reason: reason)
316273
} else {
317-
ServiceLocator.analytics.track(.ordersListLoaded, withProperties: ["status": self.statusFilter?.slug ?? String()])
274+
let status = self.viewModel.statusFilter?.slug ?? String()
275+
ServiceLocator.analytics.track(.ordersListLoaded, withProperties: ["status": status])
318276
}
319277

320278
self.transitionToResultsUpdatedState()
@@ -347,7 +305,7 @@ extension OrdersViewController {
347305
return false
348306
}
349307

350-
return highestPageBeingSynced * SyncingCoordinator.Defaults.pageSize > resultsController.numberOfObjects
308+
return highestPageBeingSynced * SyncingCoordinator.Defaults.pageSize > viewModel.numberOfObjects
351309
}
352310

353311
/// Stops animating the Footer Spinner.
@@ -452,12 +410,6 @@ private extension OrdersViewController {
452410
//
453411
private extension OrdersViewController {
454412

455-
func detailsViewModel(at indexPath: IndexPath) -> OrderDetailsViewModel {
456-
let order = resultsController.object(at: indexPath)
457-
458-
return OrderDetailsViewModel(order: order)
459-
}
460-
461413
func lookUpOrderStatus(for order: Order) -> OrderStatus? {
462414
for orderStatus in currentSiteStatuses where orderStatus.slug == order.statusKey {
463415
return orderStatus
@@ -473,21 +425,21 @@ private extension OrdersViewController {
473425
extension OrdersViewController: UITableViewDataSource {
474426

475427
func numberOfSections(in tableView: UITableView) -> Int {
476-
return resultsController.sections.count
428+
viewModel.numberOfSections
477429
}
478430

479431
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
480-
return resultsController.sections[section].numberOfObjects
432+
viewModel.numberOfRows(in: section)
481433
}
482434

483435
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
484436
guard let cell = tableView.dequeueReusableCell(withIdentifier: OrderTableViewCell.reuseIdentifier, for: indexPath) as? OrderTableViewCell else {
485437
fatalError()
486438
}
487439

488-
let viewModel = detailsViewModel(at: indexPath)
489-
let orderStatus = lookUpOrderStatus(for: viewModel.order)
490-
cell.configureCell(viewModel: viewModel, orderStatus: orderStatus)
440+
let detailsViewModel = viewModel.detailsViewModel(at: indexPath)
441+
let orderStatus = lookUpOrderStatus(for: detailsViewModel.order)
442+
cell.configureCell(viewModel: detailsViewModel, orderStatus: orderStatus)
491443
cell.layoutIfNeeded()
492444
return cell
493445
}
@@ -499,7 +451,7 @@ extension OrdersViewController: UITableViewDataSource {
499451
}
500452

501453
header.leftText = {
502-
let rawAge = resultsController.sections[section].name
454+
let rawAge = viewModel.sectionInfo(at: section).name
503455
return Age(rawValue: rawAge)?.description
504456
}()
505457
header.rightText = nil
@@ -524,13 +476,13 @@ extension OrdersViewController: UITableViewDelegate {
524476
assertionFailure("Expected OrderDetailsViewController to be instantiated")
525477
return
526478
}
527-
orderDetailsVC.viewModel = detailsViewModel(at: indexPath)
479+
orderDetailsVC.viewModel = viewModel.detailsViewModel(at: indexPath)
528480

529481
navigationController?.pushViewController(orderDetailsVC, animated: true)
530482
}
531483

532484
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
533-
let orderIndex = resultsController.objectIndex(from: indexPath)
485+
let orderIndex = viewModel.objectIndex(from: indexPath)
534486
syncingCoordinator.ensureNextPageIsSynchronized(lastVisibleIndex: orderIndex)
535487
}
536488
}
@@ -590,19 +542,19 @@ private extension OrdersViewController {
590542
/// we've got cached results, or not.
591543
///
592544
func transitionToSyncingState() {
593-
state = isEmpty ? .placeholder : .syncing
545+
state = viewModel.isEmpty ? .placeholder : .syncing
594546
}
595547

596548
/// Should be called whenever the results are updated: after Sync'ing (or after applying a filter).
597549
/// Transitions to `.results` / `.emptyFiltered` / `.emptyUnfiltered` accordingly.
598550
///
599551
func transitionToResultsUpdatedState() {
600-
if isEmpty == false {
552+
if viewModel.isEmpty == false {
601553
state = .results
602554
return
603555
}
604556

605-
if isFiltered {
557+
if viewModel.isFiltered {
606558
state = .emptyFiltered
607559
return
608560
}

0 commit comments

Comments
 (0)