Sketch out the onboarding permissions view.
This commit is contained in:
parent
bb64dc1bc9
commit
2c0aa7a222
|
@ -72,6 +72,8 @@
|
|||
34480B671FD0AA9400BC14EF /* UIFont+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = 34480B651FD0AA9400BC14EF /* UIFont+OWS.m */; };
|
||||
34480B681FD0AA9400BC14EF /* UIFont+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = 34480B661FD0AA9400BC14EF /* UIFont+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
344825C6211390C800DB4BD8 /* OWSOrphanDataCleaner.m in Sources */ = {isa = PBXBuildFile; fileRef = 344825C5211390C800DB4BD8 /* OWSOrphanDataCleaner.m */; };
|
||||
3448E15C22133274004B052E /* OnboardingPermissionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3448E15B22133274004B052E /* OnboardingPermissionsViewController.swift */; };
|
||||
3448E15E221333F5004B052E /* OnboardingDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3448E15D221333F5004B052E /* OnboardingDelegate.swift */; };
|
||||
344F248D2007CCD600CFB4F4 /* DisplayableText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344F248C2007CCD600CFB4F4 /* DisplayableText.swift */; };
|
||||
345BC30C2047030700257B7C /* OWS2FASettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 345BC30B2047030600257B7C /* OWS2FASettingsViewController.m */; };
|
||||
3461284B1FD0B94000532771 /* SAELoadViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3461284A1FD0B93F00532771 /* SAELoadViewController.swift */; };
|
||||
|
@ -723,6 +725,8 @@
|
|||
34480B661FD0AA9400BC14EF /* UIFont+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIFont+OWS.h"; sourceTree = "<group>"; };
|
||||
344825C4211390C700DB4BD8 /* OWSOrphanDataCleaner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOrphanDataCleaner.h; sourceTree = "<group>"; };
|
||||
344825C5211390C800DB4BD8 /* OWSOrphanDataCleaner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOrphanDataCleaner.m; sourceTree = "<group>"; };
|
||||
3448E15B22133274004B052E /* OnboardingPermissionsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingPermissionsViewController.swift; sourceTree = "<group>"; };
|
||||
3448E15D221333F5004B052E /* OnboardingDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingDelegate.swift; sourceTree = "<group>"; };
|
||||
34491FC11FB0F78500B3E5A3 /* my */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = my; path = translations/my.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
344F248C2007CCD600CFB4F4 /* DisplayableText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayableText.swift; sourceTree = "<group>"; };
|
||||
345BC30A2047030600257B7C /* OWS2FASettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS2FASettingsViewController.h; sourceTree = "<group>"; };
|
||||
|
@ -1439,6 +1443,8 @@
|
|||
3441FD9E21A3604F00BB9542 /* BackupRestoreViewController.swift */,
|
||||
340FC879204DAC8C007AEB0F /* CodeVerificationViewController.h */,
|
||||
340FC877204DAC8C007AEB0F /* CodeVerificationViewController.m */,
|
||||
3448E15D221333F5004B052E /* OnboardingDelegate.swift */,
|
||||
3448E15B22133274004B052E /* OnboardingPermissionsViewController.swift */,
|
||||
346E9D5321B040B600562252 /* RegistrationController.swift */,
|
||||
340FC878204DAC8C007AEB0F /* RegistrationViewController.h */,
|
||||
340FC876204DAC8C007AEB0F /* RegistrationViewController.m */,
|
||||
|
@ -3496,6 +3502,7 @@
|
|||
4542DF54208D40AC007B4E76 /* LoadingViewController.swift in Sources */,
|
||||
34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */,
|
||||
34D1F0B71F87F8850066283D /* OWSGenericAttachmentView.m in Sources */,
|
||||
3448E15C22133274004B052E /* OnboardingPermissionsViewController.swift in Sources */,
|
||||
34D920E720E179C200D51158 /* OWSMessageFooterView.m in Sources */,
|
||||
341341EF2187467A00192D59 /* ConversationViewModel.m in Sources */,
|
||||
348BB25D20A0C5530047AEC2 /* ContactShareViewHelper.swift in Sources */,
|
||||
|
@ -3586,6 +3593,7 @@
|
|||
34D1F0861F8678AA0066283D /* ConversationViewController.m in Sources */,
|
||||
3427C64320F500E000EEC730 /* OWSMessageTimerView.m in Sources */,
|
||||
B90418E6183E9DD40038554A /* DateUtil.m in Sources */,
|
||||
3448E15E221333F5004B052E /* OnboardingDelegate.swift in Sources */,
|
||||
340FC8BD204DAC8D007AEB0F /* ShowGroupMembersViewController.m in Sources */,
|
||||
3496956F21A301A100DCFE74 /* OWSBackupLazyRestore.swift in Sources */,
|
||||
459311FC1D75C948008DD4F0 /* OWSDeviceTableViewCell.m in Sources */,
|
||||
|
|
|
@ -170,6 +170,6 @@ public class BackupRestoreViewController: OWSTableViewController {
|
|||
// MARK: Orientation
|
||||
|
||||
public override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
||||
return DefaultUIInterfaceOrientationMask()
|
||||
return .portrait
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@objc
|
||||
public protocol OnboardingController: class {
|
||||
func onboardingPermissionsWasSkipped(viewController: UIViewController)
|
||||
func onboardingPermissionsDidComplete(viewController: UIViewController)
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import PromiseKit
|
||||
|
||||
@objc
|
||||
public class MockOnboardingController: NSObject, OnboardingController {
|
||||
public func onboardingPermissionsWasSkipped(viewController: UIViewController) {}
|
||||
|
||||
public func onboardingPermissionsDidComplete(viewController: UIViewController) {}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
@objc
|
||||
public class OnboardingPermissionsViewController: OWSViewController {
|
||||
// Unlike a delegate, the OnboardingController we should retain a strong
|
||||
// reference to the onboardingController.
|
||||
private var onboardingController: OnboardingController
|
||||
|
||||
@objc
|
||||
public init(onboardingController: OnboardingController) {
|
||||
self.delegate = onboardingController
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
@available(*, unavailable, message: "use other init() instead.")
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
notImplemented()
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
override public func loadView() {
|
||||
super.loadView()
|
||||
|
||||
view.backgroundColor = Theme.backgroundColor
|
||||
view.layoutMargins = UIEdgeInsets(top: 32, left: 32, bottom: 32, right: 32)
|
||||
|
||||
// TODO:
|
||||
// navigationItem.title = NSLocalizedString("SETTINGS_BACKUP", comment: "Label for the backup view in app settings.")
|
||||
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("NAVIGATION_ITEM_SKIP_BUTTON", comment: "A button to skip a view."),
|
||||
style: .plain,
|
||||
target: self,
|
||||
action: #selector(skipWasPressed))
|
||||
|
||||
let titleLabel = UILabel()
|
||||
titleLabel.text = NSLocalizedString("ONBOARDING_PERMISSIONS_TITLE", comment: "Title of the 'onboarding permissions' view.")
|
||||
titleLabel.textColor = Theme.primaryColor
|
||||
titleLabel.font = UIFont.ows_dynamicTypeTitle2.ows_mediumWeight()
|
||||
titleLabel.numberOfLines = 0
|
||||
titleLabel.lineBreakMode = .byWordWrapping
|
||||
titleLabel.textAlignment = .center
|
||||
view.addSubview(titleLabel)
|
||||
titleLabel.autoPinWidthToSuperviewMargins()
|
||||
titleLabel.autoPinEdge(toSuperviewMargin: .top)
|
||||
|
||||
let explainerLabel = UILabel()
|
||||
// TODO: Finalize copy.
|
||||
explainerLabel.text = NSLocalizedString("ONBOARDING_PERMISSIONS_EXPLANATION", comment: "Explanation in the 'onboarding permissions' view.")
|
||||
explainerLabel.textColor = Theme.secondaryColor
|
||||
explainerLabel.font = UIFont.ows_dynamicTypeCaption1
|
||||
explainerLabel.numberOfLines = 0
|
||||
explainerLabel.textAlignment = .center
|
||||
explainerLabel.lineBreakMode = .byWordWrapping
|
||||
explainerLabel.isUserInteractionEnabled = true
|
||||
explainerLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(explainerLabelTapped)))
|
||||
|
||||
// TODO: Make sure this all fits if dynamic font sizes are maxed out.
|
||||
let buttonHeight: CGFloat = 48
|
||||
let giveAccessButton = OWSFlatButton.button(title: NSLocalizedString("ONBOARDING_PERMISSIONS_GIVE_ACCESS_BUTTON",
|
||||
comment: "Label for the 'give access' button in the 'onboarding permissions' view."),
|
||||
font: OWSFlatButton.fontForHeight(buttonHeight),
|
||||
titleColor: .white,
|
||||
backgroundColor: .ows_materialBlue,
|
||||
target: self,
|
||||
selector: #selector(giveAccessPressed))
|
||||
giveAccessButton.autoSetDimension(.height, toSize: buttonHeight)
|
||||
|
||||
let notNowButton = OWSFlatButton.button(title: NSLocalizedString("ONBOARDING_PERMISSIONS_GIVE_ACCESS_BUTTON",
|
||||
comment: "Label for the 'give access' button in the 'onboarding permissions' view."),
|
||||
font: OWSFlatButton.fontForHeight(buttonHeight),
|
||||
titleColor: .white,
|
||||
backgroundColor: .ows_materialBlue,
|
||||
target: self,
|
||||
selector: #selector(notNowPressed))
|
||||
notNowButton.autoSetDimension(.height, toSize: buttonHeight)
|
||||
|
||||
let buttonStack = UIStackView(arrangedSubviews: [
|
||||
giveAccessButton,
|
||||
notNowButton
|
||||
])
|
||||
buttonStack.axis = .vertical
|
||||
buttonStack.alignment = .fill
|
||||
buttonStack.spacing = 12
|
||||
|
||||
let stackView = UIStackView(arrangedSubviews: [
|
||||
explainerLabel,
|
||||
buttonStack
|
||||
])
|
||||
stackView.axis = .vertical
|
||||
stackView.alignment = .fill
|
||||
stackView.spacing = 40
|
||||
view.addSubview(stackView)
|
||||
stackView.autoPinWidthToSuperviewMargins()
|
||||
stackView.autoVCenterInSuperview()
|
||||
NSLayoutConstraint.autoSetPriority(.defaultHigh) {
|
||||
stackView.autoPinEdge(.top, to: .bottom, of: titleLabel, withOffset: 20, relation: .greaterThanOrEqual)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Request Access
|
||||
|
||||
private func requestAccess() {
|
||||
Logger.info("")
|
||||
|
||||
// TODO: We need to defer app's request notification permissions until onboarding is complete.
|
||||
requestContactsAccess().then { _ in
|
||||
return PushRegistrationManager.shared.registerUserNotificationSettings()
|
||||
}.done { [weak self] in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
self.onboardingController.onboardingPermissionsDidComplete(viewController: self)
|
||||
}.retainUntilComplete()
|
||||
}
|
||||
|
||||
private func requestContactsAccess() -> Promise<Void> {
|
||||
Logger.info("")
|
||||
|
||||
let (promise, resolver) = Promise<Void>.pending()
|
||||
CNContactStore().requestAccess(for: CNEntityType.contacts) { (granted, error) -> Void in
|
||||
if granted {
|
||||
Logger.info("Granted.")
|
||||
} else {
|
||||
Logger.error("Error: \(String(describing: error)).")
|
||||
}
|
||||
// Always fulfill.
|
||||
resolver.fulfill(())
|
||||
}
|
||||
return promise
|
||||
}
|
||||
|
||||
// MARK: Orientation
|
||||
|
||||
public override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
||||
return .portrait
|
||||
}
|
||||
|
||||
// MARK: - Events
|
||||
|
||||
@objc func skipWasPressed() {
|
||||
Logger.info("")
|
||||
|
||||
onboardingController.onboardingPermissionsWasSkipped(viewController: self)
|
||||
}
|
||||
|
||||
@objc func explainerLabelTapped(sender: UIGestureRecognizer) {
|
||||
guard sender.state == .recognized else {
|
||||
return
|
||||
}
|
||||
// TODO:
|
||||
}
|
||||
|
||||
@objc func giveAccessPressed() {
|
||||
Logger.info("")
|
||||
|
||||
requestAccess()
|
||||
}
|
||||
|
||||
@objc func notNowPressed() {
|
||||
Logger.info("")
|
||||
|
||||
delegate?.onboardingPermissionsWasSkipped(viewController: self)
|
||||
}
|
||||
}
|
|
@ -127,7 +127,7 @@ public enum PushRegistrationError: Error {
|
|||
|
||||
// User notification settings must be registered *before* AppDelegate will
|
||||
// return any requested push tokens.
|
||||
private func registerUserNotificationSettings() -> Promise<Void> {
|
||||
public func registerUserNotificationSettings() -> Promise<Void> {
|
||||
AssertIsOnMainThread()
|
||||
Logger.info("registering user notification settings")
|
||||
return notificationPresenter.registerNotificationSettings()
|
||||
|
|
|
@ -26,6 +26,7 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value);
|
|||
// Pins the width of this view to the width of its superview, with uniform margins.
|
||||
- (NSArray<NSLayoutConstraint *> *)autoPinWidthToSuperviewWithMargin:(CGFloat)margin;
|
||||
- (NSArray<NSLayoutConstraint *> *)autoPinWidthToSuperview;
|
||||
- (NSArray<NSLayoutConstraint *> *)autoPinWidthToSuperviewMargins;
|
||||
// Pins the height of this view to the height of its superview, with uniform margins.
|
||||
- (NSArray<NSLayoutConstraint *> *)autoPinHeightToSuperviewWithMargin:(CGFloat)margin;
|
||||
- (NSArray<NSLayoutConstraint *> *)autoPinHeightToSuperview;
|
||||
|
|
|
@ -44,6 +44,15 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value)
|
|||
return result;
|
||||
}
|
||||
|
||||
- (NSArray<NSLayoutConstraint *> *)autoPinWidthToSuperviewMargins
|
||||
{
|
||||
NSArray<NSLayoutConstraint *> *result = @[
|
||||
[self autoPinEdgeToSuperviewMargin:ALEdgeLeading],
|
||||
[self autoPinEdgeToSuperviewMargin:ALEdgeTrailing],
|
||||
];
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSArray<NSLayoutConstraint *> *)autoPinWidthToSuperview
|
||||
{
|
||||
NSArray<NSLayoutConstraint *> *result = @[
|
||||
|
|
Loading…
Reference in New Issue