From 6a65ee6def7b091a9975c78cfcddb1719197fd1f Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Sat, 14 Oct 2017 11:41:54 -0400 Subject: [PATCH] Pull to refresh on homeview fetches messages. This is useful when you're using censorship circumvention and unable to receive push notifications. // FREEBIE --- Signal/src/AppDelegate.m | 7 +- Signal/src/Jobs/MessageFetcherJob.swift | 64 ++++++++++--------- .../src/ViewControllers/HomeViewController.m | 18 +++++- Signal/src/network/PushManager.m | 4 +- 4 files changed, 57 insertions(+), 36 deletions(-) diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 98ce74c6f..9a1e9459b 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -833,11 +833,12 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; // Fetch messages as soon as possible after launching. In particular, when // launching from the background, without this, we end up waiting some extra // seconds before receiving an actionable push notification. - [[Environment getCurrent].messageFetcherJob runAsync]; + __unused AnyPromise *messagePromise = [[Environment getCurrent].messageFetcherJob run]; // This should happen at any launch, background or foreground. - __unused AnyPromise *promise = [OWSSyncPushTokensJob runWithAccountManager:[Environment getCurrent].accountManager - preferences:[Environment preferences]]; + __unused AnyPromise *pushTokenpromise = + [OWSSyncPushTokensJob runWithAccountManager:[Environment getCurrent].accountManager + preferences:[Environment preferences]]; } [DeviceSleepManager.sharedInstance removeBlockWithBlockObject:self]; diff --git a/Signal/src/Jobs/MessageFetcherJob.swift b/Signal/src/Jobs/MessageFetcherJob.swift index a63696def..fe16808e6 100644 --- a/Signal/src/Jobs/MessageFetcherJob.swift +++ b/Signal/src/Jobs/MessageFetcherJob.swift @@ -8,15 +8,14 @@ import PromiseKit @objc(OWSMessageFetcherJob) class MessageFetcherJob: NSObject { - let TAG = "[MessageFetcherJob]" - var timer: Timer? + private let TAG = "[MessageFetcherJob]" - // MARK: injected dependencies - let networkManager: TSNetworkManager - let messageReceiver: OWSMessageReceiver - let signalService: OWSSignalService + private var timer: Timer? - var runPromises = [Double: Promise]() + // MARK: injected dependencies + private let networkManager: TSNetworkManager + private let messageReceiver: OWSMessageReceiver + private let signalService: OWSSignalService init(messageReceiver: OWSMessageReceiver, networkManager: TSNetworkManager, signalService: OWSSignalService) { self.messageReceiver = messageReceiver @@ -24,53 +23,58 @@ class MessageFetcherJob: NSObject { self.signalService = signalService } - func runAsync() { - Logger.debug("\(TAG) \(#function)") - guard signalService.isCensorshipCircumventionActive else { + public func run() -> Promise { + Logger.debug("\(TAG) in \(#function)") + + guard signalService.isCensorshipCircumventionActive else { Logger.debug("\(self.TAG) delegating message fetching to SocketManager since we're using normal transport.") TSSocketManager.requestSocketOpen() - return + return Promise(value: ()) } - Logger.info("\(TAG) using fallback message fetching.") + Logger.info("\(TAG) fetching messages via REST.") - let promiseId = NSDate().timeIntervalSince1970 - Logger.debug("\(self.TAG) starting promise: \(promiseId)") - let runPromise = self.fetchUndeliveredMessages().then { (envelopes: [OWSSignalServiceProtosEnvelope], more: Bool) -> Void in + let promise = self.fetchUndeliveredMessages().then { (envelopes: [OWSSignalServiceProtosEnvelope], more: Bool) -> Promise in for envelope in envelopes { Logger.info("\(self.TAG) received envelope.") self.messageReceiver.handleReceivedEnvelope(envelope) self.acknowledgeDelivery(envelope: envelope) } + if more { - Logger.info("\(self.TAG) more messages, so recursing.") - // recurse - self.runAsync() + Logger.info("\(self.TAG) fetching more messages.") + return self.run() + } else { + // All finished + return Promise(value: ()) } - }.always { - Logger.debug("\(self.TAG) cleaning up promise: \(promiseId)") - self.runPromises[promiseId] = nil } - // maintain reference to make sure it's not de-alloced prematurely. - runPromises[promiseId] = runPromise + promise.retainUntilComplete() + + return promise + } + + @objc func run() -> AnyPromise { + return AnyPromise(run()) } // use in DEBUG or wherever you can't receive push notifications to poll for messages. // Do not use in production. - func startRunLoop(timeInterval: Double) { + public func startRunLoop(timeInterval: Double) { Logger.error("\(TAG) Starting message fetch polling. This should not be used in production.") timer = WeakTimer.scheduledTimer(timeInterval: timeInterval, target: self, userInfo: nil, repeats: true) {[weak self] _ in - self?.runAsync() + let _: Promise? = self?.run() + return } } - func stopRunLoop() { + public func stopRunLoop() { timer?.invalidate() timer = nil } - func parseMessagesResponse(responseObject: Any?) -> (envelopes: [OWSSignalServiceProtosEnvelope], more: Bool)? { + private func parseMessagesResponse(responseObject: Any?) -> (envelopes: [OWSSignalServiceProtosEnvelope], more: Bool)? { guard let responseObject = responseObject else { Logger.error("\(self.TAG) response object was surpringly nil") return nil @@ -103,7 +107,7 @@ class MessageFetcherJob: NSObject { ) } - func buildEnvelope(messageDict: [String: Any]) -> OWSSignalServiceProtosEnvelope? { + private func buildEnvelope(messageDict: [String: Any]) -> OWSSignalServiceProtosEnvelope? { let builder = OWSSignalServiceProtosEnvelopeBuilder() guard let typeInt = messageDict["type"] as? Int32 else { @@ -156,7 +160,7 @@ class MessageFetcherJob: NSObject { return builder.build() } - func fetchUndeliveredMessages() -> Promise<(envelopes: [OWSSignalServiceProtosEnvelope], more: Bool)> { + private func fetchUndeliveredMessages() -> Promise<(envelopes: [OWSSignalServiceProtosEnvelope], more: Bool)> { return Promise { fulfill, reject in let messagesRequest = OWSGetMessagesRequest() @@ -181,7 +185,7 @@ class MessageFetcherJob: NSObject { } } - func acknowledgeDelivery(envelope: OWSSignalServiceProtosEnvelope) { + private func acknowledgeDelivery(envelope: OWSSignalServiceProtosEnvelope) { let request = OWSAcknowledgeMessageDeliveryRequest(source: envelope.source, timestamp: envelope.timestamp) self.networkManager.makeRequest(request, success: { (_: URLSessionDataTask?, _: Any?) -> Void in diff --git a/Signal/src/ViewControllers/HomeViewController.m b/Signal/src/ViewControllers/HomeViewController.m index f30e923aa..d4c33e35c 100644 --- a/Signal/src/ViewControllers/HomeViewController.m +++ b/Signal/src/ViewControllers/HomeViewController.m @@ -216,6 +216,13 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState }; [emptyBoxLabel autoPinToTopLayoutGuideOfViewController:self withInset:0]; [emptyBoxLabel autoPinToBottomLayoutGuideOfViewController:self withInset:0]; + UIRefreshControl *pullToRefreshView = [UIRefreshControl new]; + pullToRefreshView.tintColor = [UIColor grayColor]; + [pullToRefreshView addTarget:self + action:@selector(pullToRefreshPerformed:) + forControlEvents:UIControlEventValueChanged]; + [self.tableView insertSubview:pullToRefreshView atIndex:0]; + [self updateReminderViews]; } @@ -596,6 +603,16 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState }; return InboxTableViewCell.rowHeight; } +- (void)pullToRefreshPerformed:(UIRefreshControl *)refreshControl +{ + OWSAssert([NSThread isMainThread]); + DDLogInfo(@"%@ beggining refreshing.", self.tag); + [[Environment getCurrent].messageFetcherJob run].always(^{ + DDLogInfo(@"%@ ending refreshing.", self.tag); + [refreshControl endRefreshing]; + }); +} + #pragma mark Table Swipe to Delete - (void)tableView:(UITableView *)tableView @@ -605,7 +622,6 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState }; return; } - - (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewRowAction *deleteAction = diff --git a/Signal/src/network/PushManager.m b/Signal/src/network/PushManager.m index 309599b2d..4b8bce455 100644 --- a/Signal/src/network/PushManager.m +++ b/Signal/src/network/PushManager.m @@ -101,11 +101,11 @@ NSString *const Signal_Message_MarkAsRead_Identifier = @"Signal_Message_MarkAsRe { DDLogInfo(@"%@ received remote notification", self.tag); - [self.messageFetcherJob runAsync]; + [self.messageFetcherJob run]; } - (void)applicationDidBecomeActive { - [self.messageFetcherJob runAsync]; + [self.messageFetcherJob run]; } /**