Skip to content

Commit 1470dd8

Browse files
committed
OrdersVM: Request a resync if we receive a remote push notification
1 parent c8edb70 commit 1470dd8

File tree

4 files changed

+130
-0
lines changed

4 files changed

+130
-0
lines changed

WooCommerce/Classes/ViewRelated/Orders/OrdersViewModel.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,13 @@ final class OrdersViewModel {
2424
}
2525

2626
private let storageManager: StorageManagerType
27+
private let pushNotificationsManager: PushNotesManager
2728
private let notificationCenter: NotificationCenter
2829

30+
/// Used for cancelling the observer for Remote Notifications when `self` is deallocated.
31+
///
32+
private var disposable: ObservationToken?
33+
2934
/// The block called if self requests a resynchronization of the first page.
3035
///
3136
var onShouldResynchronizeAfterAppActivation: (() -> ())?
@@ -84,15 +89,21 @@ final class OrdersViewModel {
8489
}
8590

8691
init(storageManager: StorageManagerType = ServiceLocator.storageManager,
92+
pushNotificationsManager: PushNotesManager = ServiceLocator.pushNotesManager,
8793
notificationCenter: NotificationCenter = .default,
8894
statusFilter: OrderStatus?,
8995
includesFutureOrders: Bool = true) {
9096
self.storageManager = storageManager
97+
self.pushNotificationsManager = pushNotificationsManager
9198
self.notificationCenter = notificationCenter
9299
self.statusFilter = statusFilter
93100
self.includesFutureOrders = includesFutureOrders
94101
}
95102

103+
deinit {
104+
stopObservingForegroundRemoteNotifications()
105+
}
106+
96107
/// Start fetching DB results and forward new changes to the given `tableView`.
97108
///
98109
/// This is the main activation method for this ViewModel. This should only be called once.
@@ -106,6 +117,8 @@ final class OrdersViewModel {
106117
name: UIApplication.willResignActiveNotification, object: nil)
107118
notificationCenter.addObserver(self, selector: #selector(handleAppActivation),
108119
name: UIApplication.didBecomeActiveNotification, object: nil)
120+
121+
observeForegroundRemoteNotifications()
109122
}
110123

111124
/// Execute the `resultsController` query, logging the error if there's any.
@@ -230,6 +243,29 @@ final class OrdersViewModel {
230243
}
231244
}
232245

246+
// MARK: - Remote Notifications Observation
247+
248+
private extension OrdersViewModel {
249+
/// Watch for "new order" Remote Notifications that are received while the app is in the
250+
/// foreground.
251+
///
252+
/// A refresh will be requested when receiving them.
253+
///
254+
func observeForegroundRemoteNotifications() {
255+
disposable = pushNotificationsManager.foregroundNotifications.subscribe { [weak self] notification in
256+
guard notification.kind == .storeOrder else {
257+
return
258+
}
259+
260+
self?.onShouldResynchronizeAfterAppActivation?()
261+
}
262+
}
263+
264+
func stopObservingForegroundRemoteNotifications() {
265+
disposable?.cancel()
266+
}
267+
}
268+
233269
// MARK: - TableView Support
234270

235271
extension OrdersViewModel {

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@
324324
57F34AA12423D45A00E38AFB /* OrdersViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57F34AA02423D45A00E38AFB /* OrdersViewModelTests.swift */; };
325325
6856D2A5C2076F5BF14F2C11 /* KeyboardStateProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6856DCE1638958DA296D690F /* KeyboardStateProviderTests.swift */; };
326326
6856D31F941A33BAE66F394D /* KeyboardFrameAdjustmentProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6856D3846BBF078CB5D955B9 /* KeyboardFrameAdjustmentProvider.swift */; };
327+
6856D49DB7DCF4D87745C0B1 /* MockPushNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6856D249FD1702FE3864950A /* MockPushNotificationsManager.swift */; };
327328
6856D806DE7DB61522D54044 /* NSMutableAttributedStringHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6856D7981E11F85D5E4EFED7 /* NSMutableAttributedStringHelperTests.swift */; };
328329
6856DB2E741639716E149967 /* KeyboardStateProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6856D02484A69911F2B91714 /* KeyboardStateProvider.swift */; };
329330
6856DE479EC3B2265AC1F775 /* Calendar+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6856D66A1963092C34D20674 /* Calendar+Extensions.swift */; };
@@ -1145,6 +1146,7 @@
11451146
57F34AA02423D45A00E38AFB /* OrdersViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrdersViewModelTests.swift; sourceTree = "<group>"; };
11461147
6856D02484A69911F2B91714 /* KeyboardStateProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardStateProvider.swift; sourceTree = "<group>"; };
11471148
6856D1A5F72A36AB3704D19D /* AgeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AgeTests.swift; sourceTree = "<group>"; };
1149+
6856D249FD1702FE3864950A /* MockPushNotificationsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockPushNotificationsManager.swift; sourceTree = "<group>"; };
11481150
6856D3846BBF078CB5D955B9 /* KeyboardFrameAdjustmentProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardFrameAdjustmentProvider.swift; sourceTree = "<group>"; };
11491151
6856D66A1963092C34D20674 /* Calendar+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Calendar+Extensions.swift"; sourceTree = "<group>"; };
11501152
6856D7981E11F85D5E4EFED7 /* NSMutableAttributedStringHelperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSMutableAttributedStringHelperTests.swift; sourceTree = "<group>"; };
@@ -2452,6 +2454,7 @@
24522454
02A275C523FE9EFC005C560F /* MockFeatureFlagService.swift */,
24532455
02B653AB2429F7BF00A9C839 /* MockTaxClassStoresManager.swift */,
24542456
02EA6BFB2435EC3500FFF90A /* MockImageDownloader.swift */,
2457+
6856D249FD1702FE3864950A /* MockPushNotificationsManager.swift */,
24552458
);
24562459
path = Mockups;
24572460
sourceTree = "<group>";
@@ -4872,6 +4875,7 @@
48724875
6856D806DE7DB61522D54044 /* NSMutableAttributedStringHelperTests.swift in Sources */,
48734876
6856DF20E1BDCC391635F707 /* AgeTests.swift in Sources */,
48744877
6856DE479EC3B2265AC1F775 /* Calendar+Extensions.swift in Sources */,
4878+
6856D49DB7DCF4D87745C0B1 /* MockPushNotificationsManager.swift in Sources */,
48754879
);
48764880
runOnlyForDeploymentPostprocessing = 0;
48774881
};
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
2+
import Foundation
3+
import UIKit
4+
@testable import WooCommerce
5+
6+
final class MockPushNotificationsManager: PushNotesManager {
7+
8+
var foregroundNotifications: Observable<ForegroundNotification> {
9+
foregroundNotificationsSubject
10+
}
11+
12+
private let foregroundNotificationsSubject = PublishSubject<ForegroundNotification>()
13+
14+
func resetBadgeCount() {
15+
16+
}
17+
18+
func registerForRemoteNotifications() {
19+
20+
}
21+
22+
func unregisterForRemoteNotifications() {
23+
24+
}
25+
26+
func ensureAuthorizationIsRequested(onCompletion: ((Bool) -> ())?) {
27+
28+
}
29+
30+
func registrationDidFail(with error: Error) {
31+
32+
}
33+
34+
func registerDeviceToken(with tokenData: Data, defaultStoreID: Int64) {
35+
36+
}
37+
38+
func handleNotification(_ userInfo: [AnyHashable: Any], completionHandler: @escaping (UIKit.UIBackgroundFetchResult) -> ()) {
39+
40+
}
41+
}
42+
43+
extension MockPushNotificationsManager {
44+
func sendForegroundNotification(_ notification: ForegroundNotification) {
45+
foregroundNotificationsSubject.send(notification)
46+
}
47+
}
48+

WooCommerce/WooCommerceTests/ViewRelated/Orders/OrdersViewModelTests.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,48 @@ final class OrdersViewModelTests: XCTestCase {
366366
// Assert
367367
XCTAssertFalse(resynchronizeRequested)
368368
}
369+
370+
// MARK: - Foreground Notifications
371+
372+
func testGivenANewOrderNotificationItRequestsAResynchronization() {
373+
// Arrange
374+
let pushNotificationsManager = MockPushNotificationsManager()
375+
let viewModel = OrdersViewModel(pushNotificationsManager: pushNotificationsManager, statusFilter: nil)
376+
377+
var resynchronizeRequested = false
378+
viewModel.onShouldResynchronizeAfterAppActivation = {
379+
resynchronizeRequested = true
380+
}
381+
382+
viewModel.activateAndForwardUpdates(to: UITableView())
383+
384+
// Act
385+
let notification = ForegroundNotification(noteID: 1, kind: .storeOrder, message: "")
386+
pushNotificationsManager.sendForegroundNotification(notification)
387+
388+
// Assert
389+
XCTAssertTrue(resynchronizeRequested)
390+
}
391+
392+
func testGivenANonOrderNotificationItDoesNotRequestAResynchronization() {
393+
// Arrange
394+
let pushNotificationsManager = MockPushNotificationsManager()
395+
let viewModel = OrdersViewModel(pushNotificationsManager: pushNotificationsManager, statusFilter: nil)
396+
397+
var resynchronizeRequested = false
398+
viewModel.onShouldResynchronizeAfterAppActivation = {
399+
resynchronizeRequested = true
400+
}
401+
402+
viewModel.activateAndForwardUpdates(to: UITableView())
403+
404+
// Act
405+
let notification = ForegroundNotification(noteID: 1, kind: .comment, message: "")
406+
pushNotificationsManager.sendForegroundNotification(notification)
407+
408+
// Assert
409+
XCTAssertFalse(resynchronizeRequested)
410+
}
369411
}
370412

371413
// MARK: - Helpers

0 commit comments

Comments
 (0)