Add PN mode sheet & fix unsubscribing

This commit is contained in:
nielsandriesse 2020-04-16 13:58:43 +10:00
parent c596d5b2a3
commit cbc94dad70
10 changed files with 251 additions and 145 deletions

View File

@ -624,6 +624,8 @@
B9EB5ABD1884C002007CBB57 /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9EB5ABC1884C002007CBB57 /* MessageUI.framework */; };
BFF3FB9730634F37D25903F4 /* Pods_Signal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D17BB5C25D615AB49813100C /* Pods_Signal.framework */; };
C34C8F7423A7830B00D82669 /* SpaceMono-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C34C8F7323A7830A00D82669 /* SpaceMono-Bold.ttf */; };
C353F8F7244808E90011121A /* PNModeSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C353F8F6244808E90011121A /* PNModeSheet.swift */; };
C353F8F9244809150011121A /* PNOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C353F8F8244809150011121A /* PNOptionView.swift */; };
C3548F0624456447009433A8 /* PNModeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3548F0524456447009433A8 /* PNModeVC.swift */; };
C3548F0824456AB6009433A8 /* UIView+Wrapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */; };
C354E75A23FE2A7600CE22E3 /* BaseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C354E75923FE2A7600CE22E3 /* BaseVC.swift */; };
@ -1501,6 +1503,8 @@
B97940261832BD2400BD66CB /* UIUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIUtil.m; sourceTree = "<group>"; };
B9EB5ABC1884C002007CBB57 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; };
C34C8F7323A7830A00D82669 /* SpaceMono-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SpaceMono-Bold.ttf"; sourceTree = "<group>"; };
C353F8F6244808E90011121A /* PNModeSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNModeSheet.swift; sourceTree = "<group>"; };
C353F8F8244809150011121A /* PNOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNOptionView.swift; sourceTree = "<group>"; };
C3548F0524456447009433A8 /* PNModeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNModeVC.swift; sourceTree = "<group>"; };
C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Wrapping.swift"; sourceTree = "<group>"; };
C354E75923FE2A7600CE22E3 /* BaseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseVC.swift; sourceTree = "<group>"; };
@ -2877,6 +2881,7 @@
B8B26C8E234D629C004ED98C /* MentionCandidateSelectionView.swift */,
B8B26C90234D8CBD004ED98C /* MentionCandidateSelectionViewDelegate.swift */,
B83F2B85240C7B8F000A54AB /* NewConversationButtonSet.swift */,
C353F8F8244809150011121A /* PNOptionView.swift */,
B8BB82B02390C37000BA5194 /* SearchBar.swift */,
B85357BE23A1AE0800AAF6CD /* SeedReminderView.swift */,
B85357C023A1B81900AAF6CD /* SeedReminderViewDelegate.swift */,
@ -2922,6 +2927,7 @@
B8CCF63623961D6D0091D419 /* NewPrivateChatVC.swift */,
B894D0742339EDCF00B4D94D /* NukeDataModal.swift */,
C3DFFAC723E970080058DAF8 /* OpenGroupSuggestionSheet.swift */,
C353F8F6244808E90011121A /* PNModeSheet.swift */,
C3548F0524456447009433A8 /* PNModeVC.swift */,
B886B4A62398B23E00211ABE /* QRCodeVC.swift */,
B82B408B239A068800A248E7 /* RegisterVC.swift */,
@ -4101,6 +4107,7 @@
B82584A02315024B001B41CB /* LokiRSSFeedPoller.swift in Sources */,
24A830A22293CD0100F4CAC0 /* LokiP2PServer.swift in Sources */,
349ED990221B0194008045B0 /* Onboarding2FAViewController.swift in Sources */,
C353F8F7244808E90011121A /* PNModeSheet.swift in Sources */,
45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */,
340FC8A9204DAC8D007AEB0F /* NotificationSettingsOptionsViewController.m in Sources */,
C3548F0624456447009433A8 /* PNModeVC.swift in Sources */,
@ -4199,6 +4206,7 @@
340FC8BB204DAC8D007AEB0F /* OWSAddToContactViewController.m in Sources */,
45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */,
452C468F1E427E200087B011 /* OutboundCallInitiator.swift in Sources */,
C353F8F9244809150011121A /* PNOptionView.swift in Sources */,
B82B4094239DF15900A248E7 /* ConversationTitleView.swift in Sources */,
34D2CCDA2062E7D000CB1A14 /* OWSScreenLockUI.m in Sources */,
45F170BB1E2FC5D3003FC1F2 /* CallAudioService.swift in Sources */,

View File

@ -590,7 +590,9 @@ static BOOL isInternalTestVersion = NO;
OWSLogInfo(@"Registering for push notifications with token: %@.", deviceToken);
BOOL isUsingFullAPNs = [NSUserDefaults.standardUserDefaults boolForKey:@"isUsingFullAPNs"];
if (isUsingFullAPNs) {
[LKPushNotificationManager registerWithToken:deviceToken hexEncodedPublicKey:self.tsAccountManager.localNumber];
__unused AnyPromise *promise = [LKPushNotificationManager registerWithToken:deviceToken hexEncodedPublicKey:self.tsAccountManager.localNumber];
} else {
__unused AnyPromise *promise = [LKPushNotificationManager registerWithToken:deviceToken];
}
}

View File

@ -0,0 +1,106 @@
final class OptionView : UIView {
private let title: String
private let explanation: String
private let delegate: OptionViewDelegate
private let isRecommended: Bool
var isSelected = false { didSet { handleIsSelectedChanged() } }
init(title: String, explanation: String, delegate: OptionViewDelegate, isRecommended: Bool = false) {
self.title = title
self.explanation = explanation
self.delegate = delegate
self.isRecommended = isRecommended
super.init(frame: CGRect.zero)
setUpViewHierarchy()
}
override init(frame: CGRect) {
preconditionFailure("Use init(string:explanation:) instead.")
}
required init?(coder: NSCoder) {
preconditionFailure("Use init(string:explanation:) instead.")
}
private func setUpViewHierarchy() {
backgroundColor = Colors.pnOptionBackground
// Round corners
layer.cornerRadius = Values.pnOptionCornerRadius
// Set up border
layer.borderWidth = Values.borderThickness
layer.borderColor = Colors.pnOptionBorder.cgColor
// Set up shadow
layer.shadowColor = UIColor.black.cgColor
layer.shadowOffset = CGSize(width: 0, height: 0.8)
layer.shadowOpacity = isLightMode ? 0.4 : 1
layer.shadowRadius = isLightMode ? 4 : 6
// Set up title label
let titleLabel = UILabel()
titleLabel.textColor = Colors.text
titleLabel.font = .boldSystemFont(ofSize: Values.mediumFontSize)
titleLabel.text = title
titleLabel.numberOfLines = 0
titleLabel.lineBreakMode = .byWordWrapping
// Set up explanation label
let explanationLabel = UILabel()
explanationLabel.textColor = Colors.text
explanationLabel.font = .systemFont(ofSize: Values.verySmallFontSize)
explanationLabel.text = explanation
explanationLabel.numberOfLines = 0
explanationLabel.lineBreakMode = .byWordWrapping
// Set up stack view
let stackView = UIStackView(arrangedSubviews: [ titleLabel, explanationLabel ])
stackView.axis = .vertical
stackView.spacing = 4
stackView.alignment = .fill
addSubview(stackView)
stackView.pin(.leading, to: .leading, of: self, withInset: 12)
stackView.pin(.top, to: .top, of: self, withInset: 12)
self.pin(.trailing, to: .trailing, of: stackView, withInset: 12)
self.pin(.bottom, to: .bottom, of: stackView, withInset: 12)
// Set up recommended label if needed
if isRecommended {
let recommendedLabel = UILabel()
recommendedLabel.textColor = Colors.accent
recommendedLabel.font = .boldSystemFont(ofSize: Values.verySmallFontSize)
recommendedLabel.text = NSLocalizedString("Recommended", comment: "")
stackView.addArrangedSubview(recommendedLabel)
}
// Set up tap gesture recognizer
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
addGestureRecognizer(tapGestureRecognizer)
}
@objc private func handleTap() {
isSelected = !isSelected
}
private func handleIsSelectedChanged() {
let animationDuration: TimeInterval = 0.25
// Animate border color
let newBorderColor = isSelected ? Colors.accent.cgColor : Colors.pnOptionBorder.cgColor
let borderAnimation = CABasicAnimation(keyPath: "borderColor")
borderAnimation.fromValue = layer.shadowColor
borderAnimation.toValue = newBorderColor
borderAnimation.duration = animationDuration
layer.add(borderAnimation, forKey: borderAnimation.keyPath)
layer.borderColor = newBorderColor
// Animate shadow color
let newShadowColor = isSelected ? Colors.newConversationButtonShadow.cgColor : UIColor.black.cgColor
let shadowAnimation = CABasicAnimation(keyPath: "shadowColor")
shadowAnimation.fromValue = layer.shadowColor
shadowAnimation.toValue = newShadowColor
shadowAnimation.duration = animationDuration
layer.add(shadowAnimation, forKey: shadowAnimation.keyPath)
layer.shadowColor = newShadowColor
// Notify delegate
if isSelected { delegate.optionViewDidActivate(self) }
}
}
// MARK: Option View Delegate
protocol OptionViewDelegate {
func optionViewDidActivate(_ optionView: OptionView)
}

View File

@ -143,13 +143,13 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
isViewVisible = true
// let hasSeenOpenGroupSuggestionSheet = UserDefaults.standard[.hasSeenOpenGroupSuggestionSheet]
// if !hasSeenOpenGroupSuggestionSheet {
// let openGroupSuggestionSheet = OpenGroupSuggestionSheet()
// openGroupSuggestionSheet.modalPresentationStyle = .overFullScreen
// openGroupSuggestionSheet.modalTransitionStyle = .crossDissolve
// present(openGroupSuggestionSheet, animated: true, completion: nil)
// }
let hasSeenPNModeSheet = UserDefaults.standard[.hasSeenPNModeSheet]
if !hasSeenPNModeSheet {
let pnModeSheet = PNModeSheet()
pnModeSheet.modalPresentationStyle = .overFullScreen
pnModeSheet.modalTransitionStyle = .crossDissolve
present(pnModeSheet, animated: true, completion: nil)
}
UserDefaults.standard[.hasLaunchedOnce] = true
}

View File

@ -0,0 +1,87 @@
import PromiseKit
final class PNModeSheet : Sheet, OptionViewDelegate {
private var optionViews: [OptionView] {
[ apnsOptionView, backgroundPollingOptionView ]
}
private var selectedOptionView: OptionView? {
return optionViews.first { $0.isSelected }
}
// MARK: Components
private lazy var apnsOptionView = OptionView(title: NSLocalizedString("Apple Push Notification Service", comment: ""), explanation: NSLocalizedString("Session will use the Apple Push Notification Service to receive push notifications. Youll be notified of new messages reliably and immediately. Using APNs means that this device will communicate directly with Apples servers to retrieve push notifications, which will expose your IP address to Apple. Your messages will still be onion-routed and end-to-end encrypted, so the contents of your messages will remain completely private.", comment: ""), delegate: self, isRecommended: true)
private lazy var backgroundPollingOptionView = OptionView(title: NSLocalizedString("Background Polling", comment: ""), explanation: NSLocalizedString("Session will occasionally check for new messages in the background. This guarantees full privacy protection, but message notifications may be significantly delayed.", comment: ""), delegate: self)
// MARK: Lifecycle
override func populateContentView() {
// Set up title label
let titleLabel = UILabel()
titleLabel.textColor = Colors.text
titleLabel.font = .boldSystemFont(ofSize: isSmallScreen ? Values.largeFontSize : Values.veryLargeFontSize)
titleLabel.text = NSLocalizedString("Push Notifications", comment: "")
titleLabel.numberOfLines = 0
titleLabel.lineBreakMode = .byWordWrapping
// Set up explanation label
let explanationLabel = UILabel()
explanationLabel.textColor = Colors.text
explanationLabel.font = .systemFont(ofSize: Values.smallFontSize)
explanationLabel.text = NSLocalizedString("Session now features two ways to handle push notifications. Make sure to read the descriptions carefully before you choose.", comment: "")
explanationLabel.numberOfLines = 0
explanationLabel.lineBreakMode = .byWordWrapping
// Set up options stack view
let optionsStackView = UIStackView(arrangedSubviews: optionViews)
optionsStackView.axis = .vertical
optionsStackView.spacing = Values.smallSpacing
optionsStackView.alignment = .fill
// Set up confirm button
let confirmButton = Button(style: .prominentOutline, size: .medium)
confirmButton.set(.width, to: 240)
confirmButton.setTitle(NSLocalizedString("Confirm", comment: ""), for: UIControl.State.normal)
confirmButton.addTarget(self, action: #selector(confirm), for: UIControl.Event.touchUpInside)
// Set up dismiss button
let skipButton = Button(style: .regular, size: .medium)
skipButton.set(.width, to: 240)
skipButton.setTitle(NSLocalizedString("Skip", comment: ""), for: UIControl.State.normal)
skipButton.addTarget(self, action: #selector(close), for: UIControl.Event.touchUpInside)
// Set up button stack view
let bottomStackView = UIStackView(arrangedSubviews: [ confirmButton, skipButton ])
bottomStackView.axis = .vertical
bottomStackView.spacing = isSmallScreen ? Values.smallSpacing : Values.mediumSpacing
bottomStackView.alignment = .fill
// Set up main stack view
let stackView = UIStackView(arrangedSubviews: [ titleLabel, explanationLabel, optionsStackView, bottomStackView ])
stackView.axis = .vertical
stackView.spacing = isSmallScreen ? 12 : Values.largeSpacing
stackView.alignment = .center
// Set up constraints
contentView.addSubview(stackView)
stackView.pin(.leading, to: .leading, of: contentView, withInset: isSmallScreen ? Values.mediumSpacing : Values.largeSpacing)
stackView.pin(.top, to: .top, of: contentView, withInset: isSmallScreen ? Values.mediumSpacing : Values.largeSpacing)
contentView.pin(.trailing, to: .trailing, of: stackView, withInset: isSmallScreen ? Values.mediumSpacing : Values.largeSpacing)
contentView.pin(.bottom, to: .bottom, of: stackView, withInset: (isSmallScreen ? Values.mediumSpacing : Values.veryLargeSpacing) + overshoot)
}
// MARK: Interaction
func optionViewDidActivate(_ optionView: OptionView) {
optionViews.filter { $0 != optionView }.forEach { $0.isSelected = false }
}
@objc private func confirm() {
guard selectedOptionView != nil else {
let title = NSLocalizedString("Please Pick an Option", comment: "")
let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default, handler: nil))
return present(alert, animated: true, completion: nil)
}
UserDefaults.standard[.isUsingFullAPNs] = (selectedOptionView == apnsOptionView)
let _: Promise<Void> = SyncPushTokensJob.run(accountManager: AppEnvironment.shared.accountManager, preferences: Environment.shared.preferences)
close()
}
override func close() {
UserDefaults.standard[.hasSeenPNModeSheet] = true
super.close()
}
}

View File

@ -82,7 +82,7 @@ final class PNModeVC : BaseVC, OptionViewDelegate {
}
// MARK: Interaction
fileprivate func optionViewDidActivate(_ optionView: OptionView) {
func optionViewDidActivate(_ optionView: OptionView) {
optionViews.filter { $0 != optionView }.forEach { $0.isSelected = false }
}
@ -94,119 +94,10 @@ final class PNModeVC : BaseVC, OptionViewDelegate {
return present(alert, animated: true, completion: nil)
}
UserDefaults.standard[.isUsingFullAPNs] = (selectedOptionView == apnsOptionView)
UserDefaults.standard[.hasSeenPNModeSheet] = true // Shouldn't be shown to users who've done the new onboarding
TSAccountManager.sharedInstance().didRegister()
let homeVC = HomeVC()
navigationController!.setViewControllers([ homeVC ], animated: true)
let _: Promise<Void> = SyncPushTokensJob.run(accountManager: AppEnvironment.shared.accountManager, preferences: Environment.shared.preferences)
}
}
// MARK: Option View
private extension PNModeVC {
final class OptionView : UIView {
private let title: String
private let explanation: String
private let delegate: OptionViewDelegate
private let isRecommended: Bool
var isSelected = false { didSet { handleIsSelectedChanged() } }
init(title: String, explanation: String, delegate: OptionViewDelegate, isRecommended: Bool = false) {
self.title = title
self.explanation = explanation
self.delegate = delegate
self.isRecommended = isRecommended
super.init(frame: CGRect.zero)
setUpViewHierarchy()
}
override init(frame: CGRect) {
preconditionFailure("Use init(string:explanation:) instead.")
}
required init?(coder: NSCoder) {
preconditionFailure("Use init(string:explanation:) instead.")
}
private func setUpViewHierarchy() {
backgroundColor = Colors.pnOptionBackground
// Round corners
layer.cornerRadius = Values.pnOptionCornerRadius
// Set up border
layer.borderWidth = Values.borderThickness
layer.borderColor = Colors.pnOptionBorder.cgColor
// Set up shadow
layer.shadowColor = UIColor.black.cgColor
layer.shadowOffset = CGSize(width: 0, height: 0.8)
layer.shadowOpacity = isLightMode ? 0.4 : 1
layer.shadowRadius = isLightMode ? 4 : 6
// Set up title label
let titleLabel = UILabel()
titleLabel.textColor = Colors.text
titleLabel.font = .boldSystemFont(ofSize: Values.mediumFontSize)
titleLabel.text = title
titleLabel.numberOfLines = 0
titleLabel.lineBreakMode = .byWordWrapping
// Set up explanation label
let explanationLabel = UILabel()
explanationLabel.textColor = Colors.text
explanationLabel.font = .systemFont(ofSize: Values.verySmallFontSize)
explanationLabel.text = explanation
explanationLabel.numberOfLines = 0
explanationLabel.lineBreakMode = .byWordWrapping
// Set up stack view
let stackView = UIStackView(arrangedSubviews: [ titleLabel, explanationLabel ])
stackView.axis = .vertical
stackView.spacing = 4
stackView.alignment = .fill
addSubview(stackView)
stackView.pin(.leading, to: .leading, of: self, withInset: 12)
stackView.pin(.top, to: .top, of: self, withInset: 12)
self.pin(.trailing, to: .trailing, of: stackView, withInset: 12)
self.pin(.bottom, to: .bottom, of: stackView, withInset: 12)
// Set up recommended label if needed
if isRecommended {
let recommendedLabel = UILabel()
recommendedLabel.textColor = Colors.accent
recommendedLabel.font = .boldSystemFont(ofSize: Values.verySmallFontSize)
recommendedLabel.text = NSLocalizedString("Recommended", comment: "")
stackView.addArrangedSubview(recommendedLabel)
}
// Set up tap gesture recognizer
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
addGestureRecognizer(tapGestureRecognizer)
}
@objc private func handleTap() {
isSelected = !isSelected
}
private func handleIsSelectedChanged() {
let animationDuration: TimeInterval = 0.25
// Animate border color
let newBorderColor = isSelected ? Colors.accent.cgColor : Colors.pnOptionBorder.cgColor
let borderAnimation = CABasicAnimation(keyPath: "borderColor")
borderAnimation.fromValue = layer.shadowColor
borderAnimation.toValue = newBorderColor
borderAnimation.duration = animationDuration
layer.add(borderAnimation, forKey: borderAnimation.keyPath)
layer.borderColor = newBorderColor
// Animate shadow color
let newShadowColor = isSelected ? Colors.newConversationButtonShadow.cgColor : UIColor.black.cgColor
let shadowAnimation = CABasicAnimation(keyPath: "shadowColor")
shadowAnimation.fromValue = layer.shadowColor
shadowAnimation.toValue = newShadowColor
shadowAnimation.duration = animationDuration
layer.add(shadowAnimation, forKey: shadowAnimation.keyPath)
layer.shadowColor = newShadowColor
// Notify delegate
if isSelected { delegate.optionViewDidActivate(self) }
}
}
}
// MARK: Option View Delegate
private protocol OptionViewDelegate {
func optionViewDidActivate(_ optionView: PNModeVC.OptionView)
}

View File

@ -2818,3 +2818,4 @@
"Use APNs" = "Use APNs";
"Recommended" = "Recommended";
"Notification Strategy" = "Notification Strategy";
"Session now features two ways to handle push notifications. Make sure to read the descriptions carefully before you choose." = "Session now features two ways to handle push notifications. Make sure to read the descriptions carefully before you choose.";

View File

@ -297,26 +297,23 @@ NSString *const TSAccountManager_NeedsAccountAttributesUpdateKey = @"TSAccountMa
remainingRetries:(int)remainingRetries
{
BOOL isUsingFullAPNs = [NSUserDefaults.standardUserDefaults boolForKey:@"isUsingFullAPNs"];
if (isUsingFullAPNs) {
[LKPushNotificationManager registerWithToken:pushToken hexEncodedPublicKey:self.localNumber]
.then(^() {
successHandler();
})
.catch(^(NSError *error) {
if (remainingRetries > 0) {
[self registerForPushNotificationsWithPushToken:pushToken
voipToken:voipToken
success:successHandler
failure:failureHandler
remainingRetries:remainingRetries - 1];
} else {
if (!IsNSErrorNetworkFailure(error)) {
OWSProdError([OWSAnalyticsEvents accountsErrorRegisterPushTokensFailed]);
}
failureHandler(error);
AnyPromise *promise = isUsingFullAPNs ? [LKPushNotificationManager registerWithToken:pushToken hexEncodedPublicKey:self.localNumber]
: [LKPushNotificationManager registerWithToken:pushToken];
promise
.then(^() {
successHandler();
})
.catch(^(NSError *error) {
if (remainingRetries > 0) {
[self registerForPushNotificationsWithPushToken:pushToken voipToken:voipToken success:successHandler failure:failureHandler
remainingRetries:remainingRetries - 1];
} else {
if (!IsNSErrorNetworkFailure(error)) {
OWSProdError([OWSAnalyticsEvents accountsErrorRegisterPushTokensFailed]);
}
});
}
failureHandler(error);
}
});
}
- (void)registerWithPhoneNumber:(NSString *)phoneNumber

View File

@ -17,8 +17,7 @@ public final class LokiPushNotificationManager : NSObject {
// MARK: Registration
/// Registers the user for silent push notifications (that then trigger the app
/// into fetching messages). Only the user's device token is needed for this.
@objc(registerWithToken:)
static func register(with token: Data) {
static func register(with token: Data) -> Promise<Void> {
let hexEncodedToken = token.toHexString()
let userDefaults = UserDefaults.standard
let oldToken = userDefaults[.deviceToken]
@ -26,16 +25,18 @@ public final class LokiPushNotificationManager : NSObject {
let isUsingFullAPNs = userDefaults[.isUsingFullAPNs]
let now = Date().timeIntervalSince1970
guard hexEncodedToken != oldToken || now - lastUploadTime < tokenExpirationInterval else {
return print("[Loki] Device token hasn't changed; no need to re-upload.")
print("[Loki] Device token hasn't changed; no need to re-upload.")
return Promise<Void> { $0.fulfill(()) }
}
guard !isUsingFullAPNs else {
return print("[Loki] Using full APNs; ignoring call to register(with:).")
print("[Loki] Using full APNs; ignoring call to register(with:).")
return Promise<Void> { $0.fulfill(()) }
}
let parameters = [ "token" : hexEncodedToken ]
let url = URL(string: server + "register")!
let request = TSRequest(url: url, method: "POST", parameters: parameters)
request.allHTTPHeaderFields = [ "Content-Type" : "application/json" ]
TSNetworkManager.shared().makeRequest(request, success: { _, response in
let promise = TSNetworkManager.shared().makePromise(request: request).map { _, response in
guard let json = response as? JSON else {
return print("[Loki] Couldn't register device token.")
}
@ -45,9 +46,19 @@ public final class LokiPushNotificationManager : NSObject {
userDefaults[.deviceToken] = hexEncodedToken
userDefaults[.lastDeviceTokenUpload] = now
userDefaults[.isUsingFullAPNs] = false
}, failure: { _, error in
return
}
promise.catch { error in
print("[Loki] Couldn't register device token.")
})
}
return promise
}
/// Registers the user for silent push notifications (that then trigger the app
/// into fetching messages). Only the user's device token is needed for this.
@objc(registerWithToken:)
static func objc_register(with token: Data) -> AnyPromise {
return AnyPromise.from(register(with: token))
}
/// Registers the user for normal push notifications. Requires the user's device
@ -78,6 +89,8 @@ public final class LokiPushNotificationManager : NSObject {
return promise
}
/// Registers the user for normal push notifications. Requires the user's device
/// token and their Session ID.
@objc(registerWithToken:hexEncodedPublicKey:)
static func objc_register(with token: Data, hexEncodedPublicKey: String) -> AnyPromise {
return AnyPromise.from(register(with: token, hexEncodedPublicKey: hexEncodedPublicKey))

View File

@ -5,6 +5,7 @@ public enum LKUserDefaults {
public enum Bool : Swift.String {
case hasLaunchedOnce
case hasSeenOpenGroupSuggestionSheet
case hasSeenPNModeSheet
case hasViewedSeed
/// Whether the device was unlinked as a slave device (used to notify the user on the landing screen).
case wasUnlinked